@frank-auth/react
Version:
Flexible and customizable React UI components for Frank Authentication
1 lines • 18.6 kB
Source Map (JSON)
{"version":3,"file":"user-profile-modal.cjs","sources":["../../../../../src/components/auth/user-profile/user-profile-modal.tsx"],"sourcesContent":["/**\n * @frank-auth/react - User Profile Modal\n *\n * Modal wrapper for the user profile component with responsive\n * design and customizable modal behavior.\n */\n\n'use client';\n\nimport React from 'react';\nimport {Button, Modal, ModalBody, ModalContent, ModalFooter, ModalHeader, useDisclosure,} from '@heroui/react';\nimport {useConfig} from '../../../hooks/use-config';\nimport {UserProfile, type UserProfileProps} from './user-profile';\n\n// ============================================================================\n// User Profile Modal Interface\n// ============================================================================\n\nexport interface UserProfileModalProps extends Omit<UserProfileProps, 'onClose' | 'headerContent'> {\n /**\n * Modal trigger element\n */\n trigger?: React.ReactNode;\n\n /**\n * Whether modal is open (controlled)\n */\n isOpen?: boolean;\n\n /**\n * Modal open change handler (controlled)\n */\n onOpenChange?: (isOpen: boolean) => void;\n\n /**\n * Modal size\n */\n modalSize?: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | '2xl' | '3xl' | '4xl' | '5xl' | 'full';\n\n /**\n * Modal placement\n */\n placement?: 'auto' | 'top' | 'center' | 'bottom';\n\n /**\n * Modal backdrop type\n */\n backdrop?: 'transparent' | 'opaque' | 'blur';\n\n /**\n * Whether modal is dismissable\n */\n isDismissable?: boolean;\n\n /**\n * Whether to close on outside click\n */\n closeOnOutsideClick?: boolean;\n\n /**\n * Whether to hide close button\n */\n hideCloseButton?: boolean;\n\n /**\n * Custom modal className\n */\n modalClassName?: string;\n\n /**\n * Modal title\n */\n title?: string;\n\n /**\n * Modal subtitle\n */\n subtitle?: string;\n\n /**\n * Custom header content\n */\n customHeaderContent?: React.ReactNode;\n\n /**\n * Custom footer actions\n */\n footerActions?: React.ReactNode;\n\n /**\n * Show default footer actions\n */\n showDefaultFooter?: boolean;\n\n /**\n * Save button text\n */\n saveButtonText?: string;\n\n /**\n * Cancel button text\n */\n cancelButtonText?: string;\n\n /**\n * Save handler\n */\n onSave?: () => void;\n\n /**\n * Cancel handler\n */\n onCancel?: () => void;\n\n /**\n * Modal close handler\n */\n onClose?: () => void;\n\n /**\n * Whether save button is loading\n */\n isSaveLoading?: boolean;\n\n /**\n * Whether save button is disabled\n */\n isSaveDisabled?: boolean;\n\n /**\n * Scroll behavior\n */\n scrollBehavior?: 'inside' | 'outside';\n\n /**\n * Whether modal should be keyboard focusable\n */\n isKeyboardDismissDisabled?: boolean;\n\n /**\n * Portal container\n */\n portalContainer?: Element;\n\n /**\n * Auto focus element\n */\n autoFocus?: boolean;\n\n /**\n * Default tab to show when modal opens\n */\n defaultActiveTab?: string;\n}\n\n// ============================================================================\n// User Profile Modal Component\n// ============================================================================\n\nexport function UserProfileModal({\n trigger,\n isOpen: controlledIsOpen,\n onOpenChange: controlledOnOpenChange,\n modalSize = 'lg',\n placement = 'center',\n backdrop = 'opaque',\n isDismissable = true,\n closeOnOutsideClick = true,\n hideCloseButton = false,\n modalClassName = '',\n title = 'Profile Settings',\n subtitle = 'Manage your account settings and preferences',\n customHeaderContent,\n footerActions,\n showDefaultFooter = false,\n saveButtonText = 'Save Changes',\n cancelButtonText = 'Cancel',\n onSave,\n onCancel,\n onClose,\n isSaveLoading = false,\n isSaveDisabled = false,\n scrollBehavior = 'inside',\n isKeyboardDismissDisabled = false,\n portalContainer,\n autoFocus = true,\n defaultActiveTab,\n // UserProfile props\n defaultTab,\n tabs,\n hideTabs,\n showOrganizationSettings,\n showSecuritySettings,\n showMFASettings,\n showPasskeySettings,\n className,\n variant = 'flat',\n orientation = 'horizontal',\n tabPlacement = 'top',\n footerContent,\n onProfileUpdate,\n onSuccess,\n onError,\n isLoading,\n isDisabled,\n size = 'md',\n customTabs,\n }: UserProfileModalProps) {\n const { components } = useConfig();\n\n // Use internal disclosure if not controlled\n const disclosure = useDisclosure();\n const isOpen = controlledIsOpen !== undefined ? controlledIsOpen : disclosure.isOpen;\n const onOpenChange = controlledOnOpenChange || disclosure.onOpenChange;\n\n // Custom component override\n const CustomUserProfileModal = components.UserProfileModal;\n if (CustomUserProfileModal) {\n return <CustomUserProfileModal {...{\n trigger, isOpen: controlledIsOpen, onOpenChange: controlledOnOpenChange,\n modalSize, placement, backdrop, isDismissable, closeOnOutsideClick,\n hideCloseButton, modalClassName, title, subtitle, customHeaderContent,\n footerActions, showDefaultFooter, saveButtonText, cancelButtonText,\n onSave, onCancel, onClose, isSaveLoading, isSaveDisabled,\n scrollBehavior, isKeyboardDismissDisabled, portalContainer, autoFocus,\n defaultActiveTab, defaultTab, tabs, hideTabs, showOrganizationSettings,\n showSecuritySettings, showMFASettings, showPasskeySettings, className,\n variant, orientation, tabPlacement, footerContent, onProfileUpdate,\n onSuccess, onError, isLoading, isDisabled, size, customTabs\n }} />;\n }\n\n // Handle modal close\n const handleClose = React.useCallback(() => {\n onClose?.();\n onOpenChange(false);\n }, [onClose, onOpenChange]);\n\n // Handle cancel\n const handleCancel = React.useCallback(() => {\n onCancel?.();\n handleClose();\n }, [onCancel, handleClose]);\n\n // Handle save\n const handleSave = React.useCallback(() => {\n onSave?.();\n // Note: Don't close modal here, let the parent handle success/error\n }, [onSave]);\n\n // Success handler that can close modal\n const handleSuccess = React.useCallback((message: string) => {\n onSuccess?.(message);\n if (onSave) {\n // If there's a save handler, the parent decides when to close\n return;\n }\n // Otherwise, close on success\n handleClose();\n }, [onSuccess, onSave, handleClose]);\n\n // Render trigger button if provided\n const triggerButton = trigger && React.cloneElement(trigger as React.ReactElement, {\n onPress: () => onOpenChange(true),\n });\n\n return (\n <>\n {triggerButton}\n\n <Modal\n isOpen={isOpen}\n onOpenChange={onOpenChange}\n size={modalSize}\n placement={placement}\n backdrop={backdrop}\n isDismissable={isDismissable}\n hideCloseButton={hideCloseButton}\n scrollBehavior={scrollBehavior}\n isKeyboardDismissDisabled={isKeyboardDismissDisabled}\n portalContainer={portalContainer}\n shouldBlockScroll={true}\n className={modalClassName}\n classNames={{\n base: 'max-h-[90vh]',\n body: 'p-0',\n }}\n >\n <ModalContent>\n {(onModalClose) => (\n <>\n {/* Header */}\n {(customHeaderContent || title) && (\n <ModalHeader className=\"flex flex-col gap-1\">\n {customHeaderContent || (\n <div>\n <h3 className=\"text-lg font-semibold\">{title}</h3>\n {subtitle && (\n <p className=\"text-sm text-default-500 font-normal\">\n {subtitle}\n </p>\n )}\n </div>\n )}\n </ModalHeader>\n )}\n\n {/* Body */}\n <ModalBody>\n <UserProfile\n defaultTab={defaultActiveTab || defaultTab}\n tabs={tabs}\n hideTabs={hideTabs}\n showOrganizationSettings={showOrganizationSettings}\n showSecuritySettings={showSecuritySettings}\n showMFASettings={showMFASettings}\n showPasskeySettings={showPasskeySettings}\n className={className}\n variant={variant}\n orientation={orientation}\n tabPlacement={tabPlacement}\n footerContent={footerContent}\n onProfileUpdate={onProfileUpdate}\n onSuccess={handleSuccess}\n onError={onError}\n onClose={handleClose}\n isLoading={isLoading}\n isDisabled={isDisabled}\n size={size}\n customTabs={customTabs}\n />\n </ModalBody>\n\n {/* Footer */}\n {(footerActions || showDefaultFooter) && (\n <ModalFooter>\n {footerActions || (\n <div className=\"flex gap-2\">\n <Button\n variant=\"light\"\n onPress={handleCancel}\n isDisabled={isSaveLoading}\n >\n {cancelButtonText}\n </Button>\n {onSave && (\n <Button\n color=\"primary\"\n onPress={handleSave}\n isLoading={isSaveLoading}\n isDisabled={isSaveDisabled}\n >\n {saveButtonText}\n </Button>\n )}\n </div>\n )}\n </ModalFooter>\n )}\n </>\n )}\n </ModalContent>\n </Modal>\n </>\n );\n}\n\n// ============================================================================\n// Hook for Modal Control\n// ============================================================================\n\nexport function useUserProfileModal() {\n const disclosure = useDisclosure();\n\n return {\n ...disclosure,\n openProfile: disclosure.onOpen,\n closeProfile: disclosure.onClose,\n toggleProfile: () => disclosure.onOpenChange(!disclosure.isOpen),\n };\n}\n\n// ============================================================================\n// Export\n// ============================================================================\n\nexport default UserProfileModal;"],"names":["UserProfileModal","trigger","controlledIsOpen","controlledOnOpenChange","modalSize","placement","backdrop","isDismissable","closeOnOutsideClick","hideCloseButton","modalClassName","title","subtitle","customHeaderContent","footerActions","showDefaultFooter","saveButtonText","cancelButtonText","onSave","onCancel","onClose","isSaveLoading","isSaveDisabled","scrollBehavior","isKeyboardDismissDisabled","portalContainer","autoFocus","defaultActiveTab","defaultTab","tabs","hideTabs","showOrganizationSettings","showSecuritySettings","showMFASettings","showPasskeySettings","className","variant","orientation","tabPlacement","footerContent","onProfileUpdate","onSuccess","onError","isLoading","isDisabled","size","customTabs","components","useConfig","disclosure","useDisclosure","isOpen","onOpenChange","CustomUserProfileModal","jsx","handleClose","React","handleCancel","handleSave","handleSuccess","message","triggerButton","jsxs","Fragment","Modal","ModalContent","onModalClose","ModalHeader","ModalBody","UserProfile","ModalFooter","Button","useUserProfileModal"],"mappings":"8RA+JO,SAASA,GAAiB,CACI,QAAAC,EACA,OAAQC,EACR,aAAcC,EACd,UAAAC,EAAY,KACZ,UAAAC,EAAY,SACZ,SAAAC,EAAW,SACX,cAAAC,EAAgB,GAChB,oBAAAC,EAAsB,GACtB,gBAAAC,EAAkB,GAClB,eAAAC,EAAiB,GACjB,MAAAC,EAAQ,mBACR,SAAAC,EAAW,+CACX,oBAAAC,EACA,cAAAC,EACA,kBAAAC,EAAoB,GACpB,eAAAC,EAAiB,eACjB,iBAAAC,EAAmB,SACnB,OAAAC,EACA,SAAAC,EACA,QAAAC,EACA,cAAAC,EAAgB,GAChB,eAAAC,EAAiB,GACjB,eAAAC,EAAiB,SACjB,0BAAAC,EAA4B,GAC5B,gBAAAC,EACA,UAAAC,EAAY,GACZ,iBAAAC,EAEA,WAAAC,EACA,KAAAC,EACA,SAAAC,EACA,yBAAAC,EACA,qBAAAC,EACA,gBAAAC,EACA,oBAAAC,EACA,UAAAC,EACA,QAAAC,EAAU,OACV,YAAAC,EAAc,aACd,aAAAC,EAAe,MACf,cAAAC,EACA,gBAAAC,EACA,UAAAC,EACA,QAAAC,EACA,UAAAC,EACA,WAAAC,EACA,KAAAC,EAAO,KACP,WAAAC,CACJ,EAA0B,CACjD,KAAA,CAAE,WAAAC,EAAW,EAAIC,aAAU,EAG3BC,EAAaC,EAAAA,cAAc,EAC3BC,GAASjD,IAAqB,OAAYA,EAAmB+C,EAAW,OACxEG,EAAejD,GAA0B8C,EAAW,aAGpDI,EAAyBN,GAAW,iBAC1C,GAAIM,EACO,OAAAC,EAAA,IAACD,GACJ,QAAApD,EAAS,OAAQC,EAAkB,aAAcC,EACjD,UAAAC,EAAW,UAAAC,EAAW,SAAAC,EAAU,cAAAC,EAAe,oBAAAC,EAC/C,gBAAAC,EAAiB,eAAAC,EAAgB,MAAAC,EAAO,SAAAC,EAAU,oBAAAC,EAClD,cAAAC,EAAe,kBAAAC,EAAmB,eAAAC,EAAgB,iBAAAC,EAClD,OAAAC,EAAQ,SAAAC,EAAU,QAAAC,EAAS,cAAAC,EAAe,eAAAC,EAC1C,eAAAC,EAAgB,0BAAAC,EAA2B,gBAAAC,EAAiB,UAAAC,EAC5D,iBAAAC,EAAkB,WAAAC,EAAY,KAAAC,EAAM,SAAAC,EAAU,yBAAAC,EAC9C,qBAAAC,EAAsB,gBAAAC,EAAiB,oBAAAC,EAAqB,UAAAC,EAC5D,QAAAC,EAAS,YAAAC,EAAa,aAAAC,EAAc,cAAAC,EAAe,gBAAAC,EACnD,UAAAC,EAAW,QAAAC,EAAS,UAAAC,EAAW,WAAAC,EAAY,KAAAC,EAAM,WAAAC,EAClD,EAID,MAAAS,EAAcC,UAAM,YAAY,IAAM,CAC9BpC,IAAA,EACVgC,EAAa,EAAK,CAAA,EACnB,CAAChC,EAASgC,CAAY,CAAC,EAGpBK,GAAeD,UAAM,YAAY,IAAM,CAC9BrC,IAAA,EACCoC,EAAA,CAAA,EACb,CAACpC,EAAUoC,CAAW,CAAC,EAGpBG,GAAaF,UAAM,YAAY,IAAM,CAC9BtC,IAAA,CAAA,EAEV,CAACA,CAAM,CAAC,EAGLyC,GAAgBH,EAAAA,QAAM,YAAaI,GAAoB,CACzDnB,IAAYmB,CAAO,EACf,CAAA1C,GAKQqC,EAAA,CACb,EAAA,CAACd,EAAWvB,EAAQqC,CAAW,CAAC,EAG7BM,GAAgB5D,GAAWuD,UAAM,aAAavD,EAA+B,CAC/E,QAAS,IAAMmD,EAAa,EAAI,CAAA,CACnC,EAED,OAESU,EAAA,KAAAC,WAAA,CAAA,SAAA,CAAAF,GAEDP,EAAA,IAACU,EAAA,MAAA,CACG,OAAAb,GACA,aAAAC,EACA,KAAMhD,EACN,UAAAC,EACA,SAAAC,EACA,cAAAC,EACA,gBAAAE,EACA,eAAAc,EACA,0BAAAC,EACA,gBAAAC,EACA,kBAAmB,GACnB,UAAWf,EACX,WAAY,CACR,KAAM,eACN,KAAM,KACV,EAEA,SAAC4C,EAAAA,IAAAW,EAAA,aAAA,CACI,SAACC,GAGQJ,EAAA,KAAAC,WAAA,CAAA,SAAA,EAAAlD,GAAuBF,IACpB2C,MAAAa,EAAAA,YAAA,CAAY,UAAU,sBAClB,SAAAtD,UACI,MACG,CAAA,SAAA,CAACyC,EAAA,IAAA,KAAA,CAAG,UAAU,wBAAyB,SAAM3C,EAAA,EAC5CC,GACG0C,EAAA,IAAC,IAAE,CAAA,UAAU,uCACR,SACL1C,CAAA,CAAA,CAAA,CAAA,CAER,CAER,CAAA,QAIHwD,EAAAA,UACG,CAAA,SAAAd,EAAA,IAACe,GAAA,YAAA,CACG,WAAY1C,GAAoBC,EAChC,KAAAC,EACA,SAAAC,EACA,yBAAAC,EACA,qBAAAC,EACA,gBAAAC,EACA,oBAAAC,EACA,UAAAC,EACA,QAAAC,EACA,YAAAC,EACA,aAAAC,EACA,cAAAC,EACA,gBAAAC,EACA,UAAWmB,GACX,QAAAjB,EACA,QAASa,EACT,UAAAZ,EACA,WAAAC,EACA,KAAAC,EACA,WAAAC,CAAA,CAAA,EAER,GAGEhC,GAAiBC,IACduC,MAAAgB,EAAAA,YAAA,CACI,YACIR,EAAAA,KAAA,MAAA,CAAI,UAAU,aACX,SAAA,CAAAR,EAAA,IAACiB,EAAA,OAAA,CACG,QAAQ,QACR,QAASd,GACT,WAAYpC,EAEX,SAAAJ,CAAA,CACL,EACCC,GACGoC,EAAA,IAACiB,EAAA,OAAA,CACG,MAAM,UACN,QAASb,GACT,UAAWrC,EACX,WAAYC,EAEX,SAAAN,CAAA,CAAA,CACL,CAAA,CAER,CAER,CAAA,CAAA,CAAA,CAER,CAER,CAAA,CAAA,CAAA,CACJ,EACJ,CAER,CAMO,SAASwD,IAAsB,CAClC,MAAMvB,EAAaC,EAAAA,cAAc,EAE1B,MAAA,CACH,GAAGD,EACH,YAAaA,EAAW,OACxB,aAAcA,EAAW,QACzB,cAAe,IAAMA,EAAW,aAAa,CAACA,EAAW,MAAM,CACnE,CACJ"}