@brycks/core-front 0.3.2 → 0.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/feedback/Modal/Modal.cjs +1 -1
- package/dist/components/feedback/Modal/Modal.cjs.map +1 -1
- package/dist/components/feedback/Modal/Modal.js +7 -6
- package/dist/components/feedback/Modal/Modal.js.map +1 -1
- package/dist/feedback.d.ts +1 -1
- package/dist/index.d.ts +1 -1
- package/package.json +1 -1
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),t=require("react"),A=require("react-dom"),P=require("../../../utils/styles.cjs"),E=require("../../../design-system/primitives/layout.cjs"),s=require("../../../design-system/tokens/spacing.cjs"),j=require("../../../design-system/tokens/typography.cjs"),F=require("../../../design-system/primitives/sizing.cjs"),G={sm:"400px",md:"500px",lg:"640px",xl:"800px",full:"calc(100vw - 48px)"},J=t.memo(function(){return r.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r.jsx("path",{d:"M4 4L12 12M12 4L4 12",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})})}),w=t.forwardRef(function({isOpen:n,onClose:o,size:c="md",title:l,description:u,closeOnOverlayClick:b=!0,closeOnEscape:v=!0,showCloseButton:k=!0,className:C,style:g,testId:R,children:q,...L},i){const y=t.useRef(null),f=t.useRef(null),d=t.useRef(!1);t.useEffect(()=>{n&&!d.current?(f.current=document.activeElement,d.current=!0):!n&&d.current&&(document.activeElement instanceof HTMLElement&&document.activeElement.blur(),f.current?.focus(),f.current=null,d.current=!1)},[n]);const x=t.useRef(o);t.useEffect(()=>{x.current=o},[o]),t.useEffect(()=>{if(!n)return;const e=y.current;e&&e.focus()},[n]),t.useEffect(()=>{if(!n)return;const e=y.current,p=a=>{if(a.key==="Escape"&&v){x.current();return}if(a.key==="Tab"&&e){const m=e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),h=m[0],S=m[m.length-1];a.shiftKey&&document.activeElement===h?(a.preventDefault(),S?.focus()):!a.shiftKey&&document.activeElement===S&&(a.preventDefault(),h?.focus())}};return document.addEventListener("keydown",p),document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",p),document.body.style.overflow=""}},[n,v]);const T=t.useCallback(e=>{e.target===e.currentTarget&&b&&o()},[b,o]),z=t.useMemo(()=>({position:"fixed",inset:0,zIndex:"var(--brycks-z-modal)",display:"flex",alignItems:"center",justifyContent:"center",padding:s.spacing[6],backgroundColor:"var(--brycks-background-overlay)",backdropFilter:"blur(4px)",animation:"brycks-fade-in var(--brycks-duration-normal) var(--brycks-ease-out)"}),[]),I=t.useMemo(()=>({position:"relative",width:"100%",maxWidth:G[c],maxHeight:c==="full"?"calc(100vh - 48px)":"85vh",backgroundColor:"var(--brycks-background-elevated)",borderRadius:"var(--brycks-radius-xl)",boxShadow:"var(--brycks-shadow-2xl)",display:"flex",flexDirection:"column",overflow:"hidden",animation:"brycks-scale-in var(--brycks-duration-normal) var(--brycks-ease-spring)",outline:"none",...g}),[c,g]);if(!n)return null;const D={display:"flex",alignItems:"flex-start",justifyContent:"space-between",padding:`${s.spacing[5]}px ${s.spacing[6]}px`,borderBottom:"1px solid var(--brycks-border-muted)"},N={display:"flex",flexDirection:"column",gap:s.spacing[1]},B={fontSize:j.fontSizes.lg,fontWeight:600,color:"var(--brycks-foreground-default)",margin:0,lineHeight:1.3},W={fontSize:j.fontSizes.base,color:"var(--brycks-foreground-muted)",margin:0},H={display:"flex",alignItems:"center",justifyContent:"center",width:E.iconButtonSizes.sm,height:E.iconButtonSizes.sm,borderRadius:"var(--brycks-radius-md)",color:"var(--brycks-foreground-muted)",transition:"all var(--brycks-duration-fast) var(--brycks-ease-out)",marginLeft:F.componentGap.xl,flexShrink:0},K={flex:1,overflow:"auto",padding:s.spacing[6]},$=r.jsx("div",{className:"brycks-modal-overlay",style:z,onClick:T,children:r.jsxs("div",{ref:e=>{y.current=e,typeof i=="function"?i(e):i&&(i.current=e)},role:"dialog","aria-modal":"true","aria-labelledby":l?"brycks-modal-title":void 0,"aria-describedby":u?"brycks-modal-description":void 0,className:P.cx("brycks-modal",`brycks-modal--${c}`,C),style:I,tabIndex:-1,"data-testid":R,...L,children:[(l||k)&&r.jsxs("div",{className:"brycks-modal-header",style:D,children:[r.jsxs("div",{style:N,children:[l&&r.jsx("h2",{id:"brycks-modal-title",style:B,children:l}),u&&r.jsx("p",{id:"brycks-modal-description",style:W,children:u})]}),k&&r.jsx("button",{type:"button",className:"brycks-modal-close",style:H,onClick:o,"aria-label":"Close modal",onMouseEnter:e=>{e.currentTarget.style.backgroundColor="var(--brycks-background-muted)",e.currentTarget.style.color="var(--brycks-foreground-default)"},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color="var(--brycks-foreground-muted)"},children:r.jsx(J,{})})]}),r.jsx("div",{className:"brycks-modal-content",style:K,children:q})]})});return A.createPortal($,document.body)});w.displayName="Modal";exports.Modal=w;
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react/jsx-runtime"),t=require("react"),A=require("react-dom"),P=require("../../../utils/styles.cjs"),E=require("../../../design-system/primitives/layout.cjs"),s=require("../../../design-system/tokens/spacing.cjs"),j=require("../../../design-system/tokens/typography.cjs"),F=require("../../../design-system/primitives/sizing.cjs"),G={sm:"400px",md:"500px",lg:"640px",xl:"800px","2xl":"1200px",full:"calc(100vw - 48px)"},J=t.memo(function(){return r.jsx("svg",{width:"16",height:"16",viewBox:"0 0 16 16",fill:"none","aria-hidden":"true",children:r.jsx("path",{d:"M4 4L12 12M12 4L4 12",stroke:"currentColor",strokeWidth:"1.5",strokeLinecap:"round"})})}),w=t.forwardRef(function({isOpen:n,onClose:o,size:c="md",title:l,description:u,closeOnOverlayClick:b=!0,closeOnEscape:v=!0,showCloseButton:k=!0,className:C,style:g,testId:R,children:q,...L},i){const y=t.useRef(null),f=t.useRef(null),d=t.useRef(!1);t.useEffect(()=>{n&&!d.current?(f.current=document.activeElement,d.current=!0):!n&&d.current&&(document.activeElement instanceof HTMLElement&&document.activeElement.blur(),f.current?.focus(),f.current=null,d.current=!1)},[n]);const x=t.useRef(o);t.useEffect(()=>{x.current=o},[o]),t.useEffect(()=>{if(!n)return;const e=y.current;e&&e.focus()},[n]),t.useEffect(()=>{if(!n)return;const e=y.current,p=a=>{if(a.key==="Escape"&&v){x.current();return}if(a.key==="Tab"&&e){const m=e.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'),h=m[0],S=m[m.length-1];a.shiftKey&&document.activeElement===h?(a.preventDefault(),S?.focus()):!a.shiftKey&&document.activeElement===S&&(a.preventDefault(),h?.focus())}};return document.addEventListener("keydown",p),document.body.style.overflow="hidden",()=>{document.removeEventListener("keydown",p),document.body.style.overflow=""}},[n,v]);const T=t.useCallback(e=>{e.target===e.currentTarget&&b&&o()},[b,o]),z=t.useMemo(()=>({position:"fixed",inset:0,zIndex:"var(--brycks-z-modal)",display:"flex",alignItems:"center",justifyContent:"center",padding:s.spacing[6],backgroundColor:"var(--brycks-background-overlay)",backdropFilter:"blur(4px)",animation:"brycks-fade-in var(--brycks-duration-normal) var(--brycks-ease-out)"}),[]),I=t.useMemo(()=>({position:"relative",width:"100%",maxWidth:G[c],maxHeight:c==="full"?"calc(100vh - 48px)":"85vh",backgroundColor:"var(--brycks-background-elevated)",borderRadius:"var(--brycks-radius-xl)",boxShadow:"var(--brycks-shadow-2xl)",display:"flex",flexDirection:"column",overflow:"hidden",animation:"brycks-scale-in var(--brycks-duration-normal) var(--brycks-ease-spring)",outline:"none",...g}),[c,g]);if(!n)return null;const D={display:"flex",alignItems:"flex-start",justifyContent:"space-between",padding:`${s.spacing[5]}px ${s.spacing[6]}px`,borderBottom:"1px solid var(--brycks-border-muted)"},N={display:"flex",flexDirection:"column",gap:s.spacing[1]},B={fontSize:j.fontSizes.lg,fontWeight:600,color:"var(--brycks-foreground-default)",margin:0,lineHeight:1.3},W={fontSize:j.fontSizes.base,color:"var(--brycks-foreground-muted)",margin:0},H={display:"flex",alignItems:"center",justifyContent:"center",width:E.iconButtonSizes.sm,height:E.iconButtonSizes.sm,borderRadius:"var(--brycks-radius-md)",color:"var(--brycks-foreground-muted)",transition:"all var(--brycks-duration-fast) var(--brycks-ease-out)",marginLeft:F.componentGap.xl,flexShrink:0},K={flex:1,overflow:"auto",padding:s.spacing[6]},$=r.jsx("div",{className:"brycks-modal-overlay",style:z,onClick:T,children:r.jsxs("div",{ref:e=>{y.current=e,typeof i=="function"?i(e):i&&(i.current=e)},role:"dialog","aria-modal":"true","aria-labelledby":l?"brycks-modal-title":void 0,"aria-describedby":u?"brycks-modal-description":void 0,className:P.cx("brycks-modal",`brycks-modal--${c}`,C),style:I,tabIndex:-1,"data-testid":R,...L,children:[(l||k)&&r.jsxs("div",{className:"brycks-modal-header",style:D,children:[r.jsxs("div",{style:N,children:[l&&r.jsx("h2",{id:"brycks-modal-title",style:B,children:l}),u&&r.jsx("p",{id:"brycks-modal-description",style:W,children:u})]}),k&&r.jsx("button",{type:"button",className:"brycks-modal-close",style:H,onClick:o,"aria-label":"Close modal",onMouseEnter:e=>{e.currentTarget.style.backgroundColor="var(--brycks-background-muted)",e.currentTarget.style.color="var(--brycks-foreground-default)"},onMouseLeave:e=>{e.currentTarget.style.backgroundColor="transparent",e.currentTarget.style.color="var(--brycks-foreground-muted)"},children:r.jsx(J,{})})]}),r.jsx("div",{className:"brycks-modal-content",style:K,children:q})]})});return A.createPortal($,document.body)});w.displayName="Modal";exports.Modal=w;
|
|
2
2
|
//# sourceMappingURL=Modal.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.cjs","sources":["../../../../src/components/feedback/Modal/Modal.tsx"],"sourcesContent":["/**\r\n * Modal Component\r\n *\r\n * Accessible modal dialog with smooth Apple-inspired animations.\r\n * Supports focus trapping and keyboard navigation.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useEffect,\r\n useRef,\r\n useCallback,\r\n useMemo,\r\n memo,\r\n type CSSProperties,\r\n type ReactNode,\r\n type HTMLAttributes,\r\n} from 'react'\r\nimport { createPortal } from 'react-dom'\r\nimport { cx } from '../../../utils/styles'\r\nimport { spacing, fontSizes } from '../../../design-system'\r\nimport { componentGap, iconButtonSizes } from '../../../design-system/primitives'\r\n\r\nexport type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'\r\n\r\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\r\n /** Whether the modal is open */\r\n isOpen: boolean\r\n /** Callback when modal should close */\r\n onClose: () => void\r\n /** Modal size */\r\n size?: ModalSize\r\n /** Modal title */\r\n title?: ReactNode\r\n /** Modal description */\r\n description?: ReactNode\r\n /** Whether to close on overlay click */\r\n closeOnOverlayClick?: boolean\r\n /** Whether to close on escape key */\r\n closeOnEscape?: boolean\r\n /** Whether to show close button */\r\n showCloseButton?: boolean\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n /** Modal content */\r\n children?: ReactNode\r\n}\r\n\r\nconst sizeWidths: Record<ModalSize, string> = {\r\n sm: '400px',\r\n md: '500px',\r\n lg: '640px',\r\n xl: '800px',\r\n full: 'calc(100vw - 48px)',\r\n}\r\n\r\n/** Close icon - memoized to prevent re-renders */\r\nconst CloseIcon = memo(function CloseIcon() {\r\n return (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4 4L12 12M12 4L4 12\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n strokeLinecap=\"round\"\r\n />\r\n </svg>\r\n )\r\n})\r\n\r\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\r\n {\r\n isOpen,\r\n onClose,\r\n size = 'md',\r\n title,\r\n description,\r\n closeOnOverlayClick = true,\r\n closeOnEscape = true,\r\n showCloseButton = true,\r\n className,\r\n style,\r\n testId,\r\n children,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const modalRef = useRef<HTMLDivElement>(null)\r\n const previousActiveElement = useRef<HTMLElement | null>(null)\r\n const wasOpen = useRef(false)\r\n\r\n // Track previous open state to handle focus restoration before unmount\r\n useEffect(() => {\r\n // Modal just opened\r\n if (isOpen && !wasOpen.current) {\r\n previousActiveElement.current = document.activeElement as HTMLElement\r\n wasOpen.current = true\r\n }\r\n // Modal is about to close - restore focus BEFORE unmount\r\n else if (!isOpen && wasOpen.current) {\r\n // Blur any focused element inside modal to prevent aria-hidden warning\r\n if (document.activeElement instanceof HTMLElement) {\r\n document.activeElement.blur()\r\n }\r\n // Restore focus to previous element\r\n previousActiveElement.current?.focus()\r\n previousActiveElement.current = null\r\n wasOpen.current = false\r\n }\r\n }, [isOpen])\r\n\r\n // Store onClose in a ref to avoid re-running effects when it changes\r\n const onCloseRef = useRef(onClose)\r\n useEffect(() => {\r\n onCloseRef.current = onClose\r\n }, [onClose])\r\n\r\n // Focus modal when it opens (only once)\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n if (modal) {\r\n modal.focus()\r\n }\r\n }, [isOpen])\r\n\r\n // Keyboard handling and body scroll lock\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape' && closeOnEscape) {\r\n onCloseRef.current()\r\n return\r\n }\r\n\r\n if (e.key === 'Tab' && modal) {\r\n const focusableElements = modal.querySelectorAll<HTMLElement>(\r\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\r\n )\r\n const firstElement = focusableElements[0]\r\n const lastElement = focusableElements[focusableElements.length - 1]\r\n\r\n if (e.shiftKey && document.activeElement === firstElement) {\r\n e.preventDefault()\r\n lastElement?.focus()\r\n } else if (!e.shiftKey && document.activeElement === lastElement) {\r\n e.preventDefault()\r\n firstElement?.focus()\r\n }\r\n }\r\n }\r\n\r\n document.addEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = 'hidden'\r\n\r\n return () => {\r\n document.removeEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = ''\r\n }\r\n }, [isOpen, closeOnEscape])\r\n\r\n const handleOverlayClick = useCallback(\r\n (e: React.MouseEvent) => {\r\n if (e.target === e.currentTarget && closeOnOverlayClick) {\r\n onClose()\r\n }\r\n },\r\n [closeOnOverlayClick, onClose]\r\n )\r\n\r\n // Memoize styles to prevent object recreation on every render\r\n const overlayStyle = useMemo<CSSProperties>(() => ({\r\n position: 'fixed',\r\n inset: 0,\r\n zIndex: 'var(--brycks-z-modal)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: spacing[6],\r\n backgroundColor: 'var(--brycks-background-overlay)',\r\n backdropFilter: 'blur(4px)',\r\n animation: 'brycks-fade-in var(--brycks-duration-normal) var(--brycks-ease-out)',\r\n }), [])\r\n\r\n const modalStyle = useMemo<CSSProperties>(() => ({\r\n position: 'relative',\r\n width: '100%',\r\n maxWidth: sizeWidths[size],\r\n maxHeight: size === 'full' ? 'calc(100vh - 48px)' : '85vh',\r\n backgroundColor: 'var(--brycks-background-elevated)',\r\n borderRadius: 'var(--brycks-radius-xl)',\r\n boxShadow: 'var(--brycks-shadow-2xl)',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n overflow: 'hidden',\r\n animation: 'brycks-scale-in var(--brycks-duration-normal) var(--brycks-ease-spring)',\r\n outline: 'none',\r\n ...style,\r\n }), [size, style])\r\n\r\n if (!isOpen) return null\r\n\r\n const headerStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n justifyContent: 'space-between',\r\n padding: `${spacing[5]}px ${spacing[6]}px`,\r\n borderBottom: '1px solid var(--brycks-border-muted)',\r\n }\r\n\r\n const titleContainerStyle: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: spacing[1],\r\n }\r\n\r\n const titleStyle: CSSProperties = {\r\n fontSize: fontSizes.lg,\r\n fontWeight: 600,\r\n color: 'var(--brycks-foreground-default)',\r\n margin: 0,\r\n lineHeight: 1.3,\r\n }\r\n\r\n const descriptionStyle: CSSProperties = {\r\n fontSize: fontSizes.base,\r\n color: 'var(--brycks-foreground-muted)',\r\n margin: 0,\r\n }\r\n\r\n const closeButtonStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n width: iconButtonSizes.sm,\r\n height: iconButtonSizes.sm,\r\n borderRadius: 'var(--brycks-radius-md)',\r\n color: 'var(--brycks-foreground-muted)',\r\n transition: 'all var(--brycks-duration-fast) var(--brycks-ease-out)',\r\n marginLeft: componentGap.xl,\r\n flexShrink: 0,\r\n }\r\n\r\n const contentStyle: CSSProperties = {\r\n flex: 1,\r\n overflow: 'auto',\r\n padding: spacing[6],\r\n }\r\n\r\n const modalContent = (\r\n <div\r\n className=\"brycks-modal-overlay\"\r\n style={overlayStyle}\r\n onClick={handleOverlayClick}\r\n >\r\n <div\r\n ref={(node) => {\r\n (modalRef as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n if (typeof ref === 'function') ref(node)\r\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n }}\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-labelledby={title ? 'brycks-modal-title' : undefined}\r\n aria-describedby={description ? 'brycks-modal-description' : undefined}\r\n className={cx('brycks-modal', `brycks-modal--${size}`, className)}\r\n style={modalStyle}\r\n tabIndex={-1}\r\n data-testid={testId}\r\n {...props}\r\n >\r\n {(title || showCloseButton) && (\r\n <div className=\"brycks-modal-header\" style={headerStyle}>\r\n <div style={titleContainerStyle}>\r\n {title && (\r\n <h2 id=\"brycks-modal-title\" style={titleStyle}>\r\n {title}\r\n </h2>\r\n )}\r\n {description && (\r\n <p id=\"brycks-modal-description\" style={descriptionStyle}>\r\n {description}\r\n </p>\r\n )}\r\n </div>\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n className=\"brycks-modal-close\"\r\n style={closeButtonStyle}\r\n onClick={onClose}\r\n aria-label=\"Close modal\"\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-default)'\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = 'transparent'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-muted)'\r\n }}\r\n >\r\n <CloseIcon />\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"brycks-modal-content\" style={contentStyle}>\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n\r\n return createPortal(modalContent, document.body)\r\n})\r\n\r\nModal.displayName = 'Modal'\r\n"],"names":["sizeWidths","CloseIcon","memo","jsx","Modal","forwardRef","isOpen","onClose","size","title","description","closeOnOverlayClick","closeOnEscape","showCloseButton","className","style","testId","children","props","ref","modalRef","useRef","previousActiveElement","wasOpen","useEffect","onCloseRef","modal","handleKeyDown","e","focusableElements","firstElement","lastElement","handleOverlayClick","useCallback","overlayStyle","useMemo","spacing","modalStyle","headerStyle","titleContainerStyle","titleStyle","fontSizes","descriptionStyle","closeButtonStyle","iconButtonSizes","componentGap","contentStyle","modalContent","jsxs","node","cx","createPortal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Modal.cjs","sources":["../../../../src/components/feedback/Modal/Modal.tsx"],"sourcesContent":["/**\r\n * Modal Component\r\n *\r\n * Accessible modal dialog with smooth Apple-inspired animations.\r\n * Supports focus trapping and keyboard navigation.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useEffect,\r\n useRef,\r\n useCallback,\r\n useMemo,\r\n memo,\r\n type CSSProperties,\r\n type ReactNode,\r\n type HTMLAttributes,\r\n} from 'react'\r\nimport { createPortal } from 'react-dom'\r\nimport { cx } from '../../../utils/styles'\r\nimport { spacing, fontSizes } from '../../../design-system'\r\nimport { componentGap, iconButtonSizes } from '../../../design-system/primitives'\r\n\r\nexport type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full'\r\n\r\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\r\n /** Whether the modal is open */\r\n isOpen: boolean\r\n /** Callback when modal should close */\r\n onClose: () => void\r\n /** Modal size */\r\n size?: ModalSize\r\n /** Modal title */\r\n title?: ReactNode\r\n /** Modal description */\r\n description?: ReactNode\r\n /** Whether to close on overlay click */\r\n closeOnOverlayClick?: boolean\r\n /** Whether to close on escape key */\r\n closeOnEscape?: boolean\r\n /** Whether to show close button */\r\n showCloseButton?: boolean\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n /** Modal content */\r\n children?: ReactNode\r\n}\r\n\r\nconst sizeWidths: Record<ModalSize, string> = {\r\n sm: '400px',\r\n md: '500px',\r\n lg: '640px',\r\n xl: '800px',\r\n '2xl': '1200px',\r\n full: 'calc(100vw - 48px)',\r\n}\r\n\r\n/** Close icon - memoized to prevent re-renders */\r\nconst CloseIcon = memo(function CloseIcon() {\r\n return (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4 4L12 12M12 4L4 12\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n strokeLinecap=\"round\"\r\n />\r\n </svg>\r\n )\r\n})\r\n\r\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\r\n {\r\n isOpen,\r\n onClose,\r\n size = 'md',\r\n title,\r\n description,\r\n closeOnOverlayClick = true,\r\n closeOnEscape = true,\r\n showCloseButton = true,\r\n className,\r\n style,\r\n testId,\r\n children,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const modalRef = useRef<HTMLDivElement>(null)\r\n const previousActiveElement = useRef<HTMLElement | null>(null)\r\n const wasOpen = useRef(false)\r\n\r\n // Track previous open state to handle focus restoration before unmount\r\n useEffect(() => {\r\n // Modal just opened\r\n if (isOpen && !wasOpen.current) {\r\n previousActiveElement.current = document.activeElement as HTMLElement\r\n wasOpen.current = true\r\n }\r\n // Modal is about to close - restore focus BEFORE unmount\r\n else if (!isOpen && wasOpen.current) {\r\n // Blur any focused element inside modal to prevent aria-hidden warning\r\n if (document.activeElement instanceof HTMLElement) {\r\n document.activeElement.blur()\r\n }\r\n // Restore focus to previous element\r\n previousActiveElement.current?.focus()\r\n previousActiveElement.current = null\r\n wasOpen.current = false\r\n }\r\n }, [isOpen])\r\n\r\n // Store onClose in a ref to avoid re-running effects when it changes\r\n const onCloseRef = useRef(onClose)\r\n useEffect(() => {\r\n onCloseRef.current = onClose\r\n }, [onClose])\r\n\r\n // Focus modal when it opens (only once)\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n if (modal) {\r\n modal.focus()\r\n }\r\n }, [isOpen])\r\n\r\n // Keyboard handling and body scroll lock\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape' && closeOnEscape) {\r\n onCloseRef.current()\r\n return\r\n }\r\n\r\n if (e.key === 'Tab' && modal) {\r\n const focusableElements = modal.querySelectorAll<HTMLElement>(\r\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\r\n )\r\n const firstElement = focusableElements[0]\r\n const lastElement = focusableElements[focusableElements.length - 1]\r\n\r\n if (e.shiftKey && document.activeElement === firstElement) {\r\n e.preventDefault()\r\n lastElement?.focus()\r\n } else if (!e.shiftKey && document.activeElement === lastElement) {\r\n e.preventDefault()\r\n firstElement?.focus()\r\n }\r\n }\r\n }\r\n\r\n document.addEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = 'hidden'\r\n\r\n return () => {\r\n document.removeEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = ''\r\n }\r\n }, [isOpen, closeOnEscape])\r\n\r\n const handleOverlayClick = useCallback(\r\n (e: React.MouseEvent) => {\r\n if (e.target === e.currentTarget && closeOnOverlayClick) {\r\n onClose()\r\n }\r\n },\r\n [closeOnOverlayClick, onClose]\r\n )\r\n\r\n // Memoize styles to prevent object recreation on every render\r\n const overlayStyle = useMemo<CSSProperties>(() => ({\r\n position: 'fixed',\r\n inset: 0,\r\n zIndex: 'var(--brycks-z-modal)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: spacing[6],\r\n backgroundColor: 'var(--brycks-background-overlay)',\r\n backdropFilter: 'blur(4px)',\r\n animation: 'brycks-fade-in var(--brycks-duration-normal) var(--brycks-ease-out)',\r\n }), [])\r\n\r\n const modalStyle = useMemo<CSSProperties>(() => ({\r\n position: 'relative',\r\n width: '100%',\r\n maxWidth: sizeWidths[size],\r\n maxHeight: size === 'full' ? 'calc(100vh - 48px)' : '85vh',\r\n backgroundColor: 'var(--brycks-background-elevated)',\r\n borderRadius: 'var(--brycks-radius-xl)',\r\n boxShadow: 'var(--brycks-shadow-2xl)',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n overflow: 'hidden',\r\n animation: 'brycks-scale-in var(--brycks-duration-normal) var(--brycks-ease-spring)',\r\n outline: 'none',\r\n ...style,\r\n }), [size, style])\r\n\r\n if (!isOpen) return null\r\n\r\n const headerStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n justifyContent: 'space-between',\r\n padding: `${spacing[5]}px ${spacing[6]}px`,\r\n borderBottom: '1px solid var(--brycks-border-muted)',\r\n }\r\n\r\n const titleContainerStyle: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: spacing[1],\r\n }\r\n\r\n const titleStyle: CSSProperties = {\r\n fontSize: fontSizes.lg,\r\n fontWeight: 600,\r\n color: 'var(--brycks-foreground-default)',\r\n margin: 0,\r\n lineHeight: 1.3,\r\n }\r\n\r\n const descriptionStyle: CSSProperties = {\r\n fontSize: fontSizes.base,\r\n color: 'var(--brycks-foreground-muted)',\r\n margin: 0,\r\n }\r\n\r\n const closeButtonStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n width: iconButtonSizes.sm,\r\n height: iconButtonSizes.sm,\r\n borderRadius: 'var(--brycks-radius-md)',\r\n color: 'var(--brycks-foreground-muted)',\r\n transition: 'all var(--brycks-duration-fast) var(--brycks-ease-out)',\r\n marginLeft: componentGap.xl,\r\n flexShrink: 0,\r\n }\r\n\r\n const contentStyle: CSSProperties = {\r\n flex: 1,\r\n overflow: 'auto',\r\n padding: spacing[6],\r\n }\r\n\r\n const modalContent = (\r\n <div\r\n className=\"brycks-modal-overlay\"\r\n style={overlayStyle}\r\n onClick={handleOverlayClick}\r\n >\r\n <div\r\n ref={(node) => {\r\n (modalRef as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n if (typeof ref === 'function') ref(node)\r\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n }}\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-labelledby={title ? 'brycks-modal-title' : undefined}\r\n aria-describedby={description ? 'brycks-modal-description' : undefined}\r\n className={cx('brycks-modal', `brycks-modal--${size}`, className)}\r\n style={modalStyle}\r\n tabIndex={-1}\r\n data-testid={testId}\r\n {...props}\r\n >\r\n {(title || showCloseButton) && (\r\n <div className=\"brycks-modal-header\" style={headerStyle}>\r\n <div style={titleContainerStyle}>\r\n {title && (\r\n <h2 id=\"brycks-modal-title\" style={titleStyle}>\r\n {title}\r\n </h2>\r\n )}\r\n {description && (\r\n <p id=\"brycks-modal-description\" style={descriptionStyle}>\r\n {description}\r\n </p>\r\n )}\r\n </div>\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n className=\"brycks-modal-close\"\r\n style={closeButtonStyle}\r\n onClick={onClose}\r\n aria-label=\"Close modal\"\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-default)'\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = 'transparent'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-muted)'\r\n }}\r\n >\r\n <CloseIcon />\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"brycks-modal-content\" style={contentStyle}>\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n\r\n return createPortal(modalContent, document.body)\r\n})\r\n\r\nModal.displayName = 'Modal'\r\n"],"names":["sizeWidths","CloseIcon","memo","jsx","Modal","forwardRef","isOpen","onClose","size","title","description","closeOnOverlayClick","closeOnEscape","showCloseButton","className","style","testId","children","props","ref","modalRef","useRef","previousActiveElement","wasOpen","useEffect","onCloseRef","modal","handleKeyDown","e","focusableElements","firstElement","lastElement","handleOverlayClick","useCallback","overlayStyle","useMemo","spacing","modalStyle","headerStyle","titleContainerStyle","titleStyle","fontSizes","descriptionStyle","closeButtonStyle","iconButtonSizes","componentGap","contentStyle","modalContent","jsxs","node","cx","createPortal"],"mappings":"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"}
|
|
@@ -11,6 +11,7 @@ const X = {
|
|
|
11
11
|
md: "500px",
|
|
12
12
|
lg: "640px",
|
|
13
13
|
xl: "800px",
|
|
14
|
+
"2xl": "1200px",
|
|
14
15
|
full: "calc(100vw - 48px)"
|
|
15
16
|
}, Y = J(function() {
|
|
16
17
|
return /* @__PURE__ */ r("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", "aria-hidden": "true", children: /* @__PURE__ */ r(
|
|
@@ -32,7 +33,7 @@ const X = {
|
|
|
32
33
|
closeOnEscape: p = !0,
|
|
33
34
|
showCloseButton: g = !0,
|
|
34
35
|
className: T,
|
|
35
|
-
style:
|
|
36
|
+
style: x,
|
|
36
37
|
testId: N,
|
|
37
38
|
children: R,
|
|
38
39
|
...j
|
|
@@ -41,9 +42,9 @@ const X = {
|
|
|
41
42
|
u(() => {
|
|
42
43
|
t && !i.current ? (y.current = document.activeElement, i.current = !0) : !t && i.current && (document.activeElement instanceof HTMLElement && document.activeElement.blur(), y.current?.focus(), y.current = null, i.current = !1);
|
|
43
44
|
}, [t]);
|
|
44
|
-
const
|
|
45
|
+
const h = d(o);
|
|
45
46
|
u(() => {
|
|
46
|
-
|
|
47
|
+
h.current = o;
|
|
47
48
|
}, [o]), u(() => {
|
|
48
49
|
if (!t) return;
|
|
49
50
|
const e = f.current;
|
|
@@ -52,7 +53,7 @@ const X = {
|
|
|
52
53
|
if (!t) return;
|
|
53
54
|
const e = f.current, w = (n) => {
|
|
54
55
|
if (n.key === "Escape" && p) {
|
|
55
|
-
|
|
56
|
+
h.current();
|
|
56
57
|
return;
|
|
57
58
|
}
|
|
58
59
|
if (n.key === "Tab" && e) {
|
|
@@ -95,8 +96,8 @@ const X = {
|
|
|
95
96
|
overflow: "hidden",
|
|
96
97
|
animation: "brycks-scale-in var(--brycks-duration-normal) var(--brycks-ease-spring)",
|
|
97
98
|
outline: "none",
|
|
98
|
-
...
|
|
99
|
-
}), [l,
|
|
99
|
+
...x
|
|
100
|
+
}), [l, x]);
|
|
100
101
|
if (!t) return null;
|
|
101
102
|
const B = {
|
|
102
103
|
display: "flex",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.js","sources":["../../../../src/components/feedback/Modal/Modal.tsx"],"sourcesContent":["/**\r\n * Modal Component\r\n *\r\n * Accessible modal dialog with smooth Apple-inspired animations.\r\n * Supports focus trapping and keyboard navigation.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useEffect,\r\n useRef,\r\n useCallback,\r\n useMemo,\r\n memo,\r\n type CSSProperties,\r\n type ReactNode,\r\n type HTMLAttributes,\r\n} from 'react'\r\nimport { createPortal } from 'react-dom'\r\nimport { cx } from '../../../utils/styles'\r\nimport { spacing, fontSizes } from '../../../design-system'\r\nimport { componentGap, iconButtonSizes } from '../../../design-system/primitives'\r\n\r\nexport type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full'\r\n\r\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\r\n /** Whether the modal is open */\r\n isOpen: boolean\r\n /** Callback when modal should close */\r\n onClose: () => void\r\n /** Modal size */\r\n size?: ModalSize\r\n /** Modal title */\r\n title?: ReactNode\r\n /** Modal description */\r\n description?: ReactNode\r\n /** Whether to close on overlay click */\r\n closeOnOverlayClick?: boolean\r\n /** Whether to close on escape key */\r\n closeOnEscape?: boolean\r\n /** Whether to show close button */\r\n showCloseButton?: boolean\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n /** Modal content */\r\n children?: ReactNode\r\n}\r\n\r\nconst sizeWidths: Record<ModalSize, string> = {\r\n sm: '400px',\r\n md: '500px',\r\n lg: '640px',\r\n xl: '800px',\r\n full: 'calc(100vw - 48px)',\r\n}\r\n\r\n/** Close icon - memoized to prevent re-renders */\r\nconst CloseIcon = memo(function CloseIcon() {\r\n return (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4 4L12 12M12 4L4 12\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n strokeLinecap=\"round\"\r\n />\r\n </svg>\r\n )\r\n})\r\n\r\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\r\n {\r\n isOpen,\r\n onClose,\r\n size = 'md',\r\n title,\r\n description,\r\n closeOnOverlayClick = true,\r\n closeOnEscape = true,\r\n showCloseButton = true,\r\n className,\r\n style,\r\n testId,\r\n children,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const modalRef = useRef<HTMLDivElement>(null)\r\n const previousActiveElement = useRef<HTMLElement | null>(null)\r\n const wasOpen = useRef(false)\r\n\r\n // Track previous open state to handle focus restoration before unmount\r\n useEffect(() => {\r\n // Modal just opened\r\n if (isOpen && !wasOpen.current) {\r\n previousActiveElement.current = document.activeElement as HTMLElement\r\n wasOpen.current = true\r\n }\r\n // Modal is about to close - restore focus BEFORE unmount\r\n else if (!isOpen && wasOpen.current) {\r\n // Blur any focused element inside modal to prevent aria-hidden warning\r\n if (document.activeElement instanceof HTMLElement) {\r\n document.activeElement.blur()\r\n }\r\n // Restore focus to previous element\r\n previousActiveElement.current?.focus()\r\n previousActiveElement.current = null\r\n wasOpen.current = false\r\n }\r\n }, [isOpen])\r\n\r\n // Store onClose in a ref to avoid re-running effects when it changes\r\n const onCloseRef = useRef(onClose)\r\n useEffect(() => {\r\n onCloseRef.current = onClose\r\n }, [onClose])\r\n\r\n // Focus modal when it opens (only once)\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n if (modal) {\r\n modal.focus()\r\n }\r\n }, [isOpen])\r\n\r\n // Keyboard handling and body scroll lock\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape' && closeOnEscape) {\r\n onCloseRef.current()\r\n return\r\n }\r\n\r\n if (e.key === 'Tab' && modal) {\r\n const focusableElements = modal.querySelectorAll<HTMLElement>(\r\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\r\n )\r\n const firstElement = focusableElements[0]\r\n const lastElement = focusableElements[focusableElements.length - 1]\r\n\r\n if (e.shiftKey && document.activeElement === firstElement) {\r\n e.preventDefault()\r\n lastElement?.focus()\r\n } else if (!e.shiftKey && document.activeElement === lastElement) {\r\n e.preventDefault()\r\n firstElement?.focus()\r\n }\r\n }\r\n }\r\n\r\n document.addEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = 'hidden'\r\n\r\n return () => {\r\n document.removeEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = ''\r\n }\r\n }, [isOpen, closeOnEscape])\r\n\r\n const handleOverlayClick = useCallback(\r\n (e: React.MouseEvent) => {\r\n if (e.target === e.currentTarget && closeOnOverlayClick) {\r\n onClose()\r\n }\r\n },\r\n [closeOnOverlayClick, onClose]\r\n )\r\n\r\n // Memoize styles to prevent object recreation on every render\r\n const overlayStyle = useMemo<CSSProperties>(() => ({\r\n position: 'fixed',\r\n inset: 0,\r\n zIndex: 'var(--brycks-z-modal)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: spacing[6],\r\n backgroundColor: 'var(--brycks-background-overlay)',\r\n backdropFilter: 'blur(4px)',\r\n animation: 'brycks-fade-in var(--brycks-duration-normal) var(--brycks-ease-out)',\r\n }), [])\r\n\r\n const modalStyle = useMemo<CSSProperties>(() => ({\r\n position: 'relative',\r\n width: '100%',\r\n maxWidth: sizeWidths[size],\r\n maxHeight: size === 'full' ? 'calc(100vh - 48px)' : '85vh',\r\n backgroundColor: 'var(--brycks-background-elevated)',\r\n borderRadius: 'var(--brycks-radius-xl)',\r\n boxShadow: 'var(--brycks-shadow-2xl)',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n overflow: 'hidden',\r\n animation: 'brycks-scale-in var(--brycks-duration-normal) var(--brycks-ease-spring)',\r\n outline: 'none',\r\n ...style,\r\n }), [size, style])\r\n\r\n if (!isOpen) return null\r\n\r\n const headerStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n justifyContent: 'space-between',\r\n padding: `${spacing[5]}px ${spacing[6]}px`,\r\n borderBottom: '1px solid var(--brycks-border-muted)',\r\n }\r\n\r\n const titleContainerStyle: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: spacing[1],\r\n }\r\n\r\n const titleStyle: CSSProperties = {\r\n fontSize: fontSizes.lg,\r\n fontWeight: 600,\r\n color: 'var(--brycks-foreground-default)',\r\n margin: 0,\r\n lineHeight: 1.3,\r\n }\r\n\r\n const descriptionStyle: CSSProperties = {\r\n fontSize: fontSizes.base,\r\n color: 'var(--brycks-foreground-muted)',\r\n margin: 0,\r\n }\r\n\r\n const closeButtonStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n width: iconButtonSizes.sm,\r\n height: iconButtonSizes.sm,\r\n borderRadius: 'var(--brycks-radius-md)',\r\n color: 'var(--brycks-foreground-muted)',\r\n transition: 'all var(--brycks-duration-fast) var(--brycks-ease-out)',\r\n marginLeft: componentGap.xl,\r\n flexShrink: 0,\r\n }\r\n\r\n const contentStyle: CSSProperties = {\r\n flex: 1,\r\n overflow: 'auto',\r\n padding: spacing[6],\r\n }\r\n\r\n const modalContent = (\r\n <div\r\n className=\"brycks-modal-overlay\"\r\n style={overlayStyle}\r\n onClick={handleOverlayClick}\r\n >\r\n <div\r\n ref={(node) => {\r\n (modalRef as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n if (typeof ref === 'function') ref(node)\r\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n }}\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-labelledby={title ? 'brycks-modal-title' : undefined}\r\n aria-describedby={description ? 'brycks-modal-description' : undefined}\r\n className={cx('brycks-modal', `brycks-modal--${size}`, className)}\r\n style={modalStyle}\r\n tabIndex={-1}\r\n data-testid={testId}\r\n {...props}\r\n >\r\n {(title || showCloseButton) && (\r\n <div className=\"brycks-modal-header\" style={headerStyle}>\r\n <div style={titleContainerStyle}>\r\n {title && (\r\n <h2 id=\"brycks-modal-title\" style={titleStyle}>\r\n {title}\r\n </h2>\r\n )}\r\n {description && (\r\n <p id=\"brycks-modal-description\" style={descriptionStyle}>\r\n {description}\r\n </p>\r\n )}\r\n </div>\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n className=\"brycks-modal-close\"\r\n style={closeButtonStyle}\r\n onClick={onClose}\r\n aria-label=\"Close modal\"\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-default)'\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = 'transparent'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-muted)'\r\n }}\r\n >\r\n <CloseIcon />\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"brycks-modal-content\" style={contentStyle}>\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n\r\n return createPortal(modalContent, document.body)\r\n})\r\n\r\nModal.displayName = 'Modal'\r\n"],"names":["sizeWidths","CloseIcon","memo","jsx","Modal","forwardRef","isOpen","onClose","size","title","description","closeOnOverlayClick","closeOnEscape","showCloseButton","className","style","testId","children","props","ref","modalRef","useRef","previousActiveElement","wasOpen","useEffect","onCloseRef","modal","handleKeyDown","e","focusableElements","firstElement","lastElement","handleOverlayClick","useCallback","overlayStyle","useMemo","spacing","modalStyle","headerStyle","titleContainerStyle","titleStyle","fontSizes","descriptionStyle","closeButtonStyle","iconButtonSizes","componentGap","contentStyle","modalContent","jsxs","node","cx","createPortal"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"Modal.js","sources":["../../../../src/components/feedback/Modal/Modal.tsx"],"sourcesContent":["/**\r\n * Modal Component\r\n *\r\n * Accessible modal dialog with smooth Apple-inspired animations.\r\n * Supports focus trapping and keyboard navigation.\r\n */\r\n\r\nimport {\r\n forwardRef,\r\n useEffect,\r\n useRef,\r\n useCallback,\r\n useMemo,\r\n memo,\r\n type CSSProperties,\r\n type ReactNode,\r\n type HTMLAttributes,\r\n} from 'react'\r\nimport { createPortal } from 'react-dom'\r\nimport { cx } from '../../../utils/styles'\r\nimport { spacing, fontSizes } from '../../../design-system'\r\nimport { componentGap, iconButtonSizes } from '../../../design-system/primitives'\r\n\r\nexport type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full'\r\n\r\nexport interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\r\n /** Whether the modal is open */\r\n isOpen: boolean\r\n /** Callback when modal should close */\r\n onClose: () => void\r\n /** Modal size */\r\n size?: ModalSize\r\n /** Modal title */\r\n title?: ReactNode\r\n /** Modal description */\r\n description?: ReactNode\r\n /** Whether to close on overlay click */\r\n closeOnOverlayClick?: boolean\r\n /** Whether to close on escape key */\r\n closeOnEscape?: boolean\r\n /** Whether to show close button */\r\n showCloseButton?: boolean\r\n /** Custom class name */\r\n className?: string\r\n /** Test ID */\r\n testId?: string\r\n /** Modal content */\r\n children?: ReactNode\r\n}\r\n\r\nconst sizeWidths: Record<ModalSize, string> = {\r\n sm: '400px',\r\n md: '500px',\r\n lg: '640px',\r\n xl: '800px',\r\n '2xl': '1200px',\r\n full: 'calc(100vw - 48px)',\r\n}\r\n\r\n/** Close icon - memoized to prevent re-renders */\r\nconst CloseIcon = memo(function CloseIcon() {\r\n return (\r\n <svg width=\"16\" height=\"16\" viewBox=\"0 0 16 16\" fill=\"none\" aria-hidden=\"true\">\r\n <path\r\n d=\"M4 4L12 12M12 4L4 12\"\r\n stroke=\"currentColor\"\r\n strokeWidth=\"1.5\"\r\n strokeLinecap=\"round\"\r\n />\r\n </svg>\r\n )\r\n})\r\n\r\nexport const Modal = forwardRef<HTMLDivElement, ModalProps>(function Modal(\r\n {\r\n isOpen,\r\n onClose,\r\n size = 'md',\r\n title,\r\n description,\r\n closeOnOverlayClick = true,\r\n closeOnEscape = true,\r\n showCloseButton = true,\r\n className,\r\n style,\r\n testId,\r\n children,\r\n ...props\r\n },\r\n ref\r\n) {\r\n const modalRef = useRef<HTMLDivElement>(null)\r\n const previousActiveElement = useRef<HTMLElement | null>(null)\r\n const wasOpen = useRef(false)\r\n\r\n // Track previous open state to handle focus restoration before unmount\r\n useEffect(() => {\r\n // Modal just opened\r\n if (isOpen && !wasOpen.current) {\r\n previousActiveElement.current = document.activeElement as HTMLElement\r\n wasOpen.current = true\r\n }\r\n // Modal is about to close - restore focus BEFORE unmount\r\n else if (!isOpen && wasOpen.current) {\r\n // Blur any focused element inside modal to prevent aria-hidden warning\r\n if (document.activeElement instanceof HTMLElement) {\r\n document.activeElement.blur()\r\n }\r\n // Restore focus to previous element\r\n previousActiveElement.current?.focus()\r\n previousActiveElement.current = null\r\n wasOpen.current = false\r\n }\r\n }, [isOpen])\r\n\r\n // Store onClose in a ref to avoid re-running effects when it changes\r\n const onCloseRef = useRef(onClose)\r\n useEffect(() => {\r\n onCloseRef.current = onClose\r\n }, [onClose])\r\n\r\n // Focus modal when it opens (only once)\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n if (modal) {\r\n modal.focus()\r\n }\r\n }, [isOpen])\r\n\r\n // Keyboard handling and body scroll lock\r\n useEffect(() => {\r\n if (!isOpen) return\r\n\r\n const modal = modalRef.current\r\n\r\n const handleKeyDown = (e: KeyboardEvent) => {\r\n if (e.key === 'Escape' && closeOnEscape) {\r\n onCloseRef.current()\r\n return\r\n }\r\n\r\n if (e.key === 'Tab' && modal) {\r\n const focusableElements = modal.querySelectorAll<HTMLElement>(\r\n 'button, [href], input, select, textarea, [tabindex]:not([tabindex=\"-1\"])'\r\n )\r\n const firstElement = focusableElements[0]\r\n const lastElement = focusableElements[focusableElements.length - 1]\r\n\r\n if (e.shiftKey && document.activeElement === firstElement) {\r\n e.preventDefault()\r\n lastElement?.focus()\r\n } else if (!e.shiftKey && document.activeElement === lastElement) {\r\n e.preventDefault()\r\n firstElement?.focus()\r\n }\r\n }\r\n }\r\n\r\n document.addEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = 'hidden'\r\n\r\n return () => {\r\n document.removeEventListener('keydown', handleKeyDown)\r\n document.body.style.overflow = ''\r\n }\r\n }, [isOpen, closeOnEscape])\r\n\r\n const handleOverlayClick = useCallback(\r\n (e: React.MouseEvent) => {\r\n if (e.target === e.currentTarget && closeOnOverlayClick) {\r\n onClose()\r\n }\r\n },\r\n [closeOnOverlayClick, onClose]\r\n )\r\n\r\n // Memoize styles to prevent object recreation on every render\r\n const overlayStyle = useMemo<CSSProperties>(() => ({\r\n position: 'fixed',\r\n inset: 0,\r\n zIndex: 'var(--brycks-z-modal)',\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n padding: spacing[6],\r\n backgroundColor: 'var(--brycks-background-overlay)',\r\n backdropFilter: 'blur(4px)',\r\n animation: 'brycks-fade-in var(--brycks-duration-normal) var(--brycks-ease-out)',\r\n }), [])\r\n\r\n const modalStyle = useMemo<CSSProperties>(() => ({\r\n position: 'relative',\r\n width: '100%',\r\n maxWidth: sizeWidths[size],\r\n maxHeight: size === 'full' ? 'calc(100vh - 48px)' : '85vh',\r\n backgroundColor: 'var(--brycks-background-elevated)',\r\n borderRadius: 'var(--brycks-radius-xl)',\r\n boxShadow: 'var(--brycks-shadow-2xl)',\r\n display: 'flex',\r\n flexDirection: 'column',\r\n overflow: 'hidden',\r\n animation: 'brycks-scale-in var(--brycks-duration-normal) var(--brycks-ease-spring)',\r\n outline: 'none',\r\n ...style,\r\n }), [size, style])\r\n\r\n if (!isOpen) return null\r\n\r\n const headerStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'flex-start',\r\n justifyContent: 'space-between',\r\n padding: `${spacing[5]}px ${spacing[6]}px`,\r\n borderBottom: '1px solid var(--brycks-border-muted)',\r\n }\r\n\r\n const titleContainerStyle: CSSProperties = {\r\n display: 'flex',\r\n flexDirection: 'column',\r\n gap: spacing[1],\r\n }\r\n\r\n const titleStyle: CSSProperties = {\r\n fontSize: fontSizes.lg,\r\n fontWeight: 600,\r\n color: 'var(--brycks-foreground-default)',\r\n margin: 0,\r\n lineHeight: 1.3,\r\n }\r\n\r\n const descriptionStyle: CSSProperties = {\r\n fontSize: fontSizes.base,\r\n color: 'var(--brycks-foreground-muted)',\r\n margin: 0,\r\n }\r\n\r\n const closeButtonStyle: CSSProperties = {\r\n display: 'flex',\r\n alignItems: 'center',\r\n justifyContent: 'center',\r\n width: iconButtonSizes.sm,\r\n height: iconButtonSizes.sm,\r\n borderRadius: 'var(--brycks-radius-md)',\r\n color: 'var(--brycks-foreground-muted)',\r\n transition: 'all var(--brycks-duration-fast) var(--brycks-ease-out)',\r\n marginLeft: componentGap.xl,\r\n flexShrink: 0,\r\n }\r\n\r\n const contentStyle: CSSProperties = {\r\n flex: 1,\r\n overflow: 'auto',\r\n padding: spacing[6],\r\n }\r\n\r\n const modalContent = (\r\n <div\r\n className=\"brycks-modal-overlay\"\r\n style={overlayStyle}\r\n onClick={handleOverlayClick}\r\n >\r\n <div\r\n ref={(node) => {\r\n (modalRef as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n if (typeof ref === 'function') ref(node)\r\n else if (ref) (ref as React.MutableRefObject<HTMLDivElement | null>).current = node\r\n }}\r\n role=\"dialog\"\r\n aria-modal=\"true\"\r\n aria-labelledby={title ? 'brycks-modal-title' : undefined}\r\n aria-describedby={description ? 'brycks-modal-description' : undefined}\r\n className={cx('brycks-modal', `brycks-modal--${size}`, className)}\r\n style={modalStyle}\r\n tabIndex={-1}\r\n data-testid={testId}\r\n {...props}\r\n >\r\n {(title || showCloseButton) && (\r\n <div className=\"brycks-modal-header\" style={headerStyle}>\r\n <div style={titleContainerStyle}>\r\n {title && (\r\n <h2 id=\"brycks-modal-title\" style={titleStyle}>\r\n {title}\r\n </h2>\r\n )}\r\n {description && (\r\n <p id=\"brycks-modal-description\" style={descriptionStyle}>\r\n {description}\r\n </p>\r\n )}\r\n </div>\r\n {showCloseButton && (\r\n <button\r\n type=\"button\"\r\n className=\"brycks-modal-close\"\r\n style={closeButtonStyle}\r\n onClick={onClose}\r\n aria-label=\"Close modal\"\r\n onMouseEnter={(e) => {\r\n e.currentTarget.style.backgroundColor = 'var(--brycks-background-muted)'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-default)'\r\n }}\r\n onMouseLeave={(e) => {\r\n e.currentTarget.style.backgroundColor = 'transparent'\r\n e.currentTarget.style.color = 'var(--brycks-foreground-muted)'\r\n }}\r\n >\r\n <CloseIcon />\r\n </button>\r\n )}\r\n </div>\r\n )}\r\n\r\n <div className=\"brycks-modal-content\" style={contentStyle}>\r\n {children}\r\n </div>\r\n </div>\r\n </div>\r\n )\r\n\r\n return createPortal(modalContent, document.body)\r\n})\r\n\r\nModal.displayName = 'Modal'\r\n"],"names":["sizeWidths","CloseIcon","memo","jsx","Modal","forwardRef","isOpen","onClose","size","title","description","closeOnOverlayClick","closeOnEscape","showCloseButton","className","style","testId","children","props","ref","modalRef","useRef","previousActiveElement","wasOpen","useEffect","onCloseRef","modal","handleKeyDown","e","focusableElements","firstElement","lastElement","handleOverlayClick","useCallback","overlayStyle","useMemo","spacing","modalStyle","headerStyle","titleContainerStyle","titleStyle","fontSizes","descriptionStyle","closeButtonStyle","iconButtonSizes","componentGap","contentStyle","modalContent","jsxs","node","cx","createPortal"],"mappings":"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"}
|
package/dist/feedback.d.ts
CHANGED
|
@@ -95,7 +95,7 @@ export declare interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
95
95
|
children?: ReactNode;
|
|
96
96
|
}
|
|
97
97
|
|
|
98
|
-
export declare type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
98
|
+
export declare type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';
|
|
99
99
|
|
|
100
100
|
export declare const Popover: default_2.ForwardRefExoticComponent<PopoverProps & default_2.RefAttributes<HTMLDivElement>>;
|
|
101
101
|
|
package/dist/index.d.ts
CHANGED
|
@@ -2526,7 +2526,7 @@ export declare interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>,
|
|
|
2526
2526
|
children?: ReactNode;
|
|
2527
2527
|
}
|
|
2528
2528
|
|
|
2529
|
-
export declare type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | 'full';
|
|
2529
|
+
export declare type ModalSize = 'sm' | 'md' | 'lg' | 'xl' | '2xl' | 'full';
|
|
2530
2530
|
|
|
2531
2531
|
/**
|
|
2532
2532
|
* Modal/dialog width presets.
|