@ahrowe/ui 0.24.3 → 0.25.0

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.
Files changed (65) hide show
  1. package/dist/esm/common/configProvider/configProvider.mjs +1 -1
  2. package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
  3. package/dist/esm/common/configProvider/usePresentationDefault.mjs +2 -0
  4. package/dist/esm/common/configProvider/usePresentationDefault.mjs.map +1 -0
  5. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  6. package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
  7. package/dist/esm/common/floatingMenu/floatingMenu.mjs +1 -1
  8. package/dist/esm/common/floatingMenu/floatingMenu.mjs.map +1 -1
  9. package/dist/esm/common/floatingMenu/floatingMenu.module.mjs +1 -1
  10. package/dist/esm/common/floatingMenu/floatingMenu.module.mjs.map +1 -1
  11. package/dist/esm/common/floatingMenu/floatingMenu.types.mjs +1 -1
  12. package/dist/esm/common/floatingMenu/floatingMenu.types.mjs.map +1 -1
  13. package/dist/esm/common/floatingMenu/useFloatingPosition.mjs +1 -1
  14. package/dist/esm/common/floatingMenu/useFloatingPosition.mjs.map +1 -1
  15. package/dist/esm/common/hooks/useCoarsePointer.mjs +1 -1
  16. package/dist/esm/common/hooks/useCoarsePointer.mjs.map +1 -1
  17. package/dist/esm/common/hooks/useMediaQuery.mjs +2 -0
  18. package/dist/esm/common/hooks/useMediaQuery.mjs.map +1 -0
  19. package/dist/esm/common/hooks/useOverlay.mjs +2 -0
  20. package/dist/esm/common/hooks/useOverlay.mjs.map +1 -0
  21. package/dist/esm/common/hooks/useSheet.mjs +2 -0
  22. package/dist/esm/common/hooks/useSheet.mjs.map +1 -0
  23. package/dist/esm/common/modal/modal.mjs +1 -1
  24. package/dist/esm/common/modal/modal.mjs.map +1 -1
  25. package/dist/esm/common/modal/modal.module.mjs +1 -1
  26. package/dist/esm/common/modal/modal.module.mjs.map +1 -1
  27. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  28. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  29. package/dist/esm/common/popover/popover.mjs +1 -1
  30. package/dist/esm/common/popover/popover.mjs.map +1 -1
  31. package/dist/esm/common/popover/popover.types.mjs.map +1 -1
  32. package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
  33. package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
  34. package/dist/esm/common/sheetBackdrop/sheetBackdrop.mjs +2 -0
  35. package/dist/esm/common/sheetBackdrop/sheetBackdrop.mjs.map +1 -0
  36. package/dist/esm/common/styles/sheet.module.mjs +2 -0
  37. package/dist/esm/common/styles/sheet.module.mjs.map +1 -0
  38. package/dist/esm/index.mjs +1 -1
  39. package/dist/index.cjs +6 -6
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/style.css +1 -1
  42. package/dist/types/package/common/configProvider/configProvider.d.ts +9 -1
  43. package/dist/types/package/common/configProvider/configProvider.types.d.ts +13 -0
  44. package/dist/types/package/common/configProvider/index.d.ts +1 -0
  45. package/dist/types/package/common/configProvider/usePresentationDefault.d.ts +8 -0
  46. package/dist/types/package/common/dropdown/dropdown.types.d.ts +4 -0
  47. package/dist/types/package/common/floatingMenu/floatingMenu.d.ts +1 -1
  48. package/dist/types/package/common/floatingMenu/floatingMenu.types.d.ts +13 -1
  49. package/dist/types/package/common/hooks/useCoarsePointer.d.ts +1 -8
  50. package/dist/types/package/common/hooks/useMediaQuery.d.ts +9 -0
  51. package/dist/types/package/common/hooks/useOverlay.d.ts +26 -0
  52. package/dist/types/package/common/hooks/useSheet.d.ts +16 -0
  53. package/dist/types/package/common/modal/modal.d.ts +1 -1
  54. package/dist/types/package/common/modal/modal.types.d.ts +9 -3
  55. package/dist/types/package/common/popover/popover.d.ts +1 -1
  56. package/dist/types/package/common/popover/popover.types.d.ts +6 -1
  57. package/dist/types/package/common/sheetBackdrop/index.d.ts +2 -0
  58. package/dist/types/package/common/sheetBackdrop/sheetBackdrop.d.ts +16 -0
  59. package/dist/types/package/common/sheetBackdrop/sheetBackdrop.types.d.ts +7 -0
  60. package/docs/ConfigProvider.md +32 -1
  61. package/docs/Dropdown.md +7 -1
  62. package/docs/FloatingMenu.md +32 -3
  63. package/docs/Modal.md +27 -3
  64. package/docs/Popover.md +12 -3
  65. package/package.json +1 -1
@@ -1,2 +1,2 @@
1
- import{createContext as e,useContext as t,useMemo as n}from"react";import{jsx as r}from"react/jsx-runtime";var i=e(null);function a(e,t){if(!e)return t??{};if(!t)return e;let n={...e};for(let r in t)n[r]={...e[r],...t[r]};return n}function o({children:e,defaultProps:o}){let s=t(i),c=n(()=>a(s,o),[s,o]);return r(i.Provider,{value:c,children:e})}export{i as ConfigContext,o as default};
1
+ import{createContext as e,useContext as t,useMemo as n}from"react";import{jsx as r}from"react/jsx-runtime";var i=e(null),a=e(void 0);function o(e,t){if(!e)return t??{};if(!t)return e;let n={...e};for(let r in t)n[r]={...e[r],...t[r]};return n}function s({children:e,defaultProps:s,presentation:c}){let l=t(i),u=n(()=>o(l,s),[l,s]),d=t(a),f=c??d;return r(i.Provider,{value:u,children:r(a.Provider,{value:f,children:e})})}export{i as ConfigContext,a as PresentationContext,s as default};
2
2
  //# sourceMappingURL=configProvider.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"configProvider.mjs","names":[],"sources":["../../../../package/common/configProvider/configProvider.tsx"],"sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\nimport type { ComponentDefaults, ConfigProviderProps } from './configProvider.types';\n\nexport const ConfigContext = createContext<ComponentDefaults | null>(null);\n\n/**\n * Shallow-merge two default maps per component key, so nested ConfigProviders\n * compose: an inner provider's `Input` defaults extend (and override on\n * conflict) the outer provider's `Input` defaults rather than replacing them.\n */\nfunction mergeDefaults(\n parent: ComponentDefaults | null,\n own: ComponentDefaults | undefined,\n): ComponentDefaults {\n if (!parent) return own ?? {};\n if (!own) return parent;\n\n const merged: Record<string, object> = { ...parent };\n for (const key in own) {\n merged[key] = {\n ...(parent as Record<string, object>)[key],\n ...(own as Record<string, object>)[key],\n };\n }\n return merged as ComponentDefaults;\n}\n\nfunction ConfigProvider({ children, defaultProps }: ConfigProviderProps) {\n const parent = useContext(ConfigContext);\n const value = useMemo(() => mergeDefaults(parent, defaultProps), [parent, defaultProps]);\n\n return <ConfigContext.Provider value={value}>{children}</ConfigContext.Provider>;\n}\n\nexport default ConfigProvider;\n"],"mappings":"2GAGA,IAAa,EAAgB,EAAwC,IAAI,EAOzE,SAAS,EACP,EACA,EACmB,CACnB,GAAI,CAAC,EAAQ,OAAO,GAAO,CAAC,EAC5B,GAAI,CAAC,EAAK,OAAO,EAEjB,IAAM,EAAiC,CAAE,GAAG,CAAO,EACnD,IAAK,IAAM,KAAO,EAChB,EAAO,GAAO,CACZ,GAAI,EAAkC,GACtC,GAAI,EAA+B,EACrC,EAEF,OAAO,CACT,CAEA,SAAS,EAAe,CAAE,WAAU,gBAAqC,CACvE,IAAM,EAAS,EAAW,CAAa,EACjC,EAAQ,MAAc,EAAc,EAAQ,CAAY,EAAG,CAAC,EAAQ,CAAY,CAAC,EAEvF,OAAO,EAAC,EAAc,SAAf,CAA+B,QAAQ,UAAiC,CAAA,CACjF"}
1
+ {"version":3,"file":"configProvider.mjs","names":[],"sources":["../../../../package/common/configProvider/configProvider.tsx"],"sourcesContent":["import React, { createContext, useContext, useMemo } from 'react';\nimport type { ComponentDefaults, ConfigProviderProps } from './configProvider.types';\nimport type { Presentation } from '../floatingMenu/floatingMenu.types';\n\nexport const ConfigContext = createContext<ComponentDefaults | null>(null);\n\n/**\n * One setting for every component that can present as a bottom sheet, kept separate from\n * `defaultProps` so that turning sheets on (or off) app-wide is a single switch rather than one\n * entry per component key — the components that can do it are unrelated to each other, and a\n * consumer who missed one would get sheets in half their app.\n */\nexport const PresentationContext = createContext<Presentation | undefined>(undefined);\n\n/**\n * Shallow-merge two default maps per component key, so nested ConfigProviders\n * compose: an inner provider's `Input` defaults extend (and override on\n * conflict) the outer provider's `Input` defaults rather than replacing them.\n */\nfunction mergeDefaults(\n parent: ComponentDefaults | null,\n own: ComponentDefaults | undefined,\n): ComponentDefaults {\n if (!parent) return own ?? {};\n if (!own) return parent;\n\n const merged: Record<string, object> = { ...parent };\n for (const key in own) {\n merged[key] = {\n ...(parent as Record<string, object>)[key],\n ...(own as Record<string, object>)[key],\n };\n }\n return merged as ComponentDefaults;\n}\n\nfunction ConfigProvider({ children, defaultProps, presentation }: ConfigProviderProps) {\n const parent = useContext(ConfigContext);\n const value = useMemo(() => mergeDefaults(parent, defaultProps), [parent, defaultProps]);\n\n // A nested provider that doesn't set `presentation` keeps the outer one's, the same way\n // `defaultProps` compose.\n const inheritedPresentation = useContext(PresentationContext);\n const presentationValue = presentation ?? inheritedPresentation;\n\n return (\n <ConfigContext.Provider value={value}>\n <PresentationContext.Provider value={presentationValue}>\n {children}\n </PresentationContext.Provider>\n </ConfigContext.Provider>\n );\n}\n\nexport default ConfigProvider;\n"],"mappings":"2GAIA,IAAa,EAAgB,EAAwC,IAAI,EAQ5D,EAAsB,EAAwC,IAAA,EAAS,EAOpF,SAAS,EACP,EACA,EACmB,CACnB,GAAI,CAAC,EAAQ,OAAO,GAAO,CAAC,EAC5B,GAAI,CAAC,EAAK,OAAO,EAEjB,IAAM,EAAiC,CAAE,GAAG,CAAO,EACnD,IAAK,IAAM,KAAO,EAChB,EAAO,GAAO,CACZ,GAAI,EAAkC,GACtC,GAAI,EAA+B,EACrC,EAEF,OAAO,CACT,CAEA,SAAS,EAAe,CAAE,WAAU,eAAc,gBAAqC,CACrF,IAAM,EAAS,EAAW,CAAa,EACjC,EAAQ,MAAc,EAAc,EAAQ,CAAY,EAAG,CAAC,EAAQ,CAAY,CAAC,EAIjF,EAAwB,EAAW,CAAmB,EACtD,EAAoB,GAAgB,EAE1C,OACE,EAAC,EAAc,SAAf,CAA+B,iBAC7B,EAAC,EAAoB,SAArB,CAA8B,MAAO,EAClC,UAC2B,CAAA,CACR,CAAA,CAE5B"}
@@ -0,0 +1,2 @@
1
+ import{PresentationContext as e}from"./configProvider.mjs";import{useContext as t}from"react";function n(){return t(e)}export{n as usePresentationDefault};
2
+ //# sourceMappingURL=usePresentationDefault.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"usePresentationDefault.mjs","names":[],"sources":["../../../../package/common/configProvider/usePresentationDefault.ts"],"sourcesContent":["import { useContext } from 'react';\nimport { PresentationContext } from './configProvider';\nimport type { Presentation } from '../floatingMenu/floatingMenu.types';\n\n/**\n * The nearest `ConfigProvider`'s app-wide `presentation`, or `undefined` when none is set.\n *\n * Sits between a component-keyed global default and the component's own built-in default, so the\n * full order is: explicit prop → `defaultProps.<Component>.presentation` → this → built-in.\n */\nexport function usePresentationDefault(): Presentation | undefined {\n return useContext(PresentationContext);\n}\n"],"mappings":"8FAUA,SAAgB,GAAmD,CACjE,OAAO,EAAW,CAAmB,CACvC"}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../bodyEnd/bodyEnd.mjs";import{useFloatingPosition as n}from"../floatingMenu/useFloatingPosition.mjs";import r from"../tooltip/tooltip.mjs";import ee from"../infiniteBlock/infiniteBlock.mjs";import i from"./dropdown.module.mjs";import{useEffect as a,useLayoutEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{FontAwesomeIcon as te}from"@fortawesome/react-fontawesome";import{faChevronDown as ne}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";import re from"downshift";function f(f){let{errorMessage:p=``,className:m=``,label:h=``,value:ie=``,isValid:ae=!0,tabIndex:oe=0,isRequired:se=!1,customProps:g={},isRow:ce=!1,disabled:_=!1,readOnly:v=!1,onScroll:le=()=>Promise.resolve(),onClick:y,onChange:b,onFocus:x=null,onBlur:ue=null,onMouseEnter:S=null,onMouseLeave:C=null,dropdownLabel:w,isDropdownListWider:T=!1,inputClassName:E=``,dropDownIconClassName:D=``,dropDownClassName:de=``,formValidator:O=null,labelClassName:fe=``,dropDownInputClassName:pe=``,items:k=[],useMatLabelStyle:A=!0,alwaysFloatLabel:j=!1,placeholder:M=``,plainStyle:N=!1,scrollToSelected:P=!1,reactRef:F,...I}=e(`Dropdown`,f),[L,R]=c(!1),[z,B]=c(!1),[,me]=c(0),V=s(O),H=s(null),U=s(null),[W,he]=c(!1);o(()=>{let e=H.current,t=U.current;if(!W||!e||!t)return;let{width:n}=e.getBoundingClientRect(),{fontSize:r}=window.getComputedStyle(e);t.style.width=`${n}px`,t.style.fontSize=r},[W]),n({isOpen:W,triggerRef:H,anchorRef:U,panelRef:U,flipClassName:i.dropdownInputListAnimFlip}),a(()=>{if(V.current=O,!V.current)return;V.current.label=h??``,V.current.validate();let e=()=>me(e=>e+1);return V.current.registerOnUpdateListener(e),()=>V.current?.removeOnUpdateListener(e)},[O,h]);let ge=e=>{B(!0),S?.(e)},_e=e=>{B(!1),C?.(e)},ve=e=>{R(!0),x?.(e)},G=e=>{V.current&&(V.current.touched=!0),R(!1),ue?.(e)},ye=()=>O?O.touched&&O.hasError():!ae||!!p,K=()=>!!(se||O?.validators.find(e=>e.validatorId===`required`)),be=e=>{O?(O.set(e),b?.(O.value,g)):b?.(e,g)},q=w,J=O?O.value:ie,Y=ye();k.forEach(e=>{e.key===J&&(q=e.label)});let X=q||J,Z=X==null||typeof X==`string`&&X.trim()===``,Q=K()?u(`span`,{className:i.requiredMark,children:`*`}):null,xe=h&&K()?`${h} *`:h,$=L&&!v;return d(`div`,{...I,className:l(m,i.dropdownLabel,i.dropdown,{[i.dropdownLabelColumn]:!ce}),onMouseEnter:ge,onMouseLeave:_e,children:[u(re,{...v?{isOpen:!1}:{},onChange:e=>be((e||{key:``}).key),itemToString:e=>e?String(e.key):``,selectedItem:k.find(e=>e.key===J)??null,onStateChange:e=>{typeof e.isOpen==`boolean`&&he(e.isOpen)},stateReducer:(e,t)=>P&&Object.prototype.hasOwnProperty.call(t,`isOpen`)?{...t,highlightedIndex:t.isOpen?k.indexOf(e.selectedItem):null}:t,children:({getItemProps:e,getMenuProps:n,getToggleButtonProps:r,isOpen:a,selectedItem:o,highlightedIndex:s,setHighlightedIndex:c})=>u(`div`,{children:d(`div`,{ref:H,onFocus:ve,onBlur:G,className:l(i.dropdownInput,{[i.dropdownInputPlain]:N,[i.dropdownInputReadOnly]:v&&!_},pe),children:[u(`button`,{tabIndex:oe,type:`button`,disabled:_,"aria-readonly":v||void 0,style:T?{padding:`6px`,border:`none`}:{},className:l(i.dropdownInputButton,{[i.dropdownInputButtonDisabled]:_,[i.dropdownInputButtonReadOnly]:v&&!_},E),...r(),onClick:e=>{r().onClick?.(e),y?.(e)},ref:F,children:Z?`\xA0`:X}),u(`button`,{type:`button`,tabIndex:-1,disabled:_,className:l(i.dropdownInputButtonIcon,D),...r(),onClick:e=>{r().onClick?.(e),y?.(e)},children:!_&&!v&&u(te,{icon:ne,className:l(i.dropdownInputButtonIconArrow,{[i.dropdownInputButtonIconArrowOpen]:a})})}),!_&&!v&&a?u(t,{children:u(`div`,{...n({ref:e=>{U.current=e},"aria-label":h||M||void 0},{suppressRefError:!0}),className:l(i.dropdownInputListAnim,{[i.dropdownInputListAnimWider]:T}),children:u(ee,{onScroll:le,className:i.dropdownInputList,setHighlightedIndex:c,children:k.map((t,n)=>u(`div`,{...e({index:n,item:t,disabled:!!t.disabled}),className:l(i.dropdownInputListItem,de,{[i.dropdownInputListItemActive]:s===n,[i.dropdownInputListItemSelected]:o===t,[i.dropdownInputListItemDisabled]:!!t.disabled}),children:t.label},t.key))})})}):null,u(`fieldset`,{className:l(i.dropdownFieldset,{[i.dropdownBorderPlain]:N,[i.dropdownBorderFocused]:$,[i.dropdownBorderInvalid]:Y,[i.dropdownBorderError]:Y}),children:u(`legend`,{className:l(i.dropdownFieldsetLegend,{[i.dropdownFieldsetLegendActive]:A&&(j||$||!Z)}),children:u(`span`,{children:xe})})}),A&&h&&d(`div`,{className:l(i.dropdownMatLabel,{[i.dropdownMatLabelFloating]:j||$||!Z}),children:[h,Q]}),A&&M&&u(`div`,{className:l(i.dropdownPlaceholder,$&&!q&&i.dropdownPlaceholderShown),children:M})]})})}),h&&!A&&d(`div`,{className:l(i.dropdownLabelText,fe),children:[h,Q]}),u(r,{variant:`error`,message:O?O.getCurrentErrorMessage():p||``,isVisible:Y&&(L||z)})]})}export{f as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import n from"../bodyEnd/bodyEnd.mjs";import r from"../styles/sheet.module.mjs";import i from"../sheetBackdrop/sheetBackdrop.mjs";import{useFloatingPosition as a}from"../floatingMenu/useFloatingPosition.mjs";import{Presentation as o}from"../floatingMenu/floatingMenu.types.mjs";import s from"../hooks/useSheet.mjs";import{useOverlay as c}from"../hooks/useOverlay.mjs";import l from"../tooltip/tooltip.mjs";import ee from"../infiniteBlock/infiniteBlock.mjs";import u from"./dropdown.module.mjs";import{useEffect as d,useLayoutEffect as te,useRef as f,useState as p}from"react";import m from"classnames";import{FontAwesomeIcon as ne}from"@fortawesome/react-fontawesome";import{faChevronDown as re}from"@fortawesome/free-solid-svg-icons";import{jsx as h,jsxs as g}from"react/jsx-runtime";import ie from"downshift";function _(_){let{errorMessage:v=``,className:ae=``,label:y=``,value:b=``,isValid:x=!0,tabIndex:S=0,isRequired:C=!1,customProps:w={},isRow:oe=!1,disabled:T=!1,readOnly:E=!1,onScroll:se=()=>Promise.resolve(),onClick:D,onChange:O,onFocus:ce=null,onBlur:le=null,onMouseEnter:ue=null,onMouseLeave:de=null,dropdownLabel:fe,isDropdownListWider:k=!1,inputClassName:pe=``,dropDownIconClassName:me=``,dropDownClassName:he=``,formValidator:A=null,labelClassName:ge=``,dropDownInputClassName:_e=``,items:j=[],useMatLabelStyle:M=!0,alwaysFloatLabel:N=!1,placeholder:P=``,plainStyle:F=!1,scrollToSelected:I=!1,presentation:ve,reactRef:ye,...be}=e(`Dropdown`,_),[L,R]=p(!1),[xe,z]=p(!1),[,Se]=p(0),B=f(A),V=f(null),H=f(null),[U,Ce]=p(!1),we=t(),{isSheet:W,sheetStyle:Te}=s(ve??we??o.Default);te(()=>{let e=V.current,t=H.current;if(!U||W||!e||!t)return;let{width:n}=e.getBoundingClientRect(),{fontSize:r}=window.getComputedStyle(e);t.style.width=`${n}px`,t.style.fontSize=r},[U,W]),a({isOpen:U&&!W,triggerRef:V,anchorRef:H,panelRef:H,flipClassName:u.dropdownInputListAnimFlip}),c({isActive:U,containerRef:H,trapFocus:!1,lockScroll:W}),d(()=>{if(B.current=A,!B.current)return;B.current.label=y??``,B.current.validate();let e=()=>Se(e=>e+1);return B.current.registerOnUpdateListener(e),()=>B.current?.removeOnUpdateListener(e)},[A,y]);let Ee=e=>{z(!0),ue?.(e)},De=e=>{z(!1),de?.(e)},Oe=e=>{R(!0),ce?.(e)},G=e=>{B.current&&(B.current.touched=!0),R(!1),le?.(e)},ke=()=>A?A.touched&&A.hasError():!x||!!v,K=()=>!!(C||A?.validators.find(e=>e.validatorId===`required`)),Ae=e=>{A?(A.set(e),O?.(A.value,w)):O?.(e,w)},q=fe,J=A?A.value:b,Y=ke();j.forEach(e=>{e.key===J&&(q=e.label)});let X=q||J,Z=X==null||typeof X==`string`&&X.trim()===``,Q=K()?h(`span`,{className:u.requiredMark,children:`*`}):null,je=y&&K()?`${y} *`:y,$=L&&!E;return g(`div`,{...be,className:m(ae,u.dropdownLabel,u.dropdown,{[u.dropdownLabelColumn]:!oe}),onMouseEnter:Ee,onMouseLeave:De,children:[h(ie,{...E?{isOpen:!1}:{},onChange:e=>Ae((e||{key:``}).key),itemToString:e=>e?String(e.key):``,selectedItem:j.find(e=>e.key===J)??null,onStateChange:e=>{typeof e.isOpen==`boolean`&&Ce(e.isOpen)},stateReducer:(e,t)=>I&&Object.prototype.hasOwnProperty.call(t,`isOpen`)?{...t,highlightedIndex:t.isOpen?j.indexOf(e.selectedItem):null}:t,children:({getItemProps:e,getMenuProps:t,getToggleButtonProps:a,closeMenu:o,isOpen:s,selectedItem:c,highlightedIndex:l,setHighlightedIndex:d})=>h(`div`,{children:g(`div`,{ref:V,onFocus:Oe,onBlur:G,className:m(u.dropdownInput,{[u.dropdownInputPlain]:F,[u.dropdownInputReadOnly]:E&&!T},_e),children:[h(`button`,{tabIndex:S,type:`button`,disabled:T,"aria-readonly":E||void 0,style:k?{padding:`6px`,border:`none`}:{},className:m(u.dropdownInputButton,{[u.dropdownInputButtonDisabled]:T,[u.dropdownInputButtonReadOnly]:E&&!T},pe),...a(),onClick:e=>{a().onClick?.(e),D?.(e)},ref:ye,children:Z?`\xA0`:X}),h(`button`,{type:`button`,tabIndex:-1,disabled:T,className:m(u.dropdownInputButtonIcon,me),...a(),onClick:e=>{a().onClick?.(e),D?.(e)},children:!T&&!E&&h(ne,{icon:re,className:m(u.dropdownInputButtonIconArrow,{[u.dropdownInputButtonIconArrowOpen]:s})})}),!T&&!E&&s?g(n,{children:[W&&h(i,{onClose:o}),h(`div`,{...t({ref:e=>{H.current=e},"aria-label":y||P||void 0},{suppressRefError:!0}),style:W?Te:void 0,className:m(u.dropdownInputListAnim,{[r.sheet]:W,[u.dropdownInputListAnimWider]:k&&!W}),children:h(ee,{onScroll:se,className:m(u.dropdownInputList,W&&r.sheetScroll),setHighlightedIndex:d,children:j.map((t,n)=>h(`div`,{...e({index:n,item:t,disabled:!!t.disabled}),className:m(u.dropdownInputListItem,he,{[u.dropdownInputListItemActive]:l===n,[u.dropdownInputListItemSelected]:c===t,[u.dropdownInputListItemDisabled]:!!t.disabled}),children:t.label},t.key))})})]}):null,h(`fieldset`,{className:m(u.dropdownFieldset,{[u.dropdownBorderPlain]:F,[u.dropdownBorderFocused]:$,[u.dropdownBorderInvalid]:Y,[u.dropdownBorderError]:Y}),children:h(`legend`,{className:m(u.dropdownFieldsetLegend,{[u.dropdownFieldsetLegendActive]:M&&(N||$||!Z)}),children:h(`span`,{children:je})})}),M&&y&&g(`div`,{className:m(u.dropdownMatLabel,{[u.dropdownMatLabelFloating]:N||$||!Z}),children:[y,Q]}),M&&P&&h(`div`,{className:m(u.dropdownPlaceholder,$&&!q&&u.dropdownPlaceholderShown),children:P})]})})}),y&&!M&&g(`div`,{className:m(u.dropdownLabelText,ge),children:[y,Q]}),h(l,{variant:`error`,message:A?A.getCurrentErrorMessage():v||``,isVisible:Y&&(L||xe)})]})}export{_ as default};
2
2
  //# sourceMappingURL=dropdown.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../../../package/common/dropdown/dropdown.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport InfiniteBlock from 'components/common/infiniteBlock';\nimport BodyEnd from 'components/common/bodyEnd';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronDown as dropdownIcon } from '@fortawesome/free-solid-svg-icons';\nimport Downshift, { StateChangeOptions, DownshiftState } from 'downshift';\nimport Tooltip from 'components/common/tooltip';\n\nimport { useFloatingPosition } from '../floatingMenu/useFloatingPosition';\nimport { useComponentDefaults } from '../configProvider';\nimport styles from './dropdown.module.pcss';\nimport type { DropdownProps, DropdownItem } from './dropdown.types';\n\nfunction Dropdown(props: DropdownProps) {\n const {\n errorMessage = '',\n className = '',\n label = '',\n value = '',\n isValid = true,\n tabIndex = 0,\n isRequired = false,\n customProps = {},\n isRow = false,\n disabled = false,\n readOnly = false,\n onScroll = () => Promise.resolve(),\n onClick,\n onChange,\n onFocus: onFocusProp = null,\n onBlur: onBlurProp = null,\n onMouseEnter: onMouseEnterProp = null,\n onMouseLeave: onMouseLeaveProp = null,\n dropdownLabel: dropdownLabelProp,\n isDropdownListWider = false,\n inputClassName = '',\n dropDownIconClassName = '',\n dropDownClassName = '',\n formValidator = null,\n labelClassName = '',\n dropDownInputClassName = '',\n items = [],\n useMatLabelStyle = true,\n alwaysFloatLabel = false,\n placeholder = '',\n plainStyle = false,\n scrollToSelected = false,\n reactRef,\n ...rest\n } = useComponentDefaults('Dropdown', props);\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [, forceUpdate] = useState(0);\n const fvRef = useRef(formValidator);\n const triggerRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n const [menuIsOpen, setMenuIsOpen] = useState(false);\n\n useLayoutEffect(() => {\n const trigger = triggerRef.current;\n const menu = anchorRef.current;\n if (!menuIsOpen || !trigger || !menu) return;\n const { width } = trigger.getBoundingClientRect();\n const { fontSize } = window.getComputedStyle(trigger);\n menu.style.width = `${width}px`;\n menu.style.fontSize = fontSize;\n }, [menuIsOpen]);\n\n useFloatingPosition({\n isOpen: menuIsOpen,\n triggerRef,\n anchorRef,\n panelRef: anchorRef,\n flipClassName: styles.dropdownInputListAnimFlip,\n });\n\n useEffect(() => {\n fvRef.current = formValidator;\n if (!fvRef.current) return;\n fvRef.current.label = label ?? '';\n fvRef.current.validate();\n const listener = () => forceUpdate(n => n + 1);\n fvRef.current.registerOnUpdateListener(listener);\n return () => fvRef.current?.removeOnUpdateListener(listener);\n }, [formValidator, label]);\n\n const onMouseEnterHandler = (event: React.MouseEvent) => {\n setIsHovered(true);\n onMouseEnterProp?.(event);\n };\n\n const onMouseLeaveHandler = (event: React.MouseEvent) => {\n setIsHovered(false);\n onMouseLeaveProp?.(event);\n };\n\n const onFocusHandler = (event: React.FocusEvent) => {\n setIsFocused(true);\n onFocusProp?.(event);\n };\n\n const onBlurHandler = (event: React.FocusEvent) => {\n if (fvRef.current) fvRef.current.touched = true;\n setIsFocused(false);\n onBlurProp?.(event);\n };\n\n const hasError = (): boolean => {\n return formValidator\n ? (formValidator.touched && formValidator.hasError())\n : (!isValid || !!errorMessage);\n };\n\n const computedIsRequired = (): boolean => {\n return !!(isRequired || formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n ));\n };\n\n const onChangeHandler = (val: string | number): void => {\n if (formValidator) {\n formValidator.set(val);\n onChange?.(formValidator.value, customProps);\n } else {\n onChange?.(val, customProps);\n }\n };\n\n let dropdownLabel = dropdownLabelProp;\n const currentValue = formValidator ? formValidator.value as string | number : value;\n const hasErr = hasError();\n\n items.forEach((item: DropdownItem) => {\n if (item.key === currentValue) {\n dropdownLabel = item.label as string;\n }\n });\n\n const displayValue = dropdownLabel || currentValue;\n const isDisplayBlank =\n displayValue == null ||\n (typeof displayValue === 'string' && displayValue.trim() === '');\n\n const requiredMark = computedIsRequired() ? <span className={styles.requiredMark}>*</span> : null;\n const editedLabel = label && computedIsRequired() ? `${label} *` : label;\n\n const showFocus = isFocused && !readOnly;\n\n return (\n <div\n {...rest}\n className={cx(className, styles.dropdownLabel, styles.dropdown, {\n [styles.dropdownLabelColumn]: !isRow,\n })}\n onMouseEnter={onMouseEnterHandler}\n onMouseLeave={onMouseLeaveHandler}\n >\n <Downshift\n {...(readOnly ? { isOpen: false } : {})}\n onChange={(selection: DropdownItem | null) => onChangeHandler((selection || { key: '' }).key)}\n itemToString={(item: DropdownItem | null) => (item ? String(item.key) : '')}\n selectedItem={items.find((el) => el.key === currentValue) ?? null}\n onStateChange={(changes: StateChangeOptions<DropdownItem>) => {\n if (typeof changes.isOpen === 'boolean') setMenuIsOpen(changes.isOpen);\n }}\n stateReducer={(state: DownshiftState<DropdownItem>, changes: StateChangeOptions<DropdownItem>) => {\n if (scrollToSelected && Object.prototype.hasOwnProperty.call(changes, 'isOpen')) {\n return {\n ...changes,\n highlightedIndex: changes.isOpen ? items.indexOf(state.selectedItem as DropdownItem) : null,\n };\n }\n return changes;\n }}\n >\n {({\n getItemProps,\n getMenuProps,\n getToggleButtonProps,\n isOpen,\n selectedItem,\n highlightedIndex,\n setHighlightedIndex,\n }) => (\n <div>\n <div\n ref={triggerRef}\n onFocus={onFocusHandler}\n onBlur={onBlurHandler}\n className={cx(\n styles.dropdownInput,\n {\n [styles.dropdownInputPlain]: plainStyle,\n [styles.dropdownInputReadOnly]: readOnly && !disabled,\n },\n dropDownInputClassName\n )}\n >\n <button\n tabIndex={tabIndex}\n type=\"button\"\n disabled={disabled}\n aria-readonly={readOnly || undefined}\n style={isDropdownListWider ? { padding: '6px', border: 'none' } : {}}\n className={cx(\n styles.dropdownInputButton,\n {\n [styles.dropdownInputButtonDisabled]: disabled,\n [styles.dropdownInputButtonReadOnly]: readOnly && !disabled,\n },\n inputClassName\n )}\n {...getToggleButtonProps()}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n getToggleButtonProps().onClick?.(e);\n onClick?.(e);\n }}\n ref={reactRef}\n >\n {/* Non-breaking space when blank (same text-node layout as a\n real value) so the button keeps a full line of height. */}\n {isDisplayBlank ? '\\u00A0' : displayValue}\n </button>\n <button\n type=\"button\"\n tabIndex={-1}\n disabled={disabled}\n className={cx(styles.dropdownInputButtonIcon, dropDownIconClassName)}\n {...getToggleButtonProps()}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n getToggleButtonProps().onClick?.(e);\n onClick?.(e);\n }}\n >\n {!disabled && !readOnly && (\n <FontAwesomeIcon\n icon={dropdownIcon}\n className={cx(styles.dropdownInputButtonIconArrow, {\n [styles.dropdownInputButtonIconArrowOpen]: isOpen,\n })}\n />\n )}\n </button>\n {!disabled && !readOnly && isOpen ? (\n <BodyEnd>\n <div\n {...getMenuProps(\n {\n ref: (node: HTMLDivElement | null) => {\n anchorRef.current = node;\n },\n 'aria-label': label || placeholder || undefined,\n },\n { suppressRefError: true }\n )}\n className={cx(styles.dropdownInputListAnim, {\n [styles.dropdownInputListAnimWider]: isDropdownListWider,\n })}\n >\n <InfiniteBlock\n onScroll={onScroll}\n className={styles.dropdownInputList}\n setHighlightedIndex={setHighlightedIndex}\n >\n {items.map((item: DropdownItem, index: number) => (\n <div\n key={item.key}\n {...getItemProps({ index, item, disabled: !!item.disabled })}\n className={cx(styles.dropdownInputListItem, dropDownClassName, {\n [styles.dropdownInputListItemActive]: highlightedIndex === index,\n [styles.dropdownInputListItemSelected]: selectedItem === item,\n [styles.dropdownInputListItemDisabled]: !!item.disabled,\n })}\n >\n {item.label}\n </div>\n ))}\n </InfiniteBlock>\n </div>\n </BodyEnd>\n ) : null}\n <fieldset\n className={cx(styles.dropdownFieldset, {\n [styles.dropdownBorderPlain]: plainStyle,\n [styles.dropdownBorderFocused]: showFocus,\n [styles.dropdownBorderInvalid]: hasErr,\n [styles.dropdownBorderError]: hasErr,\n })}\n >\n <legend\n className={cx(styles.dropdownFieldsetLegend, {\n [styles.dropdownFieldsetLegendActive]:\n useMatLabelStyle && (alwaysFloatLabel || showFocus || !isDisplayBlank),\n })}\n >\n <span>{editedLabel}</span>\n </legend>\n </fieldset>\n {useMatLabelStyle && label && (\n <div\n className={cx(styles.dropdownMatLabel, {\n [styles.dropdownMatLabelFloating]: alwaysFloatLabel || showFocus || !isDisplayBlank,\n })}\n >\n {label}\n {requiredMark}\n </div>\n )}\n {useMatLabelStyle && placeholder && (\n <div\n className={cx(\n styles.dropdownPlaceholder,\n showFocus && !dropdownLabel && styles.dropdownPlaceholderShown\n )}\n >\n {placeholder}\n </div>\n )}\n </div>\n </div>\n )}\n </Downshift>\n {label && !useMatLabelStyle && (\n <div className={cx(styles.dropdownLabelText, labelClassName)}>\n {label}\n {requiredMark}\n </div>\n )}\n <Tooltip\n variant=\"error\"\n message={formValidator ? formValidator.getCurrentErrorMessage() : (errorMessage || '')}\n isVisible={hasErr && (isFocused || isHovered)}\n />\n </div>\n );\n}\n\nexport default Dropdown;\n"],"mappings":"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"}
1
+ {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../../../package/common/dropdown/dropdown.tsx"],"sourcesContent":["import React, { useState, useEffect, useLayoutEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport InfiniteBlock from 'components/common/infiniteBlock';\nimport BodyEnd from 'components/common/bodyEnd';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronDown as dropdownIcon } from '@fortawesome/free-solid-svg-icons';\nimport Downshift, { StateChangeOptions, DownshiftState } from 'downshift';\nimport Tooltip from 'components/common/tooltip';\n\nimport { useFloatingPosition } from '../floatingMenu/useFloatingPosition';\nimport { useComponentDefaults, usePresentationDefault } from '../configProvider';\nimport { useSheet } from '../hooks/useSheet';\nimport { useOverlay } from '../hooks/useOverlay';\nimport { Presentation } from '../floatingMenu/floatingMenu.types';\nimport styles from './dropdown.module.pcss';\nimport sheetStyles from '../styles/sheet.module.pcss';\nimport SheetBackdrop from '../sheetBackdrop';\nimport type { DropdownProps, DropdownItem } from './dropdown.types';\n\nfunction Dropdown(props: DropdownProps) {\n const {\n errorMessage = '',\n className = '',\n label = '',\n value = '',\n isValid = true,\n tabIndex = 0,\n isRequired = false,\n customProps = {},\n isRow = false,\n disabled = false,\n readOnly = false,\n onScroll = () => Promise.resolve(),\n onClick,\n onChange,\n onFocus: onFocusProp = null,\n onBlur: onBlurProp = null,\n onMouseEnter: onMouseEnterProp = null,\n onMouseLeave: onMouseLeaveProp = null,\n dropdownLabel: dropdownLabelProp,\n isDropdownListWider = false,\n inputClassName = '',\n dropDownIconClassName = '',\n dropDownClassName = '',\n formValidator = null,\n labelClassName = '',\n dropDownInputClassName = '',\n items = [],\n useMatLabelStyle = true,\n alwaysFloatLabel = false,\n placeholder = '',\n plainStyle = false,\n scrollToSelected = false,\n presentation: presentationProp,\n reactRef,\n ...rest\n } = useComponentDefaults('Dropdown', props);\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [, forceUpdate] = useState(0);\n const fvRef = useRef(formValidator);\n const triggerRef = useRef<HTMLDivElement>(null);\n const anchorRef = useRef<HTMLDivElement>(null);\n const [menuIsOpen, setMenuIsOpen] = useState(false);\n\n // Explicit prop → this component's global default → the app-wide one → anchored.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation ?? Presentation.Default;\n const { isSheet, sheetStyle } = useSheet(presentation);\n\n useLayoutEffect(() => {\n const trigger = triggerRef.current;\n const menu = anchorRef.current;\n // A sheet spans the screen; only an anchored list matches the trigger's width.\n if (!menuIsOpen || isSheet || !trigger || !menu) return;\n const { width } = trigger.getBoundingClientRect();\n const { fontSize } = window.getComputedStyle(trigger);\n menu.style.width = `${width}px`;\n menu.style.fontSize = fontSize;\n }, [menuIsOpen, isSheet]);\n\n // A sheet isn't anchored to anything, so there's nothing to track, flip or clamp.\n useFloatingPosition({\n isOpen: menuIsOpen && !isSheet,\n triggerRef,\n anchorRef,\n panelRef: anchorRef,\n flipClassName: styles.dropdownInputListAnimFlip,\n });\n\n // Registered for as long as the list is open, not just as a sheet: it puts the list on the\n // overlay stack so an enclosing Modal doesn't also act on the Escape that closes it. No\n // `onEscape` of its own — Downshift already closes the list from the toggle button. Focus isn't\n // trapped: Downshift keeps focus on that button and drives the list from there.\n useOverlay({\n isActive: menuIsOpen,\n containerRef: anchorRef,\n trapFocus: false,\n lockScroll: isSheet,\n });\n\n useEffect(() => {\n fvRef.current = formValidator;\n if (!fvRef.current) return;\n fvRef.current.label = label ?? '';\n fvRef.current.validate();\n const listener = () => forceUpdate(n => n + 1);\n fvRef.current.registerOnUpdateListener(listener);\n return () => fvRef.current?.removeOnUpdateListener(listener);\n }, [formValidator, label]);\n\n const onMouseEnterHandler = (event: React.MouseEvent) => {\n setIsHovered(true);\n onMouseEnterProp?.(event);\n };\n\n const onMouseLeaveHandler = (event: React.MouseEvent) => {\n setIsHovered(false);\n onMouseLeaveProp?.(event);\n };\n\n const onFocusHandler = (event: React.FocusEvent) => {\n setIsFocused(true);\n onFocusProp?.(event);\n };\n\n const onBlurHandler = (event: React.FocusEvent) => {\n if (fvRef.current) fvRef.current.touched = true;\n setIsFocused(false);\n onBlurProp?.(event);\n };\n\n const hasError = (): boolean => {\n return formValidator\n ? (formValidator.touched && formValidator.hasError())\n : (!isValid || !!errorMessage);\n };\n\n const computedIsRequired = (): boolean => {\n return !!(isRequired || formValidator?.validators.find(\n (v) => (v as { validatorId?: string }).validatorId === 'required'\n ));\n };\n\n const onChangeHandler = (val: string | number): void => {\n if (formValidator) {\n formValidator.set(val);\n onChange?.(formValidator.value, customProps);\n } else {\n onChange?.(val, customProps);\n }\n };\n\n let dropdownLabel = dropdownLabelProp;\n const currentValue = formValidator ? formValidator.value as string | number : value;\n const hasErr = hasError();\n\n items.forEach((item: DropdownItem) => {\n if (item.key === currentValue) {\n dropdownLabel = item.label as string;\n }\n });\n\n const displayValue = dropdownLabel || currentValue;\n const isDisplayBlank =\n displayValue == null ||\n (typeof displayValue === 'string' && displayValue.trim() === '');\n\n const requiredMark = computedIsRequired() ? <span className={styles.requiredMark}>*</span> : null;\n const editedLabel = label && computedIsRequired() ? `${label} *` : label;\n\n const showFocus = isFocused && !readOnly;\n\n return (\n <div\n {...rest}\n className={cx(className, styles.dropdownLabel, styles.dropdown, {\n [styles.dropdownLabelColumn]: !isRow,\n })}\n onMouseEnter={onMouseEnterHandler}\n onMouseLeave={onMouseLeaveHandler}\n >\n <Downshift\n {...(readOnly ? { isOpen: false } : {})}\n onChange={(selection: DropdownItem | null) => onChangeHandler((selection || { key: '' }).key)}\n itemToString={(item: DropdownItem | null) => (item ? String(item.key) : '')}\n selectedItem={items.find((el) => el.key === currentValue) ?? null}\n onStateChange={(changes: StateChangeOptions<DropdownItem>) => {\n if (typeof changes.isOpen === 'boolean') setMenuIsOpen(changes.isOpen);\n }}\n stateReducer={(state: DownshiftState<DropdownItem>, changes: StateChangeOptions<DropdownItem>) => {\n if (scrollToSelected && Object.prototype.hasOwnProperty.call(changes, 'isOpen')) {\n return {\n ...changes,\n highlightedIndex: changes.isOpen ? items.indexOf(state.selectedItem as DropdownItem) : null,\n };\n }\n return changes;\n }}\n >\n {({\n getItemProps,\n getMenuProps,\n getToggleButtonProps,\n closeMenu,\n isOpen,\n selectedItem,\n highlightedIndex,\n setHighlightedIndex,\n }) => (\n <div>\n <div\n ref={triggerRef}\n onFocus={onFocusHandler}\n onBlur={onBlurHandler}\n className={cx(\n styles.dropdownInput,\n {\n [styles.dropdownInputPlain]: plainStyle,\n [styles.dropdownInputReadOnly]: readOnly && !disabled,\n },\n dropDownInputClassName\n )}\n >\n <button\n tabIndex={tabIndex}\n type=\"button\"\n disabled={disabled}\n aria-readonly={readOnly || undefined}\n style={isDropdownListWider ? { padding: '6px', border: 'none' } : {}}\n className={cx(\n styles.dropdownInputButton,\n {\n [styles.dropdownInputButtonDisabled]: disabled,\n [styles.dropdownInputButtonReadOnly]: readOnly && !disabled,\n },\n inputClassName\n )}\n {...getToggleButtonProps()}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n getToggleButtonProps().onClick?.(e);\n onClick?.(e);\n }}\n ref={reactRef}\n >\n {/* Non-breaking space when blank (same text-node layout as a\n real value) so the button keeps a full line of height. */}\n {isDisplayBlank ? '\\u00A0' : displayValue}\n </button>\n <button\n type=\"button\"\n tabIndex={-1}\n disabled={disabled}\n className={cx(styles.dropdownInputButtonIcon, dropDownIconClassName)}\n {...getToggleButtonProps()}\n onClick={(e: React.MouseEvent<HTMLButtonElement>) => {\n getToggleButtonProps().onClick?.(e);\n onClick?.(e);\n }}\n >\n {!disabled && !readOnly && (\n <FontAwesomeIcon\n icon={dropdownIcon}\n className={cx(styles.dropdownInputButtonIconArrow, {\n [styles.dropdownInputButtonIconArrowOpen]: isOpen,\n })}\n />\n )}\n </button>\n {!disabled && !readOnly && isOpen ? (\n <BodyEnd>\n {isSheet && <SheetBackdrop onClose={closeMenu} />}\n <div\n {...getMenuProps(\n {\n ref: (node: HTMLDivElement | null) => {\n anchorRef.current = node;\n },\n 'aria-label': label || placeholder || undefined,\n },\n { suppressRefError: true }\n )}\n style={isSheet ? sheetStyle : undefined}\n className={cx(styles.dropdownInputListAnim, {\n [sheetStyles.sheet]: isSheet,\n [styles.dropdownInputListAnimWider]: isDropdownListWider && !isSheet,\n })}\n >\n <InfiniteBlock\n onScroll={onScroll}\n className={cx(styles.dropdownInputList, isSheet && sheetStyles.sheetScroll)}\n setHighlightedIndex={setHighlightedIndex}\n >\n {items.map((item: DropdownItem, index: number) => (\n <div\n key={item.key}\n {...getItemProps({ index, item, disabled: !!item.disabled })}\n className={cx(styles.dropdownInputListItem, dropDownClassName, {\n [styles.dropdownInputListItemActive]: highlightedIndex === index,\n [styles.dropdownInputListItemSelected]: selectedItem === item,\n [styles.dropdownInputListItemDisabled]: !!item.disabled,\n })}\n >\n {item.label}\n </div>\n ))}\n </InfiniteBlock>\n </div>\n </BodyEnd>\n ) : null}\n <fieldset\n className={cx(styles.dropdownFieldset, {\n [styles.dropdownBorderPlain]: plainStyle,\n [styles.dropdownBorderFocused]: showFocus,\n [styles.dropdownBorderInvalid]: hasErr,\n [styles.dropdownBorderError]: hasErr,\n })}\n >\n <legend\n className={cx(styles.dropdownFieldsetLegend, {\n [styles.dropdownFieldsetLegendActive]:\n useMatLabelStyle && (alwaysFloatLabel || showFocus || !isDisplayBlank),\n })}\n >\n <span>{editedLabel}</span>\n </legend>\n </fieldset>\n {useMatLabelStyle && label && (\n <div\n className={cx(styles.dropdownMatLabel, {\n [styles.dropdownMatLabelFloating]: alwaysFloatLabel || showFocus || !isDisplayBlank,\n })}\n >\n {label}\n {requiredMark}\n </div>\n )}\n {useMatLabelStyle && placeholder && (\n <div\n className={cx(\n styles.dropdownPlaceholder,\n showFocus && !dropdownLabel && styles.dropdownPlaceholderShown\n )}\n >\n {placeholder}\n </div>\n )}\n </div>\n </div>\n )}\n </Downshift>\n {label && !useMatLabelStyle && (\n <div className={cx(styles.dropdownLabelText, labelClassName)}>\n {label}\n {requiredMark}\n </div>\n )}\n <Tooltip\n variant=\"error\"\n message={formValidator ? formValidator.getCurrentErrorMessage() : (errorMessage || '')}\n isVisible={hasErr && (isFocused || isHovered)}\n />\n </div>\n );\n}\n\nexport default Dropdown;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import e from"../bodyEnd/bodyEnd.mjs";import t from"./floatingMenu.module.mjs";import{useFloatingPosition as n}from"./useFloatingPosition.mjs";import{tabbablesIn as r,useFocusBoundary as i}from"../hooks/useFocusBoundary.mjs";import{Align as a}from"./floatingMenu.types.mjs";import{useEffect as o,useRef as s,useState as c}from"react";import l from"classnames";import{jsx as u,jsxs as d}from"react/jsx-runtime";function f(e){return e.charAt(0).toUpperCase()+e.slice(1)}function p({align:p=a.Left,children:m=null,content:h=null,isOpen:g=!1,onOpenChange:_=()=>{},dontCloseOnChildClick:v=!1,className:y,style:b,classNames:x,styles:S,...C}){let w=s(null),T=s(null),E=s(null),D=s(_),[O,k]=c(10),A=s(!1);function j(){A.current=!0}o(()=>{D.current=_});function M(){if(g){v||_(!1);return}let e=E.current?.getBoundingClientRect();k(e?.width??10),_(!0)}n({isOpen:g,triggerRef:E,anchorRef:T,panelRef:w,flipClassName:t.floatingMenuAnimFlip}),o(()=>{if(!g)return;function e(e){let t=w.current,n=E.current;if(!t||!n)return;let r=e.target;if(n===r||n.contains(r))return;let i=A.current;A.current=!1,(!(i||t===r||t.contains(r))||!v)&&D.current(!1)}return window.addEventListener(`mouseup`,e),()=>window.removeEventListener(`mouseup`,e)},[g,v]);let{restoreFocusToTrigger:N,focusAfterTrigger:P}=i({triggerRef:E,contentRef:w});function F(e){if(e.key===`Escape`){e.preventDefault(),N(),D.current(!1);return}if(e.key!==`Tab`)return;let t=r(w.current);if(t.length===0)return;let n=document.activeElement;!e.shiftKey&&n===t[t.length-1]?(e.preventDefault(),P(),D.current(!1)):e.shiftKey&&n===t[0]&&(e.preventDefault(),N(),D.current(!1))}return d(`div`,{...C,className:l(t.floatingMenu,y,x?.root),style:{...b,...S?.root},children:[u(`div`,{className:l(t.floatingMenuContent,x?.trigger),style:S?.trigger,ref:E,onClick:M,children:m}),g&&u(e,{children:d(`div`,{ref:T,className:l(t.floatingMenuAnim,x?.menu),style:{width:`${O}px`,...S?.menu},children:[u(`div`,{className:l(t.floatingMenuContainerFlag,t[`floatingMenuContainerFlagAlign${f(p)}`])}),u(`div`,{ref:w,className:l(t.floatingMenuContainer,t[`floatingMenuContainerAlign${f(p)}`],x?.menuContainer),style:S?.menuContainer,onMouseUpCapture:j,onKeyDown:F,children:h})]})})]})}export{p as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import n from"../bodyEnd/bodyEnd.mjs";import r from"./floatingMenu.module.mjs";import i from"../styles/sheet.module.mjs";import a from"../sheetBackdrop/sheetBackdrop.mjs";import{useFloatingPosition as o}from"./useFloatingPosition.mjs";import{tabbablesIn as s,useFocusBoundary as c}from"../hooks/useFocusBoundary.mjs";import{Align as l,Presentation as u}from"./floatingMenu.types.mjs";import d from"../hooks/useSheet.mjs";import{useOverlay as f}from"../hooks/useOverlay.mjs";import{useEffect as p,useRef as m,useState as h}from"react";import g from"classnames";import{jsx as _,jsxs as v}from"react/jsx-runtime";function y(e){return e.charAt(0).toUpperCase()+e.slice(1)}function b(b){let{align:x=l.Left,children:S=null,content:C=null,isOpen:w=!1,onOpenChange:T=()=>{},dontCloseOnChildClick:E=!1,presentation:D,className:O,style:k,classNames:A,styles:j,...M}=e(`FloatingMenu`,b),N=m(null),P=m(null),F=m(null),I=m(T),[L,R]=h(10),z=m(!1);function B(){z.current=!0}p(()=>{I.current=T});function V(){if(w){E||T(!1);return}let e=F.current?.getBoundingClientRect();R(e?.width??10),T(!0)}let H=t(),{isSheet:U,sheetStyle:W}=d(D??H??u.Default);o({isOpen:w&&!U,triggerRef:F,anchorRef:P,panelRef:N,flipClassName:r.floatingMenuAnimFlip}),p(()=>{if(!w)return;function e(e){let t=N.current,n=F.current;if(!t||!n)return;let r=e.target;if(n===r||n.contains(r))return;let i=z.current;z.current=!1,(!(i||t===r||t.contains(r))||!E)&&I.current(!1)}return window.addEventListener(`mouseup`,e),()=>window.removeEventListener(`mouseup`,e)},[w,E]);let{restoreFocusToTrigger:G,focusAfterTrigger:K}=c({triggerRef:F,contentRef:N});f({isActive:w,containerRef:N,onEscape:()=>{N.current?.contains(document.activeElement)&&G(),I.current(!1)},trapFocus:!1,lockScroll:U});function q(e){if(e.key!==`Tab`)return;let t=s(N.current);if(t.length===0)return;let n=document.activeElement;!e.shiftKey&&n===t[t.length-1]?(e.preventDefault(),K(),I.current(!1)):e.shiftKey&&n===t[0]&&(e.preventDefault(),G(),I.current(!1))}return v(`div`,{...M,className:g(r.floatingMenu,O,A?.root),style:{...k,...j?.root},children:[_(`div`,{className:g(r.floatingMenuContent,A?.trigger),style:j?.trigger,ref:F,onClick:V,children:S}),w&&v(n,{children:[U&&_(a,{onClose:()=>I.current(!1),className:A?.backdrop,style:j?.backdrop}),v(`div`,{ref:P,className:g(U?i.sheet:r.floatingMenuAnim,A?.menu),style:{...U?W:{width:`${L}px`},...j?.menu},children:[!U&&_(`div`,{className:g(r.floatingMenuContainerFlag,r[`floatingMenuContainerFlagAlign${y(x)}`])}),_(`div`,{ref:N,className:g(r.floatingMenuContainer,U?i.sheetPanel:[r.floatingMenuContainerAnchored,r[`floatingMenuContainerAlign${y(x)}`]],A?.menuContainer),style:j?.menuContainer,onMouseUpCapture:B,onKeyDown:q,children:C})]})]})]})}export{b as default};
2
2
  //# sourceMappingURL=floatingMenu.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"floatingMenu.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.tsx"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './floatingMenu.module.pcss';\nimport { useFloatingPosition } from './useFloatingPosition';\nimport { useFocusBoundary, tabbablesIn } from '../hooks/useFocusBoundary';\nimport { Align, FloatingMenuProps } from './floatingMenu.types';\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nfunction FloatingMenu({\n align = Align.Left,\n children = null,\n content = null,\n isOpen = false,\n onOpenChange = () => {},\n dontCloseOnChildClick = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: FloatingMenuProps) {\n const menuContainerRef = useRef<HTMLDivElement>(null);\n const menuAnimRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const onOpenChangeRef = useRef(onOpenChange);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n const contentInteractedRef = useRef(false);\n function handleContentMouseUp() {\n contentInteractedRef.current = true;\n }\n\n useEffect(() => { onOpenChangeRef.current = onOpenChange; });\n\n function handleTriggerClick() {\n if (isOpen) {\n if (!dontCloseOnChildClick) onOpenChange(false);\n return;\n }\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n onOpenChange(true);\n }\n\n useFloatingPosition({\n isOpen,\n triggerRef,\n anchorRef: menuAnimRef,\n panelRef: menuContainerRef,\n flipClassName: styles.floatingMenuAnimFlip,\n });\n\n useEffect(() => {\n if (!isOpen) return;\n\n function onMouseUp(event: MouseEvent) {\n const menuElem = menuContainerRef.current;\n const triggerElem = triggerRef.current;\n if (!menuElem || !triggerElem) return;\n\n const target = event.target as Node;\n if (triggerElem === target || triggerElem.contains(target)) return;\n\n const contentInteracted = contentInteractedRef.current;\n contentInteractedRef.current = false;\n const clickedInMenu = contentInteracted || menuElem === target || menuElem.contains(target);\n\n if (!clickedInMenu || !dontCloseOnChildClick) {\n onOpenChangeRef.current(false);\n }\n }\n\n window.addEventListener('mouseup', onMouseUp);\n return () => window.removeEventListener('mouseup', onMouseUp);\n }, [isOpen, dontCloseOnChildClick]);\n\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({\n triggerRef,\n contentRef: menuContainerRef,\n });\n\n // The menu is portaled to the end of the DOM, so Tab never flows into it naturally. When\n // `content` has real focusable elements, close on Tab out of either end and continue focus as\n // if the menu sat right after the trigger. Unlike Popover, this doesn't also auto-focus the\n // first element on open, content here ranges from menus to live controls like ColorPicker's\n // hue slider, where grabbing focus on open would let a stray arrow-key press nudge a value the\n // user never interacted with. Auto-focus-on-open is still worth doing per-consumer (e.g.\n // SplitButton focuses its first enabled action), just not assumed generically here.\n function handleMenuKeyDown(event: React.KeyboardEvent) {\n if (event.key === 'Escape') {\n event.preventDefault();\n restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n return;\n }\n if (event.key !== 'Tab') return;\n const focusables = tabbablesIn(menuContainerRef.current);\n if (focusables.length === 0) return;\n const active = document.activeElement;\n if (!event.shiftKey && active === focusables[focusables.length - 1]) {\n event.preventDefault();\n focusAfterTrigger();\n onOpenChangeRef.current(false);\n } else if (event.shiftKey && active === focusables[0]) {\n event.preventDefault();\n restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n }\n }\n\n return (\n <div {...rest} className={cx(styles.floatingMenu, className, classNames?.root)} style={{ ...style, ...slotStyles?.root }}>\n <div\n className={cx(styles.floatingMenuContent, classNames?.trigger)}\n style={slotStyles?.trigger}\n ref={triggerRef}\n onClick={handleTriggerClick}\n >\n {children}\n </div>\n {isOpen && (\n <BodyEnd>\n <div\n ref={menuAnimRef}\n className={cx(styles.floatingMenuAnim, classNames?.menu)}\n style={{\n width: `${triggerWidth}px`,\n ...slotStyles?.menu,\n }}\n >\n <div className={cx(\n styles.floatingMenuContainerFlag,\n styles[`floatingMenuContainerFlagAlign${capitalize(align)}`],\n )} />\n <div\n ref={menuContainerRef}\n className={cx(\n styles.floatingMenuContainer,\n styles[`floatingMenuContainerAlign${capitalize(align)}`],\n classNames?.menuContainer,\n )}\n style={slotStyles?.menuContainer}\n onMouseUpCapture={handleContentMouseUp}\n onKeyDown={handleMenuKeyDown}\n >\n {content}\n </div>\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n\nexport default FloatingMenu;\n"],"mappings":"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"}
1
+ {"version":3,"file":"floatingMenu.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.tsx"],"sourcesContent":["import { useRef, useEffect, useState } from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './floatingMenu.module.pcss';\nimport sheetStyles from '../styles/sheet.module.pcss';\nimport SheetBackdrop from '../sheetBackdrop';\nimport { useFloatingPosition } from './useFloatingPosition';\nimport { useFocusBoundary, tabbablesIn } from '../hooks/useFocusBoundary';\nimport { useSheet } from '../hooks/useSheet';\nimport { useOverlay } from '../hooks/useOverlay';\nimport { useComponentDefaults, usePresentationDefault } from '../configProvider';\nimport { Align, Presentation, FloatingMenuProps } from './floatingMenu.types';\n\nfunction capitalize(s: string) {\n return s.charAt(0).toUpperCase() + s.slice(1);\n}\n\nfunction FloatingMenu(props: FloatingMenuProps) {\n const {\n align = Align.Left,\n children = null,\n content = null,\n isOpen = false,\n onOpenChange = () => {},\n dontCloseOnChildClick = false,\n presentation: presentationProp,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('FloatingMenu', props);\n const menuContainerRef = useRef<HTMLDivElement>(null);\n const menuAnimRef = useRef<HTMLDivElement>(null);\n const triggerRef = useRef<HTMLDivElement>(null);\n const onOpenChangeRef = useRef(onOpenChange);\n const [triggerWidth, setTriggerWidth] = useState(10);\n\n const contentInteractedRef = useRef(false);\n function handleContentMouseUp() {\n contentInteractedRef.current = true;\n }\n\n useEffect(() => { onOpenChangeRef.current = onOpenChange; });\n\n function handleTriggerClick() {\n if (isOpen) {\n if (!dontCloseOnChildClick) onOpenChange(false);\n return;\n }\n const rect = triggerRef.current?.getBoundingClientRect();\n setTriggerWidth(rect?.width ?? 10);\n onOpenChange(true);\n }\n\n // Explicit prop → this component's global default → the app-wide one → anchored.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation ?? Presentation.Default;\n const { isSheet, sheetStyle } = useSheet(presentation);\n\n // A sheet isn't anchored to anything, so there's nothing to track, flip or clamp.\n useFloatingPosition({\n isOpen: isOpen && !isSheet,\n triggerRef,\n anchorRef: menuAnimRef,\n panelRef: menuContainerRef,\n flipClassName: styles.floatingMenuAnimFlip,\n });\n\n useEffect(() => {\n if (!isOpen) return;\n\n function onMouseUp(event: MouseEvent) {\n const menuElem = menuContainerRef.current;\n const triggerElem = triggerRef.current;\n if (!menuElem || !triggerElem) return;\n\n const target = event.target as Node;\n if (triggerElem === target || triggerElem.contains(target)) return;\n\n const contentInteracted = contentInteractedRef.current;\n contentInteractedRef.current = false;\n const clickedInMenu = contentInteracted || menuElem === target || menuElem.contains(target);\n\n if (!clickedInMenu || !dontCloseOnChildClick) {\n onOpenChangeRef.current(false);\n }\n }\n\n window.addEventListener('mouseup', onMouseUp);\n return () => window.removeEventListener('mouseup', onMouseUp);\n }, [isOpen, dontCloseOnChildClick]);\n\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({\n triggerRef,\n contentRef: menuContainerRef,\n });\n\n // Registered for as long as the menu is open, not just as a sheet: this is what puts it on the\n // overlay stack, so an enclosing Modal knows something sits above it. Without that, the modal\n // stays topmost and its focus trap drags focus out of this menu — which lives outside the\n // modal's panel, in the portal — and Escape closes the modal instead of just this menu.\n // Focus is deliberately not trapped: the menu doesn't take focus on open (see\n // `handleMenuKeyDown`), so there'd be nothing inside to trap.\n useOverlay({\n isActive: isOpen,\n containerRef: menuContainerRef,\n onEscape: () => {\n if (menuContainerRef.current?.contains(document.activeElement)) restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n },\n trapFocus: false,\n lockScroll: isSheet,\n });\n\n // The menu is portaled to the end of the DOM, so Tab never flows into it naturally. When\n // `content` has real focusable elements, close on Tab out of either end and continue focus as\n // if the menu sat right after the trigger. Escape is handled by `useOverlay` above instead, so\n // that it works from the trigger too and closes only the innermost open layer.\n // Unlike Popover, this doesn't also auto-focus the\n // first element on open, content here ranges from menus to live controls like ColorPicker's\n // hue slider, where grabbing focus on open would let a stray arrow-key press nudge a value the\n // user never interacted with. Auto-focus-on-open is still worth doing per-consumer (e.g.\n // SplitButton focuses its first enabled action), just not assumed generically here.\n function handleMenuKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'Tab') return;\n const focusables = tabbablesIn(menuContainerRef.current);\n if (focusables.length === 0) return;\n const active = document.activeElement;\n if (!event.shiftKey && active === focusables[focusables.length - 1]) {\n event.preventDefault();\n focusAfterTrigger();\n onOpenChangeRef.current(false);\n } else if (event.shiftKey && active === focusables[0]) {\n event.preventDefault();\n restoreFocusToTrigger();\n onOpenChangeRef.current(false);\n }\n }\n\n return (\n <div {...rest} className={cx(styles.floatingMenu, className, classNames?.root)} style={{ ...style, ...slotStyles?.root }}>\n <div\n className={cx(styles.floatingMenuContent, classNames?.trigger)}\n style={slotStyles?.trigger}\n ref={triggerRef}\n onClick={handleTriggerClick}\n >\n {children}\n </div>\n {isOpen && (\n <BodyEnd>\n {isSheet && (\n <SheetBackdrop\n onClose={() => onOpenChangeRef.current(false)}\n className={classNames?.backdrop}\n style={slotStyles?.backdrop}\n />\n )}\n <div\n ref={menuAnimRef}\n className={cx(isSheet ? sheetStyles.sheet : styles.floatingMenuAnim, classNames?.menu)}\n style={{\n // A sheet spans the screen; only an anchored menu takes the trigger's width.\n ...(isSheet ? sheetStyle : { width: `${triggerWidth}px` }),\n ...slotStyles?.menu,\n }}\n >\n {!isSheet && (\n <div className={cx(\n styles.floatingMenuContainerFlag,\n styles[`floatingMenuContainerFlagAlign${capitalize(align)}`],\n )} />\n )}\n <div\n ref={menuContainerRef}\n className={cx(\n styles.floatingMenuContainer,\n isSheet ? sheetStyles.sheetPanel : [\n styles.floatingMenuContainerAnchored,\n styles[`floatingMenuContainerAlign${capitalize(align)}`],\n ],\n classNames?.menuContainer,\n )}\n style={slotStyles?.menuContainer}\n onMouseUpCapture={handleContentMouseUp}\n onKeyDown={handleMenuKeyDown}\n >\n {content}\n </div>\n </div>\n </BodyEnd>\n )}\n </div>\n );\n}\n\nexport default FloatingMenu;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- var e={floatingMenu:`floatingMenu_E1XCy`,"floatingMenu-content":`floatingMenu-content_AmxkA`,floatingMenuContent:`floatingMenu-content_AmxkA`,"floatingMenu-container":`floatingMenu-container_w7k-Y`,floatingMenuContainer:`floatingMenu-container_w7k-Y`,"floatingMenu-anim-flip":`floatingMenu-anim-flip_a4-Ri`,floatingMenuAnimFlip:`floatingMenu-anim-flip_a4-Ri`,"floatingMenu-container-align-left":`floatingMenu-container-align-left_InKnZ`,floatingMenuContainerAlignLeft:`floatingMenu-container-align-left_InKnZ`,"floatingMenu-container-align-right":`floatingMenu-container-align-right_a9OoS`,floatingMenuContainerAlignRight:`floatingMenu-container-align-right_a9OoS`,"floatingMenu-container-align-center":`floatingMenu-container-align-center_-8bGT`,floatingMenuContainerAlignCenter:`floatingMenu-container-align-center_-8bGT`,"floatingMenu-container-flag":`floatingMenu-container-flag_VdKHr`,floatingMenuContainerFlag:`floatingMenu-container-flag_VdKHr`,"floatingMenu-container-flag-align-right":`floatingMenu-container-flag-align-right_vxrRN`,floatingMenuContainerFlagAlignRight:`floatingMenu-container-flag-align-right_vxrRN`,"floatingMenu-container-flag-align-left":`floatingMenu-container-flag-align-left_a2Vv-`,floatingMenuContainerFlagAlignLeft:`floatingMenu-container-flag-align-left_a2Vv-`,"floatingMenu-container-flag-align-center":`floatingMenu-container-flag-align-center_SmaaY`,floatingMenuContainerFlagAlignCenter:`floatingMenu-container-flag-align-center_SmaaY`,"floatingMenu-anim":`floatingMenu-anim_5KB-f`,floatingMenuAnim:`floatingMenu-anim_5KB-f`,showMenu:`showMenu_AprCh`};export{e as default};
1
+ var e={floatingMenu:`floatingMenu_E1XCy`,"floatingMenu-content":`floatingMenu-content_AmxkA`,floatingMenuContent:`floatingMenu-content_AmxkA`,"floatingMenu-container":`floatingMenu-container_w7k-Y`,floatingMenuContainer:`floatingMenu-container_w7k-Y`,"floatingMenu-container-anchored":`floatingMenu-container-anchored_-8CHY`,floatingMenuContainerAnchored:`floatingMenu-container-anchored_-8CHY`,"floatingMenu-anim-flip":`floatingMenu-anim-flip_a4-Ri`,floatingMenuAnimFlip:`floatingMenu-anim-flip_a4-Ri`,"floatingMenu-container-align-left":`floatingMenu-container-align-left_InKnZ`,floatingMenuContainerAlignLeft:`floatingMenu-container-align-left_InKnZ`,"floatingMenu-container-align-right":`floatingMenu-container-align-right_a9OoS`,floatingMenuContainerAlignRight:`floatingMenu-container-align-right_a9OoS`,"floatingMenu-container-align-center":`floatingMenu-container-align-center_-8bGT`,floatingMenuContainerAlignCenter:`floatingMenu-container-align-center_-8bGT`,"floatingMenu-container-flag":`floatingMenu-container-flag_VdKHr`,floatingMenuContainerFlag:`floatingMenu-container-flag_VdKHr`,"floatingMenu-container-flag-align-right":`floatingMenu-container-flag-align-right_vxrRN`,floatingMenuContainerFlagAlignRight:`floatingMenu-container-flag-align-right_vxrRN`,"floatingMenu-container-flag-align-left":`floatingMenu-container-flag-align-left_a2Vv-`,floatingMenuContainerFlagAlignLeft:`floatingMenu-container-flag-align-left_a2Vv-`,"floatingMenu-container-flag-align-center":`floatingMenu-container-flag-align-center_SmaaY`,floatingMenuContainerFlagAlignCenter:`floatingMenu-container-flag-align-center_SmaaY`,"floatingMenu-anim":`floatingMenu-anim_5KB-f`,floatingMenuAnim:`floatingMenu-anim_5KB-f`,showMenu:`showMenu_AprCh`};export{e as default};
2
2
  //# sourceMappingURL=floatingMenu.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"floatingMenu.module.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.module.pcss"],"sourcesContent":[".floatingMenu {\n position: relative;\n\n &-content {\n display: flex;\n align-items: stretch;\n height: 100%;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &-container {\n color: var(--text-color);\n font-family: var(--default-font);\n font-size: var(--default-font-size);\n box-shadow: var(--card-shadow);\n position: absolute;\n margin-top: 10px;\n background: var(--background-modal);\n padding: 8px;\n border-radius: calc(var(--default-border-radius) + 4px);\n\n .floatingMenu-anim-flip & {\n top: auto;\n bottom: 0;\n margin-top: 0;\n margin-bottom: 10px;\n }\n\n &-align {\n &-left {\n left: 0px;\n }\n\n &-right {\n right: 0px;\n }\n\n &-center {\n left: 50%;\n transform: translateX(-50%);\n }\n }\n\n &-flag {\n box-shadow: var(--card-shadow);\n background: var(--background-modal);\n height: 10px;\n width: 10px;\n position: absolute;\n margin-top: 5px;\n transform: rotate(45deg);\n\n .floatingMenu-anim-flip & {\n top: auto;\n bottom: 0;\n margin-top: 0;\n margin-bottom: 5px;\n }\n\n &-align-right {\n right: 8px;\n }\n\n &-align-left {\n left: 8px;\n }\n\n &-align-center {\n left: 50%;\n transform: translateX(-50%) rotate(45deg);\n }\n }\n }\n\n &-anim {\n transform: scale(0.7);\n opacity: 0.7;\n animation: showMenu 0.1s forwards;\n position: fixed;\n z-index: 1;\n }\n\n @keyframes showMenu {\n to {\n transform: scale(1);\n opacity: 1;\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"floatingMenu.module.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.module.pcss"],"sourcesContent":[".floatingMenu {\n position: relative;\n\n &-content {\n display: flex;\n align-items: stretch;\n height: 100%;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &-container {\n color: var(--text-color);\n font-family: var(--default-font);\n font-size: var(--default-font-size);\n box-shadow: var(--card-shadow);\n background: var(--background-modal);\n padding: 8px;\n border-radius: calc(var(--default-border-radius) + 4px);\n\n /* Positioning lives here rather than on `&-container` itself, so that sheet presentation\n can leave it off instead of having to override it. */\n &-anchored {\n position: absolute;\n margin-top: 10px;\n\n .floatingMenu-anim-flip & {\n top: auto;\n bottom: 0;\n margin-top: 0;\n margin-bottom: 10px;\n }\n }\n\n &-align {\n &-left {\n left: 0px;\n }\n\n &-right {\n right: 0px;\n }\n\n &-center {\n left: 50%;\n transform: translateX(-50%);\n }\n }\n\n &-flag {\n box-shadow: var(--card-shadow);\n background: var(--background-modal);\n height: 10px;\n width: 10px;\n position: absolute;\n margin-top: 5px;\n transform: rotate(45deg);\n\n .floatingMenu-anim-flip & {\n top: auto;\n bottom: 0;\n margin-top: 0;\n margin-bottom: 5px;\n }\n\n &-align-right {\n right: 8px;\n }\n\n &-align-left {\n left: 8px;\n }\n\n &-align-center {\n left: 50%;\n transform: translateX(-50%) rotate(45deg);\n }\n }\n }\n\n &-anim {\n transform: scale(0.7);\n opacity: 0.7;\n animation: showMenu 0.1s forwards;\n position: fixed;\n z-index: 1;\n }\n\n @keyframes showMenu {\n to {\n transform: scale(1);\n opacity: 1;\n }\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- var e=function(e){return e.Left=`left`,e.Right=`right`,e.Center=`center`,e}({});export{e as Align};
1
+ var e=function(e){return e.Default=`default`,e.Sheet=`sheet`,e.Auto=`auto`,e}({}),t=function(e){return e.Left=`left`,e.Right=`right`,e.Center=`center`,e}({});export{t as Align,e as Presentation};
2
2
  //# sourceMappingURL=floatingMenu.types.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"floatingMenu.types.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from \"react\";\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\nexport enum Align {\n Left = 'left',\n Right = 'right',\n Center = 'center',\n}\n\nexport type FloatingMenuSlots = 'root' | 'trigger' | 'menu' | 'menuContainer';\n\nexport interface FloatingMenuProps extends Omit<HtmlProps, 'content'> {\n align?: Align;\n children?: ReactNode;\n content?: ReactNode;\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n dontCloseOnChildClick?: boolean;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<FloatingMenuSlots>;\n styles?: SlotStyles<FloatingMenuSlots>;\n}"],"mappings":"AAGA,IAAY,EAAL,SAAA,EAAA,OACL,GAAA,KAAA,OACA,EAAA,MAAA,QACA,EAAA,OAAA,UACF,EAAA,CAAA,CAAA"}
1
+ {"version":3,"file":"floatingMenu.types.mjs","names":[],"sources":["../../../../package/common/floatingMenu/floatingMenu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from \"react\";\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\n\n/** How a surface is presented on screen. */\nexport enum Presentation {\n /** Wherever the component normally puts it: anchored to its trigger, or centred for a Modal. */\n Default = 'default',\n /** Pinned to the bottom of the screen, full width up to a maximum. */\n Sheet = 'sheet',\n /** A sheet on touch devices with a small screen, anchored everywhere else. */\n Auto = 'auto',\n}\n\nexport enum Align {\n Left = 'left',\n Right = 'right',\n Center = 'center',\n}\n\nexport type FloatingMenuSlots = 'root' | 'trigger' | 'menu' | 'menuContainer' | 'backdrop';\n\nexport interface FloatingMenuProps extends Omit<HtmlProps, 'content'> {\n align?: Align;\n children?: ReactNode;\n content?: ReactNode;\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n dontCloseOnChildClick?: boolean;\n /** Where the menu opens: anchored to the trigger (`Default`), pinned to the bottom of the\n * screen, or the latter only on a small touch screen. */\n presentation?: Presentation;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<FloatingMenuSlots>;\n styles?: SlotStyles<FloatingMenuSlots>;\n}"],"mappings":"AAIA,IAAY,EAAL,SAAA,EAAA,OAEL,GAAA,QAAA,UAEA,EAAA,MAAA,QAEA,EAAA,KAAA,QACF,EAAA,CAAA,CAAA,EAEY,EAAL,SAAA,EAAA,OACL,GAAA,KAAA,OACA,EAAA,MAAA,QACA,EAAA,OAAA,UACF,EAAA,CAAA,CAAA"}
@@ -1,2 +1,2 @@
1
- import{getScrollableAncestors as e,isHiddenByAnyAncestor as t}from"../utils/scrollAncestors.mjs";import{getVisualViewportRect as n}from"../utils/visualViewport.mjs";import{useLayoutEffect as r}from"react";var i=8;function a({isOpen:a,triggerRef:o,anchorRef:s,panelRef:c,flipClassName:l,placement:u=`bottom`}){r(()=>{if(!a)return;let r,d;function f(){let a=o.current,p=s.current;if(!a||!p){r=requestAnimationFrame(f);return}let m=e(a);function h(){let e=a.getBoundingClientRect(),r=c.current?.offsetHeight??0,o=n(),s=o.top+o.height-e.bottom,d=e.top-o.top,f=u===`top`?d:s,h=f<r&&(u===`top`?s:d)>f,g=u===`top`?!h:h;p.classList.toggle(l,h),p.style.top=`${g?e.top-p.offsetHeight:e.bottom}px`,p.style.left=`${e.left}px`;let y=c.current;if(y){let t=y===p?0:y.offsetLeft,n=e.left+t,r=n+y.offsetWidth-(o.left+o.width-i),a=o.left+i-n;r>0?p.style.left=`${e.left-r}px`:a>0&&(p.style.left=`${e.left+a}px`)}p.style.visibility=t(e,m)?`hidden`:``;let b=c.current;b&&!_.has(b)&&v()}let g=new ResizeObserver(()=>h()),_=new Set;function v(){[p,c.current].forEach(e=>{!e||_.has(e)||(_.add(e),g.observe(e))})}h();let y=[window,...m];y.forEach(e=>e.addEventListener(`scroll`,h,{passive:!0})),window.addEventListener(`resize`,h),window.visualViewport?.addEventListener(`resize`,h),window.visualViewport?.addEventListener(`scroll`,h),d=()=>{y.forEach(e=>e.removeEventListener(`scroll`,h)),window.removeEventListener(`resize`,h),window.visualViewport?.removeEventListener(`resize`,h),window.visualViewport?.removeEventListener(`scroll`,h),g.disconnect()}}return f(),()=>{r!==void 0&&cancelAnimationFrame(r),d?.()}},[a,o,s,c,l,u])}export{a as useFloatingPosition};
1
+ import{getScrollableAncestors as e,isHiddenByAnyAncestor as t}from"../utils/scrollAncestors.mjs";import{getVisualViewportRect as n}from"../utils/visualViewport.mjs";import{useLayoutEffect as r}from"react";var i=8;function a({isOpen:a,triggerRef:o,anchorRef:s,panelRef:c,flipClassName:l,placement:u=`bottom`}){r(()=>{if(!a)return;let r,d;function f(){let a=o.current,p=s.current;if(!a||!p){r=requestAnimationFrame(f);return}let m=e(a);function h(){let e=a.getBoundingClientRect(),r=c.current?.offsetHeight??0,o=n(),s=o.top+o.height-e.bottom,d=e.top-o.top,f=u===`top`?d:s,h=f<r&&(u===`top`?s:d)>f,g=u===`top`?!h:h;p.classList.toggle(l,h),p.style.top=`${g?e.top-p.offsetHeight:e.bottom}px`,p.style.left=`${e.left}px`;let y=c.current;if(y){let t=y===p?0:y.offsetLeft,n=e.left+t,r=n+y.offsetWidth-(o.left+o.width-i),a=o.left+i-n;r>0?p.style.left=`${e.left-r}px`:a>0&&(p.style.left=`${e.left+a}px`)}p.style.visibility=t(e,m)?`hidden`:``;let b=c.current;b&&!_.has(b)&&v()}let g=new ResizeObserver(()=>h()),_=new Set;function v(){[p,c.current].forEach(e=>{!e||_.has(e)||(_.add(e),g.observe(e))})}h();let y=[window,...m];y.forEach(e=>e.addEventListener(`scroll`,h,{passive:!0})),window.addEventListener(`resize`,h),window.visualViewport?.addEventListener(`resize`,h),window.visualViewport?.addEventListener(`scroll`,h),d=()=>{y.forEach(e=>e.removeEventListener(`scroll`,h)),window.removeEventListener(`resize`,h),window.visualViewport?.removeEventListener(`resize`,h),window.visualViewport?.removeEventListener(`scroll`,h),g.disconnect(),p.style.top=``,p.style.left=``,p.style.visibility=``,p.classList.remove(l)}}return f(),()=>{r!==void 0&&cancelAnimationFrame(r),d?.()}},[a,o,s,c,l,u])}export{a as useFloatingPosition};
2
2
  //# sourceMappingURL=useFloatingPosition.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { useLayoutEffect, type RefObject } from 'react';\nimport { getScrollableAncestors, isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/** Minimum gap kept between the panel and the viewport edge when horizontally clamped. */\nconst EDGE_MARGIN = 8;\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: tracks the\n * trigger across scroll/resize on every real scrolling ancestor, flips above the trigger\n * when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n * It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS\n * only positions the panel relative to the anchor's own box and has no awareness of where\n * that box actually sits on screen, so a trigger near a screen edge would otherwise let the\n * panel overflow it with no correction.\n *\n * Position/visibility are written straight to the DOM via refs, not through React state:\n * going through setState -> re-render -> commit adds a round-trip that lags behind the\n * browser's own scroll painting by at least a frame.\n */\nexport function useFloatingPosition({ isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement = 'bottom' }: UseFloatingPositionArgs) {\n useLayoutEffect(() => {\n if (!isOpen) return;\n\n let rafId: number | undefined;\n let teardown: (() => void) | undefined;\n\n // The anchor/trigger may not be mounted yet on the very first invocation of this\n // effect: a portal target (e.g. BodyEnd's `#bodyEnd` div) can still be missing on\n // the initial render, in which case the portaled content — and this ref — commits\n // one render later. Since refs never change identity, that later commit doesn't\n // re-trigger this effect on its own, so retry on the next frame until it's there.\n function trySetup() {\n const trigger = triggerRef.current;\n const anchor = anchorRef.current;\n if (!trigger || !anchor) {\n rafId = requestAnimationFrame(trySetup);\n return;\n }\n const ancestors = getScrollableAncestors(trigger);\n\n function updatePos() {\n const rect = trigger!.getBoundingClientRect();\n const panelHeight = panelRef.current?.offsetHeight ?? 0;\n // The visible area, not the full layout viewport — shrinks on mobile when a keyboard is\n // open, so flip/clamp react to what's actually on screen instead of the keyboard hiding\n // a panel that \"fit\" against the unshrunk layout viewport.\n const vv = getVisualViewportRect();\n const spaceBelow = vv.top + vv.height - rect.bottom;\n const spaceAbove = rect.top - vv.top;\n const preferredSpace = placement === 'top' ? spaceAbove : spaceBelow;\n const alternateSpace = placement === 'top' ? spaceBelow : spaceAbove;\n const flip = preferredSpace < panelHeight && alternateSpace > preferredSpace;\n const renderAbove = placement === 'top' ? !flip : flip;\n anchor!.classList.toggle(flipClassName, flip);\n // Shift up by the anchor's own height when rendering above, so this works whether\n // the anchor is a zero-height decorative wrapper (FloatingMenu, whose real panel\n // hangs off it via absolute-positioned CSS) or the visible panel itself\n // (Dropdown) — for the former the shift is a no-op (height 0).\n anchor!.style.top = `${renderAbove ? rect.top - anchor!.offsetHeight : rect.bottom}px`;\n anchor!.style.left = `${rect.left}px`;\n\n // Horizontal clamp: shift the anchor so the panel stays within the viewport, since\n // `align` CSS only positions it relative to the anchor's own box. Use offsetWidth/\n // offsetLeft (untransformed layout geometry), not getBoundingClientRect — both this\n // anchor and Dropdown's animate in via a CSS `transform: scale(...)`, which\n // getBoundingClientRect reflects but the box-model offsets don't, so measuring via\n // the transformed rect would under- or over-correct while that entrance animation runs.\n const panelForClamp = panelRef.current;\n if (panelForClamp) {\n const relativeLeft = panelForClamp === anchor ? 0 : panelForClamp.offsetLeft;\n const panelLeft = rect.left + relativeLeft;\n const panelRight = panelLeft + panelForClamp.offsetWidth;\n const overflowRight = panelRight - (vv.left + vv.width - EDGE_MARGIN);\n const overflowLeft = vv.left + EDGE_MARGIN - panelLeft;\n if (overflowRight > 0) {\n anchor!.style.left = `${rect.left - overflowRight}px`;\n } else if (overflowLeft > 0) {\n anchor!.style.left = `${rect.left + overflowLeft}px`;\n }\n }\n\n anchor!.style.visibility = isHiddenByAnyAncestor(rect, ancestors) ? 'hidden' : '';\n // The panel can mount a commit later than the anchor; once it's observed this\n // is a single Set lookup, so it costs nothing on the scroll path.\n const panel = panelRef.current;\n if (panel && !observed.has(panel)) observeSizeTargets();\n }\n\n // The panel's own height feeds both the flip decision and, when rendering above,\n // the top offset — so a popup whose content changes size while open (a filtered\n // list shrinking, an async list loading in) has to be re-measured, or it keeps a\n // top computed for its old height and ends up detached from the trigger.\n const resizeObserver = new ResizeObserver(() => updatePos());\n const observed = new Set<Element>();\n function observeSizeTargets() {\n // Both, since they're the same element for a panel-as-anchor consumer (Dropdown)\n // but not for a zero-height wrapper whose content sits inside it (FloatingMenu).\n // Called from updatePos too: the panel can mount a commit later than the anchor.\n [anchor, panelRef.current].forEach((el) => {\n if (!el || observed.has(el)) return;\n observed.add(el);\n resizeObserver.observe(el);\n });\n }\n\n updatePos();\n\n const scrollTargets: (Window | HTMLElement)[] = [window, ...ancestors];\n scrollTargets.forEach((t) => t.addEventListener('scroll', updatePos, { passive: true }));\n window.addEventListener('resize', updatePos);\n // `window.resize` doesn't reliably fire when a mobile keyboard opens/closes — visualViewport\n // does, and is what the space/clamp math above is measured against.\n window.visualViewport?.addEventListener('resize', updatePos);\n window.visualViewport?.addEventListener('scroll', updatePos);\n teardown = () => {\n scrollTargets.forEach((t) => t.removeEventListener('scroll', updatePos));\n window.removeEventListener('resize', updatePos);\n window.visualViewport?.removeEventListener('resize', updatePos);\n window.visualViewport?.removeEventListener('scroll', updatePos);\n resizeObserver.disconnect();\n };\n }\n\n trySetup();\n\n return () => {\n if (rafId !== undefined) cancelAnimationFrame(rafId);\n teardown?.();\n };\n }, [isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement]);\n}"],"mappings":"6MAmBA,IAAM,EAAc,EAgBpB,SAAgB,EAAoB,CAAE,SAAQ,aAAY,YAAW,WAAU,gBAAe,YAAY,UAAqC,CAC7I,MAAsB,CACpB,GAAI,CAAC,EAAQ,OAEb,IAAI,EACA,EAOJ,SAAS,GAAW,CAClB,IAAM,EAAU,EAAW,QACrB,EAAS,EAAU,QACzB,GAAI,CAAC,GAAW,CAAC,EAAQ,CACvB,EAAQ,sBAAsB,CAAQ,EACtC,MACF,CACA,IAAM,EAAY,EAAuB,CAAO,EAEhD,SAAS,GAAY,CACnB,IAAM,EAAO,EAAS,sBAAsB,EACtC,EAAc,EAAS,SAAS,cAAgB,EAIhD,EAAK,EAAsB,EAC3B,EAAa,EAAG,IAAM,EAAG,OAAS,EAAK,OACvC,EAAa,EAAK,IAAM,EAAG,IAC3B,EAAiB,IAAc,MAAQ,EAAa,EAEpD,EAAO,EAAiB,IADP,IAAc,MAAQ,EAAa,GACI,EACxD,EAAc,IAAc,MAAQ,CAAC,EAAO,EAClD,EAAQ,UAAU,OAAO,EAAe,CAAI,EAK5C,EAAQ,MAAM,IAAM,GAAG,EAAc,EAAK,IAAM,EAAQ,aAAe,EAAK,OAAO,IACnF,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAK,IAQlC,IAAM,EAAgB,EAAS,QAC/B,GAAI,EAAe,CACjB,IAAM,EAAe,IAAkB,EAAS,EAAI,EAAc,WAC5D,EAAY,EAAK,KAAO,EAExB,EADa,EAAY,EAAc,aACT,EAAG,KAAO,EAAG,MAAQ,GACnD,EAAe,EAAG,KAAO,EAAc,EACzC,EAAgB,EAClB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAc,IACzC,EAAe,IACxB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAa,IAErD,CAEA,EAAQ,MAAM,WAAa,EAAsB,EAAM,CAAS,EAAI,SAAW,GAG/E,IAAM,EAAQ,EAAS,QACnB,GAAS,CAAC,EAAS,IAAI,CAAK,GAAG,EAAmB,CACxD,CAMA,IAAM,EAAiB,IAAI,mBAAqB,EAAU,CAAC,EACrD,EAAW,IAAI,IACrB,SAAS,GAAqB,CAI5B,CAAC,EAAQ,EAAS,OAAO,EAAE,QAAS,GAAO,CACrC,CAAC,GAAM,EAAS,IAAI,CAAE,IAC1B,EAAS,IAAI,CAAE,EACf,EAAe,QAAQ,CAAE,EAC3B,CAAC,CACH,CAEA,EAAU,EAEV,IAAM,EAA0C,CAAC,OAAQ,GAAG,CAAS,EACrE,EAAc,QAAS,GAAM,EAAE,iBAAiB,SAAU,EAAW,CAAE,QAAS,EAAK,CAAC,CAAC,EACvF,OAAO,iBAAiB,SAAU,CAAS,EAG3C,OAAO,gBAAgB,iBAAiB,SAAU,CAAS,EAC3D,OAAO,gBAAgB,iBAAiB,SAAU,CAAS,EAC3D,MAAiB,CACf,EAAc,QAAS,GAAM,EAAE,oBAAoB,SAAU,CAAS,CAAC,EACvE,OAAO,oBAAoB,SAAU,CAAS,EAC9C,OAAO,gBAAgB,oBAAoB,SAAU,CAAS,EAC9D,OAAO,gBAAgB,oBAAoB,SAAU,CAAS,EAC9D,EAAe,WAAW,CAC5B,CACF,CAIA,OAFA,EAAS,MAEI,CACP,IAAU,IAAA,IAAW,qBAAqB,CAAK,EACnD,IAAW,CACb,CACF,EAAG,CAAC,EAAQ,EAAY,EAAW,EAAU,EAAe,CAAS,CAAC,CACxE"}
1
+ {"version":3,"file":"useFloatingPosition.mjs","names":[],"sources":["../../../../package/common/floatingMenu/useFloatingPosition.ts"],"sourcesContent":["import { useLayoutEffect, type RefObject } from 'react';\nimport { getScrollableAncestors, isHiddenByAnyAncestor } from 'components/common/utils/scrollAncestors';\nimport { getVisualViewportRect } from 'components/common/utils/visualViewport';\n\nexport interface UseFloatingPositionArgs {\n isOpen: boolean;\n /** The element the popup is anchored to. */\n triggerRef: RefObject<HTMLElement | null>;\n /** The `position: fixed` element that gets `top`/`left`/`visibility` written to it directly. */\n anchorRef: RefObject<HTMLElement | null>;\n /** The visible panel whose height decides whether there's room to render on the preferred side. */\n panelRef: RefObject<HTMLElement | null>;\n /** Class toggled on `anchorRef` when flipped to the non-preferred side. */\n flipClassName: string;\n /** Preferred side relative to the trigger (default `'bottom'`) — flips to the other side when there's no room. */\n placement?: 'top' | 'bottom';\n}\n\n/** Minimum gap kept between the panel and the viewport edge when horizontally clamped. */\nconst EDGE_MARGIN = 8;\n\n/**\n * Keeps a portaled, `position: fixed` popup anchored to a trigger element: tracks the\n * trigger across scroll/resize on every real scrolling ancestor, flips above the trigger\n * when there's no room below, and hides (not closes) the popup when the trigger itself\n * scrolls behind a clipping ancestor — matching Floating UI's autoUpdate + hide middleware.\n * It also shifts the popup horizontally to stay within the viewport: `align`/RTL-style CSS\n * only positions the panel relative to the anchor's own box and has no awareness of where\n * that box actually sits on screen, so a trigger near a screen edge would otherwise let the\n * panel overflow it with no correction.\n *\n * Position/visibility are written straight to the DOM via refs, not through React state:\n * going through setState -> re-render -> commit adds a round-trip that lags behind the\n * browser's own scroll painting by at least a frame.\n */\nexport function useFloatingPosition({ isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement = 'bottom' }: UseFloatingPositionArgs) {\n useLayoutEffect(() => {\n if (!isOpen) return;\n\n let rafId: number | undefined;\n let teardown: (() => void) | undefined;\n\n // The anchor/trigger may not be mounted yet on the very first invocation of this\n // effect: a portal target (e.g. BodyEnd's `#bodyEnd` div) can still be missing on\n // the initial render, in which case the portaled content — and this ref — commits\n // one render later. Since refs never change identity, that later commit doesn't\n // re-trigger this effect on its own, so retry on the next frame until it's there.\n function trySetup() {\n const trigger = triggerRef.current;\n const anchor = anchorRef.current;\n if (!trigger || !anchor) {\n rafId = requestAnimationFrame(trySetup);\n return;\n }\n const ancestors = getScrollableAncestors(trigger);\n\n function updatePos() {\n const rect = trigger!.getBoundingClientRect();\n const panelHeight = panelRef.current?.offsetHeight ?? 0;\n // The visible area, not the full layout viewport — shrinks on mobile when a keyboard is\n // open, so flip/clamp react to what's actually on screen instead of the keyboard hiding\n // a panel that \"fit\" against the unshrunk layout viewport.\n const vv = getVisualViewportRect();\n const spaceBelow = vv.top + vv.height - rect.bottom;\n const spaceAbove = rect.top - vv.top;\n const preferredSpace = placement === 'top' ? spaceAbove : spaceBelow;\n const alternateSpace = placement === 'top' ? spaceBelow : spaceAbove;\n const flip = preferredSpace < panelHeight && alternateSpace > preferredSpace;\n const renderAbove = placement === 'top' ? !flip : flip;\n anchor!.classList.toggle(flipClassName, flip);\n // Shift up by the anchor's own height when rendering above, so this works whether\n // the anchor is a zero-height decorative wrapper (FloatingMenu, whose real panel\n // hangs off it via absolute-positioned CSS) or the visible panel itself\n // (Dropdown) — for the former the shift is a no-op (height 0).\n anchor!.style.top = `${renderAbove ? rect.top - anchor!.offsetHeight : rect.bottom}px`;\n anchor!.style.left = `${rect.left}px`;\n\n // Horizontal clamp: shift the anchor so the panel stays within the viewport, since\n // `align` CSS only positions it relative to the anchor's own box. Use offsetWidth/\n // offsetLeft (untransformed layout geometry), not getBoundingClientRect — both this\n // anchor and Dropdown's animate in via a CSS `transform: scale(...)`, which\n // getBoundingClientRect reflects but the box-model offsets don't, so measuring via\n // the transformed rect would under- or over-correct while that entrance animation runs.\n const panelForClamp = panelRef.current;\n if (panelForClamp) {\n const relativeLeft = panelForClamp === anchor ? 0 : panelForClamp.offsetLeft;\n const panelLeft = rect.left + relativeLeft;\n const panelRight = panelLeft + panelForClamp.offsetWidth;\n const overflowRight = panelRight - (vv.left + vv.width - EDGE_MARGIN);\n const overflowLeft = vv.left + EDGE_MARGIN - panelLeft;\n if (overflowRight > 0) {\n anchor!.style.left = `${rect.left - overflowRight}px`;\n } else if (overflowLeft > 0) {\n anchor!.style.left = `${rect.left + overflowLeft}px`;\n }\n }\n\n anchor!.style.visibility = isHiddenByAnyAncestor(rect, ancestors) ? 'hidden' : '';\n // The panel can mount a commit later than the anchor; once it's observed this\n // is a single Set lookup, so it costs nothing on the scroll path.\n const panel = panelRef.current;\n if (panel && !observed.has(panel)) observeSizeTargets();\n }\n\n // The panel's own height feeds both the flip decision and, when rendering above,\n // the top offset — so a popup whose content changes size while open (a filtered\n // list shrinking, an async list loading in) has to be re-measured, or it keeps a\n // top computed for its old height and ends up detached from the trigger.\n const resizeObserver = new ResizeObserver(() => updatePos());\n const observed = new Set<Element>();\n function observeSizeTargets() {\n // Both, since they're the same element for a panel-as-anchor consumer (Dropdown)\n // but not for a zero-height wrapper whose content sits inside it (FloatingMenu).\n // Called from updatePos too: the panel can mount a commit later than the anchor.\n [anchor, panelRef.current].forEach((el) => {\n if (!el || observed.has(el)) return;\n observed.add(el);\n resizeObserver.observe(el);\n });\n }\n\n updatePos();\n\n const scrollTargets: (Window | HTMLElement)[] = [window, ...ancestors];\n scrollTargets.forEach((t) => t.addEventListener('scroll', updatePos, { passive: true }));\n window.addEventListener('resize', updatePos);\n // `window.resize` doesn't reliably fire when a mobile keyboard opens/closes — visualViewport\n // does, and is what the space/clamp math above is measured against.\n window.visualViewport?.addEventListener('resize', updatePos);\n window.visualViewport?.addEventListener('scroll', updatePos);\n teardown = () => {\n scrollTargets.forEach((t) => t.removeEventListener('scroll', updatePos));\n window.removeEventListener('resize', updatePos);\n window.visualViewport?.removeEventListener('resize', updatePos);\n window.visualViewport?.removeEventListener('scroll', updatePos);\n resizeObserver.disconnect();\n // Positioning is written as inline styles, which outrank any class the popup might switch\n // to while it stays mounted — a popup turning into a bottom sheet (`useSheet`) would keep\n // the coordinates computed for its anchored self. Hand the element back as we found it.\n anchor!.style.top = '';\n anchor!.style.left = '';\n anchor!.style.visibility = '';\n anchor!.classList.remove(flipClassName);\n };\n }\n\n trySetup();\n\n return () => {\n if (rafId !== undefined) cancelAnimationFrame(rafId);\n teardown?.();\n };\n }, [isOpen, triggerRef, anchorRef, panelRef, flipClassName, placement]);\n}"],"mappings":"6MAmBA,IAAM,EAAc,EAgBpB,SAAgB,EAAoB,CAAE,SAAQ,aAAY,YAAW,WAAU,gBAAe,YAAY,UAAqC,CAC7I,MAAsB,CACpB,GAAI,CAAC,EAAQ,OAEb,IAAI,EACA,EAOJ,SAAS,GAAW,CAClB,IAAM,EAAU,EAAW,QACrB,EAAS,EAAU,QACzB,GAAI,CAAC,GAAW,CAAC,EAAQ,CACvB,EAAQ,sBAAsB,CAAQ,EACtC,MACF,CACA,IAAM,EAAY,EAAuB,CAAO,EAEhD,SAAS,GAAY,CACnB,IAAM,EAAO,EAAS,sBAAsB,EACtC,EAAc,EAAS,SAAS,cAAgB,EAIhD,EAAK,EAAsB,EAC3B,EAAa,EAAG,IAAM,EAAG,OAAS,EAAK,OACvC,EAAa,EAAK,IAAM,EAAG,IAC3B,EAAiB,IAAc,MAAQ,EAAa,EAEpD,EAAO,EAAiB,IADP,IAAc,MAAQ,EAAa,GACI,EACxD,EAAc,IAAc,MAAQ,CAAC,EAAO,EAClD,EAAQ,UAAU,OAAO,EAAe,CAAI,EAK5C,EAAQ,MAAM,IAAM,GAAG,EAAc,EAAK,IAAM,EAAQ,aAAe,EAAK,OAAO,IACnF,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAK,IAQlC,IAAM,EAAgB,EAAS,QAC/B,GAAI,EAAe,CACjB,IAAM,EAAe,IAAkB,EAAS,EAAI,EAAc,WAC5D,EAAY,EAAK,KAAO,EAExB,EADa,EAAY,EAAc,aACT,EAAG,KAAO,EAAG,MAAQ,GACnD,EAAe,EAAG,KAAO,EAAc,EACzC,EAAgB,EAClB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAc,IACzC,EAAe,IACxB,EAAQ,MAAM,KAAO,GAAG,EAAK,KAAO,EAAa,IAErD,CAEA,EAAQ,MAAM,WAAa,EAAsB,EAAM,CAAS,EAAI,SAAW,GAG/E,IAAM,EAAQ,EAAS,QACnB,GAAS,CAAC,EAAS,IAAI,CAAK,GAAG,EAAmB,CACxD,CAMA,IAAM,EAAiB,IAAI,mBAAqB,EAAU,CAAC,EACrD,EAAW,IAAI,IACrB,SAAS,GAAqB,CAI5B,CAAC,EAAQ,EAAS,OAAO,EAAE,QAAS,GAAO,CACrC,CAAC,GAAM,EAAS,IAAI,CAAE,IAC1B,EAAS,IAAI,CAAE,EACf,EAAe,QAAQ,CAAE,EAC3B,CAAC,CACH,CAEA,EAAU,EAEV,IAAM,EAA0C,CAAC,OAAQ,GAAG,CAAS,EACrE,EAAc,QAAS,GAAM,EAAE,iBAAiB,SAAU,EAAW,CAAE,QAAS,EAAK,CAAC,CAAC,EACvF,OAAO,iBAAiB,SAAU,CAAS,EAG3C,OAAO,gBAAgB,iBAAiB,SAAU,CAAS,EAC3D,OAAO,gBAAgB,iBAAiB,SAAU,CAAS,EAC3D,MAAiB,CACf,EAAc,QAAS,GAAM,EAAE,oBAAoB,SAAU,CAAS,CAAC,EACvE,OAAO,oBAAoB,SAAU,CAAS,EAC9C,OAAO,gBAAgB,oBAAoB,SAAU,CAAS,EAC9D,OAAO,gBAAgB,oBAAoB,SAAU,CAAS,EAC9D,EAAe,WAAW,EAI1B,EAAQ,MAAM,IAAM,GACpB,EAAQ,MAAM,KAAO,GACrB,EAAQ,MAAM,WAAa,GAC3B,EAAQ,UAAU,OAAO,CAAa,CACxC,CACF,CAIA,OAFA,EAAS,MAEI,CACP,IAAU,IAAA,IAAW,qBAAqB,CAAK,EACnD,IAAW,CACb,CACF,EAAG,CAAC,EAAQ,EAAY,EAAW,EAAU,EAAe,CAAS,CAAC,CACxE"}
@@ -1,2 +1,2 @@
1
- import{useSyncExternalStore as e}from"react";var t=`(pointer: coarse)`;function n(){return typeof window<`u`&&typeof window.matchMedia==`function`}function r(e){if(!n())return()=>{};let r=window.matchMedia(t);return r.addEventListener(`change`,e),()=>r.removeEventListener(`change`,e)}function i(){return n()&&window.matchMedia(t).matches}function a(){return!1}function o(){return e(r,i,a)}export{o as default};
1
+ import e from"./useMediaQuery.mjs";function t(){return e(`(pointer: coarse)`)}export{t as default};
2
2
  //# sourceMappingURL=useCoarsePointer.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"useCoarsePointer.mjs","names":[],"sources":["../../../../package/common/hooks/useCoarsePointer.ts"],"sourcesContent":["import { useSyncExternalStore } from 'react';\n\nconst COARSE_POINTER_QUERY = '(pointer: coarse)';\n\nfunction supported(): boolean {\n return typeof window !== 'undefined' && typeof window.matchMedia === 'function';\n}\n\nfunction subscribe(onChange: () => void): () => void {\n if (!supported()) return () => {};\n const mql = window.matchMedia(COARSE_POINTER_QUERY);\n mql.addEventListener('change', onChange);\n return () => mql.removeEventListener('change', onChange);\n}\n\nfunction getSnapshot(): boolean {\n return supported() && window.matchMedia(COARSE_POINTER_QUERY).matches;\n}\n\n/** No media query exists on the server, so the tree renders as if the pointer were fine. */\nfunction getServerSnapshot(): boolean {\n return false;\n}\n\n/**\n * `true` when the primary pointing device is coarse (touch), kept current so a device that\n * switches input modes re-renders.\n *\n * `useSyncExternalStore` rather than `useState` + `useEffect`: callers pick *markup* with this,\n * so hydration has to start from the server's answer. Reading `matchMedia` in a `useState`\n * initialiser makes the client's first render disagree with the server's HTML.\n */\nexport function useCoarsePointer(): boolean {\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\nexport default useCoarsePointer;\n"],"mappings":"6CAEA,IAAM,EAAuB,oBAE7B,SAAS,GAAqB,CAC5B,OAAO,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,UACvE,CAEA,SAAS,EAAU,EAAkC,CACnD,GAAI,CAAC,EAAU,EAAG,UAAa,CAAC,EAChC,IAAM,EAAM,OAAO,WAAW,CAAoB,EAElD,OADA,EAAI,iBAAiB,SAAU,CAAQ,MAC1B,EAAI,oBAAoB,SAAU,CAAQ,CACzD,CAEA,SAAS,GAAuB,CAC9B,OAAO,EAAU,GAAK,OAAO,WAAW,CAAoB,EAAE,OAChE,CAGA,SAAS,GAA6B,CACpC,MAAO,EACT,CAUA,SAAgB,GAA4B,CAC1C,OAAO,EAAqB,EAAW,EAAa,CAAiB,CACvE"}
1
+ {"version":3,"file":"useCoarsePointer.mjs","names":[],"sources":["../../../../package/common/hooks/useCoarsePointer.ts"],"sourcesContent":["import { useMediaQuery } from './useMediaQuery';\n\n/** `true` when the primary pointing device is coarse (touch). */\nexport function useCoarsePointer(): boolean {\n return useMediaQuery('(pointer: coarse)');\n}\n\nexport default useCoarsePointer;\n"],"mappings":"mCAGA,SAAgB,GAA4B,CAC1C,OAAO,EAAc,mBAAmB,CAC1C"}
@@ -0,0 +1,2 @@
1
+ import{useCallback as e,useSyncExternalStore as t}from"react";function n(){return typeof window<`u`&&typeof window.matchMedia==`function`}function r(r){return t(e(e=>{if(!n())return()=>{};let t=window.matchMedia(r);return t.addEventListener(`change`,e),()=>t.removeEventListener(`change`,e)},[r]),e(()=>n()&&window.matchMedia(r).matches,[r]),e(()=>!1,[]))}export{r as default};
2
+ //# sourceMappingURL=useMediaQuery.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useMediaQuery.mjs","names":[],"sources":["../../../../package/common/hooks/useMediaQuery.ts"],"sourcesContent":["import { useCallback, useSyncExternalStore } from 'react';\n\nfunction supported(): boolean {\n return typeof window !== 'undefined' && typeof window.matchMedia === 'function';\n}\n\n/**\n * `true` while `query` matches, kept current so a resize or an input-mode change re-renders.\n *\n * `useSyncExternalStore` rather than `useState` + `useEffect`: callers pick *markup* with this,\n * so hydration has to start from the server's answer. Reading `matchMedia` in a `useState`\n * initialiser makes the client's first render disagree with the server's HTML.\n */\nexport function useMediaQuery(query: string): boolean {\n const subscribe = useCallback((onChange: () => void) => {\n if (!supported()) return () => {};\n const mql = window.matchMedia(query);\n mql.addEventListener('change', onChange);\n return () => mql.removeEventListener('change', onChange);\n }, [query]);\n\n const getSnapshot = useCallback(() => supported() && window.matchMedia(query).matches, [query]);\n\n /** No media query exists on the server, so the tree renders as if nothing matched. */\n const getServerSnapshot = useCallback(() => false, []);\n\n return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);\n}\n\nexport default useMediaQuery;\n"],"mappings":"8DAEA,SAAS,GAAqB,CAC5B,OAAO,OAAO,OAAW,KAAe,OAAO,OAAO,YAAe,UACvE,CASA,SAAgB,EAAc,EAAwB,CAapD,OAAO,EAZW,EAAa,GAAyB,CACtD,GAAI,CAAC,EAAU,EAAG,UAAa,CAAC,EAChC,IAAM,EAAM,OAAO,WAAW,CAAK,EAEnC,OADA,EAAI,iBAAiB,SAAU,CAAQ,MAC1B,EAAI,oBAAoB,SAAU,CAAQ,CACzD,EAAG,CAAC,CAAK,CAOmB,EALR,MAAkB,EAAU,GAAK,OAAO,WAAW,CAAK,EAAE,QAAS,CAAC,CAAK,CAKtD,EAFb,MAAkB,GAAO,CAAC,CAEA,CAAiB,CACvE"}
@@ -0,0 +1,2 @@
1
+ import{tabbablesIn as e}from"./useFocusBoundary.mjs";import{useEffect as t,useRef as n}from"react";function r({isActive:r,containerRef:o,onEscape:s,trapFocus:c=!0,lockScroll:d=!0}){let f=n(s);t(()=>{f.current=s});let p=n(0);r&&p.current===0&&(p.current=i++),!r&&p.current!==0&&(p.current=0),t(()=>{if(!r)return;let t=p.current;a.add(t);let n=()=>t===Math.max(...a),i=document.activeElement;if(c){let t=o.current;(e(t)[0]??t)?.focus()}function s(t){if(!n())return;if(t.key===`Escape`&&f.current){t.preventDefault(),f.current();return}if(t.key!==`Tab`||!c)return;let r=e(o.current);if(r.length===0){t.preventDefault();return}let i=r[0],a=r[r.length-1],s=document.activeElement;o.current?.contains(s)?!t.shiftKey&&s===a?(t.preventDefault(),i.focus()):t.shiftKey&&s===i&&(t.preventDefault(),a.focus()):(t.preventDefault(),i.focus())}return window.addEventListener(`keydown`,s),d&&l(),()=>{window.removeEventListener(`keydown`,s),d&&u(),a.delete(t),c&&i?.focus()}},[r,c,d,o])}var i=1,a=new Set,o=0,s=``,c=``;function l(){let{body:e}=document;if(o===0){s=e.style.overflow,c=e.style.paddingRight;let t=window.innerWidth-document.documentElement.clientWidth;if(t>0){let n=parseFloat(window.getComputedStyle(e).paddingRight)||0;e.style.paddingRight=`${n+t}px`}e.style.overflow=`hidden`}o+=1}function u(){--o,!(o>0)&&(o=0,document.body.style.overflow=s,document.body.style.paddingRight=c)}export{r as useOverlay};
2
+ //# sourceMappingURL=useOverlay.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useOverlay.mjs","names":[],"sources":["../../../../package/common/hooks/useOverlay.ts"],"sourcesContent":["import { useEffect, useRef, type RefObject } from 'react';\nimport { tabbablesIn } from './useFocusBoundary';\n\nexport interface UseOverlayArgs {\n /** Whether the overlay is currently visible. Everything below is set up while this is true. */\n isActive: boolean;\n /** The overlay panel. Focus is trapped inside it and Escape is scoped to it. */\n containerRef: RefObject<HTMLElement | null>;\n /** Called when Escape is pressed while this is the topmost overlay. Omit to not handle Escape. */\n onEscape?: () => void;\n /** Keep Tab inside the panel and restore focus to the previously focused element on close. */\n trapFocus?: boolean;\n /** Prevent the page behind the overlay from scrolling. */\n lockScroll?: boolean;\n}\n\n/**\n * The three behaviours every blocking overlay needs: Escape to dismiss, a focus trap, and a\n * scroll lock on the page behind it.\n *\n * They share one module-level stack because they share one question: overlays nest (a\n * ConfirmModal opened from inside a Modal), every instance listens on `document`, and only the\n * innermost one may react. Without the stack, Escape would close every open layer at once and\n * the outer trap would yank focus out of the inner panel on the next Tab.\n *\n * The scroll lock is reference-counted for the same reason: the page stays locked until the last\n * overlay closes, and the body's original inline styles are restored rather than cleared.\n */\nexport function useOverlay({\n isActive,\n containerRef,\n onEscape,\n trapFocus = true,\n lockScroll = true,\n}: UseOverlayArgs) {\n const onEscapeRef = useRef(onEscape);\n useEffect(() => { onEscapeRef.current = onEscape; });\n\n // The layer's position in the stack is claimed during render, not in the effect below, because\n // effects run child-first: an overlay opened from *inside* another one (a menu in a modal) has\n // its effect run before its own parent's and would come out as the lower layer. Render runs\n // parent-first, which is the order the layers are actually nested in. DOM order is no help\n // either — React commits the inner portal ahead of the outer one.\n const orderRef = useRef(0);\n if (isActive && orderRef.current === 0) orderRef.current = nextLayerOrder++;\n if (!isActive && orderRef.current !== 0) orderRef.current = 0;\n\n useEffect(() => {\n if (!isActive) return;\n\n const order = orderRef.current;\n activeLayers.add(order);\n const isTopmost = () => order === Math.max(...activeLayers);\n\n const previouslyFocused = document.activeElement as HTMLElement | null;\n if (trapFocus) {\n const container = containerRef.current;\n (tabbablesIn(container)[0] ?? container)?.focus();\n }\n\n function onKeyDown(event: KeyboardEvent) {\n if (!isTopmost()) return;\n\n if (event.key === 'Escape' && onEscapeRef.current) {\n event.preventDefault();\n onEscapeRef.current();\n return;\n }\n\n if (event.key !== 'Tab' || !trapFocus) return;\n const focusables = tabbablesIn(containerRef.current);\n // Nothing to move to inside the panel, but Tab must still not escape it.\n if (focusables.length === 0) {\n event.preventDefault();\n return;\n }\n const first = focusables[0];\n const last = focusables[focusables.length - 1];\n const active = document.activeElement;\n if (!containerRef.current?.contains(active)) {\n event.preventDefault();\n first.focus();\n } else if (!event.shiftKey && active === last) {\n event.preventDefault();\n first.focus();\n } else if (event.shiftKey && active === first) {\n event.preventDefault();\n last.focus();\n }\n }\n\n // `window`, not `document`: a key event on a focused element reaches both, but a synthetic\n // one dispatched straight at `window` (as tests and some consumers do) never reaches\n // `document`, since it sits above it in the propagation path.\n window.addEventListener('keydown', onKeyDown);\n if (lockScroll) acquireScrollLock();\n\n return () => {\n window.removeEventListener('keydown', onKeyDown);\n if (lockScroll) releaseScrollLock();\n activeLayers.delete(order);\n if (trapFocus) previouslyFocused?.focus();\n };\n }, [isActive, trapFocus, lockScroll, containerRef]);\n}\n\n/** Monotonic, so a layer opened later always outranks one opened earlier. */\nlet nextLayerOrder = 1;\nconst activeLayers = new Set<number>();\n\nlet scrollLockCount = 0;\nlet previousOverflow = '';\nlet previousPaddingRight = '';\n\nfunction acquireScrollLock() {\n const { body } = document;\n if (scrollLockCount === 0) {\n previousOverflow = body.style.overflow;\n previousPaddingRight = body.style.paddingRight;\n // Removing the page's scrollbar reclaims its width, so everything behind the overlay would\n // shift right by that amount without the compensating padding.\n const scrollbarWidth = window.innerWidth - document.documentElement.clientWidth;\n if (scrollbarWidth > 0) {\n const current = parseFloat(window.getComputedStyle(body).paddingRight) || 0;\n body.style.paddingRight = `${current + scrollbarWidth}px`;\n }\n body.style.overflow = 'hidden';\n }\n scrollLockCount += 1;\n}\n\nfunction releaseScrollLock() {\n scrollLockCount -= 1;\n if (scrollLockCount > 0) return;\n scrollLockCount = 0;\n document.body.style.overflow = previousOverflow;\n document.body.style.paddingRight = previousPaddingRight;\n}\n"],"mappings":"mGA4BA,SAAgB,EAAW,CACzB,WACA,eACA,WACA,YAAY,GACZ,aAAa,IACI,CACjB,IAAM,EAAc,EAAO,CAAQ,EACnC,MAAgB,CAAE,EAAY,QAAU,CAAU,CAAC,EAOnD,IAAM,EAAW,EAAO,CAAC,EACrB,GAAY,EAAS,UAAY,IAAG,EAAS,QAAU,KACvD,CAAC,GAAY,EAAS,UAAY,IAAG,EAAS,QAAU,GAE5D,MAAgB,CACd,GAAI,CAAC,EAAU,OAEf,IAAM,EAAQ,EAAS,QACvB,EAAa,IAAI,CAAK,EACtB,IAAM,MAAkB,IAAU,KAAK,IAAI,GAAG,CAAY,EAEpD,EAAoB,SAAS,cACnC,GAAI,EAAW,CACb,IAAM,EAAY,EAAa,SAC9B,EAAY,CAAS,EAAE,IAAM,IAAY,MAAM,CAClD,CAEA,SAAS,EAAU,EAAsB,CACvC,GAAI,CAAC,EAAU,EAAG,OAElB,GAAI,EAAM,MAAQ,UAAY,EAAY,QAAS,CACjD,EAAM,eAAe,EACrB,EAAY,QAAQ,EACpB,MACF,CAEA,GAAI,EAAM,MAAQ,OAAS,CAAC,EAAW,OACvC,IAAM,EAAa,EAAY,EAAa,OAAO,EAEnD,GAAI,EAAW,SAAW,EAAG,CAC3B,EAAM,eAAe,EACrB,MACF,CACA,IAAM,EAAQ,EAAW,GACnB,EAAO,EAAW,EAAW,OAAS,GACtC,EAAS,SAAS,cACnB,EAAa,SAAS,SAAS,CAAM,EAG/B,CAAC,EAAM,UAAY,IAAW,GACvC,EAAM,eAAe,EACrB,EAAM,MAAM,GACH,EAAM,UAAY,IAAW,IACtC,EAAM,eAAe,EACrB,EAAK,MAAM,IAPX,EAAM,eAAe,EACrB,EAAM,MAAM,EAQhB,CAQA,OAHA,OAAO,iBAAiB,UAAW,CAAS,EACxC,GAAY,EAAkB,MAErB,CACX,OAAO,oBAAoB,UAAW,CAAS,EAC3C,GAAY,EAAkB,EAClC,EAAa,OAAO,CAAK,EACrB,GAAW,GAAmB,MAAM,CAC1C,CACF,EAAG,CAAC,EAAU,EAAW,EAAY,CAAY,CAAC,CACpD,CAGA,IAAI,EAAiB,EACf,EAAe,IAAI,IAErB,EAAkB,EAClB,EAAmB,GACnB,EAAuB,GAE3B,SAAS,GAAoB,CAC3B,GAAM,CAAE,QAAS,SACjB,GAAI,IAAoB,EAAG,CACzB,EAAmB,EAAK,MAAM,SAC9B,EAAuB,EAAK,MAAM,aAGlC,IAAM,EAAiB,OAAO,WAAa,SAAS,gBAAgB,YACpE,GAAI,EAAiB,EAAG,CACtB,IAAM,EAAU,WAAW,OAAO,iBAAiB,CAAI,EAAE,YAAY,GAAK,EAC1E,EAAK,MAAM,aAAe,GAAG,EAAU,EAAe,GACxD,CACA,EAAK,MAAM,SAAW,QACxB,CACA,GAAmB,CACrB,CAEA,SAAS,GAAoB,CAC3B,IACI,IAAkB,KACtB,EAAkB,EAClB,SAAS,KAAK,MAAM,SAAW,EAC/B,SAAS,KAAK,MAAM,aAAe,EACrC"}
@@ -0,0 +1,2 @@
1
+ import{Presentation as e}from"../floatingMenu/floatingMenu.types.mjs";import t from"./useMediaQuery.mjs";import n from"./useCoarsePointer.mjs";import{useVisualViewportSize as r}from"./useVisualViewportSize.mjs";var i=`(max-width: 767px)`;function a(a=e.Default){let o=n(),s=t(i),{height:c,offsetTop:l}=r();return a===e.Sheet||a===e.Auto&&o&&s?{isSheet:!0,sheetStyle:{bottom:typeof window>`u`?0:Math.max(0,window.innerHeight-(l+c))}}:{isSheet:!1,sheetStyle:void 0}}export{a as default};
2
+ //# sourceMappingURL=useSheet.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useSheet.mjs","names":[],"sources":["../../../../package/common/hooks/useSheet.ts"],"sourcesContent":["import type { CSSProperties } from 'react';\nimport { Presentation } from '../floatingMenu/floatingMenu.types';\nimport { useCoarsePointer } from './useCoarsePointer';\nimport { useMediaQuery } from './useMediaQuery';\nimport { useVisualViewportSize } from './useVisualViewportSize';\n\n/** Below this, `Presentation.Auto` switches a touch device over to a sheet. */\nconst SMALL_SCREEN_QUERY = '(max-width: 767px)';\n\nexport interface Sheet {\n /** Whether the popup should render as a bottom sheet instead of anchored to its trigger. */\n isSheet: boolean;\n /** Inline style for the sheet root, keeping it above an open on-screen keyboard. */\n sheetStyle: CSSProperties | undefined;\n}\n\n/**\n * Resolves whether a popup presents as a bottom sheet.\n *\n * `Auto` asks for a coarse pointer *and* a small screen: pointer alone turns a touchscreen laptop\n * into a phone, and width alone turns a narrow desktop window into one.\n */\nexport function useSheet(presentation: Presentation = Presentation.Default): Sheet {\n const isCoarsePointer = useCoarsePointer();\n const isSmallScreen = useMediaQuery(SMALL_SCREEN_QUERY);\n const { height: viewportHeight, offsetTop } = useVisualViewportSize();\n\n const isSheet = presentation === Presentation.Sheet\n || (presentation === Presentation.Auto && isCoarsePointer && isSmallScreen);\n\n if (!isSheet) return { isSheet: false, sheetStyle: undefined };\n\n // `position: fixed` resolves against the layout viewport, which an open keyboard doesn't\n // shrink — so a sheet at `bottom: 0` sits behind the keyboard. Lift it by the difference.\n const keyboardHeight = typeof window === 'undefined'\n ? 0\n : Math.max(0, window.innerHeight - (offsetTop + viewportHeight));\n\n return { isSheet: true, sheetStyle: { bottom: keyboardHeight } };\n}\n\nexport default useSheet;\n"],"mappings":"mNAOA,IAAM,EAAqB,qBAe3B,SAAgB,EAAS,EAA6B,EAAa,QAAgB,CACjF,IAAM,EAAkB,EAAiB,EACnC,EAAgB,EAAc,CAAkB,EAChD,CAAE,OAAQ,EAAgB,aAAc,EAAsB,EAapE,OAXgB,IAAiB,EAAa,OACxC,IAAiB,EAAa,MAAQ,GAAmB,EAUxD,CAAE,QAAS,GAAM,WAAY,CAAE,OAJf,OAAO,OAAW,IACrC,EACA,KAAK,IAAI,EAAG,OAAO,aAAe,EAAY,EAAe,CAEJ,CAAE,EAR1C,CAAE,QAAS,GAAO,WAAY,IAAA,EAAU,CAS/D"}
@@ -1,2 +1,2 @@
1
- import e from"../bodyEnd/bodyEnd.mjs";import t from"./modal.module.mjs";import{useVisualViewportSize as n}from"../hooks/useVisualViewportSize.mjs";import{useEffect as r,useState as i}from"react";import a from"classnames";import{FontAwesomeIcon as o}from"@fortawesome/react-fontawesome";import{faXmark as s}from"@fortawesome/free-solid-svg-icons";import{jsx as c,jsxs as l}from"react/jsx-runtime";function u({children:u=null,title:d=``,isOpen:f=!1,onClose:p=()=>null,className:m=``,style:h,hideHeader:g=!1,classNames:_,styles:v}){let[y,b]=i(f),[x,S]=i(f),{height:C,offsetTop:w}=n();return r(()=>{f?(b(f),setTimeout(()=>S(!0),1)):(S(!1),setTimeout(()=>b(f),300))},[f]),y?c(e,{children:l(`div`,{className:a(t.modalContainer,_?.container),style:{height:C,top:w,...v?.container},children:[c(`div`,{className:a(t.modalWrapper,x&&t.modalWrapperShown,_?.backdrop),style:v?.backdrop,onClick:p}),x&&l(`div`,{className:a(t.modal,x&&t.modalShown,m,_?.modal),style:{...h,...v?.modal},onClick:e=>e.stopPropagation(),children:[!g&&l(`div`,{className:a(t.modalHeader,_?.header),style:v?.header,children:[c(`div`,{className:_?.title,style:v?.title,children:d}),c(o,{onClick:p,icon:s,className:_?.closeButton,style:v?.closeButton})]}),u]})]})}):null}export{u as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import n from"../bodyEnd/bodyEnd.mjs";import r from"../styles/sheet.module.mjs";import{useVisualViewportSize as i}from"../hooks/useVisualViewportSize.mjs";import a from"../hooks/useSheet.mjs";import{useOverlay as o}from"../hooks/useOverlay.mjs";import s from"./modal.module.mjs";import{useEffect as c,useId as l,useRef as u,useState as d}from"react";import f from"classnames";import{FontAwesomeIcon as p}from"@fortawesome/react-fontawesome";import{faXmark as m}from"@fortawesome/free-solid-svg-icons";import{jsx as h,jsxs as g}from"react/jsx-runtime";function _(_){let{children:v=null,title:y=``,isOpen:b=!1,onClose:x=()=>null,className:S=``,style:C,hideHeader:w=!1,closeOnEscape:T=!0,presentation:E,classNames:D,styles:O,...k}=e(`Modal`,_),[A,j]=d(b),[M,N]=d(b),P=u(null),F=l(),{height:I,offsetTop:L}=i(),R=t(),{isSheet:z,sheetStyle:B}=a(E??R);if(c(()=>{b?(j(b),setTimeout(()=>N(!0),1)):(N(!1),setTimeout(()=>j(b),300))},[b]),o({isActive:A&&M,containerRef:P,onEscape:T?x:void 0}),!A)return null;let V=!w&&!!y;return h(n,{children:g(`div`,{className:f(s.modalContainer,D?.container),style:{height:I,top:L,...O?.container},children:[h(`div`,{className:f(s.modalWrapper,M&&s.modalWrapperShown,D?.backdrop),style:O?.backdrop,onClick:x}),M&&g(`div`,{...k,ref:P,role:`dialog`,"aria-modal":`true`,"aria-labelledby":V?F:void 0,tabIndex:-1,className:f(s.modal,M&&s.modalShown,z&&[r.sheet,r.sheetSurface,s.modalSheet],S,D?.modal),style:{...z?B:void 0,...C,...O?.modal},onClick:e=>e.stopPropagation(),children:[!w&&g(`div`,{className:f(s.modalHeader,D?.header),style:O?.header,children:[h(`div`,{id:F,className:D?.title,style:O?.title,children:y}),h(`button`,{type:`button`,onClick:x,"aria-label":`Close`,className:f(s.modalCloseButton,D?.closeButton),style:O?.closeButton,children:h(p,{icon:m})})]}),h(`div`,{className:f(s.modalBody,D?.body),style:O?.body,children:v})]})]})})}export{_ as default};
2
2
  //# sourceMappingURL=modal.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.mjs","names":[],"sources":["../../../../package/common/modal/modal.tsx"],"sourcesContent":["import React from 'react';\nimport cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './modal.module.pcss';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faXmark as closeIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ModalProps } from './modal.types';\nimport { useEffect, useState } from 'react';\nimport { useVisualViewportSize } from 'components/common/hooks/useVisualViewportSize';\n\nfunction Modal({\n children = null,\n title = '',\n isOpen = false,\n onClose = () => null,\n className = '',\n style,\n hideHeader = false,\n classNames,\n styles: slotStyles,\n}: ModalProps) {\n const [isRendered, setIsRendered] = useState(isOpen);\n const [animateIn, setAnimateIn] = useState(isOpen);\n // Centering/sizing against the actually-visible viewport (not the full layout viewport) keeps\n // the modal — and whatever's focused inside it — from ending up under a mobile keyboard.\n const { height: viewportHeight, offsetTop: viewportOffsetTop } = useVisualViewportSize();\n\n useEffect(() => {\n if (isOpen) {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setIsRendered(isOpen);\n setTimeout(() => setAnimateIn(true), 1);\n } else {\n setAnimateIn(false);\n setTimeout(() => setIsRendered(isOpen), 300);\n }\n }, [isOpen]);\n\n if (!isRendered) return null;\n\n return (\n <BodyEnd>\n <div\n className={cx(styles.modalContainer, classNames?.container)}\n style={{ height: viewportHeight, top: viewportOffsetTop, ...slotStyles?.container }}\n >\n <div\n className={cx(styles.modalWrapper, animateIn && styles.modalWrapperShown, classNames?.backdrop)}\n style={slotStyles?.backdrop}\n onClick={onClose}\n />\n {animateIn && (\n <div\n className={cx(styles.modal, animateIn && styles.modalShown, className, classNames?.modal)}\n style={{ ...style, ...slotStyles?.modal }}\n onClick={(e) => e.stopPropagation()}\n >\n {!hideHeader && (\n <div className={cx(styles.modalHeader, classNames?.header)} style={slotStyles?.header}>\n <div className={classNames?.title} style={slotStyles?.title}>{title}</div>\n <FontAwesomeIcon onClick={onClose} icon={closeIcon} className={classNames?.closeButton} style={slotStyles?.closeButton as React.CSSProperties & Record<`--fa-font-${string}`, string>} />\n </div>\n )}\n {children}\n </div>\n )}\n </div>\n </BodyEnd>\n );\n}\n\nexport default Modal;\n"],"mappings":"4YAWA,SAAS,EAAM,CACb,WAAW,KACX,QAAQ,GACR,SAAS,GACT,cAAgB,KAChB,YAAY,GACZ,QACA,aAAa,GACb,aACA,OAAQ,GACK,CACb,GAAM,CAAC,EAAY,GAAiB,EAAS,CAAM,EAC7C,CAAC,EAAW,GAAgB,EAAS,CAAM,EAG3C,CAAE,OAAQ,EAAgB,UAAW,GAAsB,EAAsB,EAevF,OAbA,MAAgB,CACV,GAEF,EAAc,CAAM,EACpB,eAAiB,EAAa,EAAI,EAAG,CAAC,IAEtC,EAAa,EAAK,EAClB,eAAiB,EAAc,CAAM,EAAG,GAAG,EAE/C,EAAG,CAAC,CAAM,CAAC,EAEN,EAGH,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,eAAgB,GAAY,SAAS,EAC1D,MAAO,CAAE,OAAQ,EAAgB,IAAK,EAAmB,GAAG,GAAY,SAAU,WAFpF,CAIE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,aAAc,GAAa,EAAO,kBAAmB,GAAY,QAAQ,EAC9F,MAAO,GAAY,SACnB,QAAS,CACV,CAAA,EACA,GACC,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,MAAO,GAAa,EAAO,WAAY,EAAW,GAAY,KAAK,EACxF,MAAO,CAAE,GAAG,EAAO,GAAG,GAAY,KAAM,EACxC,QAAU,GAAM,EAAE,gBAAgB,WAHpC,CAKG,CAAC,GACA,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,YAAa,GAAY,MAAM,EAAG,MAAO,GAAY,gBAA/E,CACE,EAAC,MAAD,CAAK,UAAW,GAAY,MAAO,MAAO,GAAY,eAAQ,CAAW,CAAA,EACzE,EAAC,EAAD,CAAiB,QAAS,EAAS,KAAM,EAAW,UAAW,GAAY,YAAa,MAAO,GAAY,WAA6E,CAAA,CACrL,IAEN,CACE,GAEJ,GACE,CAAA,EA7Ba,IA+B1B"}
1
+ {"version":3,"file":"modal.mjs","names":[],"sources":["../../../../package/common/modal/modal.tsx"],"sourcesContent":["import cx from 'classnames';\nimport BodyEnd from 'components/common/bodyEnd';\n\nimport styles from './modal.module.pcss';\nimport sheetStyles from 'components/common/styles/sheet.module.pcss';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faXmark as closeIcon } from '@fortawesome/free-solid-svg-icons';\nimport { ModalProps } from './modal.types';\nimport { useEffect, useId, useRef, useState } from 'react';\nimport { useVisualViewportSize } from 'components/common/hooks/useVisualViewportSize';\nimport { useOverlay } from 'components/common/hooks/useOverlay';\nimport { useSheet } from 'components/common/hooks/useSheet';\nimport { useComponentDefaults, usePresentationDefault } from 'components/common/configProvider';\n\nfunction Modal(props: ModalProps) {\n const {\n children = null,\n title = '',\n isOpen = false,\n onClose = () => null,\n className = '',\n style,\n hideHeader = false,\n closeOnEscape = true,\n presentation: presentationProp,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('Modal', props);\n const [isRendered, setIsRendered] = useState(isOpen);\n const [animateIn, setAnimateIn] = useState(isOpen);\n const modalRef = useRef<HTMLDivElement>(null);\n const titleId = useId();\n // Centering/sizing against the actually-visible viewport (not the full layout viewport) keeps\n // the modal — and whatever's focused inside it — from ending up under a mobile keyboard.\n const { height: viewportHeight, offsetTop: viewportOffsetTop } = useVisualViewportSize();\n // Explicit prop → this component's global default → the app-wide one. There's no built-in\n // fallback to add: `Default` and no presentation at all both mean the ordinary centred dialog.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation;\n const { isSheet, sheetStyle } = useSheet(presentation);\n\n useEffect(() => {\n if (isOpen) {\n // eslint-disable-next-line react-hooks/set-state-in-effect\n setIsRendered(isOpen);\n setTimeout(() => setAnimateIn(true), 1);\n } else {\n setAnimateIn(false);\n setTimeout(() => setIsRendered(isOpen), 300);\n }\n }, [isOpen]);\n\n // Keyed on `animateIn` rather than `isOpen`, because the panel this needs to focus and trap\n // focus inside of only mounts once that flips.\n useOverlay({\n isActive: isRendered && animateIn,\n containerRef: modalRef,\n onEscape: closeOnEscape ? onClose : undefined,\n });\n\n if (!isRendered) return null;\n\n const hasHeaderTitle = !hideHeader && !!title;\n\n return (\n <BodyEnd>\n <div\n className={cx(styles.modalContainer, classNames?.container)}\n style={{ height: viewportHeight, top: viewportOffsetTop, ...slotStyles?.container }}\n >\n <div\n className={cx(styles.modalWrapper, animateIn && styles.modalWrapperShown, classNames?.backdrop)}\n style={slotStyles?.backdrop}\n onClick={onClose}\n />\n {animateIn && (\n <div\n {...rest}\n ref={modalRef}\n role=\"dialog\"\n aria-modal=\"true\"\n aria-labelledby={hasHeaderTitle ? titleId : undefined}\n // Focusable so the trap has somewhere to put focus when the content has no tabbables.\n tabIndex={-1}\n className={cx(\n styles.modal,\n animateIn && styles.modalShown,\n // The panel is its own sheet surface here: there's no inner panel to fill, since\n // Modal already splits itself into a fixed header and a scrolling body.\n isSheet && [sheetStyles.sheet, sheetStyles.sheetSurface, styles.modalSheet],\n className,\n classNames?.modal,\n )}\n style={{ ...(isSheet ? sheetStyle : undefined), ...style, ...slotStyles?.modal }}\n onClick={(e) => e.stopPropagation()}\n >\n {!hideHeader && (\n <div className={cx(styles.modalHeader, classNames?.header)} style={slotStyles?.header}>\n <div id={titleId} className={classNames?.title} style={slotStyles?.title}>{title}</div>\n <button\n type=\"button\"\n onClick={onClose}\n aria-label=\"Close\"\n className={cx(styles.modalCloseButton, classNames?.closeButton)}\n style={slotStyles?.closeButton}\n >\n <FontAwesomeIcon icon={closeIcon} />\n </button>\n </div>\n )}\n <div className={cx(styles.modalBody, classNames?.body)} style={slotStyles?.body}>\n {children}\n </div>\n </div>\n )}\n </div>\n </BodyEnd>\n );\n}\n\nexport default Modal;\n"],"mappings":"+sBAcA,SAAS,EAAM,EAAmB,CAChC,GAAM,CACN,WAAW,KACX,QAAQ,GACR,SAAS,GACT,cAAgB,KAChB,YAAY,GACZ,QACA,aAAa,GACb,gBAAgB,GAChB,aAAc,EACd,aACA,OAAQ,EACR,GAAG,GACC,EAAqB,QAAS,CAAK,EACjC,CAAC,EAAY,GAAiB,EAAS,CAAM,EAC7C,CAAC,EAAW,GAAgB,EAAS,CAAM,EAC3C,EAAW,EAAuB,IAAI,EACtC,EAAU,EAAM,EAGhB,CAAE,OAAQ,EAAgB,UAAW,GAAsB,EAAsB,EAGjF,EAAkB,EAAuB,EAEzC,CAAE,UAAS,cAAe,EADX,GAAoB,CACY,EAqBrD,GAnBA,MAAgB,CACV,GAEF,EAAc,CAAM,EACpB,eAAiB,EAAa,EAAI,EAAG,CAAC,IAEtC,EAAa,EAAK,EAClB,eAAiB,EAAc,CAAM,EAAG,GAAG,EAE/C,EAAG,CAAC,CAAM,CAAC,EAIX,EAAW,CACT,SAAU,GAAc,EACxB,aAAc,EACd,SAAU,EAAgB,EAAU,IAAA,EACtC,CAAC,EAEG,CAAC,EAAY,OAAO,KAExB,IAAM,EAAiB,CAAC,GAAc,CAAC,CAAC,EAExC,OACE,EAAC,EAAD,CAAA,SACE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,eAAgB,GAAY,SAAS,EAC1D,MAAO,CAAE,OAAQ,EAAgB,IAAK,EAAmB,GAAG,GAAY,SAAU,WAFpF,CAIE,EAAC,MAAD,CACE,UAAW,EAAG,EAAO,aAAc,GAAa,EAAO,kBAAmB,GAAY,QAAQ,EAC9F,MAAO,GAAY,SACnB,QAAS,CACV,CAAA,EACA,GACC,EAAC,MAAD,CACE,GAAI,EACJ,IAAK,EACL,KAAK,SACL,aAAW,OACX,kBAAiB,EAAiB,EAAU,IAAA,GAE5C,SAAU,GACV,UAAW,EACT,EAAO,MACP,GAAa,EAAO,WAGpB,GAAW,CAAC,EAAY,MAAO,EAAY,aAAc,EAAO,UAAU,EAC1E,EACA,GAAY,KACd,EACA,MAAO,CAAE,GAAI,EAAU,EAAa,IAAA,GAAY,GAAG,EAAO,GAAG,GAAY,KAAM,EAC/E,QAAU,GAAM,EAAE,gBAAgB,WAlBpC,CAoBG,CAAC,GACA,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,YAAa,GAAY,MAAM,EAAG,MAAO,GAAY,gBAA/E,CACE,EAAC,MAAD,CAAK,GAAI,EAAS,UAAW,GAAY,MAAO,MAAO,GAAY,eAAQ,CAAW,CAAA,EACtF,EAAC,SAAD,CACE,KAAK,SACL,QAAS,EACT,aAAW,QACX,UAAW,EAAG,EAAO,iBAAkB,GAAY,WAAW,EAC9D,MAAO,GAAY,qBAEnB,EAAC,EAAD,CAAiB,KAAM,CAAY,CAAA,CAC7B,CAAA,CACL,IAEP,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,UAAW,GAAY,IAAI,EAAG,MAAO,GAAY,KACxE,UACE,CAAA,CACF,GAEJ,GACE,CAAA,CAEb"}
@@ -1,2 +1,2 @@
1
- var e={modal:`modal_L-Fkd`,slideIn:`slideIn_RVIHR`,fadeIn:`fadeIn_XSuIE`,"modal-container":`modal-container_qwKIm`,modalContainer:`modal-container_qwKIm`,"modal-header":`modal-header_DhsRr`,modalHeader:`modal-header_DhsRr`,"modal-wrapper":`modal-wrapper_r5wzq`,modalWrapper:`modal-wrapper_r5wzq`,"modal-wrapper-shown":`modal-wrapper-shown_F0BgK`,modalWrapperShown:`modal-wrapper-shown_F0BgK`};export{e as default};
1
+ var e={modal:`modal_L-Fkd`,slideIn:`slideIn_RVIHR`,fadeIn:`fadeIn_XSuIE`,"modal-sheet":`modal-sheet_WkXR4`,modalSheet:`modal-sheet_WkXR4`,"modal-container":`modal-container_qwKIm`,modalContainer:`modal-container_qwKIm`,"modal-header":`modal-header_DhsRr`,modalHeader:`modal-header_DhsRr`,"modal-body":`modal-body_Mmn0-`,modalBody:`modal-body_Mmn0-`,"modal-close-button":`modal-close-button_UMZjq`,modalCloseButton:`modal-close-button_UMZjq`,"modal-wrapper":`modal-wrapper_r5wzq`,modalWrapper:`modal-wrapper_r5wzq`,"modal-wrapper-shown":`modal-wrapper-shown_F0BgK`,modalWrapperShown:`modal-wrapper-shown_F0BgK`};export{e as default};
2
2
  //# sourceMappingURL=modal.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"modal.module.mjs","names":[],"sources":["../../../../package/common/modal/modal.module.pcss"],"sourcesContent":["\n.modal {\n padding: 16px;\n border-radius: var(--default-border-radius);\n background: var(--background-modal);\n color: var(--text-color);\n font-family: var(--default-font);\n box-sizing: border-box;\n position: relative;\n transform-origin: bottom center;\n animation:\n slideIn 0.2s,\n fadeIn 0.3s forwards;\n max-width: 95%;\n max-height: 95%;\n overflow: auto;\n\n @media not (--breakpoint-desktop) {\n max-width: 100%;\n max-height: 100%;\n }\n\n &-container {\n position: fixed;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n top: 0;\n left: 0;\n }\n\n &-header {\n display: flex;\n gap: 8px;\n justify-content: space-between;\n margin-bottom: 16px;\n\n div {\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n svg {\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n }\n\n &-wrapper {\n position: fixed;\n width: 100%;\n height: 100%;\n background: #00000052;\n top: 0;\n left: 0;\n transition: all 0.3s ease-in-out;\n opacity: 0;\n\n &-shown {\n opacity: 1;\n }\n }\n}\n\n@keyframes slideIn {\n from {\n transform: scale(0);\n }\n to {\n transform: scale(0.99);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"modal.module.mjs","names":[],"sources":["../../../../package/common/modal/modal.module.pcss"],"sourcesContent":["\n.modal {\n padding: 16px;\n border-radius: var(--default-border-radius);\n background: var(--background-modal);\n color: var(--text-color);\n font-family: var(--default-font);\n box-sizing: border-box;\n position: relative;\n display: flex;\n flex-direction: column;\n transform-origin: bottom center;\n animation:\n slideIn 0.2s,\n fadeIn 0.3s forwards;\n max-width: 95%;\n max-height: 95%;\n /* The panel itself never scrolls, so the header stays put; `&-body` is what scrolls. */\n overflow: hidden;\n\n @media (max-width: 767px) {\n max-width: 100%;\n max-height: 100%;\n }\n\n /* A sheet-presented modal carries forms and detail views, not a short menu, so it takes more\n of the screen than the shared default — and keeps the panel's own 16px at the bottom edge. */\n &-sheet {\n --sheet-max-height: 90dvh;\n --sheet-safe-padding: 16px;\n }\n\n &-container {\n position: fixed;\n width: 100%;\n height: 100%;\n display: flex;\n justify-content: center;\n align-items: center;\n top: 0;\n left: 0;\n }\n\n &-header {\n display: flex;\n gap: 8px;\n justify-content: space-between;\n align-items: center;\n margin-bottom: 16px;\n flex: 0 0 auto;\n\n div {\n overflow: hidden;\n text-overflow: ellipsis;\n }\n }\n\n &-body {\n /* `min-height: 0` lets this shrink below its content's height so it, not the panel, scrolls. */\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n }\n\n &-close-button {\n flex-shrink: 0;\n background: none;\n border: none;\n padding: 0;\n color: inherit;\n font-size: inherit;\n line-height: 1;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n }\n\n &-wrapper {\n position: fixed;\n width: 100%;\n height: 100%;\n background: #00000052;\n top: 0;\n left: 0;\n transition: all 0.3s ease-in-out;\n opacity: 0;\n\n &-shown {\n opacity: 1;\n }\n }\n}\n\n@keyframes slideIn {\n from {\n transform: scale(0);\n }\n to {\n transform: scale(0.99);\n }\n}\n\n@keyframes fadeIn {\n from {\n opacity: 0;\n }\n to {\n opacity: 1;\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{ButtonSize as t}from"../button/button.types.mjs";import n from"../button/button.mjs";import r from"../buttonGroup/buttonGroup.mjs";import i from"../input/input.mjs";import ee from"../hooks/useCoarsePointer.mjs";import a from"./numberInput.module.mjs";import o from"./useStepRepeat.mjs";import s from"react";import c from"classnames";import{FontAwesomeIcon as l}from"@fortawesome/react-fontawesome";import{faChevronDown as te,faChevronUp as u,faMinus as ne,faPlus as d}from"@fortawesome/free-solid-svg-icons";import{jsx as f,jsxs as p}from"react/jsx-runtime";import{NumericFormat as re}from"react-number-format";function m({label:e,disabled:t,direction:n,onStart:r,onStop:i}){return{tabIndex:-1,disabled:t,"aria-label":e,onPointerDown:e=>{e.button!==0&&e.pointerType===`mouse`||(e.preventDefault(),r(n,e.shiftKey?10:1))},onPointerUp:i,onPointerCancel:i,onContextMenu:e=>e.preventDefault()}}function h(e){return f(`button`,{type:`button`,...m(e),className:a.arrowBtn,children:f(l,{icon:e.icon,"aria-hidden":`true`})})}function g(e){let{disabled:r,...i}=m(e);return f(n,{...i,className:a.splitBtn,size:t.Icon,disabled:r,icon:e.icon})}function _(t){let n=s.useRef(void 0),{value:l,onChange:m,formValidator:_,label:ie,error:v,className:y,style:b,allowNegative:x=!1,decimalSeparator:ae,thousandSeparator:oe,prefix:se,suffix:ce,decimalScale:S,fixedDecimalScale:C=!0,placeholder:w,sign:T,showArrows:E=!1,step:D=1,min:O,max:k,arrowsLayout:A=`auto`,increaseLabel:j=`Increase`,decreaseLabel:M=`Decrease`,readOnly:N=!1,disabled:P=!1,isRequired:le=!1,onKeyDown:F,...ue}=e(`NumberInput`,t),[,de]=s.useState(0);s.useEffect(()=>{if(n.current=_,!_)return;let e=()=>de(e=>e+1);return _.registerOnUpdateListener(e),()=>{_.removeOnUpdateListener(e)}},[_]);let fe=le||!!_?.validators.find(e=>e.validatorId===`required`),I=_==null?l:_.value,L=T!=null&&I!=null?Math.abs(Number(I)):I,R=L==null?``:String(L);function z(e){let t=e;t!==void 0&&(T===`-`&&(t=-Math.abs(t)),T===`+`&&(t=Math.abs(t))),_?.set(t??null),m?.(t)}function B(e){let t=e;return!x&&T!==`-`&&(t=Math.max(0,t)),T===`-`&&(t=Math.min(0,t)),O!==void 0&&(t=Math.max(O,t)),k!==void 0&&(t=Math.min(k,t)),t}let V=I!=null&&I!==``?Number(I):0;function H(){if(N||P||I==null||I===``)return;let e=Number(I);if(!Number.isFinite(e))return;let t=B(e);t!==e&&z(t)}function U(e){if(N||P)return!1;let t=B(V+e);return t===V?!1:(z(t),!0)}let{start:pe,stop:me}=o(e=>U(e*D));function he(e){if(e.key===`Enter`){H(),F?.(e);return}if(!G){F?.(e);return}if(e.key===`ArrowUp`){e.preventDefault(),U(e.shiftKey?D*10:D);return}if(e.key===`ArrowDown`){e.preventDefault(),U(e.shiftKey?-D*10:-D);return}F?.(e)}let W=T===`-`?`-`:T===`+`?`+`:se,ge=ee(),G=E&&!N&&!P,K=A===`split`||A===`auto`&&ge,q=B(V+D)!==V,J=B(V-D)!==V,Y={onStart:pe,onStop:me},X=G&&!K?p(`div`,{className:a.arrows,children:[f(h,{label:j,icon:u,disabled:!q,direction:1,...Y}),f(h,{label:M,icon:te,disabled:!J,direction:-1,...Y})]}):null,_e=G?{role:`spinbutton`,"aria-valuenow":Number.isFinite(V)?V:void 0,"aria-valuemin":O,"aria-valuemax":k,"aria-valuetext":R||void 0}:{},Z=_?_.touched?!_.hasError():!0:!v,Q=G&&K,$=f(i,{label:ie,className:c(a.numberInput,{[a.numberInputSplit]:Q},Q?void 0:y),style:Q?void 0:b,value:R,onChange:()=>{},formValidator:null,isRequired:fe,onBlur:()=>{H(),n.current&&(n.current.touched=!0)},isValid:Z,errorMessage:_?_.touched?_.getCurrentErrorMessage()??``:``:v??``,placeholder:w,readOnly:N,disabled:P,suffix:X,classNames:X?{suffix:a.arrowSuffix}:void 0,inputMode:S===0?`numeric`:`decimal`,customInput:f(re,{onValueChange:e=>z(e.floatValue),allowNegative:T==null?x:!1,decimalSeparator:ae,thousandSeparator:oe,decimalScale:S,fixedDecimalScale:C,prefix:W,suffix:ce,onKeyDown:he,..._e,...ue})});return Q?p(r,{className:c(a.split,{[a.splitInvalid]:!Z},y),style:b,children:[f(g,{label:M,icon:ne,disabled:!J,direction:-1,...Y}),$,f(g,{label:j,icon:d,disabled:!q,direction:1,...Y})]}):$}export{_ as default};
1
+ import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{ButtonSize as t}from"../button/button.types.mjs";import n from"../button/button.mjs";import r from"../hooks/useCoarsePointer.mjs";import i from"../buttonGroup/buttonGroup.mjs";import ee from"../input/input.mjs";import a from"./numberInput.module.mjs";import o from"./useStepRepeat.mjs";import s from"react";import c from"classnames";import{FontAwesomeIcon as l}from"@fortawesome/react-fontawesome";import{faChevronDown as te,faChevronUp as u,faMinus as ne,faPlus as d}from"@fortawesome/free-solid-svg-icons";import{jsx as f,jsxs as p}from"react/jsx-runtime";import{NumericFormat as re}from"react-number-format";function m({label:e,disabled:t,direction:n,onStart:r,onStop:i}){return{tabIndex:-1,disabled:t,"aria-label":e,onPointerDown:e=>{e.button!==0&&e.pointerType===`mouse`||(e.preventDefault(),r(n,e.shiftKey?10:1))},onPointerUp:i,onPointerCancel:i,onContextMenu:e=>e.preventDefault()}}function h(e){return f(`button`,{type:`button`,...m(e),className:a.arrowBtn,children:f(l,{icon:e.icon,"aria-hidden":`true`})})}function g(e){let{disabled:r,...i}=m(e);return f(n,{...i,className:a.splitBtn,size:t.Icon,disabled:r,icon:e.icon})}function _(t){let n=s.useRef(void 0),{value:l,onChange:m,formValidator:_,label:ie,error:v,className:y,style:b,allowNegative:x=!1,decimalSeparator:ae,thousandSeparator:oe,prefix:se,suffix:ce,decimalScale:S,fixedDecimalScale:C=!0,placeholder:w,sign:T,showArrows:E=!1,step:D=1,min:O,max:k,arrowsLayout:A=`auto`,increaseLabel:j=`Increase`,decreaseLabel:M=`Decrease`,readOnly:N=!1,disabled:P=!1,isRequired:le=!1,onKeyDown:F,...ue}=e(`NumberInput`,t),[,de]=s.useState(0);s.useEffect(()=>{if(n.current=_,!_)return;let e=()=>de(e=>e+1);return _.registerOnUpdateListener(e),()=>{_.removeOnUpdateListener(e)}},[_]);let fe=le||!!_?.validators.find(e=>e.validatorId===`required`),I=_==null?l:_.value,L=T!=null&&I!=null?Math.abs(Number(I)):I,R=L==null?``:String(L);function z(e){let t=e;t!==void 0&&(T===`-`&&(t=-Math.abs(t)),T===`+`&&(t=Math.abs(t))),_?.set(t??null),m?.(t)}function B(e){let t=e;return!x&&T!==`-`&&(t=Math.max(0,t)),T===`-`&&(t=Math.min(0,t)),O!==void 0&&(t=Math.max(O,t)),k!==void 0&&(t=Math.min(k,t)),t}let V=I!=null&&I!==``?Number(I):0;function H(){if(N||P||I==null||I===``)return;let e=Number(I);if(!Number.isFinite(e))return;let t=B(e);t!==e&&z(t)}function U(e){if(N||P)return!1;let t=B(V+e);return t===V?!1:(z(t),!0)}let{start:pe,stop:me}=o(e=>U(e*D));function he(e){if(e.key===`Enter`){H(),F?.(e);return}if(!G){F?.(e);return}if(e.key===`ArrowUp`){e.preventDefault(),U(e.shiftKey?D*10:D);return}if(e.key===`ArrowDown`){e.preventDefault(),U(e.shiftKey?-D*10:-D);return}F?.(e)}let W=T===`-`?`-`:T===`+`?`+`:se,ge=r(),G=E&&!N&&!P,K=A===`split`||A===`auto`&&ge,q=B(V+D)!==V,J=B(V-D)!==V,Y={onStart:pe,onStop:me},X=G&&!K?p(`div`,{className:a.arrows,children:[f(h,{label:j,icon:u,disabled:!q,direction:1,...Y}),f(h,{label:M,icon:te,disabled:!J,direction:-1,...Y})]}):null,_e=G?{role:`spinbutton`,"aria-valuenow":Number.isFinite(V)?V:void 0,"aria-valuemin":O,"aria-valuemax":k,"aria-valuetext":R||void 0}:{},Z=_?_.touched?!_.hasError():!0:!v,Q=G&&K,$=f(ee,{label:ie,className:c(a.numberInput,{[a.numberInputSplit]:Q},Q?void 0:y),style:Q?void 0:b,value:R,onChange:()=>{},formValidator:null,isRequired:fe,onBlur:()=>{H(),n.current&&(n.current.touched=!0)},isValid:Z,errorMessage:_?_.touched?_.getCurrentErrorMessage()??``:``:v??``,placeholder:w,readOnly:N,disabled:P,suffix:X,classNames:X?{suffix:a.arrowSuffix}:void 0,inputMode:S===0?`numeric`:`decimal`,customInput:f(re,{onValueChange:e=>z(e.floatValue),allowNegative:T==null?x:!1,decimalSeparator:ae,thousandSeparator:oe,decimalScale:S,fixedDecimalScale:C,prefix:W,suffix:ce,onKeyDown:he,..._e,...ue})});return Q?p(i,{className:c(a.split,{[a.splitInvalid]:!Z},y),style:b,children:[f(g,{label:M,icon:ne,disabled:!J,direction:-1,...Y}),$,f(g,{label:j,icon:d,disabled:!q,direction:1,...Y})]}):$}export{_ as default};
2
2
  //# sourceMappingURL=numberInput.mjs.map