@ahrowe/ui 0.51.0 → 0.53.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 (106) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +1 -0
  3. package/dist/cjs-types/common/actionIcon/actionIcon.types.d.ts +10 -6
  4. package/dist/cjs-types/common/ahroweProvider/ahroweProvider.d.ts +1 -1
  5. package/dist/cjs-types/common/button/button.types.d.ts +25 -8
  6. package/dist/cjs-types/common/configProvider/configProvider.d.ts +2 -1
  7. package/dist/cjs-types/common/configProvider/configProvider.types.d.ts +8 -0
  8. package/dist/cjs-types/common/copyButton/copyButton.types.d.ts +4 -1
  9. package/dist/cjs-types/common/listItem/index.d.ts +2 -0
  10. package/dist/cjs-types/common/listItem/listItem.d.ts +4 -0
  11. package/dist/cjs-types/common/listItem/listItem.types.d.ts +33 -0
  12. package/dist/cjs-types/common/menu/menu.types.d.ts +2 -2
  13. package/dist/cjs-types/common/menu/menuItem.d.ts +5 -2
  14. package/dist/cjs-types/common/otpInput/otpInput.types.d.ts +1 -1
  15. package/dist/cjs-types/common/themeProvider/theme.types.d.ts +4 -0
  16. package/dist/cjs-types/common/utils/navigation.d.ts +12 -0
  17. package/dist/cjs-types/index.d.ts +3 -1
  18. package/dist/cjs-types/services/formValidation/index.d.ts +1 -1
  19. package/dist/cjs-types/services/formValidation/useFormValidatorGroup.d.ts +1 -1
  20. package/dist/esm/common/ahroweProvider/ahroweProvider.mjs +1 -1
  21. package/dist/esm/common/ahroweProvider/ahroweProvider.mjs.map +1 -1
  22. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  23. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  24. package/dist/esm/common/button/button.mjs +1 -1
  25. package/dist/esm/common/button/button.mjs.map +1 -1
  26. package/dist/esm/common/button/button.module.mjs +1 -1
  27. package/dist/esm/common/button/button.module.mjs.map +1 -1
  28. package/dist/esm/common/button/button.types.mjs.map +1 -1
  29. package/dist/esm/common/commandPalette/commandPalette.mjs +1 -1
  30. package/dist/esm/common/commandPalette/commandPalette.mjs.map +1 -1
  31. package/dist/esm/common/configProvider/configProvider.mjs +1 -1
  32. package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
  33. package/dist/esm/common/datePicker/datePicker.mjs +1 -1
  34. package/dist/esm/common/datePicker/datePicker.mjs.map +1 -1
  35. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  36. package/dist/esm/common/dropdown/dropdown.mjs.map +1 -1
  37. package/dist/esm/common/iconPicker/iconPicker.mjs +1 -1
  38. package/dist/esm/common/iconPicker/iconPicker.mjs.map +1 -1
  39. package/dist/esm/common/input/input.mjs +1 -1
  40. package/dist/esm/common/input/input.mjs.map +1 -1
  41. package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
  42. package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
  43. package/dist/esm/common/listItem/listItem.mjs +2 -0
  44. package/dist/esm/common/listItem/listItem.mjs.map +1 -0
  45. package/dist/esm/common/listItem/listItem.module.mjs +2 -0
  46. package/dist/esm/common/listItem/listItem.module.mjs.map +1 -0
  47. package/dist/esm/common/menu/menu.mjs +1 -1
  48. package/dist/esm/common/menu/menu.mjs.map +1 -1
  49. package/dist/esm/common/menu/menu.types.mjs.map +1 -1
  50. package/dist/esm/common/menu/menuItem.mjs +1 -1
  51. package/dist/esm/common/menu/menuItem.mjs.map +1 -1
  52. package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
  53. package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
  54. package/dist/esm/common/numberInput/numberInput.mjs +1 -1
  55. package/dist/esm/common/numberInput/numberInput.mjs.map +1 -1
  56. package/dist/esm/common/otpInput/otpInput.mjs +1 -1
  57. package/dist/esm/common/otpInput/otpInput.mjs.map +1 -1
  58. package/dist/esm/common/otpInput/otpInput.types.mjs.map +1 -1
  59. package/dist/esm/common/radioGroup/radioGroup.mjs +1 -1
  60. package/dist/esm/common/radioGroup/radioGroup.mjs.map +1 -1
  61. package/dist/esm/common/timeInput/timeInput.mjs +1 -1
  62. package/dist/esm/common/timeInput/timeInput.mjs.map +1 -1
  63. package/dist/esm/common/utils/navigation.mjs +2 -0
  64. package/dist/esm/common/utils/navigation.mjs.map +1 -0
  65. package/dist/esm/index.mjs +1 -1
  66. package/dist/esm/services/formValidation/useFormValidatorGroup.mjs +1 -1
  67. package/dist/esm/services/formValidation/useFormValidatorGroup.mjs.map +1 -1
  68. package/dist/esm/services/formValidation/validatableComponent.mjs +1 -1
  69. package/dist/esm/services/formValidation/validatableComponent.mjs.map +1 -1
  70. package/dist/index.cjs +5 -5
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/style.css +1 -1
  73. package/dist/types/common/actionIcon/actionIcon.types.d.ts +10 -6
  74. package/dist/types/common/ahroweProvider/ahroweProvider.d.ts +1 -1
  75. package/dist/types/common/button/button.types.d.ts +25 -8
  76. package/dist/types/common/configProvider/configProvider.d.ts +2 -1
  77. package/dist/types/common/configProvider/configProvider.types.d.ts +8 -0
  78. package/dist/types/common/copyButton/copyButton.types.d.ts +4 -1
  79. package/dist/types/common/listItem/index.d.ts +2 -0
  80. package/dist/types/common/listItem/listItem.d.ts +4 -0
  81. package/dist/types/common/listItem/listItem.types.d.ts +33 -0
  82. package/dist/types/common/menu/menu.types.d.ts +2 -2
  83. package/dist/types/common/menu/menuItem.d.ts +5 -2
  84. package/dist/types/common/otpInput/otpInput.types.d.ts +1 -1
  85. package/dist/types/common/themeProvider/theme.types.d.ts +4 -0
  86. package/dist/types/common/utils/navigation.d.ts +12 -0
  87. package/dist/types/index.d.ts +3 -1
  88. package/dist/types/services/formValidation/index.d.ts +1 -1
  89. package/dist/types/services/formValidation/useFormValidatorGroup.d.ts +1 -1
  90. package/docs/ActionIcon.md +7 -3
  91. package/docs/AhroweProvider.md +2 -1
  92. package/docs/Breadcrumb.md +4 -24
  93. package/docs/Button.md +44 -9
  94. package/docs/CLAUDE.md +4 -0
  95. package/docs/CommandPalette.md +1 -1
  96. package/docs/ConfigProvider.md +34 -1
  97. package/docs/FormValidator.md +23 -1
  98. package/docs/FormValidatorGroup.md +5 -2
  99. package/docs/InputDropdown.md +1 -1
  100. package/docs/ListItem.md +97 -0
  101. package/docs/Menu.md +2 -2
  102. package/docs/MultiSelect.md +1 -1
  103. package/docs/OtpInput.md +1 -1
  104. package/docs/RadioGroup.md +1 -1
  105. package/docs/ScrollbarProvider.md +1 -1
  106. package/package.json +2 -2
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{renderIcon as n}from"../utils/renderIcon.mjs";import{ariaKeyshortcuts as r,formatHotkey as i}from"../hooks/useHotkeys.mjs";import a from"../modal/modal.mjs";import{edgeIndex as o,nextIndex as ee,scrollOptionIntoView as s}from"../utils/listNavigation.mjs";import{hasAnyIcon as c,renderItemIcon as te,runMenuAction as l}from"../menu/menuItem.mjs";import{filterCommands as ne,groupCommands as u}from"./filterCommands.mjs";import d from"./commandPalette.module.mjs";import{useEffect as f,useId as p,useRef as m,useState as h}from"react";import g from"classnames";import{faMagnifyingGlass as re}from"@fortawesome/free-solid-svg-icons";import{jsx as _,jsxs as v}from"react/jsx-runtime";var y={label:`Search commands`,placeholder:`Type a command or search…`,empty:`No results`,loading:`Searching…`,results:e=>e===1?`1 result`:`${e} results`};function b(b){let{items:x,isOpen:S,onClose:C,onAction:w,onQueryChange:T,filter:E=!0,isLoading:D=!1,presentation:O,labels:ie,className:ae,style:oe,classNames:k,styles:A,...j}=e(`CommandPalette`,b),M=t(`CommandPalette`,ie,y),N=p(),P=m(null),[F,I]=h(``),[L,R]=h(null),[z,B]=h(S);S!==z&&(B(S),S&&(I(``),R(null)));let V=m(T);f(()=>{V.current=T}),f(()=>{S&&V.current?.(``)},[S]);let H=E?ne(u(x),F):u(x),U=c(x),W=H.flatMap(e=>e.actions),G=e=>!!W[e]?.disabled,K=W.findIndex(e=>e.id===L&&!e.disabled),q=K>=0?K:o(`first`,W.length,{isDisabled:G}),J=e=>`${N}-${encodeURIComponent(e.id)}`,Y=q===null?void 0:J(W[q]);f(()=>{Y&&s(P.current,document.getElementById(Y))},[Y]);function X(e){e&&!e.disabled&&(l(e,w),C())}function se(e){if(!e.nativeEvent.isComposing){if(e.key===`ArrowDown`||e.key===`ArrowUp`){let t=ee(q,e.key===`ArrowDown`?1:-1,W.length,{isDisabled:G});R(t===null?null:W[t].id)}else if(e.key===`Enter`)X(q===null?void 0:W[q]);else return;e.preventDefault()}}let Z=F.trim()!==``,Q=D?M.loading:M.empty,$=-1;return v(a,{...j,"aria-label":M.label,isOpen:S,onClose:C,hideHeader:!0,presentation:O,className:g(d.commandPalette,ae,k?.root),style:{...oe,...A?.root},children:[v(`div`,{className:g(d.commandPaletteSearch,k?.search),style:A?.search,children:[n(re,{className:d.commandPaletteSearchIcon}),_(`input`,{type:`text`,role:`combobox`,"aria-label":M.label,"aria-expanded":`true`,"aria-controls":N,"aria-autocomplete":`list`,"aria-activedescendant":Y,autoComplete:`off`,spellCheck:!1,placeholder:M.placeholder,value:F,onChange:e=>{I(e.target.value),R(null),T?.(e.target.value)},onKeyDown:se,className:g(d.commandPaletteInput,k?.input),style:A?.input})]}),_(`div`,{ref:P,id:N,role:`listbox`,"aria-label":M.label,className:g(d.commandPaletteList,k?.list),style:A?.list,children:H.map((e,t)=>{let n=`${N}-heading-${t}`;return v(`div`,{role:e.heading===void 0?`presentation`:`group`,"aria-labelledby":e.heading===void 0?void 0:n,children:[e.separated&&t>0&&_(`div`,{"aria-hidden":!0,className:g(d.commandPaletteSeparator,k?.separator),style:A?.separator}),e.heading!==void 0&&_(`div`,{id:n,role:`presentation`,className:g(d.commandPaletteHeading,k?.heading),style:A?.heading,children:e.heading}),e.actions.map(e=>{$+=1;let t=$;return v(`div`,{id:J(e),role:`option`,"aria-selected":t===q,"aria-disabled":e.disabled||void 0,"aria-keyshortcuts":r(e.shortcut),className:g(d.commandPaletteItem,t===q&&d.commandPaletteItemActive,e.danger&&d.commandPaletteItemDanger,e.disabled&&d.commandPaletteItemDisabled,k?.item),style:A?.item,onMouseDown:e=>e.preventDefault(),onMouseMove:()=>!e.disabled&&R(e.id),onClick:()=>X(e),children:[te(e.icon,U,{className:g(d.commandPaletteItemIcon,k?.itemIcon),style:A?.itemIcon}),_(`span`,{className:g(d.commandPaletteItemLabel,k?.itemLabel),style:A?.itemLabel,children:e.label}),e.shortcut!=null&&_(`span`,{"aria-hidden":!0,className:g(d.commandPaletteItemShortcut,k?.itemShortcut),style:A?.itemShortcut,children:i(e.shortcut)})]},e.id)})]},t)})}),Z&&W.length===0&&_(`div`,{className:g(d.commandPaletteEmpty,k?.empty),style:A?.empty,children:Q}),_(`span`,{className:d.commandPaletteStatus,role:`status`,"aria-live":`polite`,children:Z?W.length>0?M.results(W.length):Q:``})]})}export{b as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{renderIcon as n}from"../utils/renderIcon.mjs";import{ariaKeyshortcuts as ee,formatHotkey as te}from"../hooks/useHotkeys.mjs";import{useFollowHref as ne}from"../utils/navigation.mjs";import r from"../modal/modal.mjs";import{edgeIndex as i,nextIndex as a,scrollOptionIntoView as o}from"../utils/listNavigation.mjs";import{hasAnyIcon as s,renderItemIcon as c,runMenuAction as l}from"../menu/menuItem.mjs";import{filterCommands as u,groupCommands as d}from"./filterCommands.mjs";import f from"./commandPalette.module.mjs";import{useEffect as p,useId as m,useRef as h,useState as g}from"react";import _ from"classnames";import{faMagnifyingGlass as v}from"@fortawesome/free-solid-svg-icons";import{jsx as y,jsxs as b}from"react/jsx-runtime";var x={label:`Search commands`,placeholder:`Type a command or search…`,empty:`No results`,loading:`Searching…`,results:e=>e===1?`1 result`:`${e} results`};function S(S){let{items:C,isOpen:w,onClose:T,onAction:re,onQueryChange:E,filter:ie=!0,isLoading:ae=!1,presentation:oe,labels:se,className:ce,style:D,classNames:O,styles:k,...A}=e(`CommandPalette`,S),j=t(`CommandPalette`,se,x),M=m(),N=h(null),P=ne(),[F,I]=g(``),[L,R]=g(null),[z,B]=g(w);w!==z&&(B(w),w&&(I(``),R(null)));let V=h(E);p(()=>{V.current=E}),p(()=>{w&&V.current?.(``)},[w]);let H=ie?u(d(C),F):d(C),U=s(C),W=H.flatMap(e=>e.actions),G=e=>!!W[e]?.disabled,K=W.findIndex(e=>e.id===L&&!e.disabled),q=K>=0?K:i(`first`,W.length,{isDisabled:G}),J=e=>`${M}-${encodeURIComponent(e.id)}`,Y=q===null?void 0:J(W[q]);p(()=>{Y&&o(N.current,document.getElementById(Y))},[Y]);function X(e){e&&!e.disabled&&(l(e,re,P),T())}function le(e){if(!e.nativeEvent.isComposing){if(e.key===`ArrowDown`||e.key===`ArrowUp`){let t=a(q,e.key===`ArrowDown`?1:-1,W.length,{isDisabled:G});R(t===null?null:W[t].id)}else if(e.key===`Enter`)X(q===null?void 0:W[q]);else return;e.preventDefault()}}let Z=F.trim()!==``,Q=ae?j.loading:j.empty,$=-1;return b(r,{...A,"aria-label":j.label,isOpen:w,onClose:T,hideHeader:!0,presentation:oe,className:_(f.commandPalette,ce,O?.root),style:{...D,...k?.root},children:[b(`div`,{className:_(f.commandPaletteSearch,O?.search),style:k?.search,children:[n(v,{className:f.commandPaletteSearchIcon}),y(`input`,{type:`text`,role:`combobox`,"aria-label":j.label,"aria-expanded":`true`,"aria-controls":M,"aria-autocomplete":`list`,"aria-activedescendant":Y,autoComplete:`off`,spellCheck:!1,placeholder:j.placeholder,value:F,onChange:e=>{I(e.target.value),R(null),E?.(e.target.value)},onKeyDown:le,className:_(f.commandPaletteInput,O?.input),style:k?.input})]}),y(`div`,{ref:N,id:M,role:`listbox`,"aria-label":j.label,className:_(f.commandPaletteList,O?.list),style:k?.list,children:H.map((e,t)=>{let n=`${M}-heading-${t}`;return b(`div`,{role:e.heading===void 0?`presentation`:`group`,"aria-labelledby":e.heading===void 0?void 0:n,children:[e.separated&&t>0&&y(`div`,{"aria-hidden":!0,className:_(f.commandPaletteSeparator,O?.separator),style:k?.separator}),e.heading!==void 0&&y(`div`,{id:n,role:`presentation`,className:_(f.commandPaletteHeading,O?.heading),style:k?.heading,children:e.heading}),e.actions.map(e=>{$+=1;let t=$;return b(`div`,{id:J(e),role:`option`,"aria-selected":t===q,"aria-disabled":e.disabled||void 0,"aria-keyshortcuts":ee(e.shortcut),className:_(f.commandPaletteItem,t===q&&f.commandPaletteItemActive,e.danger&&f.commandPaletteItemDanger,e.disabled&&f.commandPaletteItemDisabled,O?.item),style:k?.item,onMouseDown:e=>e.preventDefault(),onMouseMove:()=>!e.disabled&&R(e.id),onClick:()=>X(e),children:[c(e.icon,U,{className:_(f.commandPaletteItemIcon,O?.itemIcon),style:k?.itemIcon}),y(`span`,{className:_(f.commandPaletteItemLabel,O?.itemLabel),style:k?.itemLabel,children:e.label}),e.shortcut!=null&&y(`span`,{"aria-hidden":!0,className:_(f.commandPaletteItemShortcut,O?.itemShortcut),style:k?.itemShortcut,children:te(e.shortcut)})]},e.id)})]},t)})}),Z&&W.length===0&&y(`div`,{className:_(f.commandPaletteEmpty,O?.empty),style:k?.empty,children:Q}),y(`span`,{className:f.commandPaletteStatus,role:`status`,"aria-live":`polite`,children:Z?W.length>0?j.results(W.length):Q:``})]})}export{S as default};
2
2
  //# sourceMappingURL=commandPalette.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"commandPalette.mjs","names":[],"sources":["../../../../package/common/commandPalette/commandPalette.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState, type KeyboardEvent, type ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons';\n\nimport Modal from '../modal';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { ariaKeyshortcuts, formatHotkey } from '../hooks/useHotkeys';\nimport { edgeIndex, nextIndex, scrollOptionIntoView } from '../utils/listNavigation';\nimport { renderIcon } from '../utils/renderIcon';\nimport type { MenuAction } from '../menu/menu.types';\nimport { hasAnyIcon, renderItemIcon, runMenuAction } from '../menu/menuItem';\nimport { filterCommands, groupCommands } from './filterCommands';\nimport type { CommandPaletteLabels, CommandPaletteProps } from './commandPalette.types';\nimport styles from './commandPalette.module.pcss';\n\nconst DEFAULT_LABELS: Required<CommandPaletteLabels> = {\n label: 'Search commands',\n placeholder: 'Type a command or search…',\n empty: 'No results',\n loading: 'Searching…',\n results: (count) => (count === 1 ? '1 result' : `${count} results`),\n};\n\nfunction CommandPalette(props: CommandPaletteProps): ReactElement {\n const {\n items,\n isOpen,\n onClose,\n onAction,\n onQueryChange,\n filter = true,\n isLoading = false,\n presentation,\n labels,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('CommandPalette', props);\n const text = useLabels('CommandPalette', labels, DEFAULT_LABELS);\n const listId = useId();\n const listRef = useRef<HTMLDivElement>(null);\n\n const [query, setQuery] = useState('');\n // An id rather than an index, so the highlight stays on the same command while server results\n // are replaced around it. Typing clears it instead, so Enter runs the best match.\n const [activeId, setActiveId] = useState<string | null>(null);\n const [wasOpen, setWasOpen] = useState(isOpen);\n if (isOpen !== wasOpen) {\n setWasOpen(isOpen);\n if (isOpen) {\n setQuery('');\n setActiveId(null);\n }\n }\n\n // Read through a ref so an inline handler does not re-fire the effect on every parent render.\n const onQueryChangeRef = useRef(onQueryChange);\n useEffect(() => {\n onQueryChangeRef.current = onQueryChange;\n });\n useEffect(() => {\n if (isOpen) onQueryChangeRef.current?.('');\n }, [isOpen]);\n\n const groups = filter ? filterCommands(groupCommands(items), query) : groupCommands(items);\n // From all items, not the matches, so the labels do not jump sideways while the user types.\n const hasIcons = hasAnyIcon(items);\n const actions = groups.flatMap((group) => group.actions);\n const isDisabled = (index: number) => !!actions[index]?.disabled;\n const found = actions.findIndex((action) => action.id === activeId && !action.disabled);\n const activeIndex = found >= 0 ? found : edgeIndex('first', actions.length, { isDisabled });\n // From the command's id, not its position: an id that stayed the same while the option under it\n // changed would not make a screen reader announce the new highlight.\n const optionId = (action: MenuAction) => `${listId}-${encodeURIComponent(action.id)}`;\n const activeOptionId = activeIndex === null ? undefined : optionId(actions[activeIndex]);\n\n useEffect(() => {\n if (!activeOptionId) return;\n scrollOptionIntoView(listRef.current, document.getElementById(activeOptionId));\n }, [activeOptionId]);\n\n function run(action: MenuAction | undefined) {\n if (!action || action.disabled) return;\n runMenuAction(action, onAction);\n onClose();\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n // Enter confirms an IME composition before it means anything here.\n if (event.nativeEvent.isComposing) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n const next = nextIndex(activeIndex, event.key === 'ArrowDown' ? 1 : -1, actions.length, { isDisabled });\n setActiveId(next === null ? null : actions[next].id);\n } else if (event.key === 'Enter') {\n run(activeIndex === null ? undefined : actions[activeIndex]);\n } else {\n return;\n }\n event.preventDefault();\n }\n\n const hasQuery = query.trim() !== '';\n const emptyText = isLoading ? text.loading : text.empty;\n let index = -1;\n\n return (\n <Modal\n {...rest}\n aria-label={text.label}\n isOpen={isOpen}\n onClose={onClose}\n hideHeader\n presentation={presentation}\n className={cx(styles.commandPalette, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <div className={cx(styles.commandPaletteSearch, classNames?.search)} style={slotStyles?.search}>\n {renderIcon(faMagnifyingGlass, { className: styles.commandPaletteSearchIcon })}\n <input\n type='text'\n role='combobox'\n aria-label={text.label}\n aria-expanded='true'\n aria-controls={listId}\n aria-autocomplete='list'\n aria-activedescendant={activeOptionId}\n autoComplete='off'\n spellCheck={false}\n placeholder={text.placeholder}\n value={query}\n onChange={(event) => {\n setQuery(event.target.value);\n setActiveId(null);\n onQueryChange?.(event.target.value);\n }}\n onKeyDown={handleKeyDown}\n className={cx(styles.commandPaletteInput, classNames?.input)}\n style={slotStyles?.input}\n />\n </div>\n\n <div\n ref={listRef}\n id={listId}\n role='listbox'\n aria-label={text.label}\n className={cx(styles.commandPaletteList, classNames?.list)}\n style={slotStyles?.list}\n >\n {groups.map((group, groupIndex) => {\n const headingId = `${listId}-heading-${groupIndex}`;\n return (\n <div\n // Groups carry no id of their own; a new query re-renders the list wholesale anyway.\n key={groupIndex}\n role={group.heading === undefined ? 'presentation' : 'group'}\n aria-labelledby={group.heading === undefined ? undefined : headingId}\n >\n {group.separated && groupIndex > 0 && (\n <div\n aria-hidden\n className={cx(styles.commandPaletteSeparator, classNames?.separator)}\n style={slotStyles?.separator}\n />\n )}\n {group.heading !== undefined && (\n <div\n id={headingId}\n role='presentation'\n className={cx(styles.commandPaletteHeading, classNames?.heading)}\n style={slotStyles?.heading}\n >\n {group.heading}\n </div>\n )}\n {group.actions.map((action) => {\n index += 1;\n const own = index;\n return (\n <div\n key={action.id}\n id={optionId(action)}\n role='option'\n aria-selected={own === activeIndex}\n aria-disabled={action.disabled || undefined}\n aria-keyshortcuts={ariaKeyshortcuts(action.shortcut)}\n className={cx(\n styles.commandPaletteItem,\n own === activeIndex && styles.commandPaletteItemActive,\n action.danger && styles.commandPaletteItemDanger,\n action.disabled && styles.commandPaletteItemDisabled,\n classNames?.item,\n )}\n style={slotStyles?.item}\n // Keeps the focus, and so the caret, in the search field.\n onMouseDown={(event) => event.preventDefault()}\n // Move, not enter: a list scrolling under a resting pointer must not steal the highlight.\n onMouseMove={() => !action.disabled && setActiveId(action.id)}\n onClick={() => run(action)}\n >\n {renderItemIcon(action.icon, hasIcons, {\n className: cx(styles.commandPaletteItemIcon, classNames?.itemIcon),\n style: slotStyles?.itemIcon,\n })}\n <span\n className={cx(styles.commandPaletteItemLabel, classNames?.itemLabel)}\n style={slotStyles?.itemLabel}\n >\n {action.label}\n </span>\n {action.shortcut != null && (\n <span\n aria-hidden\n className={cx(styles.commandPaletteItemShortcut, classNames?.itemShortcut)}\n style={slotStyles?.itemShortcut}\n >\n {formatHotkey(action.shortcut)}\n </span>\n )}\n </div>\n );\n })}\n </div>\n );\n })}\n </div>\n\n {hasQuery && actions.length === 0 && (\n <div className={cx(styles.commandPaletteEmpty, classNames?.empty)} style={slotStyles?.empty}>\n {emptyText}\n </div>\n )}\n <span className={styles.commandPaletteStatus} role='status' aria-live='polite'>\n {hasQuery ? (actions.length > 0 ? text.results(actions.length) : emptyText) : ''}\n </span>\n </Modal>\n );\n}\n\nexport default CommandPalette;\n"],"mappings":"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"}
1
+ {"version":3,"file":"commandPalette.mjs","names":[],"sources":["../../../../package/common/commandPalette/commandPalette.tsx"],"sourcesContent":["import { useEffect, useId, useRef, useState, type KeyboardEvent, type ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faMagnifyingGlass } from '@fortawesome/free-solid-svg-icons';\n\nimport Modal from '../modal';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { ariaKeyshortcuts, formatHotkey } from '../hooks/useHotkeys';\nimport { edgeIndex, nextIndex, scrollOptionIntoView } from '../utils/listNavigation';\nimport { renderIcon } from '../utils/renderIcon';\nimport { useFollowHref } from '../utils/navigation';\nimport type { MenuAction } from '../menu/menu.types';\nimport { hasAnyIcon, renderItemIcon, runMenuAction } from '../menu/menuItem';\nimport { filterCommands, groupCommands } from './filterCommands';\nimport type { CommandPaletteLabels, CommandPaletteProps } from './commandPalette.types';\nimport styles from './commandPalette.module.pcss';\n\nconst DEFAULT_LABELS: Required<CommandPaletteLabels> = {\n label: 'Search commands',\n placeholder: 'Type a command or search…',\n empty: 'No results',\n loading: 'Searching…',\n results: (count) => (count === 1 ? '1 result' : `${count} results`),\n};\n\nfunction CommandPalette(props: CommandPaletteProps): ReactElement {\n const {\n items,\n isOpen,\n onClose,\n onAction,\n onQueryChange,\n filter = true,\n isLoading = false,\n presentation,\n labels,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('CommandPalette', props);\n const text = useLabels('CommandPalette', labels, DEFAULT_LABELS);\n const listId = useId();\n const listRef = useRef<HTMLDivElement>(null);\n const followHref = useFollowHref();\n\n const [query, setQuery] = useState('');\n // An id rather than an index, so the highlight stays on the same command while server results\n // are replaced around it. Typing clears it instead, so Enter runs the best match.\n const [activeId, setActiveId] = useState<string | null>(null);\n const [wasOpen, setWasOpen] = useState(isOpen);\n if (isOpen !== wasOpen) {\n setWasOpen(isOpen);\n if (isOpen) {\n setQuery('');\n setActiveId(null);\n }\n }\n\n // Read through a ref so an inline handler does not re-fire the effect on every parent render.\n const onQueryChangeRef = useRef(onQueryChange);\n useEffect(() => {\n onQueryChangeRef.current = onQueryChange;\n });\n useEffect(() => {\n if (isOpen) onQueryChangeRef.current?.('');\n }, [isOpen]);\n\n const groups = filter ? filterCommands(groupCommands(items), query) : groupCommands(items);\n // From all items, not the matches, so the labels do not jump sideways while the user types.\n const hasIcons = hasAnyIcon(items);\n const actions = groups.flatMap((group) => group.actions);\n const isDisabled = (index: number) => !!actions[index]?.disabled;\n const found = actions.findIndex((action) => action.id === activeId && !action.disabled);\n const activeIndex = found >= 0 ? found : edgeIndex('first', actions.length, { isDisabled });\n // From the command's id, not its position: an id that stayed the same while the option under it\n // changed would not make a screen reader announce the new highlight.\n const optionId = (action: MenuAction) => `${listId}-${encodeURIComponent(action.id)}`;\n const activeOptionId = activeIndex === null ? undefined : optionId(actions[activeIndex]);\n\n useEffect(() => {\n if (!activeOptionId) return;\n scrollOptionIntoView(listRef.current, document.getElementById(activeOptionId));\n }, [activeOptionId]);\n\n function run(action: MenuAction | undefined) {\n if (!action || action.disabled) return;\n runMenuAction(action, onAction, followHref);\n onClose();\n }\n\n function handleKeyDown(event: KeyboardEvent<HTMLInputElement>) {\n // Enter confirms an IME composition before it means anything here.\n if (event.nativeEvent.isComposing) return;\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n const next = nextIndex(activeIndex, event.key === 'ArrowDown' ? 1 : -1, actions.length, { isDisabled });\n setActiveId(next === null ? null : actions[next].id);\n } else if (event.key === 'Enter') {\n run(activeIndex === null ? undefined : actions[activeIndex]);\n } else {\n return;\n }\n event.preventDefault();\n }\n\n const hasQuery = query.trim() !== '';\n const emptyText = isLoading ? text.loading : text.empty;\n let index = -1;\n\n return (\n <Modal\n {...rest}\n aria-label={text.label}\n isOpen={isOpen}\n onClose={onClose}\n hideHeader\n presentation={presentation}\n className={cx(styles.commandPalette, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <div className={cx(styles.commandPaletteSearch, classNames?.search)} style={slotStyles?.search}>\n {renderIcon(faMagnifyingGlass, { className: styles.commandPaletteSearchIcon })}\n <input\n type='text'\n role='combobox'\n aria-label={text.label}\n aria-expanded='true'\n aria-controls={listId}\n aria-autocomplete='list'\n aria-activedescendant={activeOptionId}\n autoComplete='off'\n spellCheck={false}\n placeholder={text.placeholder}\n value={query}\n onChange={(event) => {\n setQuery(event.target.value);\n setActiveId(null);\n onQueryChange?.(event.target.value);\n }}\n onKeyDown={handleKeyDown}\n className={cx(styles.commandPaletteInput, classNames?.input)}\n style={slotStyles?.input}\n />\n </div>\n\n <div\n ref={listRef}\n id={listId}\n role='listbox'\n aria-label={text.label}\n className={cx(styles.commandPaletteList, classNames?.list)}\n style={slotStyles?.list}\n >\n {groups.map((group, groupIndex) => {\n const headingId = `${listId}-heading-${groupIndex}`;\n return (\n <div\n // Groups carry no id of their own; a new query re-renders the list wholesale anyway.\n key={groupIndex}\n role={group.heading === undefined ? 'presentation' : 'group'}\n aria-labelledby={group.heading === undefined ? undefined : headingId}\n >\n {group.separated && groupIndex > 0 && (\n <div\n aria-hidden\n className={cx(styles.commandPaletteSeparator, classNames?.separator)}\n style={slotStyles?.separator}\n />\n )}\n {group.heading !== undefined && (\n <div\n id={headingId}\n role='presentation'\n className={cx(styles.commandPaletteHeading, classNames?.heading)}\n style={slotStyles?.heading}\n >\n {group.heading}\n </div>\n )}\n {group.actions.map((action) => {\n index += 1;\n const own = index;\n return (\n <div\n key={action.id}\n id={optionId(action)}\n role='option'\n aria-selected={own === activeIndex}\n aria-disabled={action.disabled || undefined}\n aria-keyshortcuts={ariaKeyshortcuts(action.shortcut)}\n className={cx(\n styles.commandPaletteItem,\n own === activeIndex && styles.commandPaletteItemActive,\n action.danger && styles.commandPaletteItemDanger,\n action.disabled && styles.commandPaletteItemDisabled,\n classNames?.item,\n )}\n style={slotStyles?.item}\n // Keeps the focus, and so the caret, in the search field.\n onMouseDown={(event) => event.preventDefault()}\n // Move, not enter: a list scrolling under a resting pointer must not steal the highlight.\n onMouseMove={() => !action.disabled && setActiveId(action.id)}\n onClick={() => run(action)}\n >\n {renderItemIcon(action.icon, hasIcons, {\n className: cx(styles.commandPaletteItemIcon, classNames?.itemIcon),\n style: slotStyles?.itemIcon,\n })}\n <span\n className={cx(styles.commandPaletteItemLabel, classNames?.itemLabel)}\n style={slotStyles?.itemLabel}\n >\n {action.label}\n </span>\n {action.shortcut != null && (\n <span\n aria-hidden\n className={cx(styles.commandPaletteItemShortcut, classNames?.itemShortcut)}\n style={slotStyles?.itemShortcut}\n >\n {formatHotkey(action.shortcut)}\n </span>\n )}\n </div>\n );\n })}\n </div>\n );\n })}\n </div>\n\n {hasQuery && actions.length === 0 && (\n <div className={cx(styles.commandPaletteEmpty, classNames?.empty)} style={slotStyles?.empty}>\n {emptyText}\n </div>\n )}\n <span className={styles.commandPaletteStatus} role='status' aria-live='polite'>\n {hasQuery ? (actions.length > 0 ? text.results(actions.length) : emptyText) : ''}\n </span>\n </Modal>\n );\n}\n\nexport default CommandPalette;\n"],"mappings":"i4BAgBA,IAAM,EAAiD,CACrD,MAAO,kBACP,YAAa,4BACb,MAAO,aACP,QAAS,aACT,QAAU,GAAW,IAAU,EAAI,WAAa,GAAG,EAAM,SAC3D,EAEA,SAAS,EAAe,EAA0C,CAChE,GAAM,CACJ,QACA,SACA,UACA,YACA,gBACA,UAAS,GACT,aAAY,GACZ,gBACA,UACA,aACA,QACA,aACA,OAAQ,EACR,GAAG,GACD,EAAqB,iBAAkB,CAAK,EAC1C,EAAO,EAAU,iBAAkB,GAAQ,CAAc,EACzD,EAAS,EAAM,EACf,EAAU,EAAuB,IAAI,EACrC,EAAa,GAAc,EAE3B,CAAC,EAAO,GAAY,EAAS,EAAE,EAG/B,CAAC,EAAU,GAAe,EAAwB,IAAI,EACtD,CAAC,EAAS,GAAc,EAAS,CAAM,EACzC,IAAW,IACb,EAAW,CAAM,EACb,IACF,EAAS,EAAE,EACX,EAAY,IAAI,IAKpB,IAAM,EAAmB,EAAO,CAAa,EAC7C,MAAgB,CACd,EAAiB,QAAU,CAC7B,CAAC,EACD,MAAgB,CACV,GAAQ,EAAiB,UAAU,EAAE,CAC3C,EAAG,CAAC,CAAM,CAAC,EAEX,IAAM,EAAS,GAAS,EAAe,EAAc,CAAK,EAAG,CAAK,EAAI,EAAc,CAAK,EAEnF,EAAW,EAAW,CAAK,EAC3B,EAAU,EAAO,QAAS,GAAU,EAAM,OAAO,EACjD,EAAc,GAAkB,CAAC,CAAC,EAAQ,EAAM,EAAE,SAClD,EAAQ,EAAQ,UAAW,GAAW,EAAO,KAAO,GAAY,CAAC,EAAO,QAAQ,EAChF,EAAc,GAAS,EAAI,EAAQ,EAAU,QAAS,EAAQ,OAAQ,CAAE,YAAW,CAAC,EAGpF,EAAY,GAAuB,GAAG,EAAO,GAAG,mBAAmB,EAAO,EAAE,IAC5E,EAAiB,IAAgB,KAAO,IAAA,GAAY,EAAS,EAAQ,EAAY,EAEvF,MAAgB,CACT,GACL,EAAqB,EAAQ,QAAS,SAAS,eAAe,CAAc,CAAC,CAC/E,EAAG,CAAC,CAAc,CAAC,EAEnB,SAAS,EAAI,EAAgC,CACtC,GAAU,GAAO,WACtB,EAAc,EAAQ,GAAU,CAAU,EAC1C,EAAQ,EACV,CAEA,SAAS,GAAc,EAAwC,CAEzD,MAAM,YAAY,YACtB,IAAI,EAAM,MAAQ,aAAe,EAAM,MAAQ,UAAW,CACxD,IAAM,EAAO,EAAU,EAAa,EAAM,MAAQ,YAAc,EAAI,GAAI,EAAQ,OAAQ,CAAE,YAAW,CAAC,EACtG,EAAY,IAAS,KAAO,KAAO,EAAQ,EAAK,CAAC,EAAE,CACrD,MAAO,GAAI,EAAM,MAAQ,QACvB,EAAI,IAAgB,KAAO,IAAA,GAAY,EAAQ,EAAY,OAE3D,OAEF,EAAM,eAAe,CAFnB,CAGJ,CAEA,IAAM,EAAW,EAAM,KAAK,IAAM,GAC5B,EAAY,GAAY,EAAK,QAAU,EAAK,MAC9C,EAAQ,GAEZ,OACE,EAAC,EAAD,CACE,GAAI,EACJ,aAAY,EAAK,MACT,SACC,UACT,WAAA,GACc,gBACd,UAAW,EAAG,EAAO,eAAgB,GAAW,GAAY,IAAI,EAChE,MAAO,CAAE,GAAG,EAAO,GAAG,GAAY,IAAK,EARzC,SAAA,CAUE,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,qBAAsB,GAAY,MAAM,EAAG,MAAO,GAAY,OAAxF,SAAA,CACG,EAAW,EAAmB,CAAE,UAAW,EAAO,wBAAyB,CAAC,EAC7E,EAAC,QAAD,CACE,KAAK,OACL,KAAK,WACL,aAAY,EAAK,MACjB,gBAAc,OACd,gBAAe,EACf,oBAAkB,OAClB,wBAAuB,EACvB,aAAa,MACb,WAAY,GACZ,YAAa,EAAK,YAClB,MAAO,EACP,SAAW,GAAU,CACnB,EAAS,EAAM,OAAO,KAAK,EAC3B,EAAY,IAAI,EAChB,IAAgB,EAAM,OAAO,KAAK,CACpC,EACA,UAAW,GACX,UAAW,EAAG,EAAO,oBAAqB,GAAY,KAAK,EAC3D,MAAO,GAAY,KACpB,CAAA,CACE,IAEL,EAAC,MAAD,CACE,IAAK,EACL,GAAI,EACJ,KAAK,UACL,aAAY,EAAK,MACjB,UAAW,EAAG,EAAO,mBAAoB,GAAY,IAAI,EACzD,MAAO,GAAY,KAElB,SAAA,EAAO,KAAK,EAAO,IAAe,CACjC,IAAM,EAAY,GAAG,EAAO,WAAW,IACvC,OACE,EAAC,MAAD,CAGE,KAAM,EAAM,UAAY,IAAA,GAAY,eAAiB,QACrD,kBAAiB,EAAM,UAAY,IAAA,GAAY,IAAA,GAAY,EAJ7D,SAAA,CAMG,EAAM,WAAa,EAAa,GAC/B,EAAC,MAAD,CACE,cAAA,GACA,UAAW,EAAG,EAAO,wBAAyB,GAAY,SAAS,EACnE,MAAO,GAAY,SACpB,CAAA,EAEF,EAAM,UAAY,IAAA,IACjB,EAAC,MAAD,CACE,GAAI,EACJ,KAAK,eACL,UAAW,EAAG,EAAO,sBAAuB,GAAY,OAAO,EAC/D,MAAO,GAAY,QAElB,SAAA,EAAM,OACJ,CAAA,EAEN,EAAM,QAAQ,IAAK,GAAW,CAC7B,GAAS,EACT,IAAM,EAAM,EACZ,OACE,EAAC,MAAD,CAEE,GAAI,EAAS,CAAM,EACnB,KAAK,SACL,gBAAe,IAAQ,EACvB,gBAAe,EAAO,UAAY,IAAA,GAClC,oBAAmB,GAAiB,EAAO,QAAQ,EACnD,UAAW,EACT,EAAO,mBACP,IAAQ,GAAe,EAAO,yBAC9B,EAAO,QAAU,EAAO,yBACxB,EAAO,UAAY,EAAO,2BAC1B,GAAY,IACd,EACA,MAAO,GAAY,KAEnB,YAAc,GAAU,EAAM,eAAe,EAE7C,gBAAmB,CAAC,EAAO,UAAY,EAAY,EAAO,EAAE,EAC5D,YAAe,EAAI,CAAM,EAnB3B,SAAA,CAqBG,EAAe,EAAO,KAAM,EAAU,CACrC,UAAW,EAAG,EAAO,uBAAwB,GAAY,QAAQ,EACjE,MAAO,GAAY,QACrB,CAAC,EACD,EAAC,OAAD,CACE,UAAW,EAAG,EAAO,wBAAyB,GAAY,SAAS,EACnE,MAAO,GAAY,UAElB,SAAA,EAAO,KACJ,CAAA,EACL,EAAO,UAAY,MAClB,EAAC,OAAD,CACE,cAAA,GACA,UAAW,EAAG,EAAO,2BAA4B,GAAY,YAAY,EACzE,MAAO,GAAY,aAElB,SAAA,GAAa,EAAO,QAAQ,CACzB,CAAA,CAEL,CAvCE,EAAA,EAAO,EAuCT,CAET,CAAC,CACE,CApEE,EAAA,CAoEF,CAET,CAAC,CACE,CAAA,EAEJ,GAAY,EAAQ,SAAW,GAC9B,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,oBAAqB,GAAY,KAAK,EAAG,MAAO,GAAY,MACnF,SAAA,CACE,CAAA,EAEP,EAAC,OAAD,CAAM,UAAW,EAAO,qBAAsB,KAAK,SAAS,YAAU,SACnE,SAAA,EAAY,EAAQ,OAAS,EAAI,EAAK,QAAQ,EAAQ,MAAM,EAAI,EAAa,EAC1E,CAAA,CACD,GAEX"}
@@ -1,2 +1,2 @@
1
- "use client";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};
1
+ "use client";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),o=e(void 0);function s(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 c({children:e,defaultProps:c,presentation:l,navigate:u}){let d=t(i),f=n(()=>s(d,c),[d,c]),p=t(a),m=l??p,h=t(o);return r(i.Provider,{value:f,children:r(a.Provider,{value:m,children:r(o.Provider,{value:u??h,children:e})})})}export{i as ConfigContext,o as NavigateContext,a as PresentationContext,c 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';\nimport type { Presentation } from '../configProvider/presentation.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(parent: ComponentDefaults | null, own: ComponentDefaults | undefined): 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}>{children}</PresentationContext.Provider>\n </ConfigContext.Provider>\n );\n}\n\nexport default ConfigProvider;\n"],"mappings":"wHAIA,IAAa,EAAgB,EAAwC,IAAI,EAQ5D,EAAsB,EAAwC,IAAA,EAAS,EAOpF,SAAS,EAAc,EAAkC,EAAuD,CAC9G,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,QAC7B,SAAA,EAAC,EAAoB,SAArB,CAA8B,MAAO,EAAoB,UAAuC,CAAA,CAC1E,CAAA,CAE5B"}
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 '../configProvider/presentation.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\nexport const NavigateContext = createContext<ConfigProviderProps['navigate']>(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(parent: ComponentDefaults | null, own: ComponentDefaults | undefined): 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, navigate }: 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 const inheritedNavigate = useContext(NavigateContext);\n\n return (\n <ConfigContext.Provider value={value}>\n <PresentationContext.Provider value={presentationValue}>\n <NavigateContext.Provider value={navigate ?? inheritedNavigate}>{children}</NavigateContext.Provider>\n </PresentationContext.Provider>\n </ConfigContext.Provider>\n );\n}\n\nexport default ConfigProvider;\n"],"mappings":"wHAIA,IAAa,EAAgB,EAAwC,IAAI,EAQ5D,EAAsB,EAAwC,IAAA,EAAS,EAEvE,EAAkB,EAA+C,IAAA,EAAS,EAOvF,SAAS,EAAc,EAAkC,EAAuD,CAC9G,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,eAAc,YAAiC,CAC/F,IAAM,EAAS,EAAW,CAAa,EACjC,EAAQ,MAAc,EAAc,EAAQ,CAAY,EAAG,CAAC,EAAQ,CAAY,CAAC,EAIjF,EAAwB,EAAW,CAAmB,EACtD,EAAoB,GAAgB,EACpC,EAAoB,EAAW,CAAe,EAEpD,OACE,EAAC,EAAc,SAAf,CAA+B,QAC7B,SAAA,EAAC,EAAoB,SAArB,CAA8B,MAAO,EACnC,SAAA,EAAC,EAAgB,SAAjB,CAA0B,MAAO,GAAY,EAAoB,UAAmC,CAAA,CACxE,CAAA,CACR,CAAA,CAE5B"}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../button/button.mjs";import n from"../actionIcon/actionIcon.mjs";import{PopoverAlign as r,PopoverPlacement as ee}from"../popover/popover.types.mjs";import te from"../popover/popover.mjs";import{asDay as i,parseDay as a}from"../utils/day.mjs";import ne from"../tooltip/tooltip.mjs";import re from"../input/input.mjs";import ie from"../modal/modal.mjs";import{getLocale as ae}from"../../services/localization.mjs";import{correctDateMaskValue as oe,getDateString as o,getMonthName as se,getMonthNames as ce,getToday as s,parseDateString as le}from"./dateFunctions.mjs";import ue from"./components/datePickerMonth/datePickerMonth.mjs";import c from"../dropdown/dropdown.mjs";import de from"../maskedInput/maskedInput.mjs";import l from"./datePicker.module.mjs";import{useEffect as u,useRef as d,useState as f}from"react";import p from"classnames";import{faChevronLeft as fe,faChevronRight as pe}from"@fortawesome/free-solid-svg-icons";import{Fragment as me,jsx as m,jsxs as h}from"react/jsx-runtime";function he(e){return e==null||e===``||i(e)?null:Object.prototype.toString.call(e)===`[object Date]`?`a Date. Convert it with dateToDay()`:`${JSON.stringify(e)}, which is not a day`}function g(g){let{className:ge=``,selected:_,onSelect:_e=()=>null,formValidator:v=null,noInput:ve=!1,noHeader:ye=!1,isModal:y=!1,isInline:b=!1,onChange:be=()=>null,minDate:x=null,maxDate:S=null,children:xe=null,showClearButton:Se=!1,label:C=``,isValid:Ce=!0,errorMessage:w=``,isRequired:we=!1,startDate:T,endDate:E,style:Te,classNames:D,styles:O,...Ee}=e(`DatePicker`,g),k=()=>i(v?v.value:_),A=i(x),j=i(S),M=k(),N=a(M)??s(),[P,F]=f(N.month),[I,L]=f(N.year),[R,z]=f(!1),[B,V]=f(()=>o(M)),[De,H]=f(!1),[Oe,U]=f(!1),[,ke]=f(0),[Ae,je]=f(_),W=d(v);if(Ae!==_){je(_);let e=a(_)??s();F(e.month),L(e.year),V(o(_))}let G=d(new Set),K=v?.value;u(()=>{let e={selected:_,formValidator:K,minDate:x,maxDate:S,startDate:T,endDate:E};for(let[t,n]of Object.entries(e)){let e=he(n);e&&!G.current.has(t)&&(G.current.add(t),console.warn(`DatePicker: \`${t}\` takes a day as a 'YYYY-MM-DD' string, and got ${e}. See "Migration from Date values" in docs/DatePicker.md.`))}},[_,K,x,S,T,E]),u(()=>{if(W.current=v,!v)return;v.label=C,v.validate();let e=()=>{let e=a(v.value);e&&(F(e.month),L(e.year)),V(o(v.value)),ke(e=>e+1)};return v.registerOnUpdateListener(e),()=>v.removeOnUpdateListener(e)},[v,C]);let Me=()=>v?v.touched&&v.hasError():!Ce||!!w,Ne=()=>!!(we||v?.validators.find(e=>e.validatorId===`required`)),q=e=>{V(o(e)),v&&v.set(e),be(e)},J=e=>{q(e),_e(e),z(!1)},Y=e=>{let t=I*12+P-1+e,n=Math.floor(t/12);n<0||n>9999||(L(n),F(t%12+1))},X=e=>{let t=le(e);return!t||A&&t<A||j&&t>j?null:t},Pe=({previousState:e,nextState:t})=>{if(t.value===e.value)return t;let n=oe(t.value,e.value,t.selection??null),r=X(n.value);return r&&q(r),n},Fe=()=>{let e=400,t=s().year-200,n=a(A),r=a(j);return n&&(t=n.year),r&&(e=Math.max(0,r.year-t+1)),Array.from(Array(e).keys()).map(e=>({key:e+t,label:e+t}))},Z=k(),Ie=Me(),Le=ye?null:h(`div`,{className:p(l.datePickerHeader,D?.header),style:O?.header,children:[m(n,{icon:fe,onClick:()=>Y(-1)}),m(`div`,{className:l.datePickerHeaderMonthAndYearContainer,children:h(`div`,{className:l.datePickerHeaderMonthAndYear,children:[m(c,{plainStyle:!0,scrollToSelected:!0,onChange:e=>F(e),className:p(l.datePickerHeaderMonth,D?.monthDropdown),style:O?.monthDropdown,value:se(ae(`-`),I,P,1),items:ce().map((e,t)=>({key:t+1,label:e}))}),m(c,{plainStyle:!0,scrollToSelected:!0,useMatLabelStyle:!1,className:p(l.datePickerHeaderYear,D?.yearDropdown),style:O?.yearDropdown,onChange:e=>L(e),value:I,items:Fe()})]})}),m(n,{icon:pe,onClick:()=>Y(1)})]}),Q=h(me,{children:[Le,m(ue,{className:p(l.datePickerMonth,D?.calendar),style:O?.calendar,month:P,year:I,onSelect:J,selectionStart:i(T)??Z,selectionEnd:i(E)??Z,minDate:A,maxDate:j,onNavigateMonth:Y}),Se&&m(t,{onClick:()=>J(null),className:D?.clearButton,style:O?.clearButton,children:`Clear`}),xe]}),$=ve?null:m(re,{autoComplete:`off`,className:D?.input,style:O?.input,readOnly:y,classNames:y?{input:l.datePickerModalInput}:void 0,label:`${C}${Ne()?` *`:``}`,value:B,onChange:e=>V(e),onClick:()=>z(!0),customInput:m(de,{mask:`99.99.9999`,beforeMaskedStateChange:Pe}),onBlur:()=>{W.current&&(W.current.touched=!0),H(!1),B!==o(k())&&q(X(B))},onFocus:()=>H(!0),onMouseEnter:()=>U(!0),onMouseLeave:()=>U(!1),isValid:!Ie}),Re=b?Q:y?m(ie,{hideHeader:!0,isOpen:R,onClose:()=>z(!1),children:Q}):m(te,{isOpen:R,onOpenChange:e=>z(e),content:Q,placement:ee.Bottom,align:r.Start,closeOnTriggerClick:!1,constrainWidth:!1,children:$});return h(`div`,{...Ee,className:p(l.datePicker,ge,D?.root),style:{...Te,...O?.root},children:[(y||b)&&$,Re,m(ne,{variant:`error`,message:v?v.getCurrentErrorMessage():w||``,isVisible:Ie&&(De||Oe)})]})}export{g as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import t from"../button/button.mjs";import n from"../actionIcon/actionIcon.mjs";import{PopoverAlign as r,PopoverPlacement as ee}from"../popover/popover.types.mjs";import te from"../popover/popover.mjs";import{asDay as i,parseDay as a}from"../utils/day.mjs";import ne from"../tooltip/tooltip.mjs";import re from"../input/input.mjs";import ie from"../modal/modal.mjs";import{getLocale as ae}from"../../services/localization.mjs";import{correctDateMaskValue as oe,getDateString as o,getMonthName as se,getMonthNames as ce,getToday as s,parseDateString as le}from"./dateFunctions.mjs";import ue from"./components/datePickerMonth/datePickerMonth.mjs";import c from"../dropdown/dropdown.mjs";import de from"../maskedInput/maskedInput.mjs";import l from"./datePicker.module.mjs";import{useEffect as u,useRef as d,useState as f}from"react";import p from"classnames";import{faChevronLeft as fe,faChevronRight as pe}from"@fortawesome/free-solid-svg-icons";import{Fragment as me,jsx as m,jsxs as h}from"react/jsx-runtime";function he(e){return e==null||e===``||i(e)?null:Object.prototype.toString.call(e)===`[object Date]`?`a Date. Convert it with dateToDay()`:`${JSON.stringify(e)}, which is not a day`}function g(g){let{className:ge=``,selected:_,onSelect:_e=()=>null,formValidator:v=null,noInput:ve=!1,noHeader:ye=!1,isModal:y=!1,isInline:b=!1,onChange:be=()=>null,minDate:x=null,maxDate:S=null,children:xe=null,showClearButton:Se=!1,label:C=``,isValid:Ce=!0,errorMessage:w=``,isRequired:we=!1,startDate:T,endDate:E,style:Te,classNames:D,styles:O,...Ee}=e(`DatePicker`,g),k=()=>i(v?v.value:_),A=i(x),j=i(S),M=k(),N=a(M)??s(),[P,F]=f(N.month),[I,L]=f(N.year),[R,z]=f(!1),[B,V]=f(()=>o(M)),[De,H]=f(!1),[Oe,U]=f(!1),[,ke]=f(0),[Ae,je]=f(_),W=d(v);if(Ae!==_){je(_);let e=a(_)??s();F(e.month),L(e.year),V(o(_))}let G=d(new Set),K=v?.value;u(()=>{let e={selected:_,formValidator:K,minDate:x,maxDate:S,startDate:T,endDate:E};for(let[t,n]of Object.entries(e)){let e=he(n);e&&!G.current.has(t)&&(G.current.add(t),console.warn(`DatePicker: \`${t}\` takes a day as a 'YYYY-MM-DD' string, and got ${e}. See "Migration from Date values" in docs/DatePicker.md.`))}},[_,K,x,S,T,E]),u(()=>{if(W.current=v,!v)return;v.label=C,v.validate();let e=()=>{let e=a(v.value);e&&(F(e.month),L(e.year)),V(o(v.value)),ke(e=>e+1)};return v.registerOnUpdateListener(e),()=>v.removeOnUpdateListener(e)},[v,C]);let Me=()=>v?v.shouldShowError:!Ce||!!w,Ne=()=>!!(we||v?.validators.find(e=>e.validatorId===`required`)),q=e=>{V(o(e)),v&&v.set(e),be(e)},J=e=>{q(e),_e(e),z(!1)},Y=e=>{let t=I*12+P-1+e,n=Math.floor(t/12);n<0||n>9999||(L(n),F(t%12+1))},X=e=>{let t=le(e);return!t||A&&t<A||j&&t>j?null:t},Pe=({previousState:e,nextState:t})=>{if(t.value===e.value)return t;let n=oe(t.value,e.value,t.selection??null),r=X(n.value);return r&&q(r),n},Fe=()=>{let e=400,t=s().year-200,n=a(A),r=a(j);return n&&(t=n.year),r&&(e=Math.max(0,r.year-t+1)),Array.from(Array(e).keys()).map(e=>({key:e+t,label:e+t}))},Z=k(),Ie=Me(),Le=ye?null:h(`div`,{className:p(l.datePickerHeader,D?.header),style:O?.header,children:[m(n,{icon:fe,onClick:()=>Y(-1)}),m(`div`,{className:l.datePickerHeaderMonthAndYearContainer,children:h(`div`,{className:l.datePickerHeaderMonthAndYear,children:[m(c,{plainStyle:!0,scrollToSelected:!0,onChange:e=>F(e),className:p(l.datePickerHeaderMonth,D?.monthDropdown),style:O?.monthDropdown,value:se(ae(`-`),I,P,1),items:ce().map((e,t)=>({key:t+1,label:e}))}),m(c,{plainStyle:!0,scrollToSelected:!0,useMatLabelStyle:!1,className:p(l.datePickerHeaderYear,D?.yearDropdown),style:O?.yearDropdown,onChange:e=>L(e),value:I,items:Fe()})]})}),m(n,{icon:pe,onClick:()=>Y(1)})]}),Q=h(me,{children:[Le,m(ue,{className:p(l.datePickerMonth,D?.calendar),style:O?.calendar,month:P,year:I,onSelect:J,selectionStart:i(T)??Z,selectionEnd:i(E)??Z,minDate:A,maxDate:j,onNavigateMonth:Y}),Se&&m(t,{onClick:()=>J(null),className:D?.clearButton,style:O?.clearButton,children:`Clear`}),xe]}),$=ve?null:m(re,{autoComplete:`off`,className:D?.input,style:O?.input,readOnly:y,classNames:y?{input:l.datePickerModalInput}:void 0,label:`${C}${Ne()?` *`:``}`,value:B,onChange:e=>V(e),onClick:()=>z(!0),customInput:m(de,{mask:`99.99.9999`,beforeMaskedStateChange:Pe}),onBlur:()=>{W.current&&(W.current.touched=!0),H(!1),B!==o(k())&&q(X(B))},onFocus:()=>H(!0),onMouseEnter:()=>U(!0),onMouseLeave:()=>U(!1),isValid:!Ie}),Re=b?Q:y?m(ie,{hideHeader:!0,isOpen:R,onClose:()=>z(!1),children:Q}):m(te,{isOpen:R,onOpenChange:e=>z(e),content:Q,placement:ee.Bottom,align:r.Start,closeOnTriggerClick:!1,constrainWidth:!1,children:$});return h(`div`,{...Ee,className:p(l.datePicker,ge,D?.root),style:{...Te,...O?.root},children:[(y||b)&&$,Re,m(ne,{variant:`error`,message:v?v.getCurrentErrorMessage():w||``,isVisible:Ie&&(De||Oe)})]})}export{g as default};
2
2
  //# sourceMappingURL=datePicker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"datePicker.mjs","names":[],"sources":["../../../../package/common/datePicker/datePicker.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport Input from '../input';\nimport { useComponentDefaults } from '../configProvider';\nimport DatePickerMonth from './components/datePickerMonth';\nimport { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';\nimport { getLocale } from 'services/localization';\nimport ActionIcon from '../actionIcon';\nimport Modal from '../modal';\nimport Popover from '../popover';\nimport Dropdown from '../dropdown';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport MaskedInput from '../maskedInput';\nimport type { BeforeMaskedStateChangeStates, MaskState } from '../maskedInput';\nimport { asDay, parseDay } from '../utils/day';\nimport {\n getMonthName,\n getMonthNames,\n getDateString,\n getToday,\n parseDateString,\n correctDateMaskValue,\n} from './dateFunctions';\nimport Button from '../button';\nimport Tooltip from '../tooltip';\nimport type { FormValidator } from 'services/formValidation';\nimport type { DatePickerProps } from './datePicker.types';\n\nimport styles from './datePicker.module.pcss';\n\n/**\n * Why `value` is not a day, or `null` when it is one or is empty. Days were `Date`s before 0.39,\n * and stored as their JSON, a timestamp; either still gets through a loosely typed validator or\n * plain JavaScript, and would otherwise just show an empty field.\n */\nfunction notADay(value: unknown): string | null {\n if (value === null || value === undefined || value === '' || asDay(value)) return null;\n if (Object.prototype.toString.call(value) === '[object Date]') return 'a Date. Convert it with dateToDay()';\n return `${JSON.stringify(value)}, which is not a day`;\n}\n\nexport default function DatePicker(props: DatePickerProps) {\n const {\n className = '',\n selected,\n onSelect = () => null,\n formValidator = null,\n noInput = false,\n noHeader = false,\n isModal = false,\n isInline = false,\n onChange = () => null,\n minDate = null,\n maxDate = null,\n children = null,\n showClearButton = false,\n label = '',\n isValid = true,\n errorMessage = '',\n isRequired = false,\n startDate,\n endDate,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('DatePicker', props);\n const getCurrValue = (): string | null => asDay(formValidator ? formValidator.value : selected);\n const minDay = asDay(minDate);\n const maxDay = asDay(maxDate);\n\n const initialValue = getCurrValue();\n const initialDay = parseDay(initialValue) ?? getToday();\n\n const [currentMonth, setCurrentMonth] = useState(initialDay.month);\n const [currentYear, setCurrentYear] = useState(initialDay.year);\n const [isPickerOpen, setIsPickerOpen] = useState(false);\n const [currentDateString, setCurrentDateString] = useState(() => getDateString(initialValue));\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [, forceUpdate] = useState(0);\n const [prevSelected, setPrevSelected] = useState(selected);\n\n const fvRef = useRef(formValidator);\n\n // Sync navigation view when `selected` prop changes externally\n if (prevSelected !== selected) {\n setPrevSelected(selected);\n const shown = parseDay(selected) ?? getToday();\n setCurrentMonth(shown.month);\n setCurrentYear(shown.year);\n setCurrentDateString(getDateString(selected));\n }\n\n // Once per prop: a `new Date()` written inline is a new object on every render.\n const warned = useRef(new Set<string>());\n const validatorValue: unknown = formValidator?.value;\n useEffect(() => {\n const values = { selected, formValidator: validatorValue, minDate, maxDate, startDate, endDate };\n for (const [name, value] of Object.entries(values)) {\n const problem = notADay(value);\n if (!problem || warned.current.has(name)) continue;\n warned.current.add(name);\n console.warn(\n `DatePicker: \\`${name}\\` takes a day as a 'YYYY-MM-DD' string, and got ${problem}. ` +\n `See \"Migration from Date values\" in docs/DatePicker.md.`,\n );\n }\n }, [selected, validatorValue, minDate, maxDate, startDate, endDate]);\n\n // Subscribe to formValidator updates (external system → setState in callback)\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n formValidator.label = label;\n formValidator.validate();\n const listener = () => {\n const shown = parseDay(formValidator.value);\n if (shown) {\n setCurrentMonth(shown.month);\n setCurrentYear(shown.year);\n }\n setCurrentDateString(getDateString(formValidator.value));\n forceUpdate((n: number) => n + 1);\n };\n formValidator.registerOnUpdateListener(listener);\n return () => formValidator.removeOnUpdateListener(listener);\n }, [formValidator, label]);\n\n const hasError = (): boolean => {\n return formValidator ? formValidator.touched && formValidator.hasError() : !isValid || !!errorMessage;\n };\n\n const computedIsRequired = (): boolean => {\n return !!(\n isRequired || formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required')\n );\n };\n\n const handleChange = (day: string | null) => {\n setCurrentDateString(getDateString(day));\n // Typed as a union so each validator TypeScript infers for a day fits; all of them hold one.\n if (formValidator) (formValidator as FormValidator<string | null>).set(day);\n onChange(day);\n };\n\n const handleSelect = (day: string | null) => {\n handleChange(day);\n onSelect(day);\n setIsPickerOpen(false);\n };\n\n const changeMonth = (delta: number) => {\n const index = currentYear * 12 + currentMonth - 1 + delta;\n const year = Math.floor(index / 12);\n // A day is written with four digits, so the calendar stops at the years it can name.\n if (year < 0 || year > 9999) return;\n setCurrentYear(year);\n setCurrentMonth((index % 12) + 1);\n };\n\n const tryParseDateString = (text: string): string | null => {\n const day = parseDateString(text);\n // `'YYYY-MM-DD'` sorts as it reads, so the bounds compare as plain strings.\n if (!day || (minDay && day < minDay) || (maxDay && day > maxDay)) return null;\n return day;\n };\n\n const beforeMaskedStateChange = ({ previousState, nextState }: BeforeMaskedStateChangeStates): MaskState => {\n // A change that moved nothing needs no correcting, and re-running the day/month padding on\n // an unchanged value would fight the caret the mask just placed.\n if (nextState.value === previousState.value) return nextState;\n\n const corrected = correctDateMaskValue(nextState.value, previousState.value, nextState.selection ?? null);\n\n const parsed = tryParseDateString(corrected.value);\n if (parsed) handleChange(parsed);\n\n return corrected;\n };\n\n const getYearDropdownOptions = () => {\n let length = 400;\n let zeroOffset = getToday().year - 200;\n const min = parseDay(minDay);\n const max = parseDay(maxDay);\n if (min) zeroOffset = min.year;\n // Never negative: a `maxDate` before `minDate` made `Array(length)` throw during render.\n if (max) length = Math.max(0, max.year - zeroOffset + 1);\n return Array.from(Array(length).keys()).map((i) => ({ key: i + zeroOffset, label: i + zeroOffset }));\n };\n\n const currValue = getCurrValue();\n const hasErr = hasError();\n\n const header = noHeader ? null : (\n <div className={cx(styles.datePickerHeader, classNames?.header)} style={slotStyles?.header}>\n <ActionIcon icon={faChevronLeft} onClick={() => changeMonth(-1)} />\n <div className={styles.datePickerHeaderMonthAndYearContainer}>\n <div className={styles.datePickerHeaderMonthAndYear}>\n <Dropdown\n plainStyle\n scrollToSelected\n onChange={(v) => setCurrentMonth(v as number)}\n className={cx(styles.datePickerHeaderMonth, classNames?.monthDropdown)}\n style={slotStyles?.monthDropdown}\n value={getMonthName(getLocale('-'), currentYear, currentMonth, 1)}\n items={getMonthNames().map((month, index) => ({ key: index + 1, label: month }))}\n />\n <Dropdown\n plainStyle\n scrollToSelected\n useMatLabelStyle={false}\n className={cx(styles.datePickerHeaderYear, classNames?.yearDropdown)}\n style={slotStyles?.yearDropdown}\n onChange={(v) => setCurrentYear(v as number)}\n value={currentYear}\n items={getYearDropdownOptions()}\n />\n </div>\n </div>\n <ActionIcon icon={faChevronRight} onClick={() => changeMonth(1)} />\n </div>\n );\n\n const pickerContent = (\n <>\n {header}\n <DatePickerMonth\n className={cx(styles.datePickerMonth, classNames?.calendar)}\n style={slotStyles?.calendar}\n month={currentMonth}\n year={currentYear}\n onSelect={handleSelect}\n selectionStart={asDay(startDate) ?? currValue}\n selectionEnd={asDay(endDate) ?? currValue}\n minDate={minDay}\n maxDate={maxDay}\n onNavigateMonth={changeMonth}\n />\n {showClearButton && (\n <Button onClick={() => handleSelect(null)} className={classNames?.clearButton} style={slotStyles?.clearButton}>\n Clear\n </Button>\n )}\n {children}\n </>\n );\n\n const input = noInput ? null : (\n <Input\n autoComplete='off'\n className={classNames?.input}\n style={slotStyles?.input}\n readOnly={isModal}\n classNames={isModal ? { input: styles.datePickerModalInput } : undefined}\n label={`${label}${computedIsRequired() ? ' *' : ''}`}\n value={currentDateString}\n onChange={(v) => setCurrentDateString(v as string)}\n onClick={() => setIsPickerOpen(true)}\n customInput={<MaskedInput mask='99.99.9999' beforeMaskedStateChange={beforeMaskedStateChange} />}\n onBlur={() => {\n if (fvRef.current) fvRef.current.touched = true;\n setIsFocused(false);\n // Only an edit is written back. A value the field cannot show, a leftover Date or a\n // timestamp, shows as empty, and writing that back would erase it on a mere tab-through.\n if (currentDateString !== getDateString(getCurrValue())) handleChange(tryParseDateString(currentDateString));\n }}\n onFocus={() => setIsFocused(true)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n isValid={!hasErr}\n />\n );\n\n const picker = (() => {\n if (isInline) return pickerContent;\n if (isModal) {\n return (\n <Modal hideHeader isOpen={isPickerOpen} onClose={() => setIsPickerOpen(false)}>\n {pickerContent}\n </Modal>\n );\n }\n return (\n <Popover\n isOpen={isPickerOpen}\n onOpenChange={(open: boolean) => setIsPickerOpen(open)}\n content={pickerContent}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n // A click to place the caret in the field must not take the panel away.\n // The focus stays there on its own: Popover only follows a keyboard open.\n closeOnTriggerClick={false}\n constrainWidth={false}\n >\n {input}\n </Popover>\n );\n })();\n\n return (\n <div\n {...rest}\n className={cx(styles.datePicker, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {(isModal || isInline) && input}\n {picker}\n <Tooltip\n variant='error'\n message={formValidator ? formValidator.getCurrentErrorMessage() : errorMessage || ''}\n isVisible={hasErr && (isFocused || isHovered)}\n />\n </div>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"datePicker.mjs","names":[],"sources":["../../../../package/common/datePicker/datePicker.tsx"],"sourcesContent":["import React, { useState, useEffect, useRef } from 'react';\nimport cx from 'classnames';\nimport Input from '../input';\nimport { useComponentDefaults } from '../configProvider';\nimport DatePickerMonth from './components/datePickerMonth';\nimport { faChevronLeft, faChevronRight } from '@fortawesome/free-solid-svg-icons';\nimport { getLocale } from 'services/localization';\nimport ActionIcon from '../actionIcon';\nimport Modal from '../modal';\nimport Popover from '../popover';\nimport Dropdown from '../dropdown';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport MaskedInput from '../maskedInput';\nimport type { BeforeMaskedStateChangeStates, MaskState } from '../maskedInput';\nimport { asDay, parseDay } from '../utils/day';\nimport {\n getMonthName,\n getMonthNames,\n getDateString,\n getToday,\n parseDateString,\n correctDateMaskValue,\n} from './dateFunctions';\nimport Button from '../button';\nimport Tooltip from '../tooltip';\nimport type { FormValidator } from 'services/formValidation';\nimport type { DatePickerProps } from './datePicker.types';\n\nimport styles from './datePicker.module.pcss';\n\n/**\n * Why `value` is not a day, or `null` when it is one or is empty. Days were `Date`s before 0.39,\n * and stored as their JSON, a timestamp; either still gets through a loosely typed validator or\n * plain JavaScript, and would otherwise just show an empty field.\n */\nfunction notADay(value: unknown): string | null {\n if (value === null || value === undefined || value === '' || asDay(value)) return null;\n if (Object.prototype.toString.call(value) === '[object Date]') return 'a Date. Convert it with dateToDay()';\n return `${JSON.stringify(value)}, which is not a day`;\n}\n\nexport default function DatePicker(props: DatePickerProps) {\n const {\n className = '',\n selected,\n onSelect = () => null,\n formValidator = null,\n noInput = false,\n noHeader = false,\n isModal = false,\n isInline = false,\n onChange = () => null,\n minDate = null,\n maxDate = null,\n children = null,\n showClearButton = false,\n label = '',\n isValid = true,\n errorMessage = '',\n isRequired = false,\n startDate,\n endDate,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('DatePicker', props);\n const getCurrValue = (): string | null => asDay(formValidator ? formValidator.value : selected);\n const minDay = asDay(minDate);\n const maxDay = asDay(maxDate);\n\n const initialValue = getCurrValue();\n const initialDay = parseDay(initialValue) ?? getToday();\n\n const [currentMonth, setCurrentMonth] = useState(initialDay.month);\n const [currentYear, setCurrentYear] = useState(initialDay.year);\n const [isPickerOpen, setIsPickerOpen] = useState(false);\n const [currentDateString, setCurrentDateString] = useState(() => getDateString(initialValue));\n const [isFocused, setIsFocused] = useState(false);\n const [isHovered, setIsHovered] = useState(false);\n const [, forceUpdate] = useState(0);\n const [prevSelected, setPrevSelected] = useState(selected);\n\n const fvRef = useRef(formValidator);\n\n // Sync navigation view when `selected` prop changes externally\n if (prevSelected !== selected) {\n setPrevSelected(selected);\n const shown = parseDay(selected) ?? getToday();\n setCurrentMonth(shown.month);\n setCurrentYear(shown.year);\n setCurrentDateString(getDateString(selected));\n }\n\n // Once per prop: a `new Date()` written inline is a new object on every render.\n const warned = useRef(new Set<string>());\n const validatorValue: unknown = formValidator?.value;\n useEffect(() => {\n const values = { selected, formValidator: validatorValue, minDate, maxDate, startDate, endDate };\n for (const [name, value] of Object.entries(values)) {\n const problem = notADay(value);\n if (!problem || warned.current.has(name)) continue;\n warned.current.add(name);\n console.warn(\n `DatePicker: \\`${name}\\` takes a day as a 'YYYY-MM-DD' string, and got ${problem}. ` +\n `See \"Migration from Date values\" in docs/DatePicker.md.`,\n );\n }\n }, [selected, validatorValue, minDate, maxDate, startDate, endDate]);\n\n // Subscribe to formValidator updates (external system → setState in callback)\n useEffect(() => {\n fvRef.current = formValidator;\n if (!formValidator) return;\n formValidator.label = label;\n formValidator.validate();\n const listener = () => {\n const shown = parseDay(formValidator.value);\n if (shown) {\n setCurrentMonth(shown.month);\n setCurrentYear(shown.year);\n }\n setCurrentDateString(getDateString(formValidator.value));\n forceUpdate((n: number) => n + 1);\n };\n formValidator.registerOnUpdateListener(listener);\n return () => formValidator.removeOnUpdateListener(listener);\n }, [formValidator, label]);\n\n const hasError = (): boolean => {\n return formValidator ? formValidator.shouldShowError : !isValid || !!errorMessage;\n };\n\n const computedIsRequired = (): boolean => {\n return !!(\n isRequired || formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required')\n );\n };\n\n const handleChange = (day: string | null) => {\n setCurrentDateString(getDateString(day));\n // Typed as a union so each validator TypeScript infers for a day fits; all of them hold one.\n if (formValidator) (formValidator as FormValidator<string | null>).set(day);\n onChange(day);\n };\n\n const handleSelect = (day: string | null) => {\n handleChange(day);\n onSelect(day);\n setIsPickerOpen(false);\n };\n\n const changeMonth = (delta: number) => {\n const index = currentYear * 12 + currentMonth - 1 + delta;\n const year = Math.floor(index / 12);\n // A day is written with four digits, so the calendar stops at the years it can name.\n if (year < 0 || year > 9999) return;\n setCurrentYear(year);\n setCurrentMonth((index % 12) + 1);\n };\n\n const tryParseDateString = (text: string): string | null => {\n const day = parseDateString(text);\n // `'YYYY-MM-DD'` sorts as it reads, so the bounds compare as plain strings.\n if (!day || (minDay && day < minDay) || (maxDay && day > maxDay)) return null;\n return day;\n };\n\n const beforeMaskedStateChange = ({ previousState, nextState }: BeforeMaskedStateChangeStates): MaskState => {\n // A change that moved nothing needs no correcting, and re-running the day/month padding on\n // an unchanged value would fight the caret the mask just placed.\n if (nextState.value === previousState.value) return nextState;\n\n const corrected = correctDateMaskValue(nextState.value, previousState.value, nextState.selection ?? null);\n\n const parsed = tryParseDateString(corrected.value);\n if (parsed) handleChange(parsed);\n\n return corrected;\n };\n\n const getYearDropdownOptions = () => {\n let length = 400;\n let zeroOffset = getToday().year - 200;\n const min = parseDay(minDay);\n const max = parseDay(maxDay);\n if (min) zeroOffset = min.year;\n // Never negative: a `maxDate` before `minDate` made `Array(length)` throw during render.\n if (max) length = Math.max(0, max.year - zeroOffset + 1);\n return Array.from(Array(length).keys()).map((i) => ({ key: i + zeroOffset, label: i + zeroOffset }));\n };\n\n const currValue = getCurrValue();\n const hasErr = hasError();\n\n const header = noHeader ? null : (\n <div className={cx(styles.datePickerHeader, classNames?.header)} style={slotStyles?.header}>\n <ActionIcon icon={faChevronLeft} onClick={() => changeMonth(-1)} />\n <div className={styles.datePickerHeaderMonthAndYearContainer}>\n <div className={styles.datePickerHeaderMonthAndYear}>\n <Dropdown\n plainStyle\n scrollToSelected\n onChange={(v) => setCurrentMonth(v as number)}\n className={cx(styles.datePickerHeaderMonth, classNames?.monthDropdown)}\n style={slotStyles?.monthDropdown}\n value={getMonthName(getLocale('-'), currentYear, currentMonth, 1)}\n items={getMonthNames().map((month, index) => ({ key: index + 1, label: month }))}\n />\n <Dropdown\n plainStyle\n scrollToSelected\n useMatLabelStyle={false}\n className={cx(styles.datePickerHeaderYear, classNames?.yearDropdown)}\n style={slotStyles?.yearDropdown}\n onChange={(v) => setCurrentYear(v as number)}\n value={currentYear}\n items={getYearDropdownOptions()}\n />\n </div>\n </div>\n <ActionIcon icon={faChevronRight} onClick={() => changeMonth(1)} />\n </div>\n );\n\n const pickerContent = (\n <>\n {header}\n <DatePickerMonth\n className={cx(styles.datePickerMonth, classNames?.calendar)}\n style={slotStyles?.calendar}\n month={currentMonth}\n year={currentYear}\n onSelect={handleSelect}\n selectionStart={asDay(startDate) ?? currValue}\n selectionEnd={asDay(endDate) ?? currValue}\n minDate={minDay}\n maxDate={maxDay}\n onNavigateMonth={changeMonth}\n />\n {showClearButton && (\n <Button onClick={() => handleSelect(null)} className={classNames?.clearButton} style={slotStyles?.clearButton}>\n Clear\n </Button>\n )}\n {children}\n </>\n );\n\n const input = noInput ? null : (\n <Input\n autoComplete='off'\n className={classNames?.input}\n style={slotStyles?.input}\n readOnly={isModal}\n classNames={isModal ? { input: styles.datePickerModalInput } : undefined}\n label={`${label}${computedIsRequired() ? ' *' : ''}`}\n value={currentDateString}\n onChange={(v) => setCurrentDateString(v as string)}\n onClick={() => setIsPickerOpen(true)}\n customInput={<MaskedInput mask='99.99.9999' beforeMaskedStateChange={beforeMaskedStateChange} />}\n onBlur={() => {\n if (fvRef.current) fvRef.current.touched = true;\n setIsFocused(false);\n // Only an edit is written back. A value the field cannot show, a leftover Date or a\n // timestamp, shows as empty, and writing that back would erase it on a mere tab-through.\n if (currentDateString !== getDateString(getCurrValue())) handleChange(tryParseDateString(currentDateString));\n }}\n onFocus={() => setIsFocused(true)}\n onMouseEnter={() => setIsHovered(true)}\n onMouseLeave={() => setIsHovered(false)}\n isValid={!hasErr}\n />\n );\n\n const picker = (() => {\n if (isInline) return pickerContent;\n if (isModal) {\n return (\n <Modal hideHeader isOpen={isPickerOpen} onClose={() => setIsPickerOpen(false)}>\n {pickerContent}\n </Modal>\n );\n }\n return (\n <Popover\n isOpen={isPickerOpen}\n onOpenChange={(open: boolean) => setIsPickerOpen(open)}\n content={pickerContent}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n // A click to place the caret in the field must not take the panel away.\n // The focus stays there on its own: Popover only follows a keyboard open.\n closeOnTriggerClick={false}\n constrainWidth={false}\n >\n {input}\n </Popover>\n );\n })();\n\n return (\n <div\n {...rest}\n className={cx(styles.datePicker, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n {(isModal || isInline) && input}\n {picker}\n <Tooltip\n variant='error'\n message={formValidator ? formValidator.getCurrentErrorMessage() : errorMessage || ''}\n isVisible={hasErr && (isFocused || isHovered)}\n />\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import{Presentation as n}from"../configProvider/presentation.types.mjs";import ee from"../loader/loader.mjs";import r from"../styles/sheet.module.mjs";import{PopoverAlign as te,PopoverPlacement as ne}from"../popover/popover.types.mjs";import re from"../hooks/useSheet.mjs";import ie from"../popover/popover.mjs";import{useInfiniteScroll as ae}from"../infiniteBlock/useInfiniteScroll.mjs";import oe from"../tooltip/tooltip.mjs";import{edgeIndex as se,nextIndex as ce,scrollOptionIntoView as le}from"../utils/listNavigation.mjs";import i from"./dropdown.module.mjs";import{useEffect as ue,useId as de,useLayoutEffect as fe,useRef as a,useState as o}from"react";import s from"classnames";import{FontAwesomeIcon as pe}from"@fortawesome/react-fontawesome";import{faChevronDown as me}from"@fortawesome/free-solid-svg-icons";import{jsx as c,jsxs as l}from"react/jsx-runtime";var he=500;function u(u){let{errorMessage:ge=``,className:_e=``,style:ve,label:d=``,value:ye=``,isValid:be=!0,tabIndex:xe=0,isRequired:Se=!1,customProps:Ce={},isRow:we=!1,disabled:f=!1,readOnly:p=!1,onLoadMore:Te,onClick:m,onChange:h,onFocus:Ee=null,onBlur:De=null,onMouseEnter:Oe=null,onMouseLeave:ke=null,dropdownLabel:Ae,isDropdownListWider:je=!1,formValidator:g=null,classNames:_,styles:v,items:y=[],useMatLabelStyle:b=!0,alwaysFloatLabel:x=!1,placeholder:S=``,plainStyle:C=!1,scrollToSelected:Me=!1,presentation:Ne,reactRef:Pe,...Fe}=e(`Dropdown`,u),[w,T]=o(!1),[Ie,E]=o(!1),[,Le]=o(0),D=a(g),O=a(null),Re=a(null),k=a(null),[ze,Be]=o(!1),[A,j]=o(null),M=a({buffer:``,at:0}),N=de(),P=`${N}-listbox`,F=`${N}-label`,I=e=>`${N}-option-${e}`,L=!f&&!p,R=ze&&L,{isLoading:z,sentinelRef:Ve}=ae(k,R?Te:void 0),He=t(),B=Ne??He??n.Default,{isSheet:V}=re(B);fe(()=>{let e=O.current,t=Re.current;R&&!V&&e&&t&&(t.style.fontSize=window.getComputedStyle(e).fontSize)},[R,V]),ue(()=>{if(D.current=g,!D.current)return;D.current.label=d??``,D.current.validate();let e=()=>Le(e=>e+1);return D.current.registerOnUpdateListener(e),()=>D.current?.removeOnUpdateListener(e)},[g,d]);let H=g?g.value:ye,U=y.findIndex(e=>e.key===H);ue(()=>{R&&A!==null&&le(k.current,document.getElementById(I(A)))},[R,A]);let Ue=e=>{E(!0),Oe?.(e)},We=e=>{E(!1),ke?.(e)},Ge=e=>{T(!0),Ee?.(e)},Ke=e=>{D.current&&(D.current.touched=!0),T(!1),De?.(e)},qe=()=>g?g.touched&&g.hasError():!be||!!ge,W=()=>!!(Se||g?.validators.find(e=>e.validatorId===`required`)),Je=e=>{g?(g.set(e),h?.(g.value,Ce)):h?.(e,Ce)};function G(e){(!e||L)&&(Be(e),e?j(Me&&U>=0?U:null):M.current={buffer:``,at:0})}function K(e){e.disabled||(Je(e.key),G(!1))}let q={isDisabled:e=>!!y[e].disabled};function J(e){let t=Date.now(),n=t-M.current.at>he?e:M.current.buffer+e;M.current={buffer:n,at:t};let ee=n.toLowerCase(),r=y.findIndex(e=>!e.disabled&&typeof e.label==`string`&&e.label.toLowerCase().startsWith(ee));r!==-1&&(R?j(r):K(y[r]))}function Ye(e){if(L){if(!R){e.key===`ArrowDown`||e.key===`ArrowUp`||e.key===`Enter`||e.key===` `?(e.preventDefault(),G(!0)):e.key.length===1&&J(e.key);return}if(e.key===`ArrowDown`||e.key===`ArrowUp`)e.preventDefault(),j(ce(A,e.key===`ArrowDown`?1:-1,y.length,q));else if(e.key===`Home`||e.key===`End`)e.preventDefault(),j(se(e.key===`Home`?`first`:`last`,y.length,q));else if(e.key===`Enter`||e.key===` `){e.preventDefault();let t=A===null?void 0:y[A];t?K(t):G(!1)}else e.key===`Escape`||e.key===`Tab`?G(!1):e.key.length===1&&J(e.key)}}let Y=Ae,X=qe();y.forEach(e=>{e.key===H&&(Y=e.label)});let Z=Y||H,Q=Z==null||typeof Z==`string`&&Z.trim()===``,Xe=W()?c(`span`,{className:i.requiredMark,children:`*`}):null,Ze=d&&W()?`${d} *`:d,$=w&&!p;return l(`div`,{...Fe,className:s(_e,_?.root,i.dropdownLabel,i.dropdown,{[i.dropdownLabelColumn]:!we,[i.dropdownWithLabel]:b&&!!d}),style:{...ve,...v?.root},onMouseEnter:Ue,onMouseLeave:We,children:[c(`div`,{children:c(ie,{isOpen:R,onOpenChange:G,disabled:!L,placement:ne.Bottom,align:te.Start,offset:0,withArrow:!1,constrainWidth:!1,width:`trigger`,focusOnOpen:!1,presentation:B,classNames:{panel:i.dropdownPanel},content:c(`div`,{ref:Re,className:s(V?i.dropdownInputListSheet:i.dropdownInputListAnim,{[i.dropdownInputListAnimWider]:je&&!V}),children:l(`div`,{ref:k,id:P,role:`listbox`,"aria-label":d||S||void 0,"aria-busy":z||void 0,className:s(i.dropdownInputList,V&&r.sheetScroll,_?.list),style:v?.list,children:[y.map((e,t)=>c(`div`,{id:I(t),role:`option`,"aria-selected":e.key===H,"aria-disabled":e.disabled||void 0,style:v?.option,className:s(i.dropdownInputListItem,_?.option,{[i.dropdownInputListItemActive]:A===t,[i.dropdownInputListItemSelected]:e.key===H,[i.dropdownInputListItemDisabled]:!!e.disabled}),onMouseDown:e=>e.preventDefault(),onMouseEnter:()=>j(t),onClick:()=>K(e),children:e.label},e.key)),c(`div`,{ref:Ve,className:i.dropdownSentinel,"aria-hidden":`true`}),z&&c(`div`,{className:i.dropdownLoadMore,"aria-hidden":`true`,children:c(ee,{size:`1.125em`})})]})}),children:l(`div`,{ref:O,onFocus:Ge,onBlur:Ke,className:s(i.dropdownInput,{[i.dropdownInputPlain]:C,[i.dropdownInputReadOnly]:p&&!f},_?.field),style:v?.field,children:[c(`button`,{tabIndex:xe,type:`button`,disabled:f,role:`combobox`,"aria-haspopup":`listbox`,"aria-expanded":R,"aria-controls":P,"aria-activedescendant":R&&A!==null?I(A):void 0,"aria-labelledby":d?F:void 0,"aria-label":d?void 0:S||void 0,"aria-readonly":p||void 0,className:s(i.dropdownInputButton,{[i.dropdownInputButtonDisabled]:f,[i.dropdownInputButtonReadOnly]:p&&!f},_?.control),style:{...je?{padding:`6px`,border:`none`}:{},...v?.control},onKeyDown:Ye,onClick:m,ref:Pe,children:Q?`\xA0`:Z}),c(`button`,{type:`button`,tabIndex:-1,disabled:f,"aria-hidden":`true`,className:s(i.dropdownInputButtonIcon,_?.icon),style:v?.icon,onMouseDown:e=>e.preventDefault(),onClick:m,children:!f&&!p&&c(pe,{icon:me,className:s(i.dropdownInputButtonIconArrow,{[i.dropdownInputButtonIconArrowOpen]:R})})}),c(`fieldset`,{className:s(i.dropdownFieldset,{[i.dropdownBorderPlain]:C,[i.dropdownBorderFocused]:$,[i.dropdownBorderInvalid]:X,[i.dropdownBorderError]:X}),children:c(`legend`,{className:s(i.dropdownFieldsetLegend,{[i.dropdownFieldsetLegendActive]:b&&(x||$||!Q)}),children:c(`span`,{children:Ze})})}),b&&d&&l(`div`,{id:F,className:s(i.dropdownMatLabel,{[i.dropdownMatLabelFloating]:x||$||!Q},_?.label),style:v?.label,children:[d,Xe]}),b&&S&&c(`div`,{className:s(i.dropdownPlaceholder,$&&!Y&&i.dropdownPlaceholderShown),children:S})]})})}),d&&!b&&l(`div`,{id:F,className:s(i.dropdownLabelText,_?.label),style:v?.label,children:[d,Xe]}),c(oe,{variant:`error`,message:g?g.getCurrentErrorMessage():ge||``,isVisible:X&&(w||Ie)})]})}export{u as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import{Presentation as n}from"../configProvider/presentation.types.mjs";import ee from"../loader/loader.mjs";import r from"../styles/sheet.module.mjs";import{PopoverAlign as te,PopoverPlacement as ne}from"../popover/popover.types.mjs";import re from"../hooks/useSheet.mjs";import ie from"../popover/popover.mjs";import{useInfiniteScroll as ae}from"../infiniteBlock/useInfiniteScroll.mjs";import oe from"../tooltip/tooltip.mjs";import{edgeIndex as se,nextIndex as ce,scrollOptionIntoView as le}from"../utils/listNavigation.mjs";import i from"./dropdown.module.mjs";import{useEffect as ue,useId as de,useLayoutEffect as fe,useRef as a,useState as o}from"react";import s from"classnames";import{FontAwesomeIcon as pe}from"@fortawesome/react-fontawesome";import{faChevronDown as me}from"@fortawesome/free-solid-svg-icons";import{jsx as c,jsxs as l}from"react/jsx-runtime";var he=500;function u(u){let{errorMessage:ge=``,className:_e=``,style:ve,label:d=``,value:ye=``,isValid:be=!0,tabIndex:xe=0,isRequired:Se=!1,customProps:Ce={},isRow:we=!1,disabled:f=!1,readOnly:p=!1,onLoadMore:Te,onClick:m,onChange:h,onFocus:Ee=null,onBlur:De=null,onMouseEnter:Oe=null,onMouseLeave:ke=null,dropdownLabel:Ae,isDropdownListWider:je=!1,formValidator:g=null,classNames:_,styles:v,items:y=[],useMatLabelStyle:b=!0,alwaysFloatLabel:x=!1,placeholder:S=``,plainStyle:C=!1,scrollToSelected:Me=!1,presentation:Ne,reactRef:Pe,...Fe}=e(`Dropdown`,u),[w,T]=o(!1),[Ie,E]=o(!1),[,Le]=o(0),D=a(g),O=a(null),Re=a(null),k=a(null),[ze,Be]=o(!1),[A,j]=o(null),M=a({buffer:``,at:0}),N=de(),P=`${N}-listbox`,F=`${N}-label`,I=e=>`${N}-option-${e}`,L=!f&&!p,R=ze&&L,{isLoading:z,sentinelRef:Ve}=ae(k,R?Te:void 0),He=t(),B=Ne??He??n.Default,{isSheet:V}=re(B);fe(()=>{let e=O.current,t=Re.current;R&&!V&&e&&t&&(t.style.fontSize=window.getComputedStyle(e).fontSize)},[R,V]),ue(()=>{if(D.current=g,!D.current)return;D.current.label=d??``,D.current.validate();let e=()=>Le(e=>e+1);return D.current.registerOnUpdateListener(e),()=>D.current?.removeOnUpdateListener(e)},[g,d]);let H=g?g.value:ye,U=y.findIndex(e=>e.key===H);ue(()=>{R&&A!==null&&le(k.current,document.getElementById(I(A)))},[R,A]);let Ue=e=>{E(!0),Oe?.(e)},We=e=>{E(!1),ke?.(e)},Ge=e=>{T(!0),Ee?.(e)},Ke=e=>{D.current&&(D.current.touched=!0),T(!1),De?.(e)},qe=()=>g?g.shouldShowError:!be||!!ge,W=()=>!!(Se||g?.validators.find(e=>e.validatorId===`required`)),Je=e=>{g?(g.set(e),h?.(g.value,Ce)):h?.(e,Ce)};function G(e){(!e||L)&&(Be(e),e?j(Me&&U>=0?U:null):M.current={buffer:``,at:0})}function K(e){e.disabled||(Je(e.key),G(!1))}let q={isDisabled:e=>!!y[e].disabled};function J(e){let t=Date.now(),n=t-M.current.at>he?e:M.current.buffer+e;M.current={buffer:n,at:t};let ee=n.toLowerCase(),r=y.findIndex(e=>!e.disabled&&typeof e.label==`string`&&e.label.toLowerCase().startsWith(ee));r!==-1&&(R?j(r):K(y[r]))}function Ye(e){if(L){if(!R){e.key===`ArrowDown`||e.key===`ArrowUp`||e.key===`Enter`||e.key===` `?(e.preventDefault(),G(!0)):e.key.length===1&&J(e.key);return}if(e.key===`ArrowDown`||e.key===`ArrowUp`)e.preventDefault(),j(ce(A,e.key===`ArrowDown`?1:-1,y.length,q));else if(e.key===`Home`||e.key===`End`)e.preventDefault(),j(se(e.key===`Home`?`first`:`last`,y.length,q));else if(e.key===`Enter`||e.key===` `){e.preventDefault();let t=A===null?void 0:y[A];t?K(t):G(!1)}else e.key===`Escape`||e.key===`Tab`?G(!1):e.key.length===1&&J(e.key)}}let Y=Ae,X=qe();y.forEach(e=>{e.key===H&&(Y=e.label)});let Z=Y||H,Q=Z==null||typeof Z==`string`&&Z.trim()===``,Xe=W()?c(`span`,{className:i.requiredMark,children:`*`}):null,Ze=d&&W()?`${d} *`:d,$=w&&!p;return l(`div`,{...Fe,className:s(_e,_?.root,i.dropdownLabel,i.dropdown,{[i.dropdownLabelColumn]:!we,[i.dropdownWithLabel]:b&&!!d}),style:{...ve,...v?.root},onMouseEnter:Ue,onMouseLeave:We,children:[c(`div`,{children:c(ie,{isOpen:R,onOpenChange:G,disabled:!L,placement:ne.Bottom,align:te.Start,offset:0,withArrow:!1,constrainWidth:!1,width:`trigger`,focusOnOpen:!1,presentation:B,classNames:{panel:i.dropdownPanel},content:c(`div`,{ref:Re,className:s(V?i.dropdownInputListSheet:i.dropdownInputListAnim,{[i.dropdownInputListAnimWider]:je&&!V}),children:l(`div`,{ref:k,id:P,role:`listbox`,"aria-label":d||S||void 0,"aria-busy":z||void 0,className:s(i.dropdownInputList,V&&r.sheetScroll,_?.list),style:v?.list,children:[y.map((e,t)=>c(`div`,{id:I(t),role:`option`,"aria-selected":e.key===H,"aria-disabled":e.disabled||void 0,style:v?.option,className:s(i.dropdownInputListItem,_?.option,{[i.dropdownInputListItemActive]:A===t,[i.dropdownInputListItemSelected]:e.key===H,[i.dropdownInputListItemDisabled]:!!e.disabled}),onMouseDown:e=>e.preventDefault(),onMouseEnter:()=>j(t),onClick:()=>K(e),children:e.label},e.key)),c(`div`,{ref:Ve,className:i.dropdownSentinel,"aria-hidden":`true`}),z&&c(`div`,{className:i.dropdownLoadMore,"aria-hidden":`true`,children:c(ee,{size:`1.125em`})})]})}),children:l(`div`,{ref:O,onFocus:Ge,onBlur:Ke,className:s(i.dropdownInput,{[i.dropdownInputPlain]:C,[i.dropdownInputReadOnly]:p&&!f},_?.field),style:v?.field,children:[c(`button`,{tabIndex:xe,type:`button`,disabled:f,role:`combobox`,"aria-haspopup":`listbox`,"aria-expanded":R,"aria-controls":P,"aria-activedescendant":R&&A!==null?I(A):void 0,"aria-labelledby":d?F:void 0,"aria-label":d?void 0:S||void 0,"aria-readonly":p||void 0,className:s(i.dropdownInputButton,{[i.dropdownInputButtonDisabled]:f,[i.dropdownInputButtonReadOnly]:p&&!f},_?.control),style:{...je?{padding:`6px`,border:`none`}:{},...v?.control},onKeyDown:Ye,onClick:m,ref:Pe,children:Q?`\xA0`:Z}),c(`button`,{type:`button`,tabIndex:-1,disabled:f,"aria-hidden":`true`,className:s(i.dropdownInputButtonIcon,_?.icon),style:v?.icon,onMouseDown:e=>e.preventDefault(),onClick:m,children:!f&&!p&&c(pe,{icon:me,className:s(i.dropdownInputButtonIconArrow,{[i.dropdownInputButtonIconArrowOpen]:R})})}),c(`fieldset`,{className:s(i.dropdownFieldset,{[i.dropdownBorderPlain]:C,[i.dropdownBorderFocused]:$,[i.dropdownBorderInvalid]:X,[i.dropdownBorderError]:X}),children:c(`legend`,{className:s(i.dropdownFieldsetLegend,{[i.dropdownFieldsetLegendActive]:b&&(x||$||!Q)}),children:c(`span`,{children:Ze})})}),b&&d&&l(`div`,{id:F,className:s(i.dropdownMatLabel,{[i.dropdownMatLabelFloating]:x||$||!Q},_?.label),style:v?.label,children:[d,Xe]}),b&&S&&c(`div`,{className:s(i.dropdownPlaceholder,$&&!Y&&i.dropdownPlaceholderShown),children:S})]})})}),d&&!b&&l(`div`,{id:F,className:s(i.dropdownLabelText,_?.label),style:v?.label,children:[d,Xe]}),c(oe,{variant:`error`,message:g?g.getCurrentErrorMessage():ge||``,isVisible:X&&(w||Ie)})]})}export{u 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, { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronDown as dropdownIcon } from '@fortawesome/free-solid-svg-icons';\nimport Tooltip from 'components/common/tooltip';\n\nimport Popover from '../popover';\nimport Loader from '../loader';\nimport { useInfiniteScroll } from '../infiniteBlock/useInfiniteScroll';\nimport { edgeIndex, nextIndex, scrollOptionIntoView, type ActiveIndex } from '../utils/listNavigation';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { useComponentDefaults, usePresentationDefault } from '../configProvider';\nimport { useSheet } from '../hooks/useSheet';\nimport { Presentation } from '../configProvider/presentation.types';\nimport styles from './dropdown.module.pcss';\nimport sheetStyles from '../styles/sheet.module.pcss';\nimport type { DropdownProps, DropdownItem } from './dropdown.types';\n\n/** How long a pause resets the type-ahead buffer, matching a native `<select>`. */\nconst TYPEAHEAD_RESET_MS = 500;\n\nfunction Dropdown(props: DropdownProps) {\n const {\n errorMessage = '',\n className = '',\n style,\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 onLoadMore,\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 formValidator = null,\n classNames,\n styles: slotStyles,\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 listRef = useRef<HTMLDivElement>(null);\n const [menuIsOpen, setMenuIsOpen] = useState(false);\n // `null` is \"nothing highlighted\", the state a list opens in unless `scrollToSelected`\n // asks for the current value. Arrowing from there enters the list at either end.\n const [activeIndex, setActiveIndex] = useState<ActiveIndex>(null);\n const typeahead = useRef({ buffer: '', at: 0 });\n\n const baseId = useId();\n const listboxId = `${baseId}-listbox`;\n const labelId = `${baseId}-label`;\n const optionId = (index: number) => `${baseId}-option-${index}`;\n\n const isInteractive = !disabled && !readOnly;\n const isOpen = menuIsOpen && isInteractive;\n\n // The list is its own scroll container. It used to render through an `InfiniteBlock`, which\n // also brought a tabbable container and a second key handler: inside a listbox that put a\n // focusable element with no role in the tab order and gave the arrows two owners.\n // Only while open: the list it watches is rendered then, and not before.\n const { isLoading: showScrollSpinner, sentinelRef } = useInfiniteScroll(listRef, isOpen ? onLoadMore : undefined);\n\n // Explicit prop → this component's global default → the app-wide one → anchored.\n // Resolved here rather than left to Popover so that this component and the panel\n // it opens can never disagree about whether they are presenting as a sheet.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation ?? Presentation.Default;\n const { isSheet } = useSheet(presentation);\n\n // The list reads at the field's size, which is not always the page's: a Dropdown\n // inside something with a smaller font should not open a list at the default one.\n // Width is Popover's job, through `width='trigger'`.\n useLayoutEffect(() => {\n const trigger = triggerRef.current;\n const menu = anchorRef.current;\n if (!isOpen || isSheet || !trigger || !menu) return;\n menu.style.fontSize = window.getComputedStyle(trigger).fontSize;\n }, [isOpen, isSheet]);\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 currentValue = formValidator ? (formValidator.value as string | number) : value;\n const selectedIndex = items.findIndex((item) => item.key === currentValue);\n\n useEffect(() => {\n if (!isOpen || activeIndex === null) return;\n scrollOptionIntoView(listRef.current, document.getElementById(optionId(activeIndex)));\n // optionId is derived from a stable useId, so it cannot go stale between renders.\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, activeIndex]);\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 ? formValidator.touched && formValidator.hasError() : !isValid || !!errorMessage;\n };\n\n const computedIsRequired = (): boolean => {\n return !!(\n isRequired || formValidator?.validators.find((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 function handleOpenChange(next: boolean) {\n if (next && !isInteractive) return;\n setMenuIsOpen(next);\n if (next) setActiveIndex(scrollToSelected && selectedIndex >= 0 ? selectedIndex : null);\n else typeahead.current = { buffer: '', at: 0 };\n }\n\n function select(item: DropdownItem) {\n if (item.disabled) return;\n onChangeHandler(item.key);\n handleOpenChange(false);\n }\n\n const navigation = { isDisabled: (index: number) => !!items[index].disabled };\n\n /** Jumps to the option whose label starts with what was typed, as a native `<select>` does. */\n function handleTypeahead(key: string) {\n const now = Date.now();\n const buffer = now - typeahead.current.at > TYPEAHEAD_RESET_MS ? key : typeahead.current.buffer + key;\n typeahead.current = { buffer, at: now };\n\n const needle = buffer.toLowerCase();\n const match = items.findIndex(\n (item) => !item.disabled && typeof item.label === 'string' && item.label.toLowerCase().startsWith(needle),\n );\n if (match === -1) return;\n if (isOpen) setActiveIndex(match);\n else select(items[match]);\n }\n\n function handleKeyDown(event: React.KeyboardEvent) {\n if (!isInteractive) return;\n\n if (!isOpen) {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter' || event.key === ' ') {\n // Without this the browser turns the key into a click on the trigger, which\n // Popover would read as a second toggle and close the list again.\n event.preventDefault();\n handleOpenChange(true);\n } else if (event.key.length === 1) {\n handleTypeahead(event.key);\n }\n return;\n }\n\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n setActiveIndex(nextIndex(activeIndex, event.key === 'ArrowDown' ? 1 : -1, items.length, navigation));\n } else if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n setActiveIndex(edgeIndex(event.key === 'Home' ? 'first' : 'last', items.length, navigation));\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n const item = activeIndex === null ? undefined : items[activeIndex];\n if (item) select(item);\n else handleOpenChange(false);\n } else if (event.key === 'Escape' || event.key === 'Tab') {\n handleOpenChange(false);\n } else if (event.key.length === 1) {\n handleTypeahead(event.key);\n }\n }\n\n let dropdownLabel = dropdownLabelProp;\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 = displayValue == null || (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, classNames?.root, styles.dropdownLabel, styles.dropdown, {\n [styles.dropdownLabelColumn]: !isRow,\n [styles.dropdownWithLabel]: useMatLabelStyle && !!label,\n })}\n style={{ ...style, ...slotStyles?.root }}\n onMouseEnter={onMouseEnterHandler}\n onMouseLeave={onMouseLeaveHandler}\n >\n <div>\n <Popover\n // Popover owns opening and closing, including the outside click, Escape and the\n // click on the field itself. The trigger only has to say what it wants.\n isOpen={isOpen}\n onOpenChange={handleOpenChange}\n disabled={!isInteractive}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n offset={0}\n withArrow={false}\n constrainWidth={false}\n width='trigger'\n // The focus stays on the trigger while the list is open, because that is what\n // `aria-activedescendant` points from.\n focusOnOpen={false}\n presentation={presentation}\n classNames={{ panel: styles.dropdownPanel }}\n content={\n <div\n ref={anchorRef}\n // A sheet's own panel does the clipping, and spans the screen rather than\n // sizing itself to the field.\n className={cx(isSheet ? styles.dropdownInputListSheet : styles.dropdownInputListAnim, {\n [styles.dropdownInputListAnimWider]: isDropdownListWider && !isSheet,\n })}\n >\n <div\n ref={listRef}\n id={listboxId}\n role='listbox'\n aria-label={label || placeholder || undefined}\n aria-busy={showScrollSpinner || undefined}\n className={cx(styles.dropdownInputList, isSheet && sheetStyles.sheetScroll, classNames?.list)}\n style={slotStyles?.list}\n >\n {items.map((item: DropdownItem, index: number) => (\n <div\n key={item.key}\n id={optionId(index)}\n role='option'\n aria-selected={item.key === currentValue}\n aria-disabled={item.disabled || undefined}\n style={slotStyles?.option}\n className={cx(styles.dropdownInputListItem, classNames?.option, {\n [styles.dropdownInputListItemActive]: activeIndex === index,\n [styles.dropdownInputListItemSelected]: item.key === currentValue,\n [styles.dropdownInputListItemDisabled]: !!item.disabled,\n })}\n // Selecting must not move the focus off the trigger, which is what\n // `aria-activedescendant` is anchored to.\n onMouseDown={(event) => event.preventDefault()}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => select(item)}\n >\n {item.label}\n </div>\n ))}\n <div ref={sentinelRef} className={styles.dropdownSentinel} aria-hidden='true' />\n {showScrollSpinner && (\n <div className={styles.dropdownLoadMore} aria-hidden='true'>\n <Loader size='1.125em' />\n </div>\n )}\n </div>\n </div>\n }\n >\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 classNames?.field,\n )}\n style={slotStyles?.field}\n >\n <button\n tabIndex={tabIndex}\n type='button'\n disabled={disabled}\n // A select-only combobox: the accessible name comes from the field's label,\n // and the element's own content is read as its value. A plain `button` role\n // would announce the value as the name and never mention the label.\n role='combobox'\n aria-haspopup='listbox'\n aria-expanded={isOpen}\n aria-controls={listboxId}\n aria-activedescendant={isOpen && activeIndex !== null ? optionId(activeIndex) : undefined}\n aria-labelledby={label ? labelId : undefined}\n aria-label={label ? undefined : placeholder || undefined}\n aria-readonly={readOnly || undefined}\n className={cx(\n styles.dropdownInputButton,\n {\n [styles.dropdownInputButtonDisabled]: disabled,\n [styles.dropdownInputButtonReadOnly]: readOnly && !disabled,\n },\n classNames?.control,\n )}\n style={{ ...(isDropdownListWider ? { padding: '6px', border: 'none' } : {}), ...slotStyles?.control }}\n onKeyDown={handleKeyDown}\n onClick={onClick}\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 ? ' ' : displayValue}\n </button>\n <button\n type='button'\n tabIndex={-1}\n disabled={disabled}\n // The chevron repeats what the combobox beside it already does, so it is a\n // pointer affordance only. Announcing it would offer the same control twice.\n aria-hidden='true'\n className={cx(styles.dropdownInputButtonIcon, classNames?.icon)}\n style={slotStyles?.icon}\n // Keeping the focus where it is, rather than letting mousedown move it here:\n // the trigger is what `aria-activedescendant` points from, and the click\n // still reaches Popover by bubbling.\n onMouseDown={(event: React.MouseEvent<HTMLButtonElement>) => event.preventDefault()}\n onClick={onClick}\n >\n {!disabled && !readOnly && (\n <FontAwesomeIcon\n icon={dropdownIcon}\n className={cx(styles.dropdownInputButtonIconArrow, {\n [styles.dropdownInputButtonIconArrowOpen]: isOpen,\n })}\n />\n )}\n </button>\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 id={labelId}\n className={cx(\n styles.dropdownMatLabel,\n {\n [styles.dropdownMatLabelFloating]: alwaysFloatLabel || showFocus || !isDisplayBlank,\n },\n // The floating and the stacked label are two renderings of\n // the same thing, so one slot reaches whichever is in use.\n classNames?.label,\n )}\n style={slotStyles?.label}\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 </Popover>\n </div>\n {label && !useMatLabelStyle && (\n <div id={labelId} className={cx(styles.dropdownLabelText, classNames?.label)} style={slotStyles?.label}>\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":"yhCAmBA,IAAM,GAAqB,IAE3B,SAAS,EAAS,EAAsB,CACtC,GAAM,CACJ,gBAAe,GACf,aAAY,GACZ,SACA,QAAQ,GACR,SAAQ,GACR,WAAU,GACV,YAAW,EACX,cAAa,GACb,eAAc,CAAC,EACf,SAAQ,GACR,WAAW,GACX,WAAW,GACX,cACA,UACA,WACA,QAAS,GAAc,KACvB,OAAQ,GAAa,KACrB,aAAc,GAAmB,KACjC,aAAc,GAAmB,KACjC,cAAe,GACf,uBAAsB,GACtB,gBAAgB,KAChB,aACA,OAAQ,EACR,QAAQ,CAAC,EACT,mBAAmB,GACnB,mBAAmB,GACnB,cAAc,GACd,aAAa,GACb,oBAAmB,GACnB,aAAc,GACd,YACA,GAAG,IACD,EAAqB,WAAY,CAAK,EACpC,CAAC,EAAW,GAAgB,EAAS,EAAK,EAC1C,CAAC,GAAW,GAAgB,EAAS,EAAK,EAC1C,EAAG,IAAe,EAAS,CAAC,EAC5B,EAAQ,EAAO,CAAa,EAC5B,EAAa,EAAuB,IAAI,EACxC,GAAY,EAAuB,IAAI,EACvC,EAAU,EAAuB,IAAI,EACrC,CAAC,GAAY,IAAiB,EAAS,EAAK,EAG5C,CAAC,EAAa,GAAkB,EAAsB,IAAI,EAC1D,EAAY,EAAO,CAAE,OAAQ,GAAI,GAAI,CAAE,CAAC,EAExC,EAAS,GAAM,EACf,EAAY,GAAG,EAAO,UACtB,EAAU,GAAG,EAAO,QACpB,EAAY,GAAkB,GAAG,EAAO,UAAU,IAElD,EAAgB,CAAC,GAAY,CAAC,EAC9B,EAAS,IAAc,EAMvB,CAAE,UAAW,EAAmB,gBAAgB,GAAkB,EAAS,EAAS,GAAa,IAAA,EAAS,EAK1G,GAAkB,EAAuB,EACzC,EAAe,IAAoB,IAAmB,EAAa,QACnE,CAAE,WAAY,GAAS,CAAY,EAKzC,OAAsB,CACpB,IAAM,EAAU,EAAW,QACrB,EAAO,GAAU,QAClB,GAAU,IAAY,GAAY,IACvC,EAAK,MAAM,SAAW,OAAO,iBAAiB,CAAO,CAAC,CAAC,SACzD,EAAG,CAAC,EAAQ,CAAO,CAAC,EAEpB,OAAgB,CAEd,GADA,EAAM,QAAU,EACZ,CAAC,EAAM,QAAS,OACpB,EAAM,QAAQ,MAAQ,GAAS,GAC/B,EAAM,QAAQ,SAAS,EACvB,IAAM,MAAiB,GAAa,GAAM,EAAI,CAAC,EAE/C,OADA,EAAM,QAAQ,yBAAyB,CAAQ,MAClC,EAAM,SAAS,uBAAuB,CAAQ,CAC7D,EAAG,CAAC,EAAe,CAAK,CAAC,EAEzB,IAAM,EAAe,EAAiB,EAAc,MAA4B,GAC1E,EAAgB,EAAM,UAAW,GAAS,EAAK,MAAQ,CAAY,EAEzE,OAAgB,CACT,GAAU,IAAgB,MAC/B,GAAqB,EAAQ,QAAS,SAAS,eAAe,EAAS,CAAW,CAAC,CAAC,CAGtF,EAAG,CAAC,EAAQ,CAAW,CAAC,EAExB,IAAM,GAAuB,GAA4B,CACvD,EAAa,EAAI,EACjB,KAAmB,CAAK,CAC1B,EAEM,GAAuB,GAA4B,CACvD,EAAa,EAAK,EAClB,KAAmB,CAAK,CAC1B,EAEM,GAAkB,GAA4B,CAClD,EAAa,EAAI,EACjB,KAAc,CAAK,CACrB,EAEM,GAAiB,GAA4B,CAC7C,EAAM,UAAS,EAAM,QAAQ,QAAU,IAC3C,EAAa,EAAK,EAClB,KAAa,CAAK,CACpB,EAEM,OACG,EAAgB,EAAc,SAAW,EAAc,SAAS,EAAI,CAAC,IAAW,CAAC,CAAC,GAGrF,MACG,CAAC,EACN,IAAc,GAAe,WAAW,KAAM,GAAO,EAA+B,cAAgB,UAAU,GAI5G,GAAmB,GAA+B,CAClD,GACF,EAAc,IAAI,CAAG,EACrB,IAAW,EAAc,MAAO,EAAW,GAE3C,IAAW,EAAK,EAAW,CAE/B,EAEA,SAAS,EAAiB,EAAe,EACnC,IAAS,KACb,GAAc,CAAI,EACd,EAAM,EAAe,IAAoB,GAAiB,EAAI,EAAgB,IAAI,EACjF,EAAU,QAAU,CAAE,OAAQ,GAAI,GAAI,CAAE,EAC/C,CAEA,SAAS,EAAO,EAAoB,CAC9B,EAAK,WACT,GAAgB,EAAK,GAAG,EACxB,EAAiB,EAAK,EACxB,CAEA,IAAM,EAAa,CAAE,WAAa,GAAkB,CAAC,CAAC,EAAM,EAAM,CAAC,QAAS,EAG5E,SAAS,EAAgB,EAAa,CACpC,IAAM,EAAM,KAAK,IAAI,EACf,EAAS,EAAM,EAAU,QAAQ,GAAK,GAAqB,EAAM,EAAU,QAAQ,OAAS,EAClG,EAAU,QAAU,CAAE,SAAQ,GAAI,CAAI,EAEtC,IAAM,GAAS,EAAO,YAAY,EAC5B,EAAQ,EAAM,UACjB,GAAS,CAAC,EAAK,UAAY,OAAO,EAAK,OAAU,UAAY,EAAK,MAAM,YAAY,CAAC,CAAC,WAAW,EAAM,CAC1G,EACI,IAAU,KACV,EAAQ,EAAe,CAAK,EAC3B,EAAO,EAAM,EAAM,EAC1B,CAEA,SAAS,GAAc,EAA4B,CAC5C,KAEL,IAAI,CAAC,EAAQ,CACP,EAAM,MAAQ,aAAe,EAAM,MAAQ,WAAa,EAAM,MAAQ,SAAW,EAAM,MAAQ,KAGjG,EAAM,eAAe,EACrB,EAAiB,EAAI,GACZ,EAAM,IAAI,SAAW,GAC9B,EAAgB,EAAM,GAAG,EAE3B,MACF,CAEA,GAAI,EAAM,MAAQ,aAAe,EAAM,MAAQ,UAC7C,EAAM,eAAe,EACrB,EAAe,GAAU,EAAa,EAAM,MAAQ,YAAc,EAAI,GAAI,EAAM,OAAQ,CAAU,CAAC,OAC9F,GAAI,EAAM,MAAQ,QAAU,EAAM,MAAQ,MAC/C,EAAM,eAAe,EACrB,EAAe,GAAU,EAAM,MAAQ,OAAS,QAAU,OAAQ,EAAM,OAAQ,CAAU,CAAC,OACtF,GAAI,EAAM,MAAQ,SAAW,EAAM,MAAQ,IAAK,CACrD,EAAM,eAAe,EACrB,IAAM,EAAO,IAAgB,KAAO,IAAA,GAAY,EAAM,GAClD,EAAM,EAAO,CAAI,EAChB,EAAiB,EAAK,CAC7B,MAAW,EAAM,MAAQ,UAAY,EAAM,MAAQ,MACjD,EAAiB,EAAK,EACb,EAAM,IAAI,SAAW,GAC9B,EAAgB,EAAM,GAAG,CAhB3B,CAkBF,CAEA,IAAI,EAAgB,GACd,EAAS,GAAS,EAExB,EAAM,QAAS,GAAuB,CAChC,EAAK,MAAQ,IACf,EAAgB,EAAK,MAEzB,CAAC,EAED,IAAM,EAAe,GAAiB,EAChC,EAAiB,GAAgB,MAAS,OAAO,GAAiB,UAAY,EAAa,KAAK,IAAM,GAEtG,GAAe,EAAmB,EAAI,EAAC,OAAD,CAAM,UAAW,EAAO,aAAc,SAAA,GAAO,CAAA,EAAI,KACvF,GAAc,GAAS,EAAmB,EAAI,GAAG,EAAM,IAAM,EAE7D,EAAY,GAAa,CAAC,EAEhC,OACE,EAAC,MAAD,CACE,GAAI,GACJ,UAAW,EAAG,GAAW,GAAY,KAAM,EAAO,cAAe,EAAO,SAAU,EAC/E,EAAO,qBAAsB,CAAC,IAC9B,EAAO,mBAAoB,GAAoB,CAAC,CAAC,CACpD,CAAC,EACD,MAAO,CAAE,GAAG,GAAO,GAAG,GAAY,IAAK,EACvC,aAAc,GACd,aAAc,GARhB,SAAA,CAUE,EAAC,MAAD,CAAA,SACE,EAAC,GAAD,CAGU,SACR,aAAc,EACd,SAAU,CAAC,EACX,UAAW,GAAiB,OAC5B,MAAO,GAAa,MACpB,OAAQ,EACR,UAAW,GACX,eAAgB,GAChB,MAAM,UAGN,YAAa,GACC,eACd,WAAY,CAAE,MAAO,EAAO,aAAc,EAC1C,QACE,EAAC,MAAD,CACE,IAAK,GAGL,UAAW,EAAG,EAAU,EAAO,uBAAyB,EAAO,sBAAuB,EACnF,EAAO,4BAA6B,IAAuB,CAAC,CAC/D,CAAC,EAED,SAAA,EAAC,MAAD,CACE,IAAK,EACL,GAAI,EACJ,KAAK,UACL,aAAY,GAAS,GAAe,IAAA,GACpC,YAAW,GAAqB,IAAA,GAChC,UAAW,EAAG,EAAO,kBAAmB,GAAW,EAAY,YAAa,GAAY,IAAI,EAC5F,MAAO,GAAY,KAPrB,SAAA,CASG,EAAM,KAAK,EAAoB,IAC9B,EAAC,MAAD,CAEE,GAAI,EAAS,CAAK,EAClB,KAAK,SACL,gBAAe,EAAK,MAAQ,EAC5B,gBAAe,EAAK,UAAY,IAAA,GAChC,MAAO,GAAY,OACnB,UAAW,EAAG,EAAO,sBAAuB,GAAY,OAAQ,EAC7D,EAAO,6BAA8B,IAAgB,GACrD,EAAO,+BAAgC,EAAK,MAAQ,GACpD,EAAO,+BAAgC,CAAC,CAAC,EAAK,QACjD,CAAC,EAGD,YAAc,GAAU,EAAM,eAAe,EAC7C,iBAAoB,EAAe,CAAK,EACxC,YAAe,EAAO,CAAI,EAEzB,SAAA,EAAK,KACH,EAlBE,EAAK,GAkBP,CACN,EACD,EAAC,MAAD,CAAK,IAAK,GAAa,UAAW,EAAO,iBAAkB,cAAY,MAAQ,CAAA,EAC9E,GACC,EAAC,MAAD,CAAK,UAAW,EAAO,iBAAkB,cAAY,OACnD,SAAA,EAAC,GAAD,CAAQ,KAAK,SAAW,CAAA,CACrB,CAAA,CAEJ,GACF,CAAA,EAGP,SAAA,EAAC,MAAD,CACE,IAAK,EACL,QAAS,GACT,OAAQ,GACR,UAAW,EACT,EAAO,cACP,EACG,EAAO,oBAAqB,GAC5B,EAAO,uBAAwB,GAAY,CAAC,CAC/C,EACA,GAAY,KACd,EACA,MAAO,GAAY,MAZrB,SAAA,CAcE,EAAC,SAAD,CACY,YACV,KAAK,SACK,WAIV,KAAK,WACL,gBAAc,UACd,gBAAe,EACf,gBAAe,EACf,wBAAuB,GAAU,IAAgB,KAAO,EAAS,CAAW,EAAI,IAAA,GAChF,kBAAiB,EAAQ,EAAU,IAAA,GACnC,aAAY,EAAQ,IAAA,GAAY,GAAe,IAAA,GAC/C,gBAAe,GAAY,IAAA,GAC3B,UAAW,EACT,EAAO,oBACP,EACG,EAAO,6BAA8B,GACrC,EAAO,6BAA8B,GAAY,CAAC,CACrD,EACA,GAAY,OACd,EACA,MAAO,CAAE,GAAI,GAAsB,CAAE,QAAS,MAAO,OAAQ,MAAO,EAAI,CAAC,EAAI,GAAG,GAAY,OAAQ,EACpG,UAAW,GACF,UACT,IAAK,GAIJ,SAAA,EAAiB,OAAM,CAClB,CAAA,EACR,EAAC,SAAD,CACE,KAAK,SACL,SAAU,GACA,WAGV,cAAY,OACZ,UAAW,EAAG,EAAO,wBAAyB,GAAY,IAAI,EAC9D,MAAO,GAAY,KAInB,YAAc,GAA+C,EAAM,eAAe,EACzE,UAER,SAAA,CAAC,GAAY,CAAC,GACb,EAAC,GAAD,CACE,KAAM,GACN,UAAW,EAAG,EAAO,6BAA8B,EAChD,EAAO,kCAAmC,CAC7C,CAAC,CACF,CAAA,CAEG,CAAA,EACR,EAAC,WAAD,CACE,UAAW,EAAG,EAAO,iBAAkB,EACpC,EAAO,qBAAsB,GAC7B,EAAO,uBAAwB,GAC/B,EAAO,uBAAwB,GAC/B,EAAO,qBAAsB,CAChC,CAAC,EAED,SAAA,EAAC,SAAD,CACE,UAAW,EAAG,EAAO,uBAAwB,EAC1C,EAAO,8BACN,IAAqB,GAAoB,GAAa,CAAC,EAC3D,CAAC,EAED,SAAA,EAAC,OAAD,CAAA,SAAO,EAAkB,CAAA,CACnB,CAAA,CACA,CAAA,EACT,GAAoB,GACnB,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EACT,EAAO,iBACP,EACG,EAAO,0BAA2B,GAAoB,GAAa,CAAC,CACvE,EAGA,GAAY,KACd,EACA,MAAO,GAAY,MAXrB,SAAA,CAaG,EACA,EACE,IAEN,GAAoB,GACnB,EAAC,MAAD,CACE,UAAW,EACT,EAAO,oBACP,GAAa,CAAC,GAAiB,EAAO,wBACxC,EAEC,SAAA,CACE,CAAA,CAEJ,GACE,CAAA,CACN,CAAA,EACJ,GAAS,CAAC,GACT,EAAC,MAAD,CAAK,GAAI,EAAS,UAAW,EAAG,EAAO,kBAAmB,GAAY,KAAK,EAAG,MAAO,GAAY,MAAjG,SAAA,CACG,EACA,EACE,IAEP,EAAC,GAAD,CACE,QAAQ,QACR,QAAS,EAAgB,EAAc,uBAAuB,EAAI,IAAgB,GAClF,UAAW,IAAW,GAAa,GACpC,CAAA,CACE,GAET"}
1
+ {"version":3,"file":"dropdown.mjs","names":[],"sources":["../../../../package/common/dropdown/dropdown.tsx"],"sourcesContent":["import React, { useEffect, useId, useLayoutEffect, useRef, useState } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faChevronDown as dropdownIcon } from '@fortawesome/free-solid-svg-icons';\nimport Tooltip from 'components/common/tooltip';\n\nimport Popover from '../popover';\nimport Loader from '../loader';\nimport { useInfiniteScroll } from '../infiniteBlock/useInfiniteScroll';\nimport { edgeIndex, nextIndex, scrollOptionIntoView, type ActiveIndex } from '../utils/listNavigation';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { useComponentDefaults, usePresentationDefault } from '../configProvider';\nimport { useSheet } from '../hooks/useSheet';\nimport { Presentation } from '../configProvider/presentation.types';\nimport styles from './dropdown.module.pcss';\nimport sheetStyles from '../styles/sheet.module.pcss';\nimport type { DropdownProps, DropdownItem } from './dropdown.types';\n\n/** How long a pause resets the type-ahead buffer, matching a native `<select>`. */\nconst TYPEAHEAD_RESET_MS = 500;\n\nfunction Dropdown(props: DropdownProps) {\n const {\n errorMessage = '',\n className = '',\n style,\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 onLoadMore,\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 formValidator = null,\n classNames,\n styles: slotStyles,\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 listRef = useRef<HTMLDivElement>(null);\n const [menuIsOpen, setMenuIsOpen] = useState(false);\n // `null` is \"nothing highlighted\", the state a list opens in unless `scrollToSelected`\n // asks for the current value. Arrowing from there enters the list at either end.\n const [activeIndex, setActiveIndex] = useState<ActiveIndex>(null);\n const typeahead = useRef({ buffer: '', at: 0 });\n\n const baseId = useId();\n const listboxId = `${baseId}-listbox`;\n const labelId = `${baseId}-label`;\n const optionId = (index: number) => `${baseId}-option-${index}`;\n\n const isInteractive = !disabled && !readOnly;\n const isOpen = menuIsOpen && isInteractive;\n\n // The list is its own scroll container. It used to render through an `InfiniteBlock`, which\n // also brought a tabbable container and a second key handler: inside a listbox that put a\n // focusable element with no role in the tab order and gave the arrows two owners.\n // Only while open: the list it watches is rendered then, and not before.\n const { isLoading: showScrollSpinner, sentinelRef } = useInfiniteScroll(listRef, isOpen ? onLoadMore : undefined);\n\n // Explicit prop → this component's global default → the app-wide one → anchored.\n // Resolved here rather than left to Popover so that this component and the panel\n // it opens can never disagree about whether they are presenting as a sheet.\n const appPresentation = usePresentationDefault();\n const presentation = presentationProp ?? appPresentation ?? Presentation.Default;\n const { isSheet } = useSheet(presentation);\n\n // The list reads at the field's size, which is not always the page's: a Dropdown\n // inside something with a smaller font should not open a list at the default one.\n // Width is Popover's job, through `width='trigger'`.\n useLayoutEffect(() => {\n const trigger = triggerRef.current;\n const menu = anchorRef.current;\n if (!isOpen || isSheet || !trigger || !menu) return;\n menu.style.fontSize = window.getComputedStyle(trigger).fontSize;\n }, [isOpen, isSheet]);\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 currentValue = formValidator ? (formValidator.value as string | number) : value;\n const selectedIndex = items.findIndex((item) => item.key === currentValue);\n\n useEffect(() => {\n if (!isOpen || activeIndex === null) return;\n scrollOptionIntoView(listRef.current, document.getElementById(optionId(activeIndex)));\n // optionId is derived from a stable useId, so it cannot go stale between renders.\n // oxlint-disable-next-line react-hooks/exhaustive-deps\n }, [isOpen, activeIndex]);\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 ? formValidator.shouldShowError : !isValid || !!errorMessage;\n };\n\n const computedIsRequired = (): boolean => {\n return !!(\n isRequired || formValidator?.validators.find((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 function handleOpenChange(next: boolean) {\n if (next && !isInteractive) return;\n setMenuIsOpen(next);\n if (next) setActiveIndex(scrollToSelected && selectedIndex >= 0 ? selectedIndex : null);\n else typeahead.current = { buffer: '', at: 0 };\n }\n\n function select(item: DropdownItem) {\n if (item.disabled) return;\n onChangeHandler(item.key);\n handleOpenChange(false);\n }\n\n const navigation = { isDisabled: (index: number) => !!items[index].disabled };\n\n /** Jumps to the option whose label starts with what was typed, as a native `<select>` does. */\n function handleTypeahead(key: string) {\n const now = Date.now();\n const buffer = now - typeahead.current.at > TYPEAHEAD_RESET_MS ? key : typeahead.current.buffer + key;\n typeahead.current = { buffer, at: now };\n\n const needle = buffer.toLowerCase();\n const match = items.findIndex(\n (item) => !item.disabled && typeof item.label === 'string' && item.label.toLowerCase().startsWith(needle),\n );\n if (match === -1) return;\n if (isOpen) setActiveIndex(match);\n else select(items[match]);\n }\n\n function handleKeyDown(event: React.KeyboardEvent) {\n if (!isInteractive) return;\n\n if (!isOpen) {\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp' || event.key === 'Enter' || event.key === ' ') {\n // Without this the browser turns the key into a click on the trigger, which\n // Popover would read as a second toggle and close the list again.\n event.preventDefault();\n handleOpenChange(true);\n } else if (event.key.length === 1) {\n handleTypeahead(event.key);\n }\n return;\n }\n\n if (event.key === 'ArrowDown' || event.key === 'ArrowUp') {\n event.preventDefault();\n setActiveIndex(nextIndex(activeIndex, event.key === 'ArrowDown' ? 1 : -1, items.length, navigation));\n } else if (event.key === 'Home' || event.key === 'End') {\n event.preventDefault();\n setActiveIndex(edgeIndex(event.key === 'Home' ? 'first' : 'last', items.length, navigation));\n } else if (event.key === 'Enter' || event.key === ' ') {\n event.preventDefault();\n const item = activeIndex === null ? undefined : items[activeIndex];\n if (item) select(item);\n else handleOpenChange(false);\n } else if (event.key === 'Escape' || event.key === 'Tab') {\n handleOpenChange(false);\n } else if (event.key.length === 1) {\n handleTypeahead(event.key);\n }\n }\n\n let dropdownLabel = dropdownLabelProp;\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 = displayValue == null || (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, classNames?.root, styles.dropdownLabel, styles.dropdown, {\n [styles.dropdownLabelColumn]: !isRow,\n [styles.dropdownWithLabel]: useMatLabelStyle && !!label,\n })}\n style={{ ...style, ...slotStyles?.root }}\n onMouseEnter={onMouseEnterHandler}\n onMouseLeave={onMouseLeaveHandler}\n >\n <div>\n <Popover\n // Popover owns opening and closing, including the outside click, Escape and the\n // click on the field itself. The trigger only has to say what it wants.\n isOpen={isOpen}\n onOpenChange={handleOpenChange}\n disabled={!isInteractive}\n placement={PopoverPlacement.Bottom}\n align={PopoverAlign.Start}\n offset={0}\n withArrow={false}\n constrainWidth={false}\n width='trigger'\n // The focus stays on the trigger while the list is open, because that is what\n // `aria-activedescendant` points from.\n focusOnOpen={false}\n presentation={presentation}\n classNames={{ panel: styles.dropdownPanel }}\n content={\n <div\n ref={anchorRef}\n // A sheet's own panel does the clipping, and spans the screen rather than\n // sizing itself to the field.\n className={cx(isSheet ? styles.dropdownInputListSheet : styles.dropdownInputListAnim, {\n [styles.dropdownInputListAnimWider]: isDropdownListWider && !isSheet,\n })}\n >\n <div\n ref={listRef}\n id={listboxId}\n role='listbox'\n aria-label={label || placeholder || undefined}\n aria-busy={showScrollSpinner || undefined}\n className={cx(styles.dropdownInputList, isSheet && sheetStyles.sheetScroll, classNames?.list)}\n style={slotStyles?.list}\n >\n {items.map((item: DropdownItem, index: number) => (\n <div\n key={item.key}\n id={optionId(index)}\n role='option'\n aria-selected={item.key === currentValue}\n aria-disabled={item.disabled || undefined}\n style={slotStyles?.option}\n className={cx(styles.dropdownInputListItem, classNames?.option, {\n [styles.dropdownInputListItemActive]: activeIndex === index,\n [styles.dropdownInputListItemSelected]: item.key === currentValue,\n [styles.dropdownInputListItemDisabled]: !!item.disabled,\n })}\n // Selecting must not move the focus off the trigger, which is what\n // `aria-activedescendant` is anchored to.\n onMouseDown={(event) => event.preventDefault()}\n onMouseEnter={() => setActiveIndex(index)}\n onClick={() => select(item)}\n >\n {item.label}\n </div>\n ))}\n <div ref={sentinelRef} className={styles.dropdownSentinel} aria-hidden='true' />\n {showScrollSpinner && (\n <div className={styles.dropdownLoadMore} aria-hidden='true'>\n <Loader size='1.125em' />\n </div>\n )}\n </div>\n </div>\n }\n >\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 classNames?.field,\n )}\n style={slotStyles?.field}\n >\n <button\n tabIndex={tabIndex}\n type='button'\n disabled={disabled}\n // A select-only combobox: the accessible name comes from the field's label,\n // and the element's own content is read as its value. A plain `button` role\n // would announce the value as the name and never mention the label.\n role='combobox'\n aria-haspopup='listbox'\n aria-expanded={isOpen}\n aria-controls={listboxId}\n aria-activedescendant={isOpen && activeIndex !== null ? optionId(activeIndex) : undefined}\n aria-labelledby={label ? labelId : undefined}\n aria-label={label ? undefined : placeholder || undefined}\n aria-readonly={readOnly || undefined}\n className={cx(\n styles.dropdownInputButton,\n {\n [styles.dropdownInputButtonDisabled]: disabled,\n [styles.dropdownInputButtonReadOnly]: readOnly && !disabled,\n },\n classNames?.control,\n )}\n style={{ ...(isDropdownListWider ? { padding: '6px', border: 'none' } : {}), ...slotStyles?.control }}\n onKeyDown={handleKeyDown}\n onClick={onClick}\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 ? ' ' : displayValue}\n </button>\n <button\n type='button'\n tabIndex={-1}\n disabled={disabled}\n // The chevron repeats what the combobox beside it already does, so it is a\n // pointer affordance only. Announcing it would offer the same control twice.\n aria-hidden='true'\n className={cx(styles.dropdownInputButtonIcon, classNames?.icon)}\n style={slotStyles?.icon}\n // Keeping the focus where it is, rather than letting mousedown move it here:\n // the trigger is what `aria-activedescendant` points from, and the click\n // still reaches Popover by bubbling.\n onMouseDown={(event: React.MouseEvent<HTMLButtonElement>) => event.preventDefault()}\n onClick={onClick}\n >\n {!disabled && !readOnly && (\n <FontAwesomeIcon\n icon={dropdownIcon}\n className={cx(styles.dropdownInputButtonIconArrow, {\n [styles.dropdownInputButtonIconArrowOpen]: isOpen,\n })}\n />\n )}\n </button>\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 id={labelId}\n className={cx(\n styles.dropdownMatLabel,\n {\n [styles.dropdownMatLabelFloating]: alwaysFloatLabel || showFocus || !isDisplayBlank,\n },\n // The floating and the stacked label are two renderings of\n // the same thing, so one slot reaches whichever is in use.\n classNames?.label,\n )}\n style={slotStyles?.label}\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 </Popover>\n </div>\n {label && !useMatLabelStyle && (\n <div id={labelId} className={cx(styles.dropdownLabelText, classNames?.label)} style={slotStyles?.label}>\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
- "use client";import e from"../ripple/ripple.mjs";import t from"./iconPicker.module.mjs";import{useRef as n}from"react";import r from"classnames";import{FontAwesomeIcon as i}from"@fortawesome/react-fontawesome";import{jsx as a,jsxs as o}from"react/jsx-runtime";function s(e){let{formValidator:t}=e;return t?t.touched&&t.hasError():!1}function c(e){let{isRequired:t,formValidator:n}=e;return!!(t||n?.validators.find(e=>e.validatorId===`required`))}function l({data:l=[],selectedId:u=null,label:d=``,onChange:f,formValidator:p=null,isRequired:m,className:h,style:g,classNames:_,styles:v,...y}){let b=p?p.value??null:u,x=s({formValidator:p,isRequired:m}),S=c({formValidator:p,isRequired:m}),C=n([]),w=n([]),T=l.findIndex(e=>e.id===b),E=T>=0?T:0;function D(e){p&&p.set(e),f?.(e)}function O(e,t){if(l.length===0)return;let n=(t+e+l.length)%l.length;C.current[n]?.focus(),D(l[n].id)}function k(e,t,n){switch(e.key){case`ArrowDown`:case`ArrowRight`:e.preventDefault(),O(1,t);break;case`ArrowUp`:case`ArrowLeft`:e.preventDefault(),O(-1,t);break;case` `:case`Enter`:e.preventDefault(),w.current[t]?.addRipple(),D(n)}}return o(`div`,{...y,className:r(t.iconPicker,{[t.iconPickerError]:x},_?.root,h),style:{...v?.root,...g},children:[d&&o(`div`,{className:r(t.iconPickerLabel,_?.label),style:v?.label,children:[d,S&&` *`]}),a(`div`,{role:`radiogroup`,"aria-label":d||void 0,className:r(t.iconPickerItemContainer,_?.itemContainer),style:v?.itemContainer,children:l.map(({id:n,label:s,icon:c,customIcon:l},u)=>{let d=b===n;return o(`div`,{ref:e=>{C.current[u]=e},className:r(t.iconPickerItem,{[t.iconPickerItemSelected]:d},_?.item),style:v?.item,title:s,tabIndex:u===E?0:-1,role:`radio`,"aria-checked":d,onClick:()=>D(n),onKeyDown:e=>k(e,u,n),children:[c&&a(i,{icon:c}),l??null,a(e,{ref:e=>{w.current[u]=e}})]},n)})})]})}export{l as default};
1
+ "use client";import e from"../ripple/ripple.mjs";import t from"./iconPicker.module.mjs";import{useRef as n}from"react";import r from"classnames";import{FontAwesomeIcon as i}from"@fortawesome/react-fontawesome";import{jsx as a,jsxs as o}from"react/jsx-runtime";function s(e){let{formValidator:t}=e;return t?t.shouldShowError:!1}function c(e){let{isRequired:t,formValidator:n}=e;return!!(t||n?.validators.find(e=>e.validatorId===`required`))}function l({data:l=[],selectedId:u=null,label:d=``,onChange:f,formValidator:p=null,isRequired:m,className:h,style:g,classNames:_,styles:v,...y}){let b=p?p.value??null:u,x=s({formValidator:p,isRequired:m}),S=c({formValidator:p,isRequired:m}),C=n([]),w=n([]),T=l.findIndex(e=>e.id===b),E=T>=0?T:0;function D(e){p&&p.set(e),f?.(e)}function O(e,t){if(l.length===0)return;let n=(t+e+l.length)%l.length;C.current[n]?.focus(),D(l[n].id)}function k(e,t,n){switch(e.key){case`ArrowDown`:case`ArrowRight`:e.preventDefault(),O(1,t);break;case`ArrowUp`:case`ArrowLeft`:e.preventDefault(),O(-1,t);break;case` `:case`Enter`:e.preventDefault(),w.current[t]?.addRipple(),D(n)}}return o(`div`,{...y,className:r(t.iconPicker,{[t.iconPickerError]:x},_?.root,h),style:{...v?.root,...g},children:[d&&o(`div`,{className:r(t.iconPickerLabel,_?.label),style:v?.label,children:[d,S&&` *`]}),a(`div`,{role:`radiogroup`,"aria-label":d||void 0,className:r(t.iconPickerItemContainer,_?.itemContainer),style:v?.itemContainer,children:l.map(({id:n,label:s,icon:c,customIcon:l},u)=>{let d=b===n;return o(`div`,{ref:e=>{C.current[u]=e},className:r(t.iconPickerItem,{[t.iconPickerItemSelected]:d},_?.item),style:v?.item,title:s,tabIndex:u===E?0:-1,role:`radio`,"aria-checked":d,onClick:()=>D(n),onKeyDown:e=>k(e,u,n),children:[c&&a(i,{icon:c}),l??null,a(e,{ref:e=>{w.current[u]=e}})]},n)})})]})}export{l as default};
2
2
  //# sourceMappingURL=iconPicker.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"iconPicker.mjs","names":[],"sources":["../../../../package/common/iconPicker/iconPicker.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport styles from './iconPicker.module.pcss';\nimport Ripple from '../ripple';\nimport type { RippleHandle } from '../ripple';\nimport type { IconPickerItem, IconPickerProps } from './iconPicker.types';\n\nfunction hasError(props: IconPickerProps): boolean {\n const { formValidator } = props;\n return formValidator ? formValidator.touched && formValidator.hasError() : false;\n}\n\nfunction isRequired(props: IconPickerProps): boolean {\n const { isRequired: reqProp, formValidator } = props;\n return !!(\n reqProp || formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required')\n );\n}\n\nexport default function IconPicker({\n data = [],\n selectedId = null,\n label = '',\n onChange,\n formValidator = null,\n isRequired: _isRequired,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: IconPickerProps) {\n const currentValue = formValidator ? ((formValidator.value as string) ?? null) : selectedId;\n const showError = hasError({ formValidator, isRequired: _isRequired });\n const required = isRequired({ formValidator, isRequired: _isRequired });\n\n const itemRefs = useRef<(HTMLDivElement | null)[]>([]);\n const rippleRefs = useRef<(RippleHandle | null)[]>([]);\n const selectedIndex = data.findIndex((item) => item.id === currentValue);\n const rovingIndex = selectedIndex >= 0 ? selectedIndex : 0;\n\n function handleSelect(id: string) {\n if (formValidator) formValidator.set(id);\n onChange?.(id);\n }\n\n function moveTo(step: 1 | -1, fromIndex: number) {\n if (data.length === 0) return;\n const next = (fromIndex + step + data.length) % data.length;\n itemRefs.current[next]?.focus();\n handleSelect(data[next].id);\n }\n\n function handleKeyDown(event: React.KeyboardEvent, index: number, id: string) {\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowRight':\n event.preventDefault();\n moveTo(1, index);\n break;\n case 'ArrowUp':\n case 'ArrowLeft':\n event.preventDefault();\n moveTo(-1, index);\n break;\n case ' ':\n case 'Enter':\n event.preventDefault();\n // No DOM click is dispatched here, so Ripple's own listener never sees the activation.\n rippleRefs.current[index]?.addRipple();\n handleSelect(id);\n break;\n default:\n break;\n }\n }\n\n return (\n <div\n {...rest}\n className={cx(styles.iconPicker, { [styles.iconPickerError]: showError }, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n >\n {label && (\n <div className={cx(styles.iconPickerLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n {required && ' *'}\n </div>\n )}\n <div\n role='radiogroup'\n aria-label={label || undefined}\n className={cx(styles.iconPickerItemContainer, classNames?.itemContainer)}\n style={slotStyles?.itemContainer}\n >\n {data.map(({ id, label: itemLabel, icon, customIcon }: IconPickerItem, index) => {\n const checked = currentValue === id;\n return (\n <div\n key={id}\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n className={cx(styles.iconPickerItem, { [styles.iconPickerItemSelected]: checked }, classNames?.item)}\n style={slotStyles?.item}\n title={itemLabel}\n tabIndex={index === rovingIndex ? 0 : -1}\n role='radio'\n aria-checked={checked}\n onClick={() => handleSelect(id)}\n onKeyDown={(event) => handleKeyDown(event, index, id)}\n >\n {icon && <FontAwesomeIcon icon={icon} />}\n {customIcon ?? null}\n <Ripple\n ref={(el) => {\n rippleRefs.current[index] = el;\n }}\n />\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":"oQAQA,SAAS,EAAS,EAAiC,CACjD,GAAM,CAAE,iBAAkB,EAC1B,OAAO,EAAgB,EAAc,SAAW,EAAc,SAAS,EAAI,EAC7E,CAEA,SAAS,EAAW,EAAiC,CACnD,GAAM,CAAE,WAAY,EAAS,iBAAkB,EAC/C,MAAO,CAAC,EACN,GAAW,GAAe,WAAW,KAAM,GAAO,EAA+B,cAAgB,UAAU,EAE/G,CAEA,SAAwB,EAAW,CACjC,OAAO,CAAC,EACR,aAAa,KACb,QAAQ,GACR,WACA,gBAAgB,KAChB,WAAY,EACZ,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACe,CAClB,IAAM,EAAe,EAAkB,EAAc,OAAoB,KAAQ,EAC3E,EAAY,EAAS,CAAE,gBAAe,WAAY,CAAY,CAAC,EAC/D,EAAW,EAAW,CAAE,gBAAe,WAAY,CAAY,CAAC,EAEhE,EAAW,EAAkC,CAAC,CAAC,EAC/C,EAAa,EAAgC,CAAC,CAAC,EAC/C,EAAgB,EAAK,UAAW,GAAS,EAAK,KAAO,CAAY,EACjE,EAAc,GAAiB,EAAI,EAAgB,EAEzD,SAAS,EAAa,EAAY,CAC5B,GAAe,EAAc,IAAI,CAAE,EACvC,IAAW,CAAE,CACf,CAEA,SAAS,EAAO,EAAc,EAAmB,CAC/C,GAAI,EAAK,SAAW,EAAG,OACvB,IAAM,GAAQ,EAAY,EAAO,EAAK,QAAU,EAAK,OACrD,EAAS,QAAQ,EAAK,EAAE,MAAM,EAC9B,EAAa,EAAK,EAAK,CAAC,EAAE,CAC5B,CAEA,SAAS,EAAc,EAA4B,EAAe,EAAY,CAC5E,OAAQ,EAAM,IAAd,CACE,IAAK,YACL,IAAK,aACH,EAAM,eAAe,EACrB,EAAO,EAAG,CAAK,EACf,MACF,IAAK,UACL,IAAK,YACH,EAAM,eAAe,EACrB,EAAO,GAAI,CAAK,EAChB,MACF,IAAK,IACL,IAAK,QACH,EAAM,eAAe,EAErB,EAAW,QAAQ,EAAM,EAAE,UAAU,EACrC,EAAa,CAAE,CAInB,CACF,CAEA,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,WAAY,EAAG,EAAO,iBAAkB,CAAU,EAAG,GAAY,KAAM,CAAS,EACrG,MAAO,CAAE,GAAG,GAAY,KAAM,GAAG,CAAM,EAHzC,SAAA,CAKG,GACC,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,gBAAiB,GAAY,KAAK,EAAG,MAAO,GAAY,MAAlF,SAAA,CACG,EACA,GAAY,IACV,CAEP,CAAA,EAAA,EAAC,MAAD,CACE,KAAK,aACL,aAAY,GAAS,IAAA,GACrB,UAAW,EAAG,EAAO,wBAAyB,GAAY,aAAa,EACvE,MAAO,GAAY,cAElB,SAAA,EAAK,KAAK,CAAE,KAAI,MAAO,EAAW,OAAM,cAA8B,IAAU,CAC/E,IAAM,EAAU,IAAiB,EACjC,OACE,EAAC,MAAD,CAEE,IAAM,GAAO,CACX,EAAS,QAAQ,GAAS,CAC5B,EACA,UAAW,EAAG,EAAO,eAAgB,EAAG,EAAO,wBAAyB,CAAQ,EAAG,GAAY,IAAI,EACnG,MAAO,GAAY,KACnB,MAAO,EACP,SAAU,IAAU,EAAc,EAAI,GACtC,KAAK,QACL,eAAc,EACd,YAAe,EAAa,CAAE,EAC9B,UAAY,GAAU,EAAc,EAAO,EAAO,CAAE,EAZtD,SAAA,CAcG,GAAQ,EAAC,EAAD,CAAuB,MAAO,CAAA,EACtC,GAAc,KACf,EAAC,EAAD,CACE,IAAM,GAAO,CACX,EAAW,QAAQ,GAAS,CAC9B,CACD,CAAA,CACE,CApBE,EAAA,CAoBF,CAET,CAAC,CACE,CAAA,CACF,GAET"}
1
+ {"version":3,"file":"iconPicker.mjs","names":[],"sources":["../../../../package/common/iconPicker/iconPicker.tsx"],"sourcesContent":["import React, { useRef } from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport styles from './iconPicker.module.pcss';\nimport Ripple from '../ripple';\nimport type { RippleHandle } from '../ripple';\nimport type { IconPickerItem, IconPickerProps } from './iconPicker.types';\n\nfunction hasError(props: IconPickerProps): boolean {\n const { formValidator } = props;\n return formValidator ? formValidator.shouldShowError : false;\n}\n\nfunction isRequired(props: IconPickerProps): boolean {\n const { isRequired: reqProp, formValidator } = props;\n return !!(\n reqProp || formValidator?.validators.find((v) => (v as { validatorId?: string }).validatorId === 'required')\n );\n}\n\nexport default function IconPicker({\n data = [],\n selectedId = null,\n label = '',\n onChange,\n formValidator = null,\n isRequired: _isRequired,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: IconPickerProps) {\n const currentValue = formValidator ? ((formValidator.value as string) ?? null) : selectedId;\n const showError = hasError({ formValidator, isRequired: _isRequired });\n const required = isRequired({ formValidator, isRequired: _isRequired });\n\n const itemRefs = useRef<(HTMLDivElement | null)[]>([]);\n const rippleRefs = useRef<(RippleHandle | null)[]>([]);\n const selectedIndex = data.findIndex((item) => item.id === currentValue);\n const rovingIndex = selectedIndex >= 0 ? selectedIndex : 0;\n\n function handleSelect(id: string) {\n if (formValidator) formValidator.set(id);\n onChange?.(id);\n }\n\n function moveTo(step: 1 | -1, fromIndex: number) {\n if (data.length === 0) return;\n const next = (fromIndex + step + data.length) % data.length;\n itemRefs.current[next]?.focus();\n handleSelect(data[next].id);\n }\n\n function handleKeyDown(event: React.KeyboardEvent, index: number, id: string) {\n switch (event.key) {\n case 'ArrowDown':\n case 'ArrowRight':\n event.preventDefault();\n moveTo(1, index);\n break;\n case 'ArrowUp':\n case 'ArrowLeft':\n event.preventDefault();\n moveTo(-1, index);\n break;\n case ' ':\n case 'Enter':\n event.preventDefault();\n // No DOM click is dispatched here, so Ripple's own listener never sees the activation.\n rippleRefs.current[index]?.addRipple();\n handleSelect(id);\n break;\n default:\n break;\n }\n }\n\n return (\n <div\n {...rest}\n className={cx(styles.iconPicker, { [styles.iconPickerError]: showError }, classNames?.root, className)}\n style={{ ...slotStyles?.root, ...style }}\n >\n {label && (\n <div className={cx(styles.iconPickerLabel, classNames?.label)} style={slotStyles?.label}>\n {label}\n {required && ' *'}\n </div>\n )}\n <div\n role='radiogroup'\n aria-label={label || undefined}\n className={cx(styles.iconPickerItemContainer, classNames?.itemContainer)}\n style={slotStyles?.itemContainer}\n >\n {data.map(({ id, label: itemLabel, icon, customIcon }: IconPickerItem, index) => {\n const checked = currentValue === id;\n return (\n <div\n key={id}\n ref={(el) => {\n itemRefs.current[index] = el;\n }}\n className={cx(styles.iconPickerItem, { [styles.iconPickerItemSelected]: checked }, classNames?.item)}\n style={slotStyles?.item}\n title={itemLabel}\n tabIndex={index === rovingIndex ? 0 : -1}\n role='radio'\n aria-checked={checked}\n onClick={() => handleSelect(id)}\n onKeyDown={(event) => handleKeyDown(event, index, id)}\n >\n {icon && <FontAwesomeIcon icon={icon} />}\n {customIcon ?? null}\n <Ripple\n ref={(el) => {\n rippleRefs.current[index] = el;\n }}\n />\n </div>\n );\n })}\n </div>\n </div>\n );\n}\n"],"mappings":"oQAQA,SAAS,EAAS,EAAiC,CACjD,GAAM,CAAE,iBAAkB,EAC1B,OAAO,EAAgB,EAAc,gBAAkB,EACzD,CAEA,SAAS,EAAW,EAAiC,CACnD,GAAM,CAAE,WAAY,EAAS,iBAAkB,EAC/C,MAAO,CAAC,EACN,GAAW,GAAe,WAAW,KAAM,GAAO,EAA+B,cAAgB,UAAU,EAE/G,CAEA,SAAwB,EAAW,CACjC,OAAO,CAAC,EACR,aAAa,KACb,QAAQ,GACR,WACA,gBAAgB,KAChB,WAAY,EACZ,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACe,CAClB,IAAM,EAAe,EAAkB,EAAc,OAAoB,KAAQ,EAC3E,EAAY,EAAS,CAAE,gBAAe,WAAY,CAAY,CAAC,EAC/D,EAAW,EAAW,CAAE,gBAAe,WAAY,CAAY,CAAC,EAEhE,EAAW,EAAkC,CAAC,CAAC,EAC/C,EAAa,EAAgC,CAAC,CAAC,EAC/C,EAAgB,EAAK,UAAW,GAAS,EAAK,KAAO,CAAY,EACjE,EAAc,GAAiB,EAAI,EAAgB,EAEzD,SAAS,EAAa,EAAY,CAC5B,GAAe,EAAc,IAAI,CAAE,EACvC,IAAW,CAAE,CACf,CAEA,SAAS,EAAO,EAAc,EAAmB,CAC/C,GAAI,EAAK,SAAW,EAAG,OACvB,IAAM,GAAQ,EAAY,EAAO,EAAK,QAAU,EAAK,OACrD,EAAS,QAAQ,EAAK,EAAE,MAAM,EAC9B,EAAa,EAAK,EAAK,CAAC,EAAE,CAC5B,CAEA,SAAS,EAAc,EAA4B,EAAe,EAAY,CAC5E,OAAQ,EAAM,IAAd,CACE,IAAK,YACL,IAAK,aACH,EAAM,eAAe,EACrB,EAAO,EAAG,CAAK,EACf,MACF,IAAK,UACL,IAAK,YACH,EAAM,eAAe,EACrB,EAAO,GAAI,CAAK,EAChB,MACF,IAAK,IACL,IAAK,QACH,EAAM,eAAe,EAErB,EAAW,QAAQ,EAAM,EAAE,UAAU,EACrC,EAAa,CAAE,CAInB,CACF,CAEA,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EAAG,EAAO,WAAY,EAAG,EAAO,iBAAkB,CAAU,EAAG,GAAY,KAAM,CAAS,EACrG,MAAO,CAAE,GAAG,GAAY,KAAM,GAAG,CAAM,EAHzC,SAAA,CAKG,GACC,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,gBAAiB,GAAY,KAAK,EAAG,MAAO,GAAY,MAAlF,SAAA,CACG,EACA,GAAY,IACV,CAEP,CAAA,EAAA,EAAC,MAAD,CACE,KAAK,aACL,aAAY,GAAS,IAAA,GACrB,UAAW,EAAG,EAAO,wBAAyB,GAAY,aAAa,EACvE,MAAO,GAAY,cAElB,SAAA,EAAK,KAAK,CAAE,KAAI,MAAO,EAAW,OAAM,cAA8B,IAAU,CAC/E,IAAM,EAAU,IAAiB,EACjC,OACE,EAAC,MAAD,CAEE,IAAM,GAAO,CACX,EAAS,QAAQ,GAAS,CAC5B,EACA,UAAW,EAAG,EAAO,eAAgB,EAAG,EAAO,wBAAyB,CAAQ,EAAG,GAAY,IAAI,EACnG,MAAO,GAAY,KACnB,MAAO,EACP,SAAU,IAAU,EAAc,EAAI,GACtC,KAAK,QACL,eAAc,EACd,YAAe,EAAa,CAAE,EAC9B,UAAY,GAAU,EAAc,EAAO,EAAO,CAAE,EAZtD,SAAA,CAcG,GAAQ,EAAC,EAAD,CAAuB,MAAO,CAAA,EACtC,GAAc,KACf,EAAC,EAAD,CACE,IAAM,GAAO,CACX,EAAW,QAAQ,GAAS,CAC9B,CACD,CAAA,CACE,CApBE,EAAA,CAoBF,CAET,CAAC,CACE,CAAA,CACF,GAET"}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{mergeRefs as n}from"../utils/mergeRefs.mjs";import{useAutoGrow as ee}from"../hooks/useAutoGrow.mjs";import te from"../tooltip/tooltip.mjs";import ne from"../animatedIcon/animatedIcon.mjs";import r from"./input.module.mjs";import{InputIconPosition as i,InputType as a}from"./input.types.mjs";import re,{useEffect as ie,useId as ae,useRef as oe,useState as o}from"react";import s from"classnames";import{FontAwesomeIcon as c}from"@fortawesome/react-fontawesome";import{faEnvelope as l,faEye as se,faEyeSlash as ce,faPen as u,faPhone as le,faSearch as ue,faXmark as de}from"@fortawesome/free-solid-svg-icons";import{jsx as d,jsxs as f}from"react/jsx-runtime";var fe={clear:`Clear`,showPassword:`Show password`,hidePassword:`Hide password`,clearSearch:`Clear search`},pe={[a.Phone]:le,[a.Email]:l,[a.Edit]:u};function p(e){if(e)return{role:`button`,tabIndex:0,onMouseDown:e=>e.preventDefault(),onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),e(t))}}}function m(l){let{name:u=``,id:le,label:m=``,errorMessage:me=``,isValid:he=!0,className:ge=``,style:_e,value:ve=``,icon:h=null,iconPosition:ye,onChange:g=()=>{},onFocus:_=null,onBlur:v=null,onMouseEnter:y=null,onMouseLeave:be=null,isUppercase:xe=!1,isRequired:Se=!1,tabIndex:Ce=0,type:b=void 0,isRow:we=!1,onIconClick:x=null,parse:S=null,formValidator:C=null,autoFocus:w=!1,suffix:T=null,upperRightLabel:E=null,labelInBorder:Te=!1,clearable:Ee=!1,onClear:De,min:Oe=null,max:ke=null,placeholder:D=``,useMatLabelStyle:O=!0,alwaysFloatLabel:Ae=!1,autoComplete:je=null,onClick:Me=()=>null,readOnly:k=!1,customInput:A,multiline:j=!1,rows:Ne,autoResize:M=!1,classNames:N,styles:P,disabled:F=!1,labels:Pe,ref:Fe,...I}=e(`Input`,l),L=t(`Input`,Pe,fe),[Ie,Le]=o(!1),[Re,ze]=o(!1),[Be,Ve]=o(!1),[R,He]=o(!1),[,Ue]=o(0),z=oe(null),B=oe(C),We=ae(),Ge=le||u||We,V=C?C.value:ve;ee(z,V,{enabled:M}),ie(()=>{w&&z.current&&setTimeout(()=>{z.current?.focus()},1)},[w]),ie(()=>{B.current=C;let e=B.current;if(!e)return;e.label=m??``,e.validate();let t=()=>Ue(e=>e+1);return e.registerOnUpdateListener(t),()=>{e.removeOnUpdateListener(t)}},[C,m]);let Ke=()=>C?C.touched&&C.hasError():!he||!!me,qe=()=>!!(Se||C&&C.validators.find(e=>e.validatorId===`required`)),Je=e=>{Ve(!0),y&&y(e)},Ye=e=>{Ve(!1),be&&be(e)},Xe=e=>{Le(!0),_&&_(e)},Ze=e=>{B.current&&(B.current.touched=!0),Le(!1),v&&v(e)},Qe=e=>{let t,n;typeof e==`string`?n=e:(t=e,n=e.target.value),S&&(n=S(n)),C&&C.set(n),g&&g(n,t)},$e=()=>{if(b!==a.Email)return b===a.Phone?`tel`:b===a.Search?`search`:b===`password`&&R?`text`:b},et=()=>{if(b===a.Email)return`email`;if(b===a.Phone)return`tel`;if(b===a.Search)return`search`},tt=b===a.Search||b===a.Password,nt=!!h,rt=nt&&!tt,it=b===a.Email||b===a.Phone||b===a.Search,H=(ye??(!O&&it?i.Left:i.Right))===i.Left,at={className:s(r.inputFieldIcon,{[r.inputFieldIconNotClickable]:!x,[r.inputFieldIconLeft]:H}),onClick:x??void 0,...p(x)},ot=b&&!nt?pe[b]:void 0,U=h,W=x??U?.props.onClick,st=rt&&U?re.cloneElement(U,{className:s(r.inputFieldIcon,{[r.inputFieldIconNotClickable]:!W,[r.inputFieldIconLeft]:H},U.props.className),onClick:W,...p(W)}):null,G=Ke(),K=m;K&&qe()&&(K=`${K} *`);let ct=qe()?d(`span`,{className:r.requiredMark,children:`*`}):null,q=Ie&&!k,J=O&&(Ae||q||V||Re||b===a.Date),lt=e=>{let{animationName:t}=e;if(t===r.inputAutofillStart){ze(!0);let t=e.currentTarget.value;t&&t!==String(V??``)&&Qe(t);return}if(t===r.inputAutofillEnd){ze(!1);return}I.onAnimationStart?.(e)},Y=!!V&&!F&&!k,X=b===a.Search&&Y;function ut(){He(!R)}let Z=st;b===a.Search?Z=d(ne,{icon:X?de:ue,className:s(r.inputFieldIcon,{[r.inputFieldIconNotClickable]:!X,[r.inputFieldIconLeft]:H}),onClick:X?$:void 0,...p(X?$:void 0),"aria-label":X?L.clearSearch:void 0}):b===a.Password?Z=d(c,{icon:R?ce:se,className:s(r.inputFieldIcon,{[r.inputFieldIconLeft]:H}),onClick:ut,...p(ut),"aria-label":R?L.hidePassword:L.showPassword}):ot&&(Z=d(c,{icon:ot,...at}));let dt=!!Z&&H,Q=A?.props;function $(){C&&C.set(``),g?.(``),De?.(),z.current?.focus()}return d(`div`,{className:s(r.input,{[r.inputIconLeft]:dt,[r.inputWithLabel]:O&&!!m},ge),style:_e,children:f(`label`,{htmlFor:Ge,className:s(r.inputLabel,N?.label,{[r.inputLabelColumn]:!we,[r.inputLabelInBorder]:Te}),style:P?.label,children:[m&&!O?f(`span`,{className:r.inputLabelText,children:[m,ct]}):null,E&&d(`div`,{className:s(r.inputUpperRightLabel,N?.upperRightLabel),style:P?.upperRightLabel,children:E}),f(`div`,{className:s(r.inputContainer,{[r.inputContainerMultiline]:j,[r.inputContainerResizable]:j&&!M,[r.inputContainerDisabled]:F},N?.container),style:P?.container,onMouseEnter:Je,onMouseLeave:Ye,children:[H&&Z,re.cloneElement(A||d(j?`textarea`:`input`,{}),{...I,className:s(r.inputField,{[r.inputFieldUppercase]:xe,[r.inputFieldDate]:b===a.Date,[r.inputFieldDefault]:b!==a.Date,[r.inputFieldWithIconLeft]:dt,[r.inputFieldMultiline]:j,[r.inputFieldMultilineAutoResize]:j&&M,[r.inputFieldReadOnly]:k&&!F},N?.input,Q?.className),style:Q?.style||P?.input?{...Q?.style,...P?.input}:void 0,name:u,id:Ge,value:V,tabIndex:Ce,ref:A?void 0:n(z,Fe),onChange:Qe,onAnimationStart:lt,onFocus:Xe,onBlur:Ze,placeholder:O?``:D,autoComplete:je,onClick:Me,readOnly:k,disabled:F,...!j&&{type:$e(),inputMode:I.inputMode??et(),min:Oe,max:ke},...j&&Ne!==void 0&&{rows:Ne}}),T&&d(`div`,{className:s(r.inputFieldSuffix,N?.suffix),style:P?.suffix,children:T}),Ee&&b!==a.Search&&d(c,{icon:de,className:s(r.inputFieldIcon,r.inputFieldIconClear,{[r.inputFieldIconClearHidden]:!Y}),onClick:Y?$:void 0,...p(Y?$:void 0),"aria-label":L.clear}),!H&&Z]}),d(`fieldset`,{className:s(r.inputFieldset,N?.fieldset,{[r.inputContainerBorderFocused]:q,[r.inputContainerBorderSearchFocused]:b===a.Search&&(q||!!V),[r.inputContainerBorderInvalid]:G,[r.inputContainerBorderError]:G}),style:P?.fieldset,children:d(`legend`,{className:s(r.inputFieldsetLegend,{[r.inputFieldsetLegendActive]:J}),children:d(`span`,{children:K})})}),O&&m&&f(`div`,{className:s(r.inputMatLabel,{[r.inputMatLabelFloating]:J,[r.inputMatLabelMultiline]:j&&!J}),children:[m,ct]}),O&&D&&d(`div`,{className:s(r.inputPlaceholder,q&&!V&&!Re&&r.inputPlaceholderShown,j&&r.inputPlaceholderMultiline),children:D}),d(te,{variant:`error`,message:C?C.getCurrentErrorMessage():me||``,isVisible:G&&(Ie||Be)})]})})}export{m as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{mergeRefs as n}from"../utils/mergeRefs.mjs";import{useAutoGrow as ee}from"../hooks/useAutoGrow.mjs";import te from"../tooltip/tooltip.mjs";import ne from"../animatedIcon/animatedIcon.mjs";import r from"./input.module.mjs";import{InputIconPosition as i,InputType as a}from"./input.types.mjs";import re,{useEffect as ie,useId as ae,useRef as oe,useState as o}from"react";import s from"classnames";import{FontAwesomeIcon as c}from"@fortawesome/react-fontawesome";import{faEnvelope as l,faEye as se,faEyeSlash as ce,faPen as u,faPhone as le,faSearch as ue,faXmark as de}from"@fortawesome/free-solid-svg-icons";import{jsx as d,jsxs as f}from"react/jsx-runtime";var fe={clear:`Clear`,showPassword:`Show password`,hidePassword:`Hide password`,clearSearch:`Clear search`},pe={[a.Phone]:le,[a.Email]:l,[a.Edit]:u};function p(e){if(e)return{role:`button`,tabIndex:0,onMouseDown:e=>e.preventDefault(),onKeyDown:t=>{(t.key===`Enter`||t.key===` `)&&(t.preventDefault(),e(t))}}}function m(l){let{name:u=``,id:le,label:m=``,errorMessage:me=``,isValid:he=!0,className:ge=``,style:_e,value:ve=``,icon:h=null,iconPosition:ye,onChange:g=()=>{},onFocus:_=null,onBlur:v=null,onMouseEnter:y=null,onMouseLeave:be=null,isUppercase:xe=!1,isRequired:Se=!1,tabIndex:Ce=0,type:b=void 0,isRow:we=!1,onIconClick:x=null,parse:S=null,formValidator:C=null,autoFocus:w=!1,suffix:T=null,upperRightLabel:E=null,labelInBorder:Te=!1,clearable:Ee=!1,onClear:De,min:Oe=null,max:ke=null,placeholder:D=``,useMatLabelStyle:O=!0,alwaysFloatLabel:Ae=!1,autoComplete:je=null,onClick:Me=()=>null,readOnly:k=!1,customInput:A,multiline:j=!1,rows:Ne,autoResize:M=!1,classNames:N,styles:P,disabled:F=!1,labels:Pe,ref:Fe,...I}=e(`Input`,l),L=t(`Input`,Pe,fe),[Ie,Le]=o(!1),[Re,ze]=o(!1),[Be,Ve]=o(!1),[R,He]=o(!1),[,Ue]=o(0),z=oe(null),B=oe(C),We=ae(),Ge=le||u||We,V=C?C.value:ve;ee(z,V,{enabled:M}),ie(()=>{w&&z.current&&setTimeout(()=>{z.current?.focus()},1)},[w]),ie(()=>{B.current=C;let e=B.current;if(!e)return;e.label=m??``,e.validate();let t=()=>Ue(e=>e+1);return e.registerOnUpdateListener(t),()=>{e.removeOnUpdateListener(t)}},[C,m]);let Ke=()=>C?C.shouldShowError:!he||!!me,qe=()=>!!(Se||C&&C.validators.find(e=>e.validatorId===`required`)),Je=e=>{Ve(!0),y&&y(e)},Ye=e=>{Ve(!1),be&&be(e)},Xe=e=>{Le(!0),_&&_(e)},Ze=e=>{B.current&&(B.current.touched=!0),Le(!1),v&&v(e)},Qe=e=>{let t,n;typeof e==`string`?n=e:(t=e,n=e.target.value),S&&(n=S(n)),C&&C.set(n),g&&g(n,t)},$e=()=>{if(b!==a.Email)return b===a.Phone?`tel`:b===a.Search?`search`:b===`password`&&R?`text`:b},et=()=>{if(b===a.Email)return`email`;if(b===a.Phone)return`tel`;if(b===a.Search)return`search`},tt=b===a.Search||b===a.Password,nt=!!h,rt=nt&&!tt,it=b===a.Email||b===a.Phone||b===a.Search,H=(ye??(!O&&it?i.Left:i.Right))===i.Left,at={className:s(r.inputFieldIcon,{[r.inputFieldIconNotClickable]:!x,[r.inputFieldIconLeft]:H}),onClick:x??void 0,...p(x)},ot=b&&!nt?pe[b]:void 0,U=h,W=x??U?.props.onClick,st=rt&&U?re.cloneElement(U,{className:s(r.inputFieldIcon,{[r.inputFieldIconNotClickable]:!W,[r.inputFieldIconLeft]:H},U.props.className),onClick:W,...p(W)}):null,G=Ke(),K=m;K&&qe()&&(K=`${K} *`);let ct=qe()?d(`span`,{className:r.requiredMark,children:`*`}):null,q=Ie&&!k,J=O&&(Ae||q||V||Re||b===a.Date),lt=e=>{let{animationName:t}=e;if(t===r.inputAutofillStart){ze(!0);let t=e.currentTarget.value;t&&t!==String(V??``)&&Qe(t);return}if(t===r.inputAutofillEnd){ze(!1);return}I.onAnimationStart?.(e)},Y=!!V&&!F&&!k,X=b===a.Search&&Y;function ut(){He(!R)}let Z=st;b===a.Search?Z=d(ne,{icon:X?de:ue,className:s(r.inputFieldIcon,{[r.inputFieldIconNotClickable]:!X,[r.inputFieldIconLeft]:H}),onClick:X?$:void 0,...p(X?$:void 0),"aria-label":X?L.clearSearch:void 0}):b===a.Password?Z=d(c,{icon:R?ce:se,className:s(r.inputFieldIcon,{[r.inputFieldIconLeft]:H}),onClick:ut,...p(ut),"aria-label":R?L.hidePassword:L.showPassword}):ot&&(Z=d(c,{icon:ot,...at}));let dt=!!Z&&H,Q=A?.props;function $(){C&&C.set(``),g?.(``),De?.(),z.current?.focus()}return d(`div`,{className:s(r.input,{[r.inputIconLeft]:dt,[r.inputWithLabel]:O&&!!m},ge),style:_e,children:f(`label`,{htmlFor:Ge,className:s(r.inputLabel,N?.label,{[r.inputLabelColumn]:!we,[r.inputLabelInBorder]:Te}),style:P?.label,children:[m&&!O?f(`span`,{className:r.inputLabelText,children:[m,ct]}):null,E&&d(`div`,{className:s(r.inputUpperRightLabel,N?.upperRightLabel),style:P?.upperRightLabel,children:E}),f(`div`,{className:s(r.inputContainer,{[r.inputContainerMultiline]:j,[r.inputContainerResizable]:j&&!M,[r.inputContainerDisabled]:F},N?.container),style:P?.container,onMouseEnter:Je,onMouseLeave:Ye,children:[H&&Z,re.cloneElement(A||d(j?`textarea`:`input`,{}),{...I,className:s(r.inputField,{[r.inputFieldUppercase]:xe,[r.inputFieldDate]:b===a.Date,[r.inputFieldDefault]:b!==a.Date,[r.inputFieldWithIconLeft]:dt,[r.inputFieldMultiline]:j,[r.inputFieldMultilineAutoResize]:j&&M,[r.inputFieldReadOnly]:k&&!F},N?.input,Q?.className),style:Q?.style||P?.input?{...Q?.style,...P?.input}:void 0,name:u,id:Ge,value:V,tabIndex:Ce,ref:A?void 0:n(z,Fe),onChange:Qe,onAnimationStart:lt,onFocus:Xe,onBlur:Ze,placeholder:O?``:D,autoComplete:je,onClick:Me,readOnly:k,disabled:F,...!j&&{type:$e(),inputMode:I.inputMode??et(),min:Oe,max:ke},...j&&Ne!==void 0&&{rows:Ne}}),T&&d(`div`,{className:s(r.inputFieldSuffix,N?.suffix),style:P?.suffix,children:T}),Ee&&b!==a.Search&&d(c,{icon:de,className:s(r.inputFieldIcon,r.inputFieldIconClear,{[r.inputFieldIconClearHidden]:!Y}),onClick:Y?$:void 0,...p(Y?$:void 0),"aria-label":L.clear}),!H&&Z]}),d(`fieldset`,{className:s(r.inputFieldset,N?.fieldset,{[r.inputContainerBorderFocused]:q,[r.inputContainerBorderSearchFocused]:b===a.Search&&(q||!!V),[r.inputContainerBorderInvalid]:G,[r.inputContainerBorderError]:G}),style:P?.fieldset,children:d(`legend`,{className:s(r.inputFieldsetLegend,{[r.inputFieldsetLegendActive]:J}),children:d(`span`,{children:K})})}),O&&m&&f(`div`,{className:s(r.inputMatLabel,{[r.inputMatLabelFloating]:J,[r.inputMatLabelMultiline]:j&&!J}),children:[m,ct]}),O&&D&&d(`div`,{className:s(r.inputPlaceholder,q&&!V&&!Re&&r.inputPlaceholderShown,j&&r.inputPlaceholderMultiline),children:D}),d(te,{variant:`error`,message:C?C.getCurrentErrorMessage():me||``,isVisible:G&&(Ie||Be)})]})})}export{m as default};
2
2
  //# sourceMappingURL=input.mjs.map