@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,20 +1,21 @@
|
|
|
1
|
-
import './Tabs.css';const _ = "
|
|
1
|
+
import './Tabs.css';const _ = "_tabs_69hbz_2", a = "_tabs__tab_69hbz_7", b = "_tabs__controls_69hbz_97", t = {
|
|
2
2
|
tabs: _,
|
|
3
|
-
"tabs__tab-list": "_tabs__tab-
|
|
3
|
+
"tabs__tab-list": "_tabs__tab-list_69hbz_7",
|
|
4
4
|
tabs__tab: a,
|
|
5
|
-
"tabs__tab--active": "_tabs__tab--
|
|
6
|
-
"tabs__tab--disabled": "_tabs__tab--
|
|
7
|
-
"tabs__tab-label": "_tabs__tab-
|
|
8
|
-
"tabs__count-badge": "_tabs__count-
|
|
9
|
-
"tabs__count-badge--active": "_tabs__count-badge--
|
|
10
|
-
"tabs__unread-badge": "_tabs__unread-
|
|
11
|
-
"tabs__unread-label": "_tabs__unread-
|
|
12
|
-
tabs__controls:
|
|
5
|
+
"tabs__tab--active": "_tabs__tab--active_69hbz_31",
|
|
6
|
+
"tabs__tab--disabled": "_tabs__tab--disabled_69hbz_31",
|
|
7
|
+
"tabs__tab-label": "_tabs__tab-label_69hbz_37",
|
|
8
|
+
"tabs__count-badge": "_tabs__count-badge_69hbz_40",
|
|
9
|
+
"tabs__count-badge--active": "_tabs__count-badge--active_69hbz_75",
|
|
10
|
+
"tabs__unread-badge": "_tabs__unread-badge_69hbz_79",
|
|
11
|
+
"tabs__unread-label": "_tabs__unread-label_69hbz_86",
|
|
12
|
+
tabs__controls: b,
|
|
13
|
+
"tabs--appearance-underlined": "_tabs--appearance-underlined_69hbz_103"
|
|
13
14
|
};
|
|
14
15
|
export {
|
|
15
|
-
|
|
16
|
+
t as default,
|
|
16
17
|
_ as tabs,
|
|
17
|
-
|
|
18
|
+
b as tabs__controls,
|
|
18
19
|
a as tabs__tab
|
|
19
20
|
};
|
|
20
21
|
//# sourceMappingURL=Tabs.module.scss.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"Tabs.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"Tabs.module.scss.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/tabs/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,QAAQ,CAAC;AACzC,YAAY,EAAE,SAAS,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const d=require("react"),S=["a[href]","area[href]","button:not([disabled])",'input:not([disabled]):not([type="hidden"])',"select:not([disabled])","textarea:not([disabled])","summary",'[contenteditable=""]','[contenteditable="true"]',"[tabindex]"].join(",");function w(r,s){for(let t=r;t;t=t.parentElement){if(t.hidden||t.hasAttribute("inert")||t.getAttribute("aria-hidden")==="true")return!0;const l=getComputedStyle(t);if(l.display==="none"||t===r&&l.visibility==="hidden")return!0;if(t===s)break}return!1}function x(r){return Array.from(r.querySelectorAll(S)).filter(s=>s.tabIndex>=0&&!s.matches(":disabled")&&!w(s,r))}const u=[];function T(r,{initialFocusRef:s,closeOnEscape:t=!0,onClose:l,active:p=!0}){const y=d.useRef(s);y.current=s;const m=d.useRef({closeOnEscape:t,onClose:l});m.current={closeOnEscape:t,onClose:l};const v=d.useRef(null),a=d.useRef(null);d.useEffect(()=>{var i;const c=document.activeElement;function b(){const o=u[u.length-1],f=v.current;return f&&u.includes(f)?o===f:a.current?a.current.wasTop&&o===a.current.below:o===void 0}const e=r.current,n=(i=y.current)==null?void 0:i.current;return n&&(e!=null&&e.contains(n))&&n.focus(),(!n||document.activeElement!==n)&&(e==null||e.focus()),()=>{b()&&c&&c.isConnected&&typeof c.focus=="function"&&c.focus()}},[r]),d.useEffect(()=>{if(!p)return;const c={};u.push(c),v.current=c,a.current=null;function b(e){var E,k;if(e.defaultPrevented||u[u.length-1]!==c)return;const n=r.current;if(!n)return;if(e.key==="Escape"){m.current.closeOnEscape&&((k=(E=m.current).onClose)==null||k.call(E));return}if(e.key!=="Tab")return;const i=x(n);if(i.length===0){e.preventDefault(),n.focus();return}const o=i[0],f=i[i.length-1],h=document.activeElement,g=!n.contains(h);e.shiftKey?(g||h===o||h===n)&&(e.preventDefault(),f.focus()):(g||h===f)&&(e.preventDefault(),o.focus())}return document.addEventListener("keydown",b),()=>{document.removeEventListener("keydown",b);const e=u.indexOf(c);a.current={wasTop:e===u.length-1,below:u[e-1]},u.splice(e,1)}},[r,p])}exports.useModalFocus=T;
|
|
2
|
+
//# sourceMappingURL=use-modal-focus.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-modal-focus.cjs","sources":["../../src/hooks/use-modal-focus.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport type { RefObject } from 'react';\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled]):not([type=\"hidden\"])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'summary',\n '[contenteditable=\"\"]',\n '[contenteditable=\"true\"]',\n '[tabindex]',\n].join(',');\n\nfunction isHidden(el: HTMLElement, root: HTMLElement): boolean {\n for (let node: HTMLElement | null = el; node; node = node.parentElement) {\n if (node.hidden || node.hasAttribute('inert')) return true;\n if (node.getAttribute('aria-hidden') === 'true') return true;\n const style = getComputedStyle(node);\n if (style.display === 'none') return true;\n if (node === el && style.visibility === 'hidden') return true;\n if (node === root) break;\n }\n return false;\n}\n\nfunction getFocusable(root: HTMLElement): HTMLElement[] {\n return Array.from(\n root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),\n ).filter(\n (el) => el.tabIndex >= 0 && !el.matches(':disabled') && !isHidden(el, root),\n );\n}\n\n/** Open modals in mount order; only the last one reacts to Tab and Escape. */\nconst modalStack: object[] = [];\n\nexport interface UseModalFocusOptions {\n /** Element to focus on mount. Falls back to the dialog root. */\n initialFocusRef?: RefObject<HTMLElement | null>;\n /** Close on Escape. Default true. */\n closeOnEscape?: boolean;\n onClose?: () => void;\n /**\n * When false (e.g. during an exit transition) Tab and Escape are no longer\n * handled and the modal leaves the stack, but focus is still restored on\n * unmount. Default true.\n */\n active?: boolean;\n}\n\n/**\n * Dialog focus and keyboard behavior for a modal panel: initial focus, Tab trap\n * (focusable elements computed at keypress), Escape (skipped when already\n * handled), and focus restore on unmount.\n *\n * Tab and Escape are handled by one document listener, so the trap still holds\n * when focus sits outside the dialog (e.g. after a backdrop click), and only\n * the topmost active modal responds. Events whose default was prevented (by an\n * inner widget or the host's `onKeyDown`) are ignored.\n */\nexport function useModalFocus(\n rootRef: RefObject<HTMLElement | null>,\n {\n initialFocusRef,\n closeOnEscape = true,\n onClose,\n active = true,\n }: UseModalFocusOptions,\n): void {\n const initialFocusRefRef = useRef(initialFocusRef);\n initialFocusRefRef.current = initialFocusRef;\n const latest = useRef({ closeOnEscape, onClose });\n latest.current = { closeOnEscape, onClose };\n const keyToken = useRef<object | null>(null);\n // Stack position recorded when the token leaves the stack (exit start).\n const exit = useRef<{ wasTop: boolean; below: object | undefined } | null>(\n null,\n );\n\n useEffect(() => {\n const previous = document.activeElement as HTMLElement | null;\n function shouldRestoreFocus(): boolean {\n const top = modalStack[modalStack.length - 1];\n const token = keyToken.current;\n if (token && modalStack.includes(token)) return top === token;\n if (!exit.current) return top === undefined;\n return exit.current.wasTop && top === exit.current.below;\n }\n const root = rootRef.current;\n const target = initialFocusRefRef.current?.current;\n if (target && root?.contains(target)) target.focus();\n if (!target || document.activeElement !== target) root?.focus();\n return () => {\n if (\n shouldRestoreFocus() &&\n previous &&\n previous.isConnected &&\n typeof previous.focus === 'function'\n ) {\n previous.focus();\n }\n };\n }, [rootRef]);\n\n useEffect(() => {\n if (!active) return;\n const token = {};\n modalStack.push(token);\n keyToken.current = token;\n exit.current = null;\n\n function handle(e: KeyboardEvent) {\n if (e.defaultPrevented || modalStack[modalStack.length - 1] !== token)\n return;\n const dialog = rootRef.current;\n if (!dialog) return;\n if (e.key === 'Escape') {\n if (latest.current.closeOnEscape) latest.current.onClose?.();\n return;\n }\n if (e.key !== 'Tab') return;\n const focusable = getFocusable(dialog);\n if (focusable.length === 0) {\n e.preventDefault();\n dialog.focus();\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const current = document.activeElement;\n const outside = !dialog.contains(current);\n if (e.shiftKey) {\n if (outside || current === first || current === dialog) {\n e.preventDefault();\n last.focus();\n }\n } else if (outside || current === last) {\n e.preventDefault();\n first.focus();\n }\n }\n document.addEventListener('keydown', handle);\n return () => {\n document.removeEventListener('keydown', handle);\n const index = modalStack.indexOf(token);\n exit.current = {\n wasTop: index === modalStack.length - 1,\n below: modalStack[index - 1],\n };\n modalStack.splice(index, 1);\n };\n }, [rootRef, active]);\n}\n"],"names":["FOCUSABLE_SELECTOR","isHidden","el","root","node","style","getFocusable","modalStack","useModalFocus","rootRef","initialFocusRef","closeOnEscape","onClose","active","initialFocusRefRef","useRef","latest","keyToken","exit","useEffect","previous","shouldRestoreFocus","top","token","target","_a","handle","dialog","_b","focusable","first","last","current","outside","index"],"mappings":"yGAGMA,EAAqB,CACzB,UACA,aACA,yBACA,6CACA,yBACA,2BACA,UACA,uBACA,2BACA,YACF,EAAE,KAAK,GAAG,EAEV,SAASC,EAASC,EAAiBC,EAA4B,CAC7D,QAASC,EAA2BF,EAAIE,EAAMA,EAAOA,EAAK,cAAe,CAEvE,GADIA,EAAK,QAAUA,EAAK,aAAa,OAAO,GACxCA,EAAK,aAAa,aAAa,IAAM,OAAQ,MAAO,GACxD,MAAMC,EAAQ,iBAAiBD,CAAI,EAEnC,GADIC,EAAM,UAAY,QAClBD,IAASF,GAAMG,EAAM,aAAe,SAAU,MAAO,GACzD,GAAID,IAASD,EAAM,KACrB,CACA,MAAO,EACT,CAEA,SAASG,EAAaH,EAAkC,CACtD,OAAO,MAAM,KACXA,EAAK,iBAA8BH,CAAkB,CAAA,EACrD,OACCE,GAAOA,EAAG,UAAY,GAAK,CAACA,EAAG,QAAQ,WAAW,GAAK,CAACD,EAASC,EAAIC,CAAI,CAAA,CAE9E,CAGA,MAAMI,EAAuB,CAAA,EA0BtB,SAASC,EACdC,EACA,CACE,gBAAAC,EACA,cAAAC,EAAgB,GAChB,QAAAC,EACA,OAAAC,EAAS,EACX,EACM,CACN,MAAMC,EAAqBC,EAAAA,OAAOL,CAAe,EACjDI,EAAmB,QAAUJ,EAC7B,MAAMM,EAASD,EAAAA,OAAO,CAAE,cAAAJ,EAAe,QAAAC,EAAS,EAChDI,EAAO,QAAU,CAAE,cAAAL,EAAe,QAAAC,CAAA,EAClC,MAAMK,EAAWF,EAAAA,OAAsB,IAAI,EAErCG,EAAOH,EAAAA,OACX,IAAA,EAGFI,EAAAA,UAAU,IAAM,OACd,MAAMC,EAAW,SAAS,cAC1B,SAASC,GAA8B,CACrC,MAAMC,EAAMf,EAAWA,EAAW,OAAS,CAAC,EACtCgB,EAAQN,EAAS,QACvB,OAAIM,GAAShB,EAAW,SAASgB,CAAK,EAAUD,IAAQC,EACnDL,EAAK,QACHA,EAAK,QAAQ,QAAUI,IAAQJ,EAAK,QAAQ,MADzBI,IAAQ,MAEpC,CACA,MAAMnB,EAAOM,EAAQ,QACfe,GAASC,EAAAX,EAAmB,UAAnB,YAAAW,EAA4B,QAC3C,OAAID,IAAUrB,GAAA,MAAAA,EAAM,SAASqB,OAAgB,MAAA,GACzC,CAACA,GAAU,SAAS,gBAAkBA,gBAAc,SACjD,IAAM,CAETH,EAAA,GACAD,GACAA,EAAS,aACT,OAAOA,EAAS,OAAU,YAE1BA,EAAS,MAAA,CAEb,CACF,EAAG,CAACX,CAAO,CAAC,EAEZU,EAAAA,UAAU,IAAM,CACd,GAAI,CAACN,EAAQ,OACb,MAAMU,EAAQ,CAAA,EACdhB,EAAW,KAAKgB,CAAK,EACrBN,EAAS,QAAUM,EACnBL,EAAK,QAAU,KAEf,SAASQ,EAAO,EAAkB,SAChC,GAAI,EAAE,kBAAoBnB,EAAWA,EAAW,OAAS,CAAC,IAAMgB,EAC9D,OACF,MAAMI,EAASlB,EAAQ,QACvB,GAAI,CAACkB,EAAQ,OACb,GAAI,EAAE,MAAQ,SAAU,CAClBX,EAAO,QAAQ,iBAAeY,GAAAH,EAAAT,EAAO,SAAQ,UAAf,MAAAY,EAAA,KAAAH,IAClC,MACF,CACA,GAAI,EAAE,MAAQ,MAAO,OACrB,MAAMI,EAAYvB,EAAaqB,CAAM,EACrC,GAAIE,EAAU,SAAW,EAAG,CAC1B,EAAE,eAAA,EACFF,EAAO,MAAA,EACP,MACF,CACA,MAAMG,EAAQD,EAAU,CAAC,EACnBE,EAAOF,EAAUA,EAAU,OAAS,CAAC,EACrCG,EAAU,SAAS,cACnBC,EAAU,CAACN,EAAO,SAASK,CAAO,EACpC,EAAE,UACAC,GAAWD,IAAYF,GAASE,IAAYL,KAC9C,EAAE,eAAA,EACFI,EAAK,MAAA,IAEEE,GAAWD,IAAYD,KAChC,EAAE,eAAA,EACFD,EAAM,MAAA,EAEV,CACA,gBAAS,iBAAiB,UAAWJ,CAAM,EACpC,IAAM,CACX,SAAS,oBAAoB,UAAWA,CAAM,EAC9C,MAAMQ,EAAQ3B,EAAW,QAAQgB,CAAK,EACtCL,EAAK,QAAU,CACb,OAAQgB,IAAU3B,EAAW,OAAS,EACtC,MAAOA,EAAW2B,EAAQ,CAAC,CAAA,EAE7B3B,EAAW,OAAO2B,EAAO,CAAC,CAC5B,CACF,EAAG,CAACzB,EAASI,CAAM,CAAC,CACtB"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export interface UseModalFocusOptions {
|
|
3
|
+
/** Element to focus on mount. Falls back to the dialog root. */
|
|
4
|
+
initialFocusRef?: RefObject<HTMLElement | null>;
|
|
5
|
+
/** Close on Escape. Default true. */
|
|
6
|
+
closeOnEscape?: boolean;
|
|
7
|
+
onClose?: () => void;
|
|
8
|
+
/**
|
|
9
|
+
* When false (e.g. during an exit transition) Tab and Escape are no longer
|
|
10
|
+
* handled and the modal leaves the stack, but focus is still restored on
|
|
11
|
+
* unmount. Default true.
|
|
12
|
+
*/
|
|
13
|
+
active?: boolean;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Dialog focus and keyboard behavior for a modal panel: initial focus, Tab trap
|
|
17
|
+
* (focusable elements computed at keypress), Escape (skipped when already
|
|
18
|
+
* handled), and focus restore on unmount.
|
|
19
|
+
*
|
|
20
|
+
* Tab and Escape are handled by one document listener, so the trap still holds
|
|
21
|
+
* when focus sits outside the dialog (e.g. after a backdrop click), and only
|
|
22
|
+
* the topmost active modal responds. Events whose default was prevented (by an
|
|
23
|
+
* inner widget or the host's `onKeyDown`) are ignored.
|
|
24
|
+
*/
|
|
25
|
+
export declare function useModalFocus(rootRef: RefObject<HTMLElement | null>, { initialFocusRef, closeOnEscape, onClose, active, }: UseModalFocusOptions): void;
|
|
26
|
+
//# sourceMappingURL=use-modal-focus.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-modal-focus.d.ts","sourceRoot":"","sources":["../../src/hooks/use-modal-focus.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAsCvC,MAAM,WAAW,oBAAoB;IACnC,gEAAgE;IAChE,eAAe,CAAC,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;IAChD,qCAAqC;IACrC,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB;;;;OAIG;IACH,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,wBAAgB,aAAa,CAC3B,OAAO,EAAE,SAAS,CAAC,WAAW,GAAG,IAAI,CAAC,EACtC,EACE,eAAe,EACf,aAAoB,EACpB,OAAO,EACP,MAAa,GACd,EAAE,oBAAoB,GACtB,IAAI,CAoFN"}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { useRef as m, useEffect as x } from "react";
|
|
2
|
+
const w = [
|
|
3
|
+
"a[href]",
|
|
4
|
+
"area[href]",
|
|
5
|
+
"button:not([disabled])",
|
|
6
|
+
'input:not([disabled]):not([type="hidden"])',
|
|
7
|
+
"select:not([disabled])",
|
|
8
|
+
"textarea:not([disabled])",
|
|
9
|
+
"summary",
|
|
10
|
+
'[contenteditable=""]',
|
|
11
|
+
'[contenteditable="true"]',
|
|
12
|
+
"[tabindex]"
|
|
13
|
+
].join(",");
|
|
14
|
+
function A(r, i) {
|
|
15
|
+
for (let t = r; t; t = t.parentElement) {
|
|
16
|
+
if (t.hidden || t.hasAttribute("inert") || t.getAttribute("aria-hidden") === "true") return !0;
|
|
17
|
+
const d = getComputedStyle(t);
|
|
18
|
+
if (d.display === "none" || t === r && d.visibility === "hidden") return !0;
|
|
19
|
+
if (t === i) break;
|
|
20
|
+
}
|
|
21
|
+
return !1;
|
|
22
|
+
}
|
|
23
|
+
function S(r) {
|
|
24
|
+
return Array.from(
|
|
25
|
+
r.querySelectorAll(w)
|
|
26
|
+
).filter(
|
|
27
|
+
(i) => i.tabIndex >= 0 && !i.matches(":disabled") && !A(i, r)
|
|
28
|
+
);
|
|
29
|
+
}
|
|
30
|
+
const u = [];
|
|
31
|
+
function C(r, {
|
|
32
|
+
initialFocusRef: i,
|
|
33
|
+
closeOnEscape: t = !0,
|
|
34
|
+
onClose: d,
|
|
35
|
+
active: h = !0
|
|
36
|
+
}) {
|
|
37
|
+
const y = m(i);
|
|
38
|
+
y.current = i;
|
|
39
|
+
const p = m({ closeOnEscape: t, onClose: d });
|
|
40
|
+
p.current = { closeOnEscape: t, onClose: d };
|
|
41
|
+
const v = m(null), l = m(
|
|
42
|
+
null
|
|
43
|
+
);
|
|
44
|
+
x(() => {
|
|
45
|
+
var o;
|
|
46
|
+
const c = document.activeElement;
|
|
47
|
+
function a() {
|
|
48
|
+
const s = u[u.length - 1], f = v.current;
|
|
49
|
+
return f && u.includes(f) ? s === f : l.current ? l.current.wasTop && s === l.current.below : s === void 0;
|
|
50
|
+
}
|
|
51
|
+
const e = r.current, n = (o = y.current) == null ? void 0 : o.current;
|
|
52
|
+
return n && (e != null && e.contains(n)) && n.focus(), (!n || document.activeElement !== n) && (e == null || e.focus()), () => {
|
|
53
|
+
a() && c && c.isConnected && typeof c.focus == "function" && c.focus();
|
|
54
|
+
};
|
|
55
|
+
}, [r]), x(() => {
|
|
56
|
+
if (!h) return;
|
|
57
|
+
const c = {};
|
|
58
|
+
u.push(c), v.current = c, l.current = null;
|
|
59
|
+
function a(e) {
|
|
60
|
+
var g, k;
|
|
61
|
+
if (e.defaultPrevented || u[u.length - 1] !== c)
|
|
62
|
+
return;
|
|
63
|
+
const n = r.current;
|
|
64
|
+
if (!n) return;
|
|
65
|
+
if (e.key === "Escape") {
|
|
66
|
+
p.current.closeOnEscape && ((k = (g = p.current).onClose) == null || k.call(g));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
if (e.key !== "Tab") return;
|
|
70
|
+
const o = S(n);
|
|
71
|
+
if (o.length === 0) {
|
|
72
|
+
e.preventDefault(), n.focus();
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
const s = o[0], f = o[o.length - 1], b = document.activeElement, E = !n.contains(b);
|
|
76
|
+
e.shiftKey ? (E || b === s || b === n) && (e.preventDefault(), f.focus()) : (E || b === f) && (e.preventDefault(), s.focus());
|
|
77
|
+
}
|
|
78
|
+
return document.addEventListener("keydown", a), () => {
|
|
79
|
+
document.removeEventListener("keydown", a);
|
|
80
|
+
const e = u.indexOf(c);
|
|
81
|
+
l.current = {
|
|
82
|
+
wasTop: e === u.length - 1,
|
|
83
|
+
below: u[e - 1]
|
|
84
|
+
}, u.splice(e, 1);
|
|
85
|
+
};
|
|
86
|
+
}, [r, h]);
|
|
87
|
+
}
|
|
88
|
+
export {
|
|
89
|
+
C as useModalFocus
|
|
90
|
+
};
|
|
91
|
+
//# sourceMappingURL=use-modal-focus.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-modal-focus.js","sources":["../../src/hooks/use-modal-focus.ts"],"sourcesContent":["import { useEffect, useRef } from 'react';\nimport type { RefObject } from 'react';\n\nconst FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'area[href]',\n 'button:not([disabled])',\n 'input:not([disabled]):not([type=\"hidden\"])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n 'summary',\n '[contenteditable=\"\"]',\n '[contenteditable=\"true\"]',\n '[tabindex]',\n].join(',');\n\nfunction isHidden(el: HTMLElement, root: HTMLElement): boolean {\n for (let node: HTMLElement | null = el; node; node = node.parentElement) {\n if (node.hidden || node.hasAttribute('inert')) return true;\n if (node.getAttribute('aria-hidden') === 'true') return true;\n const style = getComputedStyle(node);\n if (style.display === 'none') return true;\n if (node === el && style.visibility === 'hidden') return true;\n if (node === root) break;\n }\n return false;\n}\n\nfunction getFocusable(root: HTMLElement): HTMLElement[] {\n return Array.from(\n root.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR),\n ).filter(\n (el) => el.tabIndex >= 0 && !el.matches(':disabled') && !isHidden(el, root),\n );\n}\n\n/** Open modals in mount order; only the last one reacts to Tab and Escape. */\nconst modalStack: object[] = [];\n\nexport interface UseModalFocusOptions {\n /** Element to focus on mount. Falls back to the dialog root. */\n initialFocusRef?: RefObject<HTMLElement | null>;\n /** Close on Escape. Default true. */\n closeOnEscape?: boolean;\n onClose?: () => void;\n /**\n * When false (e.g. during an exit transition) Tab and Escape are no longer\n * handled and the modal leaves the stack, but focus is still restored on\n * unmount. Default true.\n */\n active?: boolean;\n}\n\n/**\n * Dialog focus and keyboard behavior for a modal panel: initial focus, Tab trap\n * (focusable elements computed at keypress), Escape (skipped when already\n * handled), and focus restore on unmount.\n *\n * Tab and Escape are handled by one document listener, so the trap still holds\n * when focus sits outside the dialog (e.g. after a backdrop click), and only\n * the topmost active modal responds. Events whose default was prevented (by an\n * inner widget or the host's `onKeyDown`) are ignored.\n */\nexport function useModalFocus(\n rootRef: RefObject<HTMLElement | null>,\n {\n initialFocusRef,\n closeOnEscape = true,\n onClose,\n active = true,\n }: UseModalFocusOptions,\n): void {\n const initialFocusRefRef = useRef(initialFocusRef);\n initialFocusRefRef.current = initialFocusRef;\n const latest = useRef({ closeOnEscape, onClose });\n latest.current = { closeOnEscape, onClose };\n const keyToken = useRef<object | null>(null);\n // Stack position recorded when the token leaves the stack (exit start).\n const exit = useRef<{ wasTop: boolean; below: object | undefined } | null>(\n null,\n );\n\n useEffect(() => {\n const previous = document.activeElement as HTMLElement | null;\n function shouldRestoreFocus(): boolean {\n const top = modalStack[modalStack.length - 1];\n const token = keyToken.current;\n if (token && modalStack.includes(token)) return top === token;\n if (!exit.current) return top === undefined;\n return exit.current.wasTop && top === exit.current.below;\n }\n const root = rootRef.current;\n const target = initialFocusRefRef.current?.current;\n if (target && root?.contains(target)) target.focus();\n if (!target || document.activeElement !== target) root?.focus();\n return () => {\n if (\n shouldRestoreFocus() &&\n previous &&\n previous.isConnected &&\n typeof previous.focus === 'function'\n ) {\n previous.focus();\n }\n };\n }, [rootRef]);\n\n useEffect(() => {\n if (!active) return;\n const token = {};\n modalStack.push(token);\n keyToken.current = token;\n exit.current = null;\n\n function handle(e: KeyboardEvent) {\n if (e.defaultPrevented || modalStack[modalStack.length - 1] !== token)\n return;\n const dialog = rootRef.current;\n if (!dialog) return;\n if (e.key === 'Escape') {\n if (latest.current.closeOnEscape) latest.current.onClose?.();\n return;\n }\n if (e.key !== 'Tab') return;\n const focusable = getFocusable(dialog);\n if (focusable.length === 0) {\n e.preventDefault();\n dialog.focus();\n return;\n }\n const first = focusable[0];\n const last = focusable[focusable.length - 1];\n const current = document.activeElement;\n const outside = !dialog.contains(current);\n if (e.shiftKey) {\n if (outside || current === first || current === dialog) {\n e.preventDefault();\n last.focus();\n }\n } else if (outside || current === last) {\n e.preventDefault();\n first.focus();\n }\n }\n document.addEventListener('keydown', handle);\n return () => {\n document.removeEventListener('keydown', handle);\n const index = modalStack.indexOf(token);\n exit.current = {\n wasTop: index === modalStack.length - 1,\n below: modalStack[index - 1],\n };\n modalStack.splice(index, 1);\n };\n }, [rootRef, active]);\n}\n"],"names":["FOCUSABLE_SELECTOR","isHidden","el","root","node","style","getFocusable","modalStack","useModalFocus","rootRef","initialFocusRef","closeOnEscape","onClose","active","initialFocusRefRef","useRef","latest","keyToken","exit","useEffect","previous","shouldRestoreFocus","top","token","target","_a","handle","dialog","_b","focusable","first","last","current","outside","index"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const r=require("react"),m=require("../utils/duration.cjs"),s=150;function f(e,i="--duration-quick"){const[a,n]=r.useState(e),[u,o]=r.useState(!1);return r.useEffect(()=>{if(e){n(!0);let t=0;const l=requestAnimationFrame(()=>{t=requestAnimationFrame(()=>o(!0))});return()=>{cancelAnimationFrame(l),t&&cancelAnimationFrame(t)}}o(!1);const c=window.setTimeout(()=>n(!1),m.readDurationMs(i,s));return()=>window.clearTimeout(c)},[e,i]),{mounted:a,visible:u}}exports.POPOVER_TRANSITION_MS=s;exports.usePopoverTransition=f;
|
|
2
2
|
//# sourceMappingURL=use-popover-transition.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-popover-transition.cjs","sources":["../../src/hooks/use-popover-transition.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n
|
|
1
|
+
{"version":3,"file":"use-popover-transition.cjs","sources":["../../src/hooks/use-popover-transition.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { readDurationMs } from '@/utils/duration';\n\n/** Fallback for `--duration-quick` when the token is not available. */\nexport const POPOVER_TRANSITION_MS = 150;\n\n/**\n * Keeps a surface mounted for the duration of its exit animation so the close\n * transition can play before React unmounts the node. The exit wait is read\n * from `durationToken` (default `--duration-quick`) so it always matches the\n * CSS transition. See CLAUDE.md: \"Animation: popover panel open/close\".\n */\nexport function usePopoverTransition(\n open: boolean,\n durationToken = '--duration-quick',\n) {\n const [mounted, setMounted] = useState(open);\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n if (open) {\n setMounted(true);\n let raf2 = 0;\n const raf1 = requestAnimationFrame(() => {\n raf2 = requestAnimationFrame(() => setVisible(true));\n });\n return () => {\n cancelAnimationFrame(raf1);\n if (raf2) cancelAnimationFrame(raf2);\n };\n }\n setVisible(false);\n const t = window.setTimeout(\n () => setMounted(false),\n readDurationMs(durationToken, POPOVER_TRANSITION_MS),\n );\n return () => window.clearTimeout(t);\n }, [open, durationToken]);\n\n return { mounted, visible };\n}\n"],"names":["POPOVER_TRANSITION_MS","usePopoverTransition","open","durationToken","mounted","setMounted","useState","visible","setVisible","useEffect","raf2","raf1","t","readDurationMs"],"mappings":"4IAIaA,EAAwB,IAQ9B,SAASC,EACdC,EACAC,EAAgB,mBAChB,CACA,KAAM,CAACC,EAASC,CAAU,EAAIC,EAAAA,SAASJ,CAAI,EACrC,CAACK,EAASC,CAAU,EAAIF,EAAAA,SAAS,EAAK,EAE5CG,OAAAA,EAAAA,UAAU,IAAM,CACd,GAAIP,EAAM,CACRG,EAAW,EAAI,EACf,IAAIK,EAAO,EACX,MAAMC,EAAO,sBAAsB,IAAM,CACvCD,EAAO,sBAAsB,IAAMF,EAAW,EAAI,CAAC,CACrD,CAAC,EACD,MAAO,IAAM,CACX,qBAAqBG,CAAI,EACrBD,wBAA2BA,CAAI,CACrC,CACF,CACAF,EAAW,EAAK,EAChB,MAAMI,EAAI,OAAO,WACf,IAAMP,EAAW,EAAK,EACtBQ,EAAAA,eAAeV,EAAeH,CAAqB,CAAA,EAErD,MAAO,IAAM,OAAO,aAAaY,CAAC,CACpC,EAAG,CAACV,EAAMC,CAAa,CAAC,EAEjB,CAAE,QAAAC,EAAS,QAAAG,CAAA,CACpB"}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
/** Fallback for `--duration-quick` when the token is not available. */
|
|
1
2
|
export declare const POPOVER_TRANSITION_MS = 150;
|
|
2
3
|
/**
|
|
3
|
-
* Keeps a
|
|
4
|
-
* transition can play before React unmounts the node.
|
|
5
|
-
*
|
|
4
|
+
* Keeps a surface mounted for the duration of its exit animation so the close
|
|
5
|
+
* transition can play before React unmounts the node. The exit wait is read
|
|
6
|
+
* from `durationToken` (default `--duration-quick`) so it always matches the
|
|
7
|
+
* CSS transition. See CLAUDE.md: "Animation: popover panel open/close".
|
|
6
8
|
*/
|
|
7
|
-
export declare function usePopoverTransition(open: boolean): {
|
|
9
|
+
export declare function usePopoverTransition(open: boolean, durationToken?: string): {
|
|
8
10
|
mounted: boolean;
|
|
9
11
|
visible: boolean;
|
|
10
12
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-popover-transition.d.ts","sourceRoot":"","sources":["../../src/hooks/use-popover-transition.ts"],"names":[],"mappings":"AAGA,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC
|
|
1
|
+
{"version":3,"file":"use-popover-transition.d.ts","sourceRoot":"","sources":["../../src/hooks/use-popover-transition.ts"],"names":[],"mappings":"AAGA,uEAAuE;AACvE,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAEzC;;;;;GAKG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,OAAO,EACb,aAAa,SAAqB;;;EA0BnC"}
|
|
@@ -1,25 +1,29 @@
|
|
|
1
|
-
import { useState as
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
1
|
+
import { useState as o, useEffect as c } from "react";
|
|
2
|
+
import { readDurationMs as f } from "../utils/duration.js";
|
|
3
|
+
const l = 150;
|
|
4
|
+
function w(e, r = "--duration-quick") {
|
|
5
|
+
const [a, i] = o(e), [s, n] = o(!1);
|
|
6
|
+
return c(() => {
|
|
6
7
|
if (e) {
|
|
7
|
-
|
|
8
|
+
i(!0);
|
|
8
9
|
let t = 0;
|
|
9
|
-
const
|
|
10
|
-
t = requestAnimationFrame(() =>
|
|
10
|
+
const m = requestAnimationFrame(() => {
|
|
11
|
+
t = requestAnimationFrame(() => n(!0));
|
|
11
12
|
});
|
|
12
13
|
return () => {
|
|
13
|
-
cancelAnimationFrame(
|
|
14
|
+
cancelAnimationFrame(m), t && cancelAnimationFrame(t);
|
|
14
15
|
};
|
|
15
16
|
}
|
|
16
|
-
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
|
|
17
|
+
n(!1);
|
|
18
|
+
const u = window.setTimeout(
|
|
19
|
+
() => i(!1),
|
|
20
|
+
f(r, l)
|
|
21
|
+
);
|
|
22
|
+
return () => window.clearTimeout(u);
|
|
23
|
+
}, [e, r]), { mounted: a, visible: s };
|
|
20
24
|
}
|
|
21
25
|
export {
|
|
22
|
-
|
|
23
|
-
|
|
26
|
+
l as POPOVER_TRANSITION_MS,
|
|
27
|
+
w as usePopoverTransition
|
|
24
28
|
};
|
|
25
29
|
//# sourceMappingURL=use-popover-transition.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-popover-transition.js","sources":["../../src/hooks/use-popover-transition.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\n\n
|
|
1
|
+
{"version":3,"file":"use-popover-transition.js","sources":["../../src/hooks/use-popover-transition.ts"],"sourcesContent":["import { useEffect, useState } from 'react';\nimport { readDurationMs } from '@/utils/duration';\n\n/** Fallback for `--duration-quick` when the token is not available. */\nexport const POPOVER_TRANSITION_MS = 150;\n\n/**\n * Keeps a surface mounted for the duration of its exit animation so the close\n * transition can play before React unmounts the node. The exit wait is read\n * from `durationToken` (default `--duration-quick`) so it always matches the\n * CSS transition. See CLAUDE.md: \"Animation: popover panel open/close\".\n */\nexport function usePopoverTransition(\n open: boolean,\n durationToken = '--duration-quick',\n) {\n const [mounted, setMounted] = useState(open);\n const [visible, setVisible] = useState(false);\n\n useEffect(() => {\n if (open) {\n setMounted(true);\n let raf2 = 0;\n const raf1 = requestAnimationFrame(() => {\n raf2 = requestAnimationFrame(() => setVisible(true));\n });\n return () => {\n cancelAnimationFrame(raf1);\n if (raf2) cancelAnimationFrame(raf2);\n };\n }\n setVisible(false);\n const t = window.setTimeout(\n () => setMounted(false),\n readDurationMs(durationToken, POPOVER_TRANSITION_MS),\n );\n return () => window.clearTimeout(t);\n }, [open, durationToken]);\n\n return { mounted, visible };\n}\n"],"names":["POPOVER_TRANSITION_MS","usePopoverTransition","open","durationToken","mounted","setMounted","useState","visible","setVisible","useEffect","raf2","raf1","t","readDurationMs"],"mappings":";;AAIO,MAAMA,IAAwB;AAQ9B,SAASC,EACdC,GACAC,IAAgB,oBAChB;AACA,QAAM,CAACC,GAASC,CAAU,IAAIC,EAASJ,CAAI,GACrC,CAACK,GAASC,CAAU,IAAIF,EAAS,EAAK;AAE5C,SAAAG,EAAU,MAAM;AACd,QAAIP,GAAM;AACR,MAAAG,EAAW,EAAI;AACf,UAAIK,IAAO;AACX,YAAMC,IAAO,sBAAsB,MAAM;AACvC,QAAAD,IAAO,sBAAsB,MAAMF,EAAW,EAAI,CAAC;AAAA,MACrD,CAAC;AACD,aAAO,MAAM;AACX,6BAAqBG,CAAI,GACrBD,0BAA2BA,CAAI;AAAA,MACrC;AAAA,IACF;AACA,IAAAF,EAAW,EAAK;AAChB,UAAMI,IAAI,OAAO;AAAA,MACf,MAAMP,EAAW,EAAK;AAAA,MACtBQ,EAAeV,GAAeH,CAAqB;AAAA,IAAA;AAErD,WAAO,MAAM,OAAO,aAAaY,CAAC;AAAA,EACpC,GAAG,CAACV,GAAMC,CAAa,CAAC,GAEjB,EAAE,SAAAC,GAAS,SAAAG,EAAA;AACpB;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});function u(n,t){if(typeof document>"u")return t;const o=getComputedStyle(document.documentElement).getPropertyValue(n).trim(),e=/^(\d*\.?\d+)(ms|s)$/.exec(o);if(!e)return t;const r=parseFloat(e[1]);return e[2]==="s"?r*1e3:r}exports.readDurationMs=u;
|
|
2
|
+
//# sourceMappingURL=duration.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration.cjs","sources":["../../src/utils/duration.ts"],"sourcesContent":["/**\n * Reads a duration token (e.g. `--duration-quick`) from the document root and\n * returns milliseconds, so JS timers that wait on a CSS transition follow the\n * token instead of a hard-coded copy. Falls back when the token is missing\n * (SSR, tests, hosts that did not load the stylesheet).\n */\nexport function readDurationMs(token: string, fallbackMs: number): number {\n if (typeof document === 'undefined') return fallbackMs;\n const raw = getComputedStyle(document.documentElement)\n .getPropertyValue(token)\n .trim();\n const match = /^(\\d*\\.?\\d+)(ms|s)$/.exec(raw);\n if (!match) return fallbackMs;\n const value = parseFloat(match[1]);\n return match[2] === 's' ? value * 1000 : value;\n}\n"],"names":["readDurationMs","token","fallbackMs","raw","match","value"],"mappings":"gFAMO,SAASA,EAAeC,EAAeC,EAA4B,CACxE,GAAI,OAAO,SAAa,IAAa,OAAOA,EAC5C,MAAMC,EAAM,iBAAiB,SAAS,eAAe,EAClD,iBAAiBF,CAAK,EACtB,KAAA,EACGG,EAAQ,sBAAsB,KAAKD,CAAG,EAC5C,GAAI,CAACC,EAAO,OAAOF,EACnB,MAAMG,EAAQ,WAAWD,EAAM,CAAC,CAAC,EACjC,OAAOA,EAAM,CAAC,IAAM,IAAMC,EAAQ,IAAOA,CAC3C"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Reads a duration token (e.g. `--duration-quick`) from the document root and
|
|
3
|
+
* returns milliseconds, so JS timers that wait on a CSS transition follow the
|
|
4
|
+
* token instead of a hard-coded copy. Falls back when the token is missing
|
|
5
|
+
* (SSR, tests, hosts that did not load the stylesheet).
|
|
6
|
+
*/
|
|
7
|
+
export declare function readDurationMs(token: string, fallbackMs: number): number;
|
|
8
|
+
//# sourceMappingURL=duration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration.d.ts","sourceRoot":"","sources":["../../src/utils/duration.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CASxE"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
function u(r, t) {
|
|
2
|
+
if (typeof document > "u") return t;
|
|
3
|
+
const o = getComputedStyle(document.documentElement).getPropertyValue(r).trim(), e = /^(\d*\.?\d+)(ms|s)$/.exec(o);
|
|
4
|
+
if (!e) return t;
|
|
5
|
+
const n = parseFloat(e[1]);
|
|
6
|
+
return e[2] === "s" ? n * 1e3 : n;
|
|
7
|
+
}
|
|
8
|
+
export {
|
|
9
|
+
u as readDurationMs
|
|
10
|
+
};
|
|
11
|
+
//# sourceMappingURL=duration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"duration.js","sources":["../../src/utils/duration.ts"],"sourcesContent":["/**\n * Reads a duration token (e.g. `--duration-quick`) from the document root and\n * returns milliseconds, so JS timers that wait on a CSS transition follow the\n * token instead of a hard-coded copy. Falls back when the token is missing\n * (SSR, tests, hosts that did not load the stylesheet).\n */\nexport function readDurationMs(token: string, fallbackMs: number): number {\n if (typeof document === 'undefined') return fallbackMs;\n const raw = getComputedStyle(document.documentElement)\n .getPropertyValue(token)\n .trim();\n const match = /^(\\d*\\.?\\d+)(ms|s)$/.exec(raw);\n if (!match) return fallbackMs;\n const value = parseFloat(match[1]);\n return match[2] === 's' ? value * 1000 : value;\n}\n"],"names":["readDurationMs","token","fallbackMs","raw","match","value"],"mappings":"AAMO,SAASA,EAAeC,GAAeC,GAA4B;AACxE,MAAI,OAAO,WAAa,IAAa,QAAOA;AAC5C,QAAMC,IAAM,iBAAiB,SAAS,eAAe,EAClD,iBAAiBF,CAAK,EACtB,KAAA,GACGG,IAAQ,sBAAsB,KAAKD,CAAG;AAC5C,MAAI,CAACC,EAAO,QAAOF;AACnB,QAAMG,IAAQ,WAAWD,EAAM,CAAC,CAAC;AACjC,SAAOA,EAAM,CAAC,MAAM,MAAMC,IAAQ,MAAOA;AAC3C;"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
"use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const u=require("react"),d=require("./props.cjs");function R(e,t){typeof e=="function"?e(t):e!=null&&(e.current=t)}function y(...e){return t=>{for(const n of e)R(n,t)}}function g(e){var n;const t=(n=e.props)==null?void 0:n.ref;return t!==void 0?t:e.ref}function v(e){var t;return e.length>2&&e.startsWith("on")&&e[2]===((t=e[2])==null?void 0:t.toUpperCase())}function h(e,t){const n={...t};for(const r of Object.keys(e)){const o=e[r],s=t[r];v(r)?typeof o=="function"&&typeof s=="function"?n[r]=(...c)=>{const l=c[0];s(...c),l!=null&&l.defaultPrevented||o(...c)}:typeof o=="function"&&(n[r]=o):r==="style"?n.style={...typeof o=="object"&&o!=null?o:null,...typeof s=="object"&&s!=null?s:null}:r==="className"?n.className=d.mergeClassNames(typeof o=="string"?o:void 0,typeof s=="string"?s:void 0):r in t||(n[r]=o)}return n}function C(e){return e==null||e===!1||e===!0?!1:typeof e=="string"?e.length>0:Array.isArray(e)?e.some(C):!0}function m(e){e.preventDefault(),e.stopPropagation()}function b({child:e,props:t,ref:n,content:r,disabled:o=!1,disabledClassName:s,warnOnChildContent:c=!1}){const l=process.env.NODE_ENV!=="production";let i=null;try{i=u.Children.only(e)}catch{i=null}if(!u.isValidElement(i))return l&&console.warn("asChild expects a single React element child (e.g. <a> or <Link>)."),null;const p=i.props;l&&c&&C(p.children)&&console.warn(`asChild replaces the child element's children with component anatomy. Pass an empty element (e.g. <a href="…" />).`);const f={...t};delete f.type,o&&(f["aria-disabled"]=!0,s&&(f.className=d.mergeClassNames(typeof f.className=="string"?f.className:void 0,s)));const a=h(f,p);o&&(a.onClick=m,a.onAuxClick=m);const N=g(i);return u.cloneElement(i,{...a,ref:y(n,N),children:r})}exports.composeRefs=y;exports.getElementRef=g;exports.mergeSlotProps=h;exports.renderAsChild=b;
|
|
2
|
+
//# sourceMappingURL=slot.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.cjs","sources":["../../src/utils/slot.ts"],"sourcesContent":["import {\n Children,\n cloneElement,\n isValidElement,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefCallback,\n} from 'react';\nimport { mergeClassNames } from '@/utils/props';\n\ntype PossibleRef<T> = Ref<T> | undefined;\n\n/** Assigns a value to a callback or object ref. */\nfunction setRef<T>(ref: PossibleRef<T>, value: T | null) {\n if (typeof ref === 'function') {\n ref(value);\n } else if (ref != null) {\n (ref as { current: T | null }).current = value;\n }\n}\n\n/** Composes multiple refs into a single callback ref. */\nexport function composeRefs<T>(...refs: Array<PossibleRef<T>>): RefCallback<T> {\n return (node) => {\n for (const ref of refs) {\n setRef(ref, node);\n }\n };\n}\n\n/**\n * Reads the ref from a React element across React 18 (`element.ref`) and\n * React 19 (`element.props.ref`).\n */\nexport function getElementRef(element: ReactElement): Ref<unknown> | undefined {\n // React 19: ref is a regular prop. React 18: ref is on the element.\n const propsRef = (element.props as { ref?: Ref<unknown> } | null | undefined)\n ?.ref;\n if (propsRef !== undefined) {\n return propsRef;\n }\n return (element as ReactElement & { ref?: Ref<unknown> }).ref;\n}\n\ntype AnyProps = Record<string, unknown>;\n\nfunction isHandlerKey(key: string): boolean {\n return (\n key.length > 2 && key.startsWith('on') && key[2] === key[2]?.toUpperCase()\n );\n}\n\n/**\n * Merges Slot (asChild host) props with the child's props.\n * Child props win by default; event handlers are composed (child first;\n * host skipped when the child called `preventDefault()`); `className` and\n * `style` are merged.\n */\nexport function mergeSlotProps(\n slotProps: AnyProps,\n childProps: AnyProps,\n): AnyProps {\n const override: AnyProps = { ...childProps };\n\n for (const propName of Object.keys(slotProps)) {\n const slotValue = slotProps[propName];\n const childValue = childProps[propName];\n\n if (isHandlerKey(propName)) {\n if (typeof slotValue === 'function' && typeof childValue === 'function') {\n override[propName] = (...args: unknown[]) => {\n const event = args[0] as { defaultPrevented?: boolean } | undefined;\n childValue(...args);\n if (!event?.defaultPrevented) {\n slotValue(...args);\n }\n };\n } else if (typeof slotValue === 'function') {\n override[propName] = slotValue;\n }\n } else if (propName === 'style') {\n override.style = {\n ...(typeof slotValue === 'object' && slotValue != null\n ? (slotValue as CSSProperties)\n : null),\n ...(typeof childValue === 'object' && childValue != null\n ? (childValue as CSSProperties)\n : null),\n };\n } else if (propName === 'className') {\n override.className = mergeClassNames(\n typeof slotValue === 'string' ? slotValue : undefined,\n typeof childValue === 'string' ? childValue : undefined,\n );\n } else if (!(propName in childProps)) {\n override[propName] = slotValue;\n }\n }\n\n return override;\n}\n\nfunction hasRenderableChildren(children: ReactNode): boolean {\n if (children == null || children === false || children === true) {\n return false;\n }\n if (typeof children === 'string') {\n return children.length > 0;\n }\n if (Array.isArray(children)) {\n return children.some(hasRenderableChildren);\n }\n return true;\n}\n\nfunction blockNavigation(event: {\n preventDefault: () => void;\n stopPropagation: () => void;\n}) {\n event.preventDefault();\n event.stopPropagation();\n}\n\nexport interface RenderAsChildOptions {\n /** Single React element to clone (e.g. `<a>` or `<Link>`). */\n child: ReactNode;\n /** Props owned by the host component (className, handlers, aria-*, …). */\n props: AnyProps;\n /** Forwarded ref from the host. */\n ref?: Ref<unknown>;\n /** Anatomy nodes that replace the child's children. */\n content: ReactNode;\n /** When true, apply disabled-link semantics. */\n disabled?: boolean;\n /** BEM disabled class (e.g. `button--disabled`). */\n disabledClassName?: string;\n /**\n * When true, warn in development if the child already has children (they\n * will be replaced). Use for hosts that own their full anatomy\n * (IconButton, ActionButton). Leave false when the host wraps the child's\n * text (Button label).\n */\n warnOnChildContent?: boolean;\n}\n\n/**\n * Clones a single child element with merged host props, composed refs, and\n * replacement content. Never forwards `type`. When `disabled`, sets\n * `aria-disabled`, the disabled class, and blocks click / auxclick navigation.\n */\nexport function renderAsChild({\n child,\n props,\n ref,\n content,\n disabled = false,\n disabledClassName,\n warnOnChildContent = false,\n}: RenderAsChildOptions): ReactElement | null {\n const warn = process.env.NODE_ENV !== 'production';\n\n let onlyChild: ReactNode = null;\n try {\n onlyChild = Children.only(child);\n } catch {\n onlyChild = null;\n }\n\n if (!isValidElement(onlyChild)) {\n if (warn) {\n console.warn(\n 'asChild expects a single React element child (e.g. <a> or <Link>).',\n );\n }\n return null;\n }\n\n const childProps = onlyChild.props as AnyProps & { children?: ReactNode };\n\n if (\n warn &&\n warnOnChildContent &&\n hasRenderableChildren(childProps.children)\n ) {\n console.warn(\n 'asChild replaces the child element\\'s children with component anatomy. Pass an empty element (e.g. <a href=\"…\" />).',\n );\n }\n\n // Strip `type` — on <a> it means MIME type, not button type.\n const slotProps: AnyProps = { ...props };\n delete slotProps.type;\n\n if (disabled) {\n slotProps['aria-disabled'] = true;\n if (disabledClassName) {\n slotProps.className = mergeClassNames(\n typeof slotProps.className === 'string'\n ? slotProps.className\n : undefined,\n disabledClassName,\n );\n }\n }\n\n const merged = mergeSlotProps(slotProps, childProps);\n\n if (disabled) {\n merged.onClick = blockNavigation;\n merged.onAuxClick = blockNavigation;\n }\n\n const childRef = getElementRef(onlyChild);\n\n return cloneElement(onlyChild, {\n ...merged,\n ref: composeRefs(ref, childRef),\n children: content,\n } as AnyProps);\n}\n"],"names":["setRef","ref","value","composeRefs","refs","node","getElementRef","element","propsRef","_a","isHandlerKey","key","mergeSlotProps","slotProps","childProps","override","propName","slotValue","childValue","args","event","mergeClassNames","hasRenderableChildren","children","blockNavigation","renderAsChild","child","props","content","disabled","disabledClassName","warnOnChildContent","warn","onlyChild","Children","isValidElement","merged","childRef","cloneElement"],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ReactElement, ReactNode, Ref, RefCallback } from 'react';
|
|
2
|
+
type PossibleRef<T> = Ref<T> | undefined;
|
|
3
|
+
/** Composes multiple refs into a single callback ref. */
|
|
4
|
+
export declare function composeRefs<T>(...refs: Array<PossibleRef<T>>): RefCallback<T>;
|
|
5
|
+
/**
|
|
6
|
+
* Reads the ref from a React element across React 18 (`element.ref`) and
|
|
7
|
+
* React 19 (`element.props.ref`).
|
|
8
|
+
*/
|
|
9
|
+
export declare function getElementRef(element: ReactElement): Ref<unknown> | undefined;
|
|
10
|
+
type AnyProps = Record<string, unknown>;
|
|
11
|
+
/**
|
|
12
|
+
* Merges Slot (asChild host) props with the child's props.
|
|
13
|
+
* Child props win by default; event handlers are composed (child first;
|
|
14
|
+
* host skipped when the child called `preventDefault()`); `className` and
|
|
15
|
+
* `style` are merged.
|
|
16
|
+
*/
|
|
17
|
+
export declare function mergeSlotProps(slotProps: AnyProps, childProps: AnyProps): AnyProps;
|
|
18
|
+
export interface RenderAsChildOptions {
|
|
19
|
+
/** Single React element to clone (e.g. `<a>` or `<Link>`). */
|
|
20
|
+
child: ReactNode;
|
|
21
|
+
/** Props owned by the host component (className, handlers, aria-*, …). */
|
|
22
|
+
props: AnyProps;
|
|
23
|
+
/** Forwarded ref from the host. */
|
|
24
|
+
ref?: Ref<unknown>;
|
|
25
|
+
/** Anatomy nodes that replace the child's children. */
|
|
26
|
+
content: ReactNode;
|
|
27
|
+
/** When true, apply disabled-link semantics. */
|
|
28
|
+
disabled?: boolean;
|
|
29
|
+
/** BEM disabled class (e.g. `button--disabled`). */
|
|
30
|
+
disabledClassName?: string;
|
|
31
|
+
/**
|
|
32
|
+
* When true, warn in development if the child already has children (they
|
|
33
|
+
* will be replaced). Use for hosts that own their full anatomy
|
|
34
|
+
* (IconButton, ActionButton). Leave false when the host wraps the child's
|
|
35
|
+
* text (Button label).
|
|
36
|
+
*/
|
|
37
|
+
warnOnChildContent?: boolean;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Clones a single child element with merged host props, composed refs, and
|
|
41
|
+
* replacement content. Never forwards `type`. When `disabled`, sets
|
|
42
|
+
* `aria-disabled`, the disabled class, and blocks click / auxclick navigation.
|
|
43
|
+
*/
|
|
44
|
+
export declare function renderAsChild({ child, props, ref, content, disabled, disabledClassName, warnOnChildContent, }: RenderAsChildOptions): ReactElement | null;
|
|
45
|
+
export {};
|
|
46
|
+
//# sourceMappingURL=slot.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.d.ts","sourceRoot":"","sources":["../../src/utils/slot.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,YAAY,EACjB,KAAK,SAAS,EACd,KAAK,GAAG,EACR,KAAK,WAAW,EACjB,MAAM,OAAO,CAAC;AAGf,KAAK,WAAW,CAAC,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AAWzC,yDAAyD;AACzD,wBAAgB,WAAW,CAAC,CAAC,EAAE,GAAG,IAAI,EAAE,KAAK,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,CAM7E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,GAAG,CAAC,OAAO,CAAC,GAAG,SAAS,CAQ7E;AAED,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAQxC;;;;;GAKG;AACH,wBAAgB,cAAc,CAC5B,SAAS,EAAE,QAAQ,EACnB,UAAU,EAAE,QAAQ,GACnB,QAAQ,CAuCV;AAuBD,MAAM,WAAW,oBAAoB;IACnC,8DAA8D;IAC9D,KAAK,EAAE,SAAS,CAAC;IACjB,0EAA0E;IAC1E,KAAK,EAAE,QAAQ,CAAC;IAChB,mCAAmC;IACnC,GAAG,CAAC,EAAE,GAAG,CAAC,OAAO,CAAC,CAAC;IACnB,uDAAuD;IACvD,OAAO,EAAE,SAAS,CAAC;IACnB,gDAAgD;IAChD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,oDAAoD;IACpD,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAC3B;;;;;OAKG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAC;CAC9B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,EAC5B,KAAK,EACL,KAAK,EACL,GAAG,EACH,OAAO,EACP,QAAgB,EAChB,iBAAiB,EACjB,kBAA0B,GAC3B,EAAE,oBAAoB,GAAG,YAAY,GAAG,IAAI,CA6D5C"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { Children as h, isValidElement as g, cloneElement as C } from "react";
|
|
2
|
+
import { mergeClassNames as m } from "./props.js";
|
|
3
|
+
function N(e, t) {
|
|
4
|
+
typeof e == "function" ? e(t) : e != null && (e.current = t);
|
|
5
|
+
}
|
|
6
|
+
function R(...e) {
|
|
7
|
+
return (t) => {
|
|
8
|
+
for (const n of e)
|
|
9
|
+
N(n, t);
|
|
10
|
+
};
|
|
11
|
+
}
|
|
12
|
+
function v(e) {
|
|
13
|
+
var n;
|
|
14
|
+
const t = (n = e.props) == null ? void 0 : n.ref;
|
|
15
|
+
return t !== void 0 ? t : e.ref;
|
|
16
|
+
}
|
|
17
|
+
function E(e) {
|
|
18
|
+
var t;
|
|
19
|
+
return e.length > 2 && e.startsWith("on") && e[2] === ((t = e[2]) == null ? void 0 : t.toUpperCase());
|
|
20
|
+
}
|
|
21
|
+
function b(e, t) {
|
|
22
|
+
const n = { ...t };
|
|
23
|
+
for (const r of Object.keys(e)) {
|
|
24
|
+
const o = e[r], l = t[r];
|
|
25
|
+
E(r) ? typeof o == "function" && typeof l == "function" ? n[r] = (...c) => {
|
|
26
|
+
const s = c[0];
|
|
27
|
+
l(...c), s != null && s.defaultPrevented || o(...c);
|
|
28
|
+
} : typeof o == "function" && (n[r] = o) : r === "style" ? n.style = {
|
|
29
|
+
...typeof o == "object" && o != null ? o : null,
|
|
30
|
+
...typeof l == "object" && l != null ? l : null
|
|
31
|
+
} : r === "className" ? n.className = m(
|
|
32
|
+
typeof o == "string" ? o : void 0,
|
|
33
|
+
typeof l == "string" ? l : void 0
|
|
34
|
+
) : r in t || (n[r] = o);
|
|
35
|
+
}
|
|
36
|
+
return n;
|
|
37
|
+
}
|
|
38
|
+
function y(e) {
|
|
39
|
+
return e == null || e === !1 || e === !0 ? !1 : typeof e == "string" ? e.length > 0 : Array.isArray(e) ? e.some(y) : !0;
|
|
40
|
+
}
|
|
41
|
+
function p(e) {
|
|
42
|
+
e.preventDefault(), e.stopPropagation();
|
|
43
|
+
}
|
|
44
|
+
function V({
|
|
45
|
+
child: e,
|
|
46
|
+
props: t,
|
|
47
|
+
ref: n,
|
|
48
|
+
content: r,
|
|
49
|
+
disabled: o = !1,
|
|
50
|
+
disabledClassName: l,
|
|
51
|
+
warnOnChildContent: c = !1
|
|
52
|
+
}) {
|
|
53
|
+
const s = process.env.NODE_ENV !== "production";
|
|
54
|
+
let i = null;
|
|
55
|
+
try {
|
|
56
|
+
i = h.only(e);
|
|
57
|
+
} catch {
|
|
58
|
+
i = null;
|
|
59
|
+
}
|
|
60
|
+
if (!g(i))
|
|
61
|
+
return s && console.warn(
|
|
62
|
+
"asChild expects a single React element child (e.g. <a> or <Link>)."
|
|
63
|
+
), null;
|
|
64
|
+
const u = i.props;
|
|
65
|
+
s && c && y(u.children) && console.warn(
|
|
66
|
+
`asChild replaces the child element's children with component anatomy. Pass an empty element (e.g. <a href="…" />).`
|
|
67
|
+
);
|
|
68
|
+
const f = { ...t };
|
|
69
|
+
delete f.type, o && (f["aria-disabled"] = !0, l && (f.className = m(
|
|
70
|
+
typeof f.className == "string" ? f.className : void 0,
|
|
71
|
+
l
|
|
72
|
+
)));
|
|
73
|
+
const a = b(f, u);
|
|
74
|
+
o && (a.onClick = p, a.onAuxClick = p);
|
|
75
|
+
const d = v(i);
|
|
76
|
+
return C(i, {
|
|
77
|
+
...a,
|
|
78
|
+
ref: R(n, d),
|
|
79
|
+
children: r
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
R as composeRefs,
|
|
84
|
+
v as getElementRef,
|
|
85
|
+
b as mergeSlotProps,
|
|
86
|
+
V as renderAsChild
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=slot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"slot.js","sources":["../../src/utils/slot.ts"],"sourcesContent":["import {\n Children,\n cloneElement,\n isValidElement,\n type CSSProperties,\n type ReactElement,\n type ReactNode,\n type Ref,\n type RefCallback,\n} from 'react';\nimport { mergeClassNames } from '@/utils/props';\n\ntype PossibleRef<T> = Ref<T> | undefined;\n\n/** Assigns a value to a callback or object ref. */\nfunction setRef<T>(ref: PossibleRef<T>, value: T | null) {\n if (typeof ref === 'function') {\n ref(value);\n } else if (ref != null) {\n (ref as { current: T | null }).current = value;\n }\n}\n\n/** Composes multiple refs into a single callback ref. */\nexport function composeRefs<T>(...refs: Array<PossibleRef<T>>): RefCallback<T> {\n return (node) => {\n for (const ref of refs) {\n setRef(ref, node);\n }\n };\n}\n\n/**\n * Reads the ref from a React element across React 18 (`element.ref`) and\n * React 19 (`element.props.ref`).\n */\nexport function getElementRef(element: ReactElement): Ref<unknown> | undefined {\n // React 19: ref is a regular prop. React 18: ref is on the element.\n const propsRef = (element.props as { ref?: Ref<unknown> } | null | undefined)\n ?.ref;\n if (propsRef !== undefined) {\n return propsRef;\n }\n return (element as ReactElement & { ref?: Ref<unknown> }).ref;\n}\n\ntype AnyProps = Record<string, unknown>;\n\nfunction isHandlerKey(key: string): boolean {\n return (\n key.length > 2 && key.startsWith('on') && key[2] === key[2]?.toUpperCase()\n );\n}\n\n/**\n * Merges Slot (asChild host) props with the child's props.\n * Child props win by default; event handlers are composed (child first;\n * host skipped when the child called `preventDefault()`); `className` and\n * `style` are merged.\n */\nexport function mergeSlotProps(\n slotProps: AnyProps,\n childProps: AnyProps,\n): AnyProps {\n const override: AnyProps = { ...childProps };\n\n for (const propName of Object.keys(slotProps)) {\n const slotValue = slotProps[propName];\n const childValue = childProps[propName];\n\n if (isHandlerKey(propName)) {\n if (typeof slotValue === 'function' && typeof childValue === 'function') {\n override[propName] = (...args: unknown[]) => {\n const event = args[0] as { defaultPrevented?: boolean } | undefined;\n childValue(...args);\n if (!event?.defaultPrevented) {\n slotValue(...args);\n }\n };\n } else if (typeof slotValue === 'function') {\n override[propName] = slotValue;\n }\n } else if (propName === 'style') {\n override.style = {\n ...(typeof slotValue === 'object' && slotValue != null\n ? (slotValue as CSSProperties)\n : null),\n ...(typeof childValue === 'object' && childValue != null\n ? (childValue as CSSProperties)\n : null),\n };\n } else if (propName === 'className') {\n override.className = mergeClassNames(\n typeof slotValue === 'string' ? slotValue : undefined,\n typeof childValue === 'string' ? childValue : undefined,\n );\n } else if (!(propName in childProps)) {\n override[propName] = slotValue;\n }\n }\n\n return override;\n}\n\nfunction hasRenderableChildren(children: ReactNode): boolean {\n if (children == null || children === false || children === true) {\n return false;\n }\n if (typeof children === 'string') {\n return children.length > 0;\n }\n if (Array.isArray(children)) {\n return children.some(hasRenderableChildren);\n }\n return true;\n}\n\nfunction blockNavigation(event: {\n preventDefault: () => void;\n stopPropagation: () => void;\n}) {\n event.preventDefault();\n event.stopPropagation();\n}\n\nexport interface RenderAsChildOptions {\n /** Single React element to clone (e.g. `<a>` or `<Link>`). */\n child: ReactNode;\n /** Props owned by the host component (className, handlers, aria-*, …). */\n props: AnyProps;\n /** Forwarded ref from the host. */\n ref?: Ref<unknown>;\n /** Anatomy nodes that replace the child's children. */\n content: ReactNode;\n /** When true, apply disabled-link semantics. */\n disabled?: boolean;\n /** BEM disabled class (e.g. `button--disabled`). */\n disabledClassName?: string;\n /**\n * When true, warn in development if the child already has children (they\n * will be replaced). Use for hosts that own their full anatomy\n * (IconButton, ActionButton). Leave false when the host wraps the child's\n * text (Button label).\n */\n warnOnChildContent?: boolean;\n}\n\n/**\n * Clones a single child element with merged host props, composed refs, and\n * replacement content. Never forwards `type`. When `disabled`, sets\n * `aria-disabled`, the disabled class, and blocks click / auxclick navigation.\n */\nexport function renderAsChild({\n child,\n props,\n ref,\n content,\n disabled = false,\n disabledClassName,\n warnOnChildContent = false,\n}: RenderAsChildOptions): ReactElement | null {\n const warn = process.env.NODE_ENV !== 'production';\n\n let onlyChild: ReactNode = null;\n try {\n onlyChild = Children.only(child);\n } catch {\n onlyChild = null;\n }\n\n if (!isValidElement(onlyChild)) {\n if (warn) {\n console.warn(\n 'asChild expects a single React element child (e.g. <a> or <Link>).',\n );\n }\n return null;\n }\n\n const childProps = onlyChild.props as AnyProps & { children?: ReactNode };\n\n if (\n warn &&\n warnOnChildContent &&\n hasRenderableChildren(childProps.children)\n ) {\n console.warn(\n 'asChild replaces the child element\\'s children with component anatomy. Pass an empty element (e.g. <a href=\"…\" />).',\n );\n }\n\n // Strip `type` — on <a> it means MIME type, not button type.\n const slotProps: AnyProps = { ...props };\n delete slotProps.type;\n\n if (disabled) {\n slotProps['aria-disabled'] = true;\n if (disabledClassName) {\n slotProps.className = mergeClassNames(\n typeof slotProps.className === 'string'\n ? slotProps.className\n : undefined,\n disabledClassName,\n );\n }\n }\n\n const merged = mergeSlotProps(slotProps, childProps);\n\n if (disabled) {\n merged.onClick = blockNavigation;\n merged.onAuxClick = blockNavigation;\n }\n\n const childRef = getElementRef(onlyChild);\n\n return cloneElement(onlyChild, {\n ...merged,\n ref: composeRefs(ref, childRef),\n children: content,\n } as AnyProps);\n}\n"],"names":["setRef","ref","value","composeRefs","refs","node","getElementRef","element","propsRef","_a","isHandlerKey","key","mergeSlotProps","slotProps","childProps","override","propName","slotValue","childValue","args","event","mergeClassNames","hasRenderableChildren","children","blockNavigation","renderAsChild","child","props","content","disabled","disabledClassName","warnOnChildContent","warn","onlyChild","Children","isValidElement","merged","childRef","cloneElement"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mattermost/compass-ui",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.15",
|
|
4
4
|
"description": "Compass design system UI components for Mattermost products",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -81,6 +81,7 @@
|
|
|
81
81
|
"@vitejs/plugin-react": "^4.3.4",
|
|
82
82
|
"react": "^19.0.0",
|
|
83
83
|
"react-dom": "^19.0.0",
|
|
84
|
+
"react-router-dom": "^6.28.0",
|
|
84
85
|
"sass": "^1.83.4",
|
|
85
86
|
"simplebar-react": "^3.3.2",
|
|
86
87
|
"storybook": "^8.6.14",
|
|
@@ -331,6 +332,9 @@
|
|
|
331
332
|
"hooks/use-exit-animation": [
|
|
332
333
|
"./dist/hooks/use-exit-animation.d.ts"
|
|
333
334
|
],
|
|
335
|
+
"hooks/use-modal-focus": [
|
|
336
|
+
"./dist/hooks/use-modal-focus.d.ts"
|
|
337
|
+
],
|
|
334
338
|
"hooks/use-outside-close": [
|
|
335
339
|
"./dist/hooks/use-outside-close.d.ts"
|
|
336
340
|
],
|