@mattermost/compass-ui 0.1.0-alpha.13 → 0.1.0-alpha.15
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/action-button/ActionButton.cjs +1 -1
- package/dist/components/action-button/ActionButton.cjs.map +1 -1
- package/dist/components/action-button/ActionButton.css +1 -1
- package/dist/components/action-button/ActionButton.d.ts +41 -5
- package/dist/components/action-button/ActionButton.d.ts.map +1 -1
- package/dist/components/action-button/ActionButton.js +68 -35
- package/dist/components/action-button/ActionButton.js.map +1 -1
- package/dist/components/action-button/ActionButton.module.scss.cjs +1 -1
- package/dist/components/action-button/ActionButton.module.scss.js +6 -5
- package/dist/components/action-button/ActionButton.module.scss.js.map +1 -1
- package/dist/components/action-button/index.d.ts +1 -1
- package/dist/components/action-button/index.d.ts.map +1 -1
- package/dist/components/button/Button.cjs +1 -1
- package/dist/components/button/Button.cjs.map +1 -1
- package/dist/components/button/Button.css +1 -1
- package/dist/components/button/Button.d.ts +37 -6
- package/dist/components/button/Button.d.ts.map +1 -1
- package/dist/components/button/Button.js +106 -44
- package/dist/components/button/Button.js.map +1 -1
- package/dist/components/button/Button.module.scss.cjs +1 -1
- package/dist/components/button/Button.module.scss.js +16 -15
- package/dist/components/button/Button.module.scss.js.map +1 -1
- package/dist/components/button/index.d.ts +1 -1
- package/dist/components/button/index.d.ts.map +1 -1
- package/dist/components/channel-sidebar-item/ChannelSidebarItem.cjs +1 -1
- package/dist/components/channel-sidebar-item/ChannelSidebarItem.cjs.map +1 -1
- package/dist/components/channel-sidebar-item/ChannelSidebarItem.d.ts.map +1 -1
- package/dist/components/channel-sidebar-item/ChannelSidebarItem.js +32 -31
- package/dist/components/channel-sidebar-item/ChannelSidebarItem.js.map +1 -1
- package/dist/components/checkbox/Checkbox.css +1 -1
- package/dist/components/checkbox/Checkbox.module.scss.cjs +1 -1
- package/dist/components/checkbox/Checkbox.module.scss.js +10 -10
- package/dist/components/icon-button/IconButton.cjs +1 -1
- package/dist/components/icon-button/IconButton.cjs.map +1 -1
- package/dist/components/icon-button/IconButton.css +1 -1
- package/dist/components/icon-button/IconButton.d.ts +48 -7
- package/dist/components/icon-button/IconButton.d.ts.map +1 -1
- package/dist/components/icon-button/IconButton.js +136 -62
- package/dist/components/icon-button/IconButton.js.map +1 -1
- package/dist/components/icon-button/IconButton.module.scss.cjs +1 -1
- package/dist/components/icon-button/IconButton.module.scss.js +16 -15
- package/dist/components/icon-button/IconButton.module.scss.js.map +1 -1
- package/dist/components/icon-button/index.d.ts +1 -1
- package/dist/components/icon-button/index.d.ts.map +1 -1
- package/dist/components/modal/Modal.cjs +1 -1
- package/dist/components/modal/Modal.cjs.map +1 -1
- package/dist/components/modal/Modal.css +1 -1
- package/dist/components/modal/Modal.d.ts +25 -3
- package/dist/components/modal/Modal.d.ts.map +1 -1
- package/dist/components/modal/Modal.js +105 -68
- package/dist/components/modal/Modal.js.map +1 -1
- package/dist/components/modal/Modal.module.scss.cjs +1 -1
- package/dist/components/modal/Modal.module.scss.js +14 -12
- package/dist/components/modal/Modal.module.scss.js.map +1 -1
- package/dist/components/modal-header/ModalHeader.css +1 -1
- package/dist/components/modal-header/ModalHeader.module.scss.cjs +1 -1
- package/dist/components/modal-header/ModalHeader.module.scss.js +15 -15
- package/dist/components/popover-menu/PopoverMenu.cjs +1 -1
- package/dist/components/popover-menu/PopoverMenu.cjs.map +1 -1
- package/dist/components/popover-menu/PopoverMenu.css +1 -1
- package/dist/components/popover-menu/PopoverMenu.d.ts +9 -1
- package/dist/components/popover-menu/PopoverMenu.d.ts.map +1 -1
- package/dist/components/popover-menu/PopoverMenu.js +39 -28
- package/dist/components/popover-menu/PopoverMenu.js.map +1 -1
- package/dist/components/popover-menu/PopoverMenu.module.scss.cjs +1 -1
- package/dist/components/popover-menu/PopoverMenu.module.scss.js +12 -10
- package/dist/components/popover-menu/PopoverMenu.module.scss.js.map +1 -1
- package/dist/components/radio/Radio.css +1 -1
- package/dist/components/radio/Radio.module.scss.cjs +1 -1
- package/dist/components/radio/Radio.module.scss.js +14 -14
- package/dist/components/right-sidebar-header/RightSidebarHeader.cjs +1 -1
- package/dist/components/right-sidebar-header/RightSidebarHeader.cjs.map +1 -1
- package/dist/components/right-sidebar-header/RightSidebarHeader.d.ts +5 -1
- package/dist/components/right-sidebar-header/RightSidebarHeader.d.ts.map +1 -1
- package/dist/components/right-sidebar-header/RightSidebarHeader.js +60 -48
- package/dist/components/right-sidebar-header/RightSidebarHeader.js.map +1 -1
- package/dist/components/switch/Switch.css +1 -1
- package/dist/components/switch/Switch.module.scss.cjs +1 -1
- package/dist/components/switch/Switch.module.scss.js +11 -11
- package/dist/components/tabs/Tabs.cjs +1 -1
- package/dist/components/tabs/Tabs.cjs.map +1 -1
- package/dist/components/tabs/Tabs.css +1 -1
- package/dist/components/tabs/Tabs.d.ts +4 -1
- package/dist/components/tabs/Tabs.d.ts.map +1 -1
- package/dist/components/tabs/Tabs.js +41 -35
- package/dist/components/tabs/Tabs.js.map +1 -1
- package/dist/components/tabs/Tabs.module.scss.cjs +1 -1
- package/dist/components/tabs/Tabs.module.scss.js +13 -12
- package/dist/components/tabs/Tabs.module.scss.js.map +1 -1
- package/dist/components/tabs/index.d.ts +1 -1
- package/dist/components/tabs/index.d.ts.map +1 -1
- package/dist/hooks/use-modal-focus.cjs +2 -0
- package/dist/hooks/use-modal-focus.cjs.map +1 -0
- package/dist/hooks/use-modal-focus.d.ts +26 -0
- package/dist/hooks/use-modal-focus.d.ts.map +1 -0
- package/dist/hooks/use-modal-focus.js +91 -0
- package/dist/hooks/use-modal-focus.js.map +1 -0
- package/dist/hooks/use-popover-transition.cjs +1 -1
- package/dist/hooks/use-popover-transition.cjs.map +1 -1
- package/dist/hooks/use-popover-transition.d.ts +6 -4
- package/dist/hooks/use-popover-transition.d.ts.map +1 -1
- package/dist/hooks/use-popover-transition.js +19 -15
- package/dist/hooks/use-popover-transition.js.map +1 -1
- package/dist/utils/duration.cjs +2 -0
- package/dist/utils/duration.cjs.map +1 -0
- package/dist/utils/duration.d.ts +8 -0
- package/dist/utils/duration.d.ts.map +1 -0
- package/dist/utils/duration.js +11 -0
- package/dist/utils/duration.js.map +1 -0
- package/dist/utils/slot.cjs +2 -0
- package/dist/utils/slot.cjs.map +1 -0
- package/dist/utils/slot.d.ts +46 -0
- package/dist/utils/slot.d.ts.map +1 -0
- package/dist/utils/slot.js +88 -0
- package/dist/utils/slot.js.map +1 -0
- package/package.json +5 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.js","sources":["../../../src/components/icon-button/IconButton.tsx"],"sourcesContent":["import { forwardRef, type ButtonHTMLAttributes, type ReactNode } from 'react';\nimport { IconSlotContext } from '@/components/icon/Icon';\nimport Spinner from '@/components/spinner/Spinner';\nimport { toKebab } from '@/utils/string';\nimport styles from './IconButton.module.scss';\n\nexport type IconButtonSize = 'x-small' | 'small' | 'medium' | 'large';\n\n/** Figma \"Style\": Default (light context) | Inverted (dark context). */\nexport type IconButtonStyle = 'default' | 'inverted';\n\nexport type IconButtonPadding = 'default' | 'compact';\n\nexport interface IconButtonProps extends Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n 'style'\n> {\n /** When true, forces the subtler pressed/active visual (lighter than toggled). */\n active?: boolean;\n /** Optional CSS class name. */\n className?: string;\n /** Numeric count shown inline after the icon. Figma: Count. */\n count?: number;\n /** When true, uses destructive (danger) styling. Figma: Destructive. */\n destructive?: boolean;\n /** Icon to show. Pass `<Icon glyph={<YourIcon />} />` — IconButton provides the correct size via context; no `size` prop needed on the Icon. */\n icon: ReactNode;\n /** When true, shows a Spinner in place of the icon and disables the button. */\n loading?: boolean;\n /** Padding variant. Figma: Padding = Default | Compact. */\n padding?: IconButtonPadding;\n /** When true, uses full border radius (pill). Figma: Rounded = On. */\n rounded?: boolean;\n /** Size variant. Figma: Size. Default: Medium. */\n size?: IconButtonSize;\n /** Default | Inverted. Figma: Style (for light vs dark backgrounds). */\n style?: IconButtonStyle;\n /** When true, shows toggled/selected state. Figma: Toggled = On. When omitted, the control is not a toggle. */\n toggled?: boolean;\n /** When true, shows a small unread dot over the icon. Figma: Unread Badge. */\n unreadBadge?: boolean;\n}\n\n/**\n * @deprecated No longer needed — IconButton sets the icon size via context.\n * Pass `<Icon glyph={<YourIcon />} />` without a size prop.\n */\nexport const ICON_BUTTON_ICON_SIZES: Record<\n IconButtonSize,\n '12' | '16' | '20' | '24'\n> = {\n 'x-small': '12',\n small: '16',\n medium: '20',\n large: '24',\n};\n\n/**\n * Icon Buttons are compact, label-free actions for tight surfaces — channel headers, message\n * hover actions, modal dismissals, toolbar slots. They lean on the icon to communicate\n * intent, so every Icon Button must pair with a tooltip or `aria-label` that makes the\n * action explicit.\n */\nconst IconButton = forwardRef<HTMLButtonElement, IconButtonProps>(\n function IconButton(\n {\n active = false,\n className = '',\n count,\n destructive = false,\n icon,\n loading = false,\n padding = 'default',\n rounded = false,\n size = 'medium',\n style = 'default',\n toggled,\n unreadBadge = false,\n disabled,\n type = 'button',\n 'aria-label': ariaLabel,\n ...rest\n },\n ref,\n ) {\n const sizeClass = styles[`icon-button--size-${toKebab(size)}`];\n const paddingClass =\n padding === 'compact' ? styles['icon-button--padding-compact'] : '';\n const styleClass =\n style === 'inverted' ? styles['icon-button--style-inverted'] : '';\n const destructiveClass = destructive\n ? styles['icon-button--destructive']\n : '';\n const roundedClass = rounded ? styles['icon-button--rounded'] : '';\n const toggledClass = toggled ? styles['icon-button--toggled'] : '';\n const activeClass = active ? styles['icon-button--active'] : '';\n const hasCount = count !== undefined;\n const hasCountClass = hasCount ? styles['icon-button--has-count'] : '';\n\n const rootClass = [\n styles['icon-button'],\n sizeClass,\n paddingClass,\n styleClass,\n destructiveClass,\n roundedClass,\n toggledClass,\n activeClass,\n hasCountClass,\n className,\n ]\n .filter(Boolean)\n .join(' ');\n\n const spinnerSize = ICON_BUTTON_ICON_SIZES[size];\n\n return (\n <button\n ref={ref}\n className={rootClass}\n type={type}\n disabled={disabled || loading}\n aria-label={ariaLabel}\n aria-pressed={toggled === undefined ? undefined : toggled}\n data-active={active ? 'true' : undefined}\n {...rest}\n >\n <span className={styles['icon-button__icon-slot']} aria-hidden>\n {loading ? (\n <Spinner size={spinnerSize} inverted={style === 'inverted'} />\n ) : (\n <IconSlotContext.Provider value={{ size: spinnerSize }}>\n {icon}\n </IconSlotContext.Provider>\n )}\n {unreadBadge && !loading && (\n <span className={styles['icon-button__unread-badge']} />\n )}\n </span>\n {hasCount && (\n <span className={styles['icon-button__count']}>{count}</span>\n )}\n </button>\n );\n },\n);\n\nIconButton.displayName = 'IconButton';\n\nexport default IconButton;\n"],"names":["ICON_BUTTON_ICON_SIZES","IconButton","forwardRef","active","className","count","destructive","icon","loading","padding","rounded","size","style","toggled","unreadBadge","disabled","type","ariaLabel","rest","ref","sizeClass","styles","toKebab","paddingClass","styleClass","destructiveClass","roundedClass","toggledClass","activeClass","hasCount","hasCountClass","rootClass","spinnerSize","jsxs","Spinner","jsx","IconSlotContext"],"mappings":";;;;;;AA+CO,MAAMA,IAGT;AAAA,EACF,WAAW;AAAA,EACX,OAAO;AAAA,EACP,QAAQ;AAAA,EACR,OAAO;AACT,GAQMC,IAAaC;AAAA,EACjB,SACE;AAAA,IACE,QAAAC,IAAS;AAAA,IACT,WAAAC,IAAY;AAAA,IACZ,OAAAC;AAAA,IACA,aAAAC,IAAc;AAAA,IACd,MAAAC;AAAA,IACA,SAAAC,IAAU;AAAA,IACV,SAAAC,IAAU;AAAA,IACV,SAAAC,IAAU;AAAA,IACV,MAAAC,IAAO;AAAA,IACP,OAAAC,IAAQ;AAAA,IACR,SAAAC;AAAA,IACA,aAAAC,IAAc;AAAA,IACd,UAAAC;AAAA,IACA,MAAAC,IAAO;AAAA,IACP,cAAcC;AAAA,IACd,GAAGC;AAAA,EAAA,GAELC,GACA;AACA,UAAMC,IAAYC,EAAO,qBAAqBC,EAAQX,CAAI,CAAC,EAAE,GACvDY,IACJd,MAAY,YAAYY,EAAO,8BAA8B,IAAI,IAC7DG,IACJZ,MAAU,aAAaS,EAAO,6BAA6B,IAAI,IAC3DI,IAAmBnB,IACrBe,EAAO,0BAA0B,IACjC,IACEK,IAAehB,IAAUW,EAAO,sBAAsB,IAAI,IAC1DM,IAAed,IAAUQ,EAAO,sBAAsB,IAAI,IAC1DO,IAAczB,IAASkB,EAAO,qBAAqB,IAAI,IACvDQ,IAAWxB,MAAU,QACrByB,IAAgBD,IAAWR,EAAO,wBAAwB,IAAI,IAE9DU,IAAY;AAAA,MAChBV,EAAO,aAAa;AAAA,MACpBD;AAAA,MACAG;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAC;AAAA,MACAE;AAAA,MACA1B;AAAA,IAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG,GAEL4B,IAAchC,EAAuBW,CAAI;AAE/C,WACE,gBAAAsB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,KAAAd;AAAA,QACA,WAAWY;AAAA,QACX,MAAAf;AAAA,QACA,UAAUD,KAAYP;AAAA,QACtB,cAAYS;AAAA,QACZ,gBAAcJ,MAAY,SAAY,SAAYA;AAAA,QAClD,eAAaV,IAAS,SAAS;AAAA,QAC9B,GAAGe;AAAA,QAEJ,UAAA;AAAA,UAAA,gBAAAe,EAAC,UAAK,WAAWZ,EAAO,wBAAwB,GAAG,eAAW,IAC3D,UAAA;AAAA,YAAAb,sBACE0B,GAAA,EAAQ,MAAMF,GAAa,UAAUpB,MAAU,YAAY,IAE5D,gBAAAuB,EAACC,EAAgB,UAAhB,EAAyB,OAAO,EAAE,MAAMJ,EAAA,GACtC,UAAAzB,GACH;AAAA,YAEDO,KAAe,CAACN,KACf,gBAAA2B,EAAC,UAAK,WAAWd,EAAO,2BAA2B,EAAA,CAAG;AAAA,UAAA,GAE1D;AAAA,UACCQ,KACC,gBAAAM,EAAC,QAAA,EAAK,WAAWd,EAAO,oBAAoB,GAAI,UAAAhB,EAAA,CAAM;AAAA,QAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAI9D;AACF;AAEAJ,EAAW,cAAc;"}
|
|
1
|
+
{"version":3,"file":"IconButton.js","sources":["../../../src/components/icon-button/IconButton.tsx"],"sourcesContent":["import {\n forwardRef,\n type ButtonHTMLAttributes,\n type HTMLAttributes,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefAttributes,\n} from 'react';\nimport { IconSlotContext } from '@/components/icon/Icon';\nimport Spinner from '@/components/spinner/Spinner';\nimport { renderAsChild } from '@/utils/slot';\nimport { toKebab } from '@/utils/string';\nimport styles from './IconButton.module.scss';\n\nexport type IconButtonSize = 'x-small' | 'small' | 'medium' | 'large';\n\n/** Figma \"Style\": Default (light context) | Inverted (dark context). */\nexport type IconButtonStyle = 'default' | 'inverted';\n\nexport type IconButtonPadding = 'default' | 'compact';\n\ninterface IconButtonOwnProps {\n /** When true, forces the subtler pressed/active visual (lighter than toggled). */\n active?: boolean;\n /** Optional CSS class name. */\n className?: string;\n /** Numeric count shown inline after the icon. Figma: Count. */\n count?: number;\n /** When true, uses destructive (danger) styling. Figma: Destructive. */\n destructive?: boolean;\n /** Icon to show. Pass `<Icon glyph={<YourIcon />} />` — IconButton provides the correct size via context; no `size` prop needed on the Icon. */\n icon: ReactNode;\n /** When true, shows a Spinner in place of the icon and disables the button (or blocks navigation when `asChild`). */\n loading?: boolean;\n /** Padding variant. Figma: Padding = Default | Compact. */\n padding?: IconButtonPadding;\n /** When true, uses full border radius (pill). Figma: Rounded = On. */\n rounded?: boolean;\n /** Size variant. Figma: Size. Default: Medium. */\n size?: IconButtonSize;\n /** Default | Inverted. Figma: Style (for light vs dark backgrounds). Replaces the HTML `style` attribute. */\n style?: IconButtonStyle;\n /** When true, shows a small unread dot over the icon. Figma: Unread Badge. */\n unreadBadge?: boolean;\n /**\n * When true, disables the control. On a native `<button>`, sets the `disabled`\n * attribute. With `asChild`, sets `aria-disabled`, applies disabled styles, and\n * blocks click / middle-click navigation (the link stays focusable).\n */\n disabled?: boolean;\n}\n\nexport interface IconButtonProps\n extends\n IconButtonOwnProps,\n Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'style'> {\n /**\n * When true, merges IconButton props onto the single child element instead of\n * rendering a `<button>`. Use with `<a>` or a router `Link`. Default: false.\n */\n asChild?: false;\n /**\n * When true, shows toggled/selected state. Figma: Toggled = On. When omitted,\n * the control is not a toggle. Only applies to the native `<button>` (maps to\n * `aria-pressed`); not available with `asChild`.\n */\n toggled?: boolean;\n}\n\nexport interface IconButtonAsChildProps\n extends\n IconButtonOwnProps,\n Omit<HTMLAttributes<HTMLElement>, 'children' | 'color' | 'style'> {\n /**\n * Merges IconButton props onto the single child element instead of rendering a\n * `<button>`. The child's own props (`href`, `to`, `target`, …) stay on the\n * child. Do not pass `type` or `toggled` — they are not available on links.\n * Pass an empty child; IconButton supplies the icon anatomy.\n */\n asChild: true;\n /** Single empty element to render as the IconButton (e.g. `<a href=\"…\" />`). */\n children: ReactElement;\n /**\n * Accessible name for the icon-only link. Required with `asChild`. An\n * `aria-label` on the child also satisfies this (child props win).\n */\n 'aria-label': string;\n}\n\n/**\n * @deprecated No longer needed — IconButton sets the icon size via context.\n * Pass `<Icon glyph={<YourIcon />} />` without a size prop.\n */\nexport const ICON_BUTTON_ICON_SIZES: Record<\n IconButtonSize,\n '12' | '16' | '20' | '24'\n> = {\n 'x-small': '12',\n small: '16',\n medium: '20',\n large: '24',\n};\n\ntype IconButtonComponent = {\n (\n props: IconButtonAsChildProps & RefAttributes<HTMLElement>,\n ): ReactElement | null;\n (\n props: IconButtonProps & RefAttributes<HTMLButtonElement>,\n ): ReactElement | null;\n displayName?: string;\n};\n\nfunction buildRootClass({\n className = '',\n count,\n destructive = false,\n padding = 'default',\n rounded = false,\n size = 'medium',\n style = 'default',\n active = false,\n toggled,\n}: {\n className?: string;\n count?: number;\n destructive?: boolean;\n padding?: IconButtonPadding;\n rounded?: boolean;\n size?: IconButtonSize;\n style?: IconButtonStyle;\n active?: boolean;\n toggled?: boolean;\n}): string {\n return [\n styles['icon-button'],\n styles[`icon-button--size-${toKebab(size)}`],\n padding === 'compact' ? styles['icon-button--padding-compact'] : '',\n style === 'inverted' ? styles['icon-button--style-inverted'] : '',\n destructive ? styles['icon-button--destructive'] : '',\n rounded ? styles['icon-button--rounded'] : '',\n toggled ? styles['icon-button--toggled'] : '',\n active ? styles['icon-button--active'] : '',\n count !== undefined ? styles['icon-button--has-count'] : '',\n className,\n ]\n .filter(Boolean)\n .join(' ');\n}\n\n/**\n * Icon Buttons are compact, label-free actions for tight surfaces — channel headers, message\n * hover actions, modal dismissals, toolbar slots. They lean on the icon to communicate\n * intent, so every Icon Button must pair with a tooltip or `aria-label` that makes the\n * action explicit.\n *\n * Pass `asChild` with a single empty `<a>` or router `Link` child to render a navigational\n * icon control with Icon Button styling (no nested `<button>`).\n */\nconst IconButton = forwardRef(function IconButton(\n props: IconButtonProps | IconButtonAsChildProps,\n ref: Ref<HTMLButtonElement | HTMLElement>,\n) {\n if (props.asChild) {\n const {\n active = false,\n className = '',\n count,\n destructive = false,\n icon,\n loading = false,\n padding = 'default',\n rounded = false,\n size = 'medium',\n style = 'default',\n unreadBadge = false,\n disabled,\n children,\n 'aria-label': ariaLabel,\n asChild,\n ...rest\n } = props;\n void asChild;\n\n const rootClass = buildRootClass({\n className,\n count,\n destructive,\n padding,\n rounded,\n size,\n style,\n active,\n });\n const spinnerSize = ICON_BUTTON_ICON_SIZES[size];\n const isDisabled = Boolean(disabled || loading);\n const hasCount = count !== undefined;\n\n const anatomy = (\n <>\n <span className={styles['icon-button__icon-slot']} aria-hidden>\n {loading ? (\n <Spinner size={spinnerSize} inverted={style === 'inverted'} />\n ) : (\n <IconSlotContext.Provider value={{ size: spinnerSize }}>\n {icon}\n </IconSlotContext.Provider>\n )}\n {unreadBadge && !loading && (\n <span className={styles['icon-button__unread-badge']} />\n )}\n </span>\n {hasCount && (\n <span className={styles['icon-button__count']}>{count}</span>\n )}\n </>\n );\n\n return renderAsChild({\n child: children,\n props: {\n ...rest,\n className: rootClass,\n 'aria-label': ariaLabel,\n 'data-active': active ? 'true' : undefined,\n ...(loading ? { 'aria-busy': true } : null),\n },\n ref,\n content: anatomy,\n disabled: isDisabled,\n disabledClassName: styles['icon-button--disabled'],\n warnOnChildContent: true,\n });\n }\n\n const {\n active = false,\n className = '',\n count,\n destructive = false,\n icon,\n loading = false,\n padding = 'default',\n rounded = false,\n size = 'medium',\n style = 'default',\n toggled,\n unreadBadge = false,\n disabled,\n type = 'button',\n 'aria-label': ariaLabel,\n asChild,\n ...rest\n } = props;\n void asChild;\n\n const rootClass = buildRootClass({\n className,\n count,\n destructive,\n padding,\n rounded,\n size,\n style,\n active,\n toggled,\n });\n const spinnerSize = ICON_BUTTON_ICON_SIZES[size];\n const isDisabled = Boolean(disabled || loading);\n const hasCount = count !== undefined;\n\n return (\n <button\n ref={ref as Ref<HTMLButtonElement>}\n className={rootClass}\n type={type}\n disabled={isDisabled}\n aria-label={ariaLabel}\n aria-pressed={toggled === undefined ? undefined : toggled}\n data-active={active ? 'true' : undefined}\n {...rest}\n >\n <span className={styles['icon-button__icon-slot']} aria-hidden>\n {loading ? (\n <Spinner size={spinnerSize} inverted={style === 'inverted'} />\n ) : (\n <IconSlotContext.Provider value={{ size: spinnerSize }}>\n {icon}\n </IconSlotContext.Provider>\n )}\n {unreadBadge && !loading && (\n <span className={styles['icon-button__unread-badge']} />\n )}\n </span>\n {hasCount && (\n <span className={styles['icon-button__count']}>{count}</span>\n )}\n </button>\n );\n}) as IconButtonComponent;\n\nIconButton.displayName = 'IconButton';\n\nexport default IconButton;\n"],"names":["ICON_BUTTON_ICON_SIZES","buildRootClass","className","count","destructive","padding","rounded","size","style","active","toggled","styles","toKebab","IconButton","forwardRef","props","ref","icon","loading","unreadBadge","disabled","children","ariaLabel","asChild","rest","rootClass","spinnerSize","isDisabled","hasCount","anatomy","jsxs","Fragment","jsx","Spinner","IconSlotContext","renderAsChild","type"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require('./IconButton.css');const t={"icon-button":"_icon-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require('./IconButton.css');const t={"icon-button":"_icon-button_13ryy_2","icon-button--disabled":"_icon-button--disabled_13ryy_27","icon-button--active":"_icon-button--active_13ryy_31","icon-button--toggled":"_icon-button--toggled_13ryy_31","icon-button__icon-slot":"_icon-button__icon-slot_13ryy_41","icon-button__unread-badge":"_icon-button__unread-badge_13ryy_48","icon-button__count":"_icon-button__count_13ryy_59","icon-button--size-x-small":"_icon-button--size-x-small_13ryy_63","icon-button--padding-compact":"_icon-button--padding-compact_13ryy_72","icon-button--size-small":"_icon-button--size-small_13ryy_77","icon-button--size-medium":"_icon-button--size-medium_13ryy_91","icon-button--size-large":"_icon-button--size-large_13ryy_105","icon-button--has-count":"_icon-button--has-count_13ryy_119","icon-button--rounded":"_icon-button--rounded_13ryy_123","icon-button--style-inverted":"_icon-button--style-inverted_13ryy_159","icon-button--destructive":"_icon-button--destructive_13ryy_210"};exports.default=t;
|
|
2
2
|
//# sourceMappingURL=IconButton.module.scss.cjs.map
|
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
import './IconButton.css';const t = {
|
|
2
|
-
"icon-button": "_icon-
|
|
3
|
-
"icon-button--
|
|
4
|
-
"icon-button--
|
|
5
|
-
"icon-
|
|
6
|
-
"icon-
|
|
7
|
-
"icon-
|
|
8
|
-
"icon-
|
|
9
|
-
"icon-button--
|
|
10
|
-
"icon-button--
|
|
11
|
-
"icon-button--size-
|
|
12
|
-
"icon-button--size-
|
|
13
|
-
"icon-button--
|
|
14
|
-
"icon-button--
|
|
15
|
-
"icon-button--
|
|
16
|
-
"icon-button--
|
|
2
|
+
"icon-button": "_icon-button_13ryy_2",
|
|
3
|
+
"icon-button--disabled": "_icon-button--disabled_13ryy_27",
|
|
4
|
+
"icon-button--active": "_icon-button--active_13ryy_31",
|
|
5
|
+
"icon-button--toggled": "_icon-button--toggled_13ryy_31",
|
|
6
|
+
"icon-button__icon-slot": "_icon-button__icon-slot_13ryy_41",
|
|
7
|
+
"icon-button__unread-badge": "_icon-button__unread-badge_13ryy_48",
|
|
8
|
+
"icon-button__count": "_icon-button__count_13ryy_59",
|
|
9
|
+
"icon-button--size-x-small": "_icon-button--size-x-small_13ryy_63",
|
|
10
|
+
"icon-button--padding-compact": "_icon-button--padding-compact_13ryy_72",
|
|
11
|
+
"icon-button--size-small": "_icon-button--size-small_13ryy_77",
|
|
12
|
+
"icon-button--size-medium": "_icon-button--size-medium_13ryy_91",
|
|
13
|
+
"icon-button--size-large": "_icon-button--size-large_13ryy_105",
|
|
14
|
+
"icon-button--has-count": "_icon-button--has-count_13ryy_119",
|
|
15
|
+
"icon-button--rounded": "_icon-button--rounded_13ryy_123",
|
|
16
|
+
"icon-button--style-inverted": "_icon-button--style-inverted_13ryy_159",
|
|
17
|
+
"icon-button--destructive": "_icon-button--destructive_13ryy_210"
|
|
17
18
|
};
|
|
18
19
|
export {
|
|
19
20
|
t as default
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"IconButton.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"IconButton.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export { default as IconButton } from './IconButton';
|
|
2
|
-
export { ICON_BUTTON_ICON_SIZES, type IconButtonProps, type IconButtonSize, type IconButtonStyle, type IconButtonPadding, } from './IconButton';
|
|
2
|
+
export { ICON_BUTTON_ICON_SIZES, type IconButtonProps, type IconButtonAsChildProps, type IconButtonSize, type IconButtonStyle, type IconButtonPadding, } from './IconButton';
|
|
3
3
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/icon-button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/icon-button/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,sBAAsB,EACtB,KAAK,eAAe,EACpB,KAAK,sBAAsB,EAC3B,KAAK,cAAc,EACnB,KAAK,eAAe,EACpB,KAAK,iBAAiB,GACvB,MAAM,cAAc,CAAC"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});const o=require("react/jsx-runtime"),n=require("react"),T=require("../../hooks/use-modal-focus.cjs"),$=require("../../hooks/use-popover-transition.cjs"),A=require("../scrollbar/Scrollbar.cjs"),D=require("../modal-footer/ModalFooter.cjs"),G=require("../modal-header/ModalHeader.cjs"),J=require("../../utils/string.cjs"),e=require("./Modal.module.scss.cjs");function Q({className:s="",style:a,size:i="small",title:r,subtitle:l,subtitlePlacement:c="below",hideTitle:u=!1,showBackButton:t=!1,onBack:d,backLabel:x,backButtonProps:y,onClose:m,closeLabel:I,closeButtonProps:R,headerDivider:g=!0,headerAction:F,headerSlot:w,bodyPadding:b="default",scrollable:N=!0,children:P,footer:_,footerLeading:v,footerType:f="2-actions",footerDivider:S=!0,closeOnEscape:k=!0,initialFocusRef:p,active:z,transition:j,visible:B,...C}){const M=n.useRef(null);T.useModalFocus(M,{initialFocusRef:p,closeOnEscape:k,onClose:m,active:z});const q=n.useId(),H=e.default[`modal--size-${J.toKebab(i)}`],K=[e.default["modal__body-inner"],b==="menu"&&e.default["modal__body-inner--menu"],b==="none"&&e.default["modal__body-inner--none"]].filter(Boolean).join(" "),h=o.jsx("div",{className:K,children:P}),O=_!=null||v!=null||f==="spacer-small"||f==="spacer-large";return o.jsxs("div",{...C,ref:M,tabIndex:-1,className:[e.default.modal,H,j&&e.default["modal--transition"],j&&B&&e.default["modal--visible"],s].filter(Boolean).join(" "),style:a,role:"dialog","aria-modal":"true","aria-labelledby":q,children:[o.jsx(G.default,{title:r,titleId:q,subtitle:l,subtitlePlacement:c,hideTitle:u,showBackButton:t,onBack:d,backLabel:x,backButtonProps:y,onClose:m,closeLabel:I,closeButtonProps:R,divider:g,headerAction:F,headerSlot:w}),o.jsx("div",{className:e.default.modal__body,children:N?o.jsx(A.default,{children:h}):h}),O&&o.jsx(D.default,{type:f,divider:S,leading:v,children:_})]})}function U({open:s,onExited:a,...i}){const r=s!==void 0,{mounted:l,visible:c}=$.usePopoverTransition(s??!0),u=n.useRef(l),t=n.useRef(a);return t.current=a,n.useEffect(()=>{var d;u.current&&!l&&r&&((d=t.current)==null||d.call(t)),u.current=l},[l,r]),r&&!l?null:o.jsx(Q,{...i,active:s??!0,transition:r,visible:c})}exports.default=U;
|
|
2
2
|
//# sourceMappingURL=Modal.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.cjs","sources":["../../../src/components/modal/Modal.tsx"],"sourcesContent":["import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\nimport { useId } from 'react';\nimport Scrollbar from '@/components/scrollbar/Scrollbar';\nimport ModalFooter from '@/components/modal-footer/ModalFooter';\nimport type { ModalFooterType } from '@/components/modal-footer/ModalFooter';\nimport ModalHeader from '@/components/modal-header/ModalHeader';\nimport type { ModalSubtitlePlacement } from '@/components/modal-header/ModalHeader';\nimport type { BuiltInButtonProps } from '@/utils/props';\nimport { toKebab } from '@/utils/string';\nimport styles from './Modal.module.scss';\n\nexport type ModalSize = 'small' | 'medium' | 'large';\n\n/**\n * Body inset. `menu` is for MenuItem lists — 8px vertical / 16px horizontal so\n * row labels align with the 32px header/footer margins. `none` removes inset\n * for host-owned full-bleed layouts (e.g. settings sidebars).\n */\nexport type ModalBodyPadding = 'default' | 'menu' | 'none';\n\nexport type { ModalFooterType, ModalSubtitlePlacement };\n\nexport interface ModalProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title' | 'children' | 'style'\n> {\n /** Extra class on the dialog root (size + chrome classes still apply). */\n className?: string;\n /** Inline style on the dialog root — prefer `className` for layout overrides. */\n style?: CSSProperties;\n /** Width variant. Figma: Size — Small 600px, Medium 704px, Large 832px. */\n size?: ModalSize;\n /** Modal heading text. Required for a11y; use `hideTitle` for close-only chrome. */\n title: ReactNode;\n /** Optional secondary line — placement via `subtitlePlacement`. */\n subtitle?: ReactNode;\n /**\n * Where the subtitle sits. Figma Modal Header: Below | Beside.\n * Default: `below`.\n */\n subtitlePlacement?: ModalSubtitlePlacement;\n /** Visually hide the title (close-only header); title remains for `aria-labelledby`. */\n hideTitle?: boolean;\n /** When true, shows a back-arrow button before the title. */\n showBackButton?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible name for the back button. Default: \"Go back\". */\n backLabel?: string;\n /** Extra attributes for the back button (e.g. `data-testid`). */\n backButtonProps?: BuiltInButtonProps;\n /** Called when the × close button is clicked. */\n onClose?: () => void;\n /** Accessible name for the close button. Default: \"Close\". */\n closeLabel?: string;\n /** Extra attributes for the close button (e.g. `data-testid`). */\n closeButtonProps?: BuiltInButtonProps;\n /** Show divider between header and body. Default: true. */\n headerDivider?: boolean;\n /** Optional control before close (Button, search field, …). */\n headerAction?: ReactNode;\n /**\n * Full-width slot rendered below the title row and above the header divider.\n * Accepts any ReactNode — SearchInput, Tabs, a custom toolbar, etc.\n */\n headerSlot?: ReactNode;\n /**\n * Body inset. Default is 32px horizontal / 28px vertical. Use `menu` for\n * MenuItem lists. Use `none` when the host owns padding.\n */\n bodyPadding?: ModalBodyPadding;\n /**\n * When true (default), wraps body content in Scrollbar. Set false when the\n * host manages scroll inside panes.\n */\n scrollable?: boolean;\n /** Body content. */\n children: ReactNode;\n /** Footer slot — typically Buttons. Wrapped in `ModalFooter`. */\n footer?: ReactNode;\n /** Left footer slot (pagination status, PaginationDots, …). */\n footerLeading?: ReactNode;\n /** Footer layout. Figma Modal Footer Type. Default: `2-actions`. */\n footerType?: ModalFooterType;\n /** Show divider between body and footer. Default: true. */\n footerDivider?: boolean;\n}\n\n/**\n * Modal dialog shell — composes ModalHeader, scrollable body, and ModalFooter.\n * Host owns portal, overlay, focus trap, and open/close.\n */\nexport default function Modal({\n className = '',\n style,\n size = 'small',\n title,\n subtitle,\n subtitlePlacement = 'below',\n hideTitle = false,\n showBackButton = false,\n onBack,\n backLabel,\n backButtonProps,\n onClose,\n closeLabel,\n closeButtonProps,\n headerDivider = true,\n headerAction,\n headerSlot,\n bodyPadding = 'default',\n scrollable = true,\n children,\n footer,\n footerLeading,\n footerType = '2-actions',\n footerDivider = true,\n ...rest\n}: ModalProps) {\n const titleId = useId();\n const sizeClass = styles[`modal--size-${toKebab(size)}`];\n const bodyInnerClass = [\n styles['modal__body-inner'],\n bodyPadding === 'menu' && styles['modal__body-inner--menu'],\n bodyPadding === 'none' && styles['modal__body-inner--none'],\n ]\n .filter(Boolean)\n .join(' ');\n\n const bodyInner = <div className={bodyInnerClass}>{children}</div>;\n const showFooter =\n footer != null ||\n footerLeading != null ||\n footerType === 'spacer-small' ||\n footerType === 'spacer-large';\n\n return (\n <div\n {...rest}\n className={[styles.modal, sizeClass, className].filter(Boolean).join(' ')}\n style={style}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n >\n <ModalHeader\n title={title}\n titleId={titleId}\n subtitle={subtitle}\n subtitlePlacement={subtitlePlacement}\n hideTitle={hideTitle}\n showBackButton={showBackButton}\n onBack={onBack}\n backLabel={backLabel}\n backButtonProps={backButtonProps}\n onClose={onClose}\n closeLabel={closeLabel}\n closeButtonProps={closeButtonProps}\n divider={headerDivider}\n headerAction={headerAction}\n headerSlot={headerSlot}\n />\n\n <div className={styles['modal__body']}>\n {scrollable ? <Scrollbar>{bodyInner}</Scrollbar> : bodyInner}\n </div>\n\n {showFooter && (\n <ModalFooter\n type={footerType}\n divider={footerDivider}\n leading={footerLeading}\n >\n {footer}\n </ModalFooter>\n )}\n </div>\n );\n}\n"],"names":["Modal","className","style","size","title","subtitle","subtitlePlacement","hideTitle","showBackButton","onBack","backLabel","backButtonProps","onClose","closeLabel","closeButtonProps","headerDivider","headerAction","headerSlot","bodyPadding","scrollable","children","footer","footerLeading","footerType","footerDivider","rest","titleId","useId","sizeClass","styles","toKebab","bodyInnerClass","bodyInner","jsx","showFooter","jsxs","ModalHeader","Scrollbar","ModalFooter"],"mappings":"6WA4FA,SAAwBA,EAAM,CAC5B,UAAAC,EAAY,GACZ,MAAAC,EACA,KAAAC,EAAO,QACP,MAAAC,EACA,SAAAC,EACA,kBAAAC,EAAoB,QACpB,UAAAC,EAAY,GACZ,eAAAC,EAAiB,GACjB,OAAAC,EACA,UAAAC,EACA,gBAAAC,EACA,QAAAC,EACA,WAAAC,EACA,iBAAAC,EACA,cAAAC,EAAgB,GAChB,aAAAC,EACA,WAAAC,EACA,YAAAC,EAAc,UACd,WAAAC,EAAa,GACb,SAAAC,EACA,OAAAC,EACA,cAAAC,EACA,WAAAC,EAAa,YACb,cAAAC,EAAgB,GAChB,GAAGC,CACL,EAAe,CACb,MAAMC,EAAUC,EAAAA,MAAA,EACVC,EAAYC,EAAAA,QAAO,eAAeC,EAAAA,QAAQ3B,CAAI,CAAC,EAAE,EACjD4B,EAAiB,CACrBF,EAAAA,QAAO,mBAAmB,EAC1BX,IAAgB,QAAUW,EAAAA,QAAO,yBAAyB,EAC1DX,IAAgB,QAAUW,EAAAA,QAAO,yBAAyB,CAAA,EAEzD,OAAO,OAAO,EACd,KAAK,GAAG,EAELG,EAAYC,EAAAA,IAAC,MAAA,CAAI,UAAWF,EAAiB,SAAAX,EAAS,EACtDc,EACJb,GAAU,MACVC,GAAiB,MACjBC,IAAe,gBACfA,IAAe,eAEjB,OACEY,EAAAA,KAAC,MAAA,CACE,GAAGV,EACJ,UAAW,CAACI,EAAAA,QAAO,MAAOD,EAAW3B,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,EACxE,MAAAC,EACA,KAAK,SACL,aAAW,OACX,kBAAiBwB,EAEjB,SAAA,CAAAO,EAAAA,IAACG,EAAAA,QAAA,CACC,MAAAhC,EACA,QAAAsB,EACA,SAAArB,EACA,kBAAAC,EACA,UAAAC,EACA,eAAAC,EACA,OAAAC,EACA,UAAAC,EACA,gBAAAC,EACA,QAAAC,EACA,WAAAC,EACA,iBAAAC,EACA,QAASC,EACT,aAAAC,EACA,WAAAC,CAAA,CAAA,EAGFgB,EAAAA,IAAC,MAAA,CAAI,UAAWJ,EAAAA,QAAO,YACpB,SAAAV,EAAac,EAAAA,IAACI,EAAAA,QAAA,CAAW,SAAAL,CAAA,CAAU,EAAeA,EACrD,EAECE,GACCD,EAAAA,IAACK,EAAAA,QAAA,CACC,KAAMf,EACN,QAASC,EACT,QAASF,EAER,SAAAD,CAAA,CAAA,CACH,CAAA,CAAA,CAIR"}
|
|
1
|
+
{"version":3,"file":"Modal.cjs","sources":["../../../src/components/modal/Modal.tsx"],"sourcesContent":["import type {\n CSSProperties,\n HTMLAttributes,\n ReactNode,\n RefObject,\n} from 'react';\nimport { useEffect, useId, useRef } from 'react';\nimport { useModalFocus } from '@/hooks/use-modal-focus';\nimport { usePopoverTransition } from '@/hooks/use-popover-transition';\nimport Scrollbar from '@/components/scrollbar/Scrollbar';\nimport ModalFooter from '@/components/modal-footer/ModalFooter';\nimport type { ModalFooterType } from '@/components/modal-footer/ModalFooter';\nimport ModalHeader from '@/components/modal-header/ModalHeader';\nimport type { ModalSubtitlePlacement } from '@/components/modal-header/ModalHeader';\nimport type { BuiltInButtonProps } from '@/utils/props';\nimport { toKebab } from '@/utils/string';\nimport styles from './Modal.module.scss';\n\nexport type ModalSize = 'small' | 'medium' | 'large';\n\n/**\n * Body inset. `menu` is for MenuItem lists — 8px vertical / 16px horizontal so\n * row labels align with the 32px header/footer margins. `none` removes inset\n * for host-owned full-bleed layouts (e.g. settings sidebars).\n */\nexport type ModalBodyPadding = 'default' | 'menu' | 'none';\n\nexport type { ModalFooterType, ModalSubtitlePlacement };\n\nexport interface ModalProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title' | 'children' | 'style'\n> {\n /** Extra class on the dialog root (size + chrome classes still apply). */\n className?: string;\n /** Inline style on the dialog root — prefer `className` for layout overrides. */\n style?: CSSProperties;\n /** Width variant. Figma: Size — Small 600px, Medium 704px, Large 832px. */\n size?: ModalSize;\n /** Modal heading text. Required for a11y; use `hideTitle` for close-only chrome. */\n title: ReactNode;\n /** Optional secondary line — placement via `subtitlePlacement`. */\n subtitle?: ReactNode;\n /**\n * Where the subtitle sits. Figma Modal Header: Below | Beside.\n * Default: `below`.\n */\n subtitlePlacement?: ModalSubtitlePlacement;\n /** Visually hide the title (close-only header); title remains for `aria-labelledby`. */\n hideTitle?: boolean;\n /** When true, shows a back-arrow button before the title. */\n showBackButton?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible name for the back button. Default: \"Go back\". */\n backLabel?: string;\n /** Extra attributes for the back button (e.g. `data-testid`). */\n backButtonProps?: BuiltInButtonProps;\n /** Called when the × close button is clicked. */\n onClose?: () => void;\n /** Accessible name for the close button. Default: \"Close\". */\n closeLabel?: string;\n /** Extra attributes for the close button (e.g. `data-testid`). */\n closeButtonProps?: BuiltInButtonProps;\n /** Show divider between header and body. Default: true. */\n headerDivider?: boolean;\n /** Optional control before close (Button, search field, …). */\n headerAction?: ReactNode;\n /**\n * Full-width slot rendered below the title row and above the header divider.\n * Accepts any ReactNode — SearchInput, Tabs, a custom toolbar, etc.\n */\n headerSlot?: ReactNode;\n /**\n * Body inset. Default is 32px horizontal / 28px vertical. Use `menu` for\n * MenuItem lists. Use `none` when the host owns padding.\n */\n bodyPadding?: ModalBodyPadding;\n /**\n * When true (default), wraps body content in Scrollbar. Set false when the\n * host manages scroll inside panes.\n */\n scrollable?: boolean;\n /** Body content. */\n children: ReactNode;\n /** Footer slot — typically Buttons. Wrapped in `ModalFooter`. */\n footer?: ReactNode;\n /** Left footer slot (pagination status, PaginationDots, …). */\n footerLeading?: ReactNode;\n /** Footer layout. Figma Modal Footer Type. Default: `2-actions`. */\n footerType?: ModalFooterType;\n /** Show divider between body and footer. Default: true. */\n footerDivider?: boolean;\n /**\n * Close on Escape via a document listener while mounted. Escapes already\n * handled by an inner widget (`defaultPrevented`) are ignored. Default: true.\n */\n closeOnEscape?: boolean;\n /**\n * Element to focus when the modal mounts (e.g. the first form field).\n * Default: the dialog root.\n */\n initialFocusRef?: RefObject<HTMLElement | null>;\n /**\n * Controlled visibility with the Compass enter/exit transition (fade + drop from the top + subtle scale 98%→100%,\n * reverse on close, `--duration-quick`); the modal unmounts after the exit,\n * and focus is restored then. Omit to keep the mount-controlled behavior\n * (always rendered, no transition). The host still owns the state.\n */\n open?: boolean;\n /** Called after the exit transition finishes and the modal unmounts (only when `open` is controlled). */\n onExited?: () => void;\n}\n\ninterface ModalPanelState {\n active: boolean;\n transition: boolean;\n visible: boolean;\n}\n\nfunction ModalPanel({\n className = '',\n style,\n size = 'small',\n title,\n subtitle,\n subtitlePlacement = 'below',\n hideTitle = false,\n showBackButton = false,\n onBack,\n backLabel,\n backButtonProps,\n onClose,\n closeLabel,\n closeButtonProps,\n headerDivider = true,\n headerAction,\n headerSlot,\n bodyPadding = 'default',\n scrollable = true,\n children,\n footer,\n footerLeading,\n footerType = '2-actions',\n footerDivider = true,\n closeOnEscape = true,\n initialFocusRef,\n active,\n transition,\n visible,\n ...rest\n}: ModalProps & ModalPanelState) {\n const rootRef = useRef<HTMLDivElement>(null);\n useModalFocus(rootRef, {\n initialFocusRef,\n closeOnEscape,\n onClose,\n active,\n });\n const titleId = useId();\n const sizeClass = styles[`modal--size-${toKebab(size)}`];\n const bodyInnerClass = [\n styles['modal__body-inner'],\n bodyPadding === 'menu' && styles['modal__body-inner--menu'],\n bodyPadding === 'none' && styles['modal__body-inner--none'],\n ]\n .filter(Boolean)\n .join(' ');\n\n const bodyInner = <div className={bodyInnerClass}>{children}</div>;\n const showFooter =\n footer != null ||\n footerLeading != null ||\n footerType === 'spacer-small' ||\n footerType === 'spacer-large';\n\n return (\n <div\n {...rest}\n ref={rootRef}\n tabIndex={-1}\n className={[\n styles.modal,\n sizeClass,\n transition && styles['modal--transition'],\n transition && visible && styles['modal--visible'],\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n style={style}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n >\n <ModalHeader\n title={title}\n titleId={titleId}\n subtitle={subtitle}\n subtitlePlacement={subtitlePlacement}\n hideTitle={hideTitle}\n showBackButton={showBackButton}\n onBack={onBack}\n backLabel={backLabel}\n backButtonProps={backButtonProps}\n onClose={onClose}\n closeLabel={closeLabel}\n closeButtonProps={closeButtonProps}\n divider={headerDivider}\n headerAction={headerAction}\n headerSlot={headerSlot}\n />\n\n <div className={styles['modal__body']}>\n {scrollable ? <Scrollbar>{bodyInner}</Scrollbar> : bodyInner}\n </div>\n\n {showFooter && (\n <ModalFooter\n type={footerType}\n divider={footerDivider}\n leading={footerLeading}\n >\n {footer}\n </ModalFooter>\n )}\n </div>\n );\n}\n\n/**\n * Modal dialog shell — composes ModalHeader, scrollable body, and ModalFooter.\n * Owns dialog-level focus and keyboard behavior: initial focus, Tab trap,\n * Escape, and focus restore on unmount. Host owns portal, overlay/backdrop,\n * scroll lock, stacking, and open state. Mount-controlled by default; pass\n * `open` for the enter/exit transition.\n */\nexport default function Modal({ open, onExited, ...props }: ModalProps) {\n const controlled = open !== undefined;\n const { mounted, visible } = usePopoverTransition(open ?? true);\n const wasMounted = useRef(mounted);\n const onExitedRef = useRef(onExited);\n onExitedRef.current = onExited;\n\n useEffect(() => {\n if (wasMounted.current && !mounted && controlled) {\n onExitedRef.current?.();\n }\n wasMounted.current = mounted;\n }, [mounted, controlled]);\n\n if (controlled && !mounted) return null;\n\n return (\n <ModalPanel\n {...props}\n active={open ?? true}\n transition={controlled}\n visible={visible}\n />\n );\n}\n"],"names":["ModalPanel","className","style","size","title","subtitle","subtitlePlacement","hideTitle","showBackButton","onBack","backLabel","backButtonProps","onClose","closeLabel","closeButtonProps","headerDivider","headerAction","headerSlot","bodyPadding","scrollable","children","footer","footerLeading","footerType","footerDivider","closeOnEscape","initialFocusRef","active","transition","visible","rest","rootRef","useRef","useModalFocus","titleId","useId","sizeClass","styles","toKebab","bodyInnerClass","bodyInner","jsx","showFooter","jsxs","ModalHeader","Scrollbar","ModalFooter","Modal","open","onExited","props","controlled","mounted","usePopoverTransition","wasMounted","onExitedRef","useEffect","_a"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
.
|
|
1
|
+
._modal_14reu_2{background-color:var(--center-channel-bg);border:1px solid rgba(var(--center-channel-color-rgb),.16);border-radius:var(--radius-l);box-shadow:var(--elevation-6);display:flex;flex-direction:column;overflow:hidden}._modal--transition_14reu_11{opacity:0;transform:translateY(calc(-1 * var(--spacing-xxxl))) scale(.98);transform-origin:top center;pointer-events:none;transition:opacity var(--duration-quick) var(--ease-exit),transform var(--duration-quick) var(--ease-exit)}@media(prefers-reduced-motion:reduce){._modal--transition_14reu_11{transform:none;transition:none}}._modal--visible_14reu_24{opacity:1;transform:translateY(0) scale(1);pointer-events:auto;transition:opacity var(--duration-quick) var(--ease-entrance),transform var(--duration-quick) var(--ease-entrance)}@media(prefers-reduced-motion:reduce){._modal--visible_14reu_24{transition:none}}._modal_14reu_2:focus{outline:none}._modal--size-small_14reu_38{width:600px}._modal--size-medium_14reu_41{width:704px}._modal--size-large_14reu_44{width:832px}._modal__body_14reu_47{flex:1;min-height:0}._modal__body-inner_14reu_51{padding:28px var(--spacing-xxxl)}._modal__body-inner--menu_14reu_54{padding:var(--spacing-xs) var(--spacing-l)}._modal__body-inner--none_14reu_57{padding:0}._modal__body_14reu_47>._modal__body-inner_14reu_51{height:100%}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CSSProperties, HTMLAttributes, ReactNode } from 'react';
|
|
1
|
+
import { CSSProperties, HTMLAttributes, ReactNode, RefObject } from 'react';
|
|
2
2
|
import { ModalFooterType } from '../modal-footer/ModalFooter';
|
|
3
3
|
import { ModalSubtitlePlacement } from '../modal-header/ModalHeader';
|
|
4
4
|
import { BuiltInButtonProps } from '../../utils/props';
|
|
@@ -71,10 +71,32 @@ export interface ModalProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'
|
|
|
71
71
|
footerType?: ModalFooterType;
|
|
72
72
|
/** Show divider between body and footer. Default: true. */
|
|
73
73
|
footerDivider?: boolean;
|
|
74
|
+
/**
|
|
75
|
+
* Close on Escape via a document listener while mounted. Escapes already
|
|
76
|
+
* handled by an inner widget (`defaultPrevented`) are ignored. Default: true.
|
|
77
|
+
*/
|
|
78
|
+
closeOnEscape?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Element to focus when the modal mounts (e.g. the first form field).
|
|
81
|
+
* Default: the dialog root.
|
|
82
|
+
*/
|
|
83
|
+
initialFocusRef?: RefObject<HTMLElement | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Controlled visibility with the Compass enter/exit transition (fade + drop from the top + subtle scale 98%→100%,
|
|
86
|
+
* reverse on close, `--duration-quick`); the modal unmounts after the exit,
|
|
87
|
+
* and focus is restored then. Omit to keep the mount-controlled behavior
|
|
88
|
+
* (always rendered, no transition). The host still owns the state.
|
|
89
|
+
*/
|
|
90
|
+
open?: boolean;
|
|
91
|
+
/** Called after the exit transition finishes and the modal unmounts (only when `open` is controlled). */
|
|
92
|
+
onExited?: () => void;
|
|
74
93
|
}
|
|
75
94
|
/**
|
|
76
95
|
* Modal dialog shell — composes ModalHeader, scrollable body, and ModalFooter.
|
|
77
|
-
*
|
|
96
|
+
* Owns dialog-level focus and keyboard behavior: initial focus, Tab trap,
|
|
97
|
+
* Escape, and focus restore on unmount. Host owns portal, overlay/backdrop,
|
|
98
|
+
* scroll lock, stacking, and open state. Mount-controlled by default; pass
|
|
99
|
+
* `open` for the enter/exit transition.
|
|
78
100
|
*/
|
|
79
|
-
export default function Modal({
|
|
101
|
+
export default function Modal({ open, onExited, ...props }: ModalProps): import("react/jsx-runtime").JSX.Element | null;
|
|
80
102
|
//# sourceMappingURL=Modal.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../src/components/modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"Modal.d.ts","sourceRoot":"","sources":["../../../src/components/modal/Modal.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,aAAa,EACb,cAAc,EACd,SAAS,EACT,SAAS,EACV,MAAM,OAAO,CAAC;AAMf,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAE5E,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAIxD,MAAM,MAAM,SAAS,GAAG,OAAO,GAAG,QAAQ,GAAG,OAAO,CAAC;AAErD;;;;GAIG;AACH,MAAM,MAAM,gBAAgB,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,CAAC;AAE3D,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,CAAC;AAExD,MAAM,WAAW,UAAW,SAAQ,IAAI,CACtC,cAAc,CAAC,cAAc,CAAC,EAC9B,OAAO,GAAG,UAAU,GAAG,OAAO,CAC/B;IACC,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iFAAiF;IACjF,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,2EAA2E;IAC3E,IAAI,CAAC,EAAE,SAAS,CAAC;IACjB,oFAAoF;IACpF,KAAK,EAAE,SAAS,CAAC;IACjB,mEAAmE;IACnE,QAAQ,CAAC,EAAE,SAAS,CAAC;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,6DAA6D;IAC7D,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,eAAe,CAAC,EAAE,kBAAkB,CAAC;IACrC,iDAAiD;IACjD,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,8DAA8D;IAC9D,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,kBAAkB,CAAC;IACtC,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,+DAA+D;IAC/D,YAAY,CAAC,EAAE,SAAS,CAAC;IACzB;;;OAGG;IACH,UAAU,CAAC,EAAE,SAAS,CAAC;IACvB;;;OAGG;IACH,WAAW,CAAC,EAAE,gBAAgB,CAAC;IAC/B;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,oBAAoB;IACpB,QAAQ,EAAE,SAAS,CAAC;IACpB,iEAAiE;IACjE,MAAM,CAAC,EAAE,SAAS,CAAC;IACnB,+DAA+D;IAC/D,aAAa,CAAC,EAAE,SAAS,CAAC;IAC1B,oEAAoE;IACpE,UAAU,CAAC,EAAE,eAAe,CAAC;IAC7B,2DAA2D;IAC3D,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,eAAe,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAChD;;;;;OAKG;IACH,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,yGAAyG;IACzG,QAAQ,CAAC,EAAE,MAAM,IAAI,CAAC;CACvB;AAsHD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,KAAK,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,EAAE,EAAE,UAAU,kDAwBrE"}
|
|
@@ -1,87 +1,124 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { useId as
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
1
|
+
import { jsx as n, jsxs as A } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as c, useEffect as D, useId as G } from "react";
|
|
3
|
+
import { useModalFocus as J } from "../../hooks/use-modal-focus.js";
|
|
4
|
+
import { usePopoverTransition as O } from "../../hooks/use-popover-transition.js";
|
|
5
|
+
import Q from "../scrollbar/Scrollbar.js";
|
|
6
|
+
import U from "../modal-footer/ModalFooter.js";
|
|
7
|
+
import V from "../modal-header/ModalHeader.js";
|
|
8
|
+
import { toKebab as W } from "../../utils/string.js";
|
|
9
|
+
import o from "./Modal.module.scss.js";
|
|
10
|
+
function X({
|
|
11
|
+
className: t = "",
|
|
12
|
+
style: a,
|
|
13
|
+
size: d = "small",
|
|
14
|
+
title: e,
|
|
15
|
+
subtitle: r,
|
|
16
|
+
subtitlePlacement: m = "below",
|
|
17
|
+
hideTitle: s = !1,
|
|
18
|
+
showBackButton: l = !1,
|
|
19
|
+
onBack: i,
|
|
20
|
+
backLabel: I,
|
|
21
|
+
backButtonProps: j,
|
|
22
|
+
onClose: f,
|
|
23
|
+
closeLabel: w,
|
|
24
|
+
closeButtonProps: F,
|
|
25
|
+
headerDivider: N = !0,
|
|
26
|
+
headerAction: x,
|
|
27
|
+
headerSlot: z,
|
|
28
|
+
bodyPadding: b = "default",
|
|
29
|
+
scrollable: B = !0,
|
|
30
|
+
children: g,
|
|
31
|
+
footer: p,
|
|
32
|
+
footerLeading: v,
|
|
33
|
+
footerType: u = "2-actions",
|
|
34
|
+
footerDivider: C = !0,
|
|
35
|
+
closeOnEscape: H = !0,
|
|
36
|
+
initialFocusRef: K,
|
|
37
|
+
active: P,
|
|
38
|
+
transition: _,
|
|
39
|
+
visible: R,
|
|
40
|
+
...S
|
|
34
41
|
}) {
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
42
|
+
const y = c(null);
|
|
43
|
+
J(y, {
|
|
44
|
+
initialFocusRef: K,
|
|
45
|
+
closeOnEscape: H,
|
|
46
|
+
onClose: f,
|
|
47
|
+
active: P
|
|
48
|
+
});
|
|
49
|
+
const M = G(), $ = o[`modal--size-${W(d)}`], k = [
|
|
50
|
+
o["modal__body-inner"],
|
|
51
|
+
b === "menu" && o["modal__body-inner--menu"],
|
|
52
|
+
b === "none" && o["modal__body-inner--none"]
|
|
53
|
+
].filter(Boolean).join(" "), h = /* @__PURE__ */ n("div", { className: k, children: g }), q = p != null || v != null || u === "spacer-small" || u === "spacer-large";
|
|
54
|
+
return /* @__PURE__ */ A(
|
|
41
55
|
"div",
|
|
42
56
|
{
|
|
43
|
-
...
|
|
44
|
-
|
|
45
|
-
|
|
57
|
+
...S,
|
|
58
|
+
ref: y,
|
|
59
|
+
tabIndex: -1,
|
|
60
|
+
className: [
|
|
61
|
+
o.modal,
|
|
62
|
+
$,
|
|
63
|
+
_ && o["modal--transition"],
|
|
64
|
+
_ && R && o["modal--visible"],
|
|
65
|
+
t
|
|
66
|
+
].filter(Boolean).join(" "),
|
|
67
|
+
style: a,
|
|
46
68
|
role: "dialog",
|
|
47
69
|
"aria-modal": "true",
|
|
48
|
-
"aria-labelledby":
|
|
70
|
+
"aria-labelledby": M,
|
|
49
71
|
children: [
|
|
50
|
-
/* @__PURE__ */
|
|
51
|
-
|
|
72
|
+
/* @__PURE__ */ n(
|
|
73
|
+
V,
|
|
52
74
|
{
|
|
53
|
-
title:
|
|
54
|
-
titleId:
|
|
55
|
-
subtitle:
|
|
56
|
-
subtitlePlacement:
|
|
57
|
-
hideTitle:
|
|
58
|
-
showBackButton:
|
|
59
|
-
onBack:
|
|
60
|
-
backLabel:
|
|
61
|
-
backButtonProps:
|
|
62
|
-
onClose:
|
|
63
|
-
closeLabel:
|
|
64
|
-
closeButtonProps:
|
|
65
|
-
divider:
|
|
66
|
-
headerAction:
|
|
67
|
-
headerSlot:
|
|
75
|
+
title: e,
|
|
76
|
+
titleId: M,
|
|
77
|
+
subtitle: r,
|
|
78
|
+
subtitlePlacement: m,
|
|
79
|
+
hideTitle: s,
|
|
80
|
+
showBackButton: l,
|
|
81
|
+
onBack: i,
|
|
82
|
+
backLabel: I,
|
|
83
|
+
backButtonProps: j,
|
|
84
|
+
onClose: f,
|
|
85
|
+
closeLabel: w,
|
|
86
|
+
closeButtonProps: F,
|
|
87
|
+
divider: N,
|
|
88
|
+
headerAction: x,
|
|
89
|
+
headerSlot: z
|
|
68
90
|
}
|
|
69
91
|
),
|
|
70
|
-
/* @__PURE__ */
|
|
71
|
-
|
|
72
|
-
|
|
92
|
+
/* @__PURE__ */ n("div", { className: o.modal__body, children: B ? /* @__PURE__ */ n(Q, { children: h }) : h }),
|
|
93
|
+
q && /* @__PURE__ */ n(
|
|
94
|
+
U,
|
|
73
95
|
{
|
|
74
|
-
type:
|
|
75
|
-
divider:
|
|
76
|
-
leading:
|
|
77
|
-
children:
|
|
96
|
+
type: u,
|
|
97
|
+
divider: C,
|
|
98
|
+
leading: v,
|
|
99
|
+
children: p
|
|
78
100
|
}
|
|
79
101
|
)
|
|
80
102
|
]
|
|
81
103
|
}
|
|
82
104
|
);
|
|
83
105
|
}
|
|
106
|
+
function no({ open: t, onExited: a, ...d }) {
|
|
107
|
+
const e = t !== void 0, { mounted: r, visible: m } = O(t ?? !0), s = c(r), l = c(a);
|
|
108
|
+
return l.current = a, D(() => {
|
|
109
|
+
var i;
|
|
110
|
+
s.current && !r && e && ((i = l.current) == null || i.call(l)), s.current = r;
|
|
111
|
+
}, [r, e]), e && !r ? null : /* @__PURE__ */ n(
|
|
112
|
+
X,
|
|
113
|
+
{
|
|
114
|
+
...d,
|
|
115
|
+
active: t ?? !0,
|
|
116
|
+
transition: e,
|
|
117
|
+
visible: m
|
|
118
|
+
}
|
|
119
|
+
);
|
|
120
|
+
}
|
|
84
121
|
export {
|
|
85
|
-
|
|
122
|
+
no as default
|
|
86
123
|
};
|
|
87
124
|
//# sourceMappingURL=Modal.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.js","sources":["../../../src/components/modal/Modal.tsx"],"sourcesContent":["import type { CSSProperties, HTMLAttributes, ReactNode } from 'react';\nimport { useId } from 'react';\nimport Scrollbar from '@/components/scrollbar/Scrollbar';\nimport ModalFooter from '@/components/modal-footer/ModalFooter';\nimport type { ModalFooterType } from '@/components/modal-footer/ModalFooter';\nimport ModalHeader from '@/components/modal-header/ModalHeader';\nimport type { ModalSubtitlePlacement } from '@/components/modal-header/ModalHeader';\nimport type { BuiltInButtonProps } from '@/utils/props';\nimport { toKebab } from '@/utils/string';\nimport styles from './Modal.module.scss';\n\nexport type ModalSize = 'small' | 'medium' | 'large';\n\n/**\n * Body inset. `menu` is for MenuItem lists — 8px vertical / 16px horizontal so\n * row labels align with the 32px header/footer margins. `none` removes inset\n * for host-owned full-bleed layouts (e.g. settings sidebars).\n */\nexport type ModalBodyPadding = 'default' | 'menu' | 'none';\n\nexport type { ModalFooterType, ModalSubtitlePlacement };\n\nexport interface ModalProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title' | 'children' | 'style'\n> {\n /** Extra class on the dialog root (size + chrome classes still apply). */\n className?: string;\n /** Inline style on the dialog root — prefer `className` for layout overrides. */\n style?: CSSProperties;\n /** Width variant. Figma: Size — Small 600px, Medium 704px, Large 832px. */\n size?: ModalSize;\n /** Modal heading text. Required for a11y; use `hideTitle` for close-only chrome. */\n title: ReactNode;\n /** Optional secondary line — placement via `subtitlePlacement`. */\n subtitle?: ReactNode;\n /**\n * Where the subtitle sits. Figma Modal Header: Below | Beside.\n * Default: `below`.\n */\n subtitlePlacement?: ModalSubtitlePlacement;\n /** Visually hide the title (close-only header); title remains for `aria-labelledby`. */\n hideTitle?: boolean;\n /** When true, shows a back-arrow button before the title. */\n showBackButton?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible name for the back button. Default: \"Go back\". */\n backLabel?: string;\n /** Extra attributes for the back button (e.g. `data-testid`). */\n backButtonProps?: BuiltInButtonProps;\n /** Called when the × close button is clicked. */\n onClose?: () => void;\n /** Accessible name for the close button. Default: \"Close\". */\n closeLabel?: string;\n /** Extra attributes for the close button (e.g. `data-testid`). */\n closeButtonProps?: BuiltInButtonProps;\n /** Show divider between header and body. Default: true. */\n headerDivider?: boolean;\n /** Optional control before close (Button, search field, …). */\n headerAction?: ReactNode;\n /**\n * Full-width slot rendered below the title row and above the header divider.\n * Accepts any ReactNode — SearchInput, Tabs, a custom toolbar, etc.\n */\n headerSlot?: ReactNode;\n /**\n * Body inset. Default is 32px horizontal / 28px vertical. Use `menu` for\n * MenuItem lists. Use `none` when the host owns padding.\n */\n bodyPadding?: ModalBodyPadding;\n /**\n * When true (default), wraps body content in Scrollbar. Set false when the\n * host manages scroll inside panes.\n */\n scrollable?: boolean;\n /** Body content. */\n children: ReactNode;\n /** Footer slot — typically Buttons. Wrapped in `ModalFooter`. */\n footer?: ReactNode;\n /** Left footer slot (pagination status, PaginationDots, …). */\n footerLeading?: ReactNode;\n /** Footer layout. Figma Modal Footer Type. Default: `2-actions`. */\n footerType?: ModalFooterType;\n /** Show divider between body and footer. Default: true. */\n footerDivider?: boolean;\n}\n\n/**\n * Modal dialog shell — composes ModalHeader, scrollable body, and ModalFooter.\n * Host owns portal, overlay, focus trap, and open/close.\n */\nexport default function Modal({\n className = '',\n style,\n size = 'small',\n title,\n subtitle,\n subtitlePlacement = 'below',\n hideTitle = false,\n showBackButton = false,\n onBack,\n backLabel,\n backButtonProps,\n onClose,\n closeLabel,\n closeButtonProps,\n headerDivider = true,\n headerAction,\n headerSlot,\n bodyPadding = 'default',\n scrollable = true,\n children,\n footer,\n footerLeading,\n footerType = '2-actions',\n footerDivider = true,\n ...rest\n}: ModalProps) {\n const titleId = useId();\n const sizeClass = styles[`modal--size-${toKebab(size)}`];\n const bodyInnerClass = [\n styles['modal__body-inner'],\n bodyPadding === 'menu' && styles['modal__body-inner--menu'],\n bodyPadding === 'none' && styles['modal__body-inner--none'],\n ]\n .filter(Boolean)\n .join(' ');\n\n const bodyInner = <div className={bodyInnerClass}>{children}</div>;\n const showFooter =\n footer != null ||\n footerLeading != null ||\n footerType === 'spacer-small' ||\n footerType === 'spacer-large';\n\n return (\n <div\n {...rest}\n className={[styles.modal, sizeClass, className].filter(Boolean).join(' ')}\n style={style}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n >\n <ModalHeader\n title={title}\n titleId={titleId}\n subtitle={subtitle}\n subtitlePlacement={subtitlePlacement}\n hideTitle={hideTitle}\n showBackButton={showBackButton}\n onBack={onBack}\n backLabel={backLabel}\n backButtonProps={backButtonProps}\n onClose={onClose}\n closeLabel={closeLabel}\n closeButtonProps={closeButtonProps}\n divider={headerDivider}\n headerAction={headerAction}\n headerSlot={headerSlot}\n />\n\n <div className={styles['modal__body']}>\n {scrollable ? <Scrollbar>{bodyInner}</Scrollbar> : bodyInner}\n </div>\n\n {showFooter && (\n <ModalFooter\n type={footerType}\n divider={footerDivider}\n leading={footerLeading}\n >\n {footer}\n </ModalFooter>\n )}\n </div>\n );\n}\n"],"names":["Modal","className","style","size","title","subtitle","subtitlePlacement","hideTitle","showBackButton","onBack","backLabel","backButtonProps","onClose","closeLabel","closeButtonProps","headerDivider","headerAction","headerSlot","bodyPadding","scrollable","children","footer","footerLeading","footerType","footerDivider","rest","titleId","useId","sizeClass","styles","toKebab","bodyInnerClass","bodyInner","jsx","showFooter","jsxs","ModalHeader","Scrollbar","ModalFooter"],"mappings":";;;;;;;AA4FA,SAAwBA,EAAM;AAAA,EAC5B,WAAAC,IAAY;AAAA,EACZ,OAAAC;AAAA,EACA,MAAAC,IAAO;AAAA,EACP,OAAAC;AAAA,EACA,UAAAC;AAAA,EACA,mBAAAC,IAAoB;AAAA,EACpB,WAAAC,IAAY;AAAA,EACZ,gBAAAC,IAAiB;AAAA,EACjB,QAAAC;AAAA,EACA,WAAAC;AAAA,EACA,iBAAAC;AAAA,EACA,SAAAC;AAAA,EACA,YAAAC;AAAA,EACA,kBAAAC;AAAA,EACA,eAAAC,IAAgB;AAAA,EAChB,cAAAC;AAAA,EACA,YAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,YAAAC,IAAa;AAAA,EACb,UAAAC;AAAA,EACA,QAAAC;AAAA,EACA,eAAAC;AAAA,EACA,YAAAC,IAAa;AAAA,EACb,eAAAC,IAAgB;AAAA,EAChB,GAAGC;AACL,GAAe;AACb,QAAMC,IAAUC,EAAA,GACVC,IAAYC,EAAO,eAAeC,EAAQ3B,CAAI,CAAC,EAAE,GACjD4B,IAAiB;AAAA,IACrBF,EAAO,mBAAmB;AAAA,IAC1BX,MAAgB,UAAUW,EAAO,yBAAyB;AAAA,IAC1DX,MAAgB,UAAUW,EAAO,yBAAyB;AAAA,EAAA,EAEzD,OAAO,OAAO,EACd,KAAK,GAAG,GAELG,IAAY,gBAAAC,EAAC,OAAA,EAAI,WAAWF,GAAiB,UAAAX,GAAS,GACtDc,IACJb,KAAU,QACVC,KAAiB,QACjBC,MAAe,kBACfA,MAAe;AAEjB,SACE,gBAAAY;AAAA,IAAC;AAAA,IAAA;AAAA,MACE,GAAGV;AAAA,MACJ,WAAW,CAACI,EAAO,OAAOD,GAAW3B,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG;AAAA,MACxE,OAAAC;AAAA,MACA,MAAK;AAAA,MACL,cAAW;AAAA,MACX,mBAAiBwB;AAAA,MAEjB,UAAA;AAAA,QAAA,gBAAAO;AAAA,UAACG;AAAA,UAAA;AAAA,YACC,OAAAhC;AAAA,YACA,SAAAsB;AAAA,YACA,UAAArB;AAAA,YACA,mBAAAC;AAAA,YACA,WAAAC;AAAA,YACA,gBAAAC;AAAA,YACA,QAAAC;AAAA,YACA,WAAAC;AAAA,YACA,iBAAAC;AAAA,YACA,SAAAC;AAAA,YACA,YAAAC;AAAA,YACA,kBAAAC;AAAA,YACA,SAASC;AAAA,YACT,cAAAC;AAAA,YACA,YAAAC;AAAA,UAAA;AAAA,QAAA;AAAA,QAGF,gBAAAgB,EAAC,OAAA,EAAI,WAAWJ,EAAO,aACpB,UAAAV,IAAa,gBAAAc,EAACI,GAAA,EAAW,UAAAL,EAAA,CAAU,IAAeA,GACrD;AAAA,QAECE,KACC,gBAAAD;AAAA,UAACK;AAAA,UAAA;AAAA,YACC,MAAMf;AAAA,YACN,SAASC;AAAA,YACT,SAASF;AAAA,YAER,UAAAD;AAAA,UAAA;AAAA,QAAA;AAAA,MACH;AAAA,IAAA;AAAA,EAAA;AAIR;"}
|
|
1
|
+
{"version":3,"file":"Modal.js","sources":["../../../src/components/modal/Modal.tsx"],"sourcesContent":["import type {\n CSSProperties,\n HTMLAttributes,\n ReactNode,\n RefObject,\n} from 'react';\nimport { useEffect, useId, useRef } from 'react';\nimport { useModalFocus } from '@/hooks/use-modal-focus';\nimport { usePopoverTransition } from '@/hooks/use-popover-transition';\nimport Scrollbar from '@/components/scrollbar/Scrollbar';\nimport ModalFooter from '@/components/modal-footer/ModalFooter';\nimport type { ModalFooterType } from '@/components/modal-footer/ModalFooter';\nimport ModalHeader from '@/components/modal-header/ModalHeader';\nimport type { ModalSubtitlePlacement } from '@/components/modal-header/ModalHeader';\nimport type { BuiltInButtonProps } from '@/utils/props';\nimport { toKebab } from '@/utils/string';\nimport styles from './Modal.module.scss';\n\nexport type ModalSize = 'small' | 'medium' | 'large';\n\n/**\n * Body inset. `menu` is for MenuItem lists — 8px vertical / 16px horizontal so\n * row labels align with the 32px header/footer margins. `none` removes inset\n * for host-owned full-bleed layouts (e.g. settings sidebars).\n */\nexport type ModalBodyPadding = 'default' | 'menu' | 'none';\n\nexport type { ModalFooterType, ModalSubtitlePlacement };\n\nexport interface ModalProps extends Omit<\n HTMLAttributes<HTMLDivElement>,\n 'title' | 'children' | 'style'\n> {\n /** Extra class on the dialog root (size + chrome classes still apply). */\n className?: string;\n /** Inline style on the dialog root — prefer `className` for layout overrides. */\n style?: CSSProperties;\n /** Width variant. Figma: Size — Small 600px, Medium 704px, Large 832px. */\n size?: ModalSize;\n /** Modal heading text. Required for a11y; use `hideTitle` for close-only chrome. */\n title: ReactNode;\n /** Optional secondary line — placement via `subtitlePlacement`. */\n subtitle?: ReactNode;\n /**\n * Where the subtitle sits. Figma Modal Header: Below | Beside.\n * Default: `below`.\n */\n subtitlePlacement?: ModalSubtitlePlacement;\n /** Visually hide the title (close-only header); title remains for `aria-labelledby`. */\n hideTitle?: boolean;\n /** When true, shows a back-arrow button before the title. */\n showBackButton?: boolean;\n /** Called when the back button is clicked. */\n onBack?: () => void;\n /** Accessible name for the back button. Default: \"Go back\". */\n backLabel?: string;\n /** Extra attributes for the back button (e.g. `data-testid`). */\n backButtonProps?: BuiltInButtonProps;\n /** Called when the × close button is clicked. */\n onClose?: () => void;\n /** Accessible name for the close button. Default: \"Close\". */\n closeLabel?: string;\n /** Extra attributes for the close button (e.g. `data-testid`). */\n closeButtonProps?: BuiltInButtonProps;\n /** Show divider between header and body. Default: true. */\n headerDivider?: boolean;\n /** Optional control before close (Button, search field, …). */\n headerAction?: ReactNode;\n /**\n * Full-width slot rendered below the title row and above the header divider.\n * Accepts any ReactNode — SearchInput, Tabs, a custom toolbar, etc.\n */\n headerSlot?: ReactNode;\n /**\n * Body inset. Default is 32px horizontal / 28px vertical. Use `menu` for\n * MenuItem lists. Use `none` when the host owns padding.\n */\n bodyPadding?: ModalBodyPadding;\n /**\n * When true (default), wraps body content in Scrollbar. Set false when the\n * host manages scroll inside panes.\n */\n scrollable?: boolean;\n /** Body content. */\n children: ReactNode;\n /** Footer slot — typically Buttons. Wrapped in `ModalFooter`. */\n footer?: ReactNode;\n /** Left footer slot (pagination status, PaginationDots, …). */\n footerLeading?: ReactNode;\n /** Footer layout. Figma Modal Footer Type. Default: `2-actions`. */\n footerType?: ModalFooterType;\n /** Show divider between body and footer. Default: true. */\n footerDivider?: boolean;\n /**\n * Close on Escape via a document listener while mounted. Escapes already\n * handled by an inner widget (`defaultPrevented`) are ignored. Default: true.\n */\n closeOnEscape?: boolean;\n /**\n * Element to focus when the modal mounts (e.g. the first form field).\n * Default: the dialog root.\n */\n initialFocusRef?: RefObject<HTMLElement | null>;\n /**\n * Controlled visibility with the Compass enter/exit transition (fade + drop from the top + subtle scale 98%→100%,\n * reverse on close, `--duration-quick`); the modal unmounts after the exit,\n * and focus is restored then. Omit to keep the mount-controlled behavior\n * (always rendered, no transition). The host still owns the state.\n */\n open?: boolean;\n /** Called after the exit transition finishes and the modal unmounts (only when `open` is controlled). */\n onExited?: () => void;\n}\n\ninterface ModalPanelState {\n active: boolean;\n transition: boolean;\n visible: boolean;\n}\n\nfunction ModalPanel({\n className = '',\n style,\n size = 'small',\n title,\n subtitle,\n subtitlePlacement = 'below',\n hideTitle = false,\n showBackButton = false,\n onBack,\n backLabel,\n backButtonProps,\n onClose,\n closeLabel,\n closeButtonProps,\n headerDivider = true,\n headerAction,\n headerSlot,\n bodyPadding = 'default',\n scrollable = true,\n children,\n footer,\n footerLeading,\n footerType = '2-actions',\n footerDivider = true,\n closeOnEscape = true,\n initialFocusRef,\n active,\n transition,\n visible,\n ...rest\n}: ModalProps & ModalPanelState) {\n const rootRef = useRef<HTMLDivElement>(null);\n useModalFocus(rootRef, {\n initialFocusRef,\n closeOnEscape,\n onClose,\n active,\n });\n const titleId = useId();\n const sizeClass = styles[`modal--size-${toKebab(size)}`];\n const bodyInnerClass = [\n styles['modal__body-inner'],\n bodyPadding === 'menu' && styles['modal__body-inner--menu'],\n bodyPadding === 'none' && styles['modal__body-inner--none'],\n ]\n .filter(Boolean)\n .join(' ');\n\n const bodyInner = <div className={bodyInnerClass}>{children}</div>;\n const showFooter =\n footer != null ||\n footerLeading != null ||\n footerType === 'spacer-small' ||\n footerType === 'spacer-large';\n\n return (\n <div\n {...rest}\n ref={rootRef}\n tabIndex={-1}\n className={[\n styles.modal,\n sizeClass,\n transition && styles['modal--transition'],\n transition && visible && styles['modal--visible'],\n className,\n ]\n .filter(Boolean)\n .join(' ')}\n style={style}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={titleId}\n >\n <ModalHeader\n title={title}\n titleId={titleId}\n subtitle={subtitle}\n subtitlePlacement={subtitlePlacement}\n hideTitle={hideTitle}\n showBackButton={showBackButton}\n onBack={onBack}\n backLabel={backLabel}\n backButtonProps={backButtonProps}\n onClose={onClose}\n closeLabel={closeLabel}\n closeButtonProps={closeButtonProps}\n divider={headerDivider}\n headerAction={headerAction}\n headerSlot={headerSlot}\n />\n\n <div className={styles['modal__body']}>\n {scrollable ? <Scrollbar>{bodyInner}</Scrollbar> : bodyInner}\n </div>\n\n {showFooter && (\n <ModalFooter\n type={footerType}\n divider={footerDivider}\n leading={footerLeading}\n >\n {footer}\n </ModalFooter>\n )}\n </div>\n );\n}\n\n/**\n * Modal dialog shell — composes ModalHeader, scrollable body, and ModalFooter.\n * Owns dialog-level focus and keyboard behavior: initial focus, Tab trap,\n * Escape, and focus restore on unmount. Host owns portal, overlay/backdrop,\n * scroll lock, stacking, and open state. Mount-controlled by default; pass\n * `open` for the enter/exit transition.\n */\nexport default function Modal({ open, onExited, ...props }: ModalProps) {\n const controlled = open !== undefined;\n const { mounted, visible } = usePopoverTransition(open ?? true);\n const wasMounted = useRef(mounted);\n const onExitedRef = useRef(onExited);\n onExitedRef.current = onExited;\n\n useEffect(() => {\n if (wasMounted.current && !mounted && controlled) {\n onExitedRef.current?.();\n }\n wasMounted.current = mounted;\n }, [mounted, controlled]);\n\n if (controlled && !mounted) return null;\n\n return (\n <ModalPanel\n {...props}\n active={open ?? true}\n transition={controlled}\n visible={visible}\n />\n );\n}\n"],"names":["ModalPanel","className","style","size","title","subtitle","subtitlePlacement","hideTitle","showBackButton","onBack","backLabel","backButtonProps","onClose","closeLabel","closeButtonProps","headerDivider","headerAction","headerSlot","bodyPadding","scrollable","children","footer","footerLeading","footerType","footerDivider","closeOnEscape","initialFocusRef","active","transition","visible","rest","rootRef","useRef","useModalFocus","titleId","useId","sizeClass","styles","toKebab","bodyInnerClass","bodyInner","jsx","showFooter","jsxs","ModalHeader","Scrollbar","ModalFooter","Modal","open","onExited","props","controlled","mounted","usePopoverTransition","wasMounted","onExitedRef","useEffect","_a"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require('./Modal.css');const _="
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require('./Modal.css');const _="_modal_14reu_2",e="_modal__body_14reu_47",o={modal:_,"modal--transition":"_modal--transition_14reu_11","modal--visible":"_modal--visible_14reu_24","modal--size-small":"_modal--size-small_14reu_38","modal--size-medium":"_modal--size-medium_14reu_41","modal--size-large":"_modal--size-large_14reu_44",modal__body:e,"modal__body-inner":"_modal__body-inner_14reu_51","modal__body-inner--menu":"_modal__body-inner--menu_14reu_54","modal__body-inner--none":"_modal__body-inner--none_14reu_57"};exports.default=o;exports.modal=_;exports.modal__body=e;
|
|
2
2
|
//# sourceMappingURL=Modal.module.scss.cjs.map
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
import './Modal.css';const
|
|
2
|
-
modal:
|
|
3
|
-
"modal--
|
|
4
|
-
"modal--
|
|
5
|
-
"modal--size-
|
|
6
|
-
|
|
7
|
-
"
|
|
8
|
-
|
|
9
|
-
"modal__body-inner
|
|
1
|
+
import './Modal.css';const _ = "_modal_14reu_2", o = "_modal__body_14reu_47", e = {
|
|
2
|
+
modal: _,
|
|
3
|
+
"modal--transition": "_modal--transition_14reu_11",
|
|
4
|
+
"modal--visible": "_modal--visible_14reu_24",
|
|
5
|
+
"modal--size-small": "_modal--size-small_14reu_38",
|
|
6
|
+
"modal--size-medium": "_modal--size-medium_14reu_41",
|
|
7
|
+
"modal--size-large": "_modal--size-large_14reu_44",
|
|
8
|
+
modal__body: o,
|
|
9
|
+
"modal__body-inner": "_modal__body-inner_14reu_51",
|
|
10
|
+
"modal__body-inner--menu": "_modal__body-inner--menu_14reu_54",
|
|
11
|
+
"modal__body-inner--none": "_modal__body-inner--none_14reu_57"
|
|
10
12
|
};
|
|
11
13
|
export {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
14
|
+
e as default,
|
|
15
|
+
_ as modal,
|
|
16
|
+
o as modal__body
|
|
15
17
|
};
|
|
16
18
|
//# sourceMappingURL=Modal.module.scss.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Modal.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Modal.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
._modal-
|
|
1
|
+
._modal-header_1wwv5_2{display:flex;flex-direction:column;flex-shrink:0;border-bottom:1px solid rgba(var(--center-channel-color-rgb),.12)}._modal-header--no-divider_1wwv5_8{border-bottom:none}._modal-header--no-divider_1wwv5_8 ._modal-header__content_1wwv5_11,._modal-header--has-slot_1wwv5_14 ._modal-header__content_1wwv5_11{padding-bottom:0}._modal-header--close-only_1wwv5_17 ._modal-header__content_1wwv5_11{justify-content:flex-end}._modal-header__content_1wwv5_11{display:flex;align-items:flex-start;gap:10px;width:100%;padding:var(--spacing-xxl) var(--spacing-xxxl)}._modal-header__titles_1wwv5_27{display:flex;flex:1 1 auto;flex-direction:column;align-items:flex-start;gap:var(--spacing-m);min-width:0;padding:var(--spacing-xxxxs) 0}._modal-header__primary_1wwv5_36{display:flex;align-items:center;gap:var(--spacing-m);width:100%;min-height:var(--line-height-500)}._modal-header__title_1wwv5_27{flex:0 1 auto;min-width:0;margin:0;font-family:var(--font-family-heading);font-size:var(--font-size-500);font-weight:var(--font-weight-semibold);line-height:var(--line-height-500);color:var(--center-channel-color)}._modal-header__title-sr_1wwv5_53{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip-path:inset(50%);white-space:nowrap;border:0}._modal-header__subtitle_1wwv5_64{margin:0;font-family:var(--font-family-body);font-size:var(--font-size-75);font-weight:var(--font-weight-regular);line-height:var(--line-height-75);color:rgba(var(--center-channel-color-rgb),.72)}._modal-header__subtitle-beside_1wwv5_72{display:flex;flex-shrink:0;align-items:center;gap:var(--spacing-xs)}._modal-header__subtitle-beside_1wwv5_72 ._modal-header__subtitle_1wwv5_64{line-height:var(--line-height-200);white-space:nowrap}._modal-header__subtitle-divider_1wwv5_82{display:block;width:1px;height:var(--line-height-500);background-color:rgba(var(--center-channel-color-rgb),.16)}._modal-header__actions_1wwv5_88{display:flex;flex-shrink:0;align-items:center;justify-content:flex-end;gap:7px;height:28px}._modal-header__close_1wwv5_96{margin-right:-12px;margin-top:-6px;margin-bottom:-6px}._modal-header__slot_1wwv5_101{padding:var(--spacing-l) var(--spacing-xxxl) var(--spacing-xxl)}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require('./ModalHeader.css');const e={"modal-header":"_modal-
|
|
1
|
+
"use strict";Object.defineProperties(exports,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}});require('./ModalHeader.css');const e={"modal-header":"_modal-header_1wwv5_2","modal-header--no-divider":"_modal-header--no-divider_1wwv5_8","modal-header__content":"_modal-header__content_1wwv5_11","modal-header--has-slot":"_modal-header--has-slot_1wwv5_14","modal-header--close-only":"_modal-header--close-only_1wwv5_17","modal-header__titles":"_modal-header__titles_1wwv5_27","modal-header__primary":"_modal-header__primary_1wwv5_36","modal-header__title":"_modal-header__title_1wwv5_27","modal-header__title-sr":"_modal-header__title-sr_1wwv5_53","modal-header__subtitle":"_modal-header__subtitle_1wwv5_64","modal-header__subtitle-beside":"_modal-header__subtitle-beside_1wwv5_72","modal-header__subtitle-divider":"_modal-header__subtitle-divider_1wwv5_82","modal-header__actions":"_modal-header__actions_1wwv5_88","modal-header__close":"_modal-header__close_1wwv5_96","modal-header__slot":"_modal-header__slot_1wwv5_101"};exports.default=e;
|
|
2
2
|
//# sourceMappingURL=ModalHeader.module.scss.cjs.map
|