@ahrowe/ui 0.51.0 → 0.52.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 (69) hide show
  1. package/CHANGELOG.md +13 -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/themeProvider/theme.types.d.ts +4 -0
  15. package/dist/cjs-types/common/utils/navigation.d.ts +12 -0
  16. package/dist/cjs-types/index.d.ts +2 -0
  17. package/dist/esm/common/ahroweProvider/ahroweProvider.mjs +1 -1
  18. package/dist/esm/common/ahroweProvider/ahroweProvider.mjs.map +1 -1
  19. package/dist/esm/common/breadcrumb/breadcrumb.mjs +1 -1
  20. package/dist/esm/common/breadcrumb/breadcrumb.mjs.map +1 -1
  21. package/dist/esm/common/button/button.mjs +1 -1
  22. package/dist/esm/common/button/button.mjs.map +1 -1
  23. package/dist/esm/common/button/button.module.mjs +1 -1
  24. package/dist/esm/common/button/button.module.mjs.map +1 -1
  25. package/dist/esm/common/button/button.types.mjs.map +1 -1
  26. package/dist/esm/common/commandPalette/commandPalette.mjs +1 -1
  27. package/dist/esm/common/commandPalette/commandPalette.mjs.map +1 -1
  28. package/dist/esm/common/configProvider/configProvider.mjs +1 -1
  29. package/dist/esm/common/configProvider/configProvider.mjs.map +1 -1
  30. package/dist/esm/common/listItem/listItem.mjs +2 -0
  31. package/dist/esm/common/listItem/listItem.mjs.map +1 -0
  32. package/dist/esm/common/listItem/listItem.module.mjs +2 -0
  33. package/dist/esm/common/listItem/listItem.module.mjs.map +1 -0
  34. package/dist/esm/common/menu/menu.mjs +1 -1
  35. package/dist/esm/common/menu/menu.mjs.map +1 -1
  36. package/dist/esm/common/menu/menu.types.mjs.map +1 -1
  37. package/dist/esm/common/menu/menuItem.mjs +1 -1
  38. package/dist/esm/common/menu/menuItem.mjs.map +1 -1
  39. package/dist/esm/common/utils/navigation.mjs +2 -0
  40. package/dist/esm/common/utils/navigation.mjs.map +1 -0
  41. package/dist/esm/index.mjs +1 -1
  42. package/dist/index.cjs +5 -5
  43. package/dist/index.cjs.map +1 -1
  44. package/dist/style.css +1 -1
  45. package/dist/types/common/actionIcon/actionIcon.types.d.ts +10 -6
  46. package/dist/types/common/ahroweProvider/ahroweProvider.d.ts +1 -1
  47. package/dist/types/common/button/button.types.d.ts +25 -8
  48. package/dist/types/common/configProvider/configProvider.d.ts +2 -1
  49. package/dist/types/common/configProvider/configProvider.types.d.ts +8 -0
  50. package/dist/types/common/copyButton/copyButton.types.d.ts +4 -1
  51. package/dist/types/common/listItem/index.d.ts +2 -0
  52. package/dist/types/common/listItem/listItem.d.ts +4 -0
  53. package/dist/types/common/listItem/listItem.types.d.ts +33 -0
  54. package/dist/types/common/menu/menu.types.d.ts +2 -2
  55. package/dist/types/common/menu/menuItem.d.ts +5 -2
  56. package/dist/types/common/themeProvider/theme.types.d.ts +4 -0
  57. package/dist/types/common/utils/navigation.d.ts +12 -0
  58. package/dist/types/index.d.ts +2 -0
  59. package/docs/ActionIcon.md +7 -3
  60. package/docs/AhroweProvider.md +2 -1
  61. package/docs/Breadcrumb.md +4 -24
  62. package/docs/Button.md +44 -9
  63. package/docs/CLAUDE.md +4 -0
  64. package/docs/CommandPalette.md +1 -1
  65. package/docs/ConfigProvider.md +34 -1
  66. package/docs/ListItem.md +97 -0
  67. package/docs/Menu.md +2 -2
  68. package/docs/ScrollbarProvider.md +1 -1
  69. package/package.json +1 -1
@@ -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":"00BAeA,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,WACA,gBACA,SAAS,GACT,YAAY,GACZ,eACA,UACA,aACA,SACA,aACA,OAAQ,EACR,GAAG,GACD,EAAqB,iBAAkB,CAAK,EAC1C,EAAO,EAAU,iBAAkB,GAAQ,CAAc,EACzD,EAAS,EAAM,EACf,EAAU,EAAuB,IAAI,EAErC,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,EAAS,GAAe,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,CAAQ,EAC9B,EAAQ,EACV,CAEA,SAAS,GAAc,EAAwC,CAEzD,MAAM,YAAY,YACtB,IAAI,EAAM,MAAQ,aAAe,EAAM,MAAQ,UAAW,CACxD,IAAM,EAAO,GAAU,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,EAAY,EAAK,QAAU,EAAK,MAC9C,EAAQ,GAEZ,OACE,EAAC,EAAD,CACE,GAAI,EACJ,aAAY,EAAK,MACT,SACC,UACT,WAAA,GACc,eACd,UAAW,EAAG,EAAO,eAAgB,GAAW,GAAY,IAAI,EAChE,MAAO,CAAE,GAAG,GAAO,GAAG,GAAY,IAAK,EARzC,SAAA,CAUE,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,qBAAsB,GAAY,MAAM,EAAG,MAAO,GAAY,OAAxF,SAAA,CACG,EAAW,GAAmB,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,EAAiB,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,GAAe,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,EAAa,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
+ {"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":"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"}
@@ -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"}
@@ -0,0 +1,2 @@
1
+ "use client";import{renderIcon as e}from"../utils/renderIcon.mjs";import{useLinkClick as t}from"../utils/navigation.mjs";import n from"./listItem.module.mjs";import{useId as r}from"react";import i from"classnames";import{faChevronRight as a}from"@fortawesome/free-solid-svg-icons";import{jsx as o,jsxs as s}from"react/jsx-runtime";var c=e=>e!=null&&typeof e!=`boolean`&&e!==``;function l({icon:l,title:u,subtitle:d,endContent:f,href:p,target:m,rel:h,download:g,onClick:_,selected:v=!1,chevron:y=p!==void 0,className:b,style:x,classNames:S,styles:C,...w}){let T=t(),E=r(),D=c(d),O=c(f),k=p!==void 0||_!==void 0,A=[D&&`${E}-subtitle`,typeof f==`string`&&`${E}-end`].filter(Boolean).join(` `),j=o(`span`,{className:i(n.listItemTitle,S?.title),style:C?.title,children:u}),M={className:i(n.listItemTrigger,S?.trigger),style:C?.trigger,"aria-describedby":A||void 0},N=p===void 0?_?o(`button`,{...M,type:`button`,"aria-pressed":v||void 0,onClick:_,children:j}):j:o(`a`,{...M,href:p,target:m,rel:h,download:g,"aria-current":v?`page`:void 0,onClick:e=>{_?.(e),T(e)},children:j});return s(`div`,{...w,className:i(n.listItem,{[n.listItemInteractive]:k,[n.listItemSelected]:v},b,S?.root),style:{...x,...C?.root},children:[l!=null&&e(l,{className:i(n.listItemIcon,S?.icon),style:C?.icon}),s(`div`,{className:i(n.listItemLabels,S?.labels),style:C?.labels,children:[N,D&&o(`div`,{id:`${E}-subtitle`,className:i(n.listItemSubtitle,S?.subtitle),style:C?.subtitle,children:d})]}),O&&o(`div`,{id:`${E}-end`,className:i(n.listItemEndContent,S?.endContent),style:C?.endContent,children:f}),y&&e(a,{className:i(n.listItemChevron,S?.chevron),style:C?.chevron})]})}export{l as default};
2
+ //# sourceMappingURL=listItem.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listItem.mjs","names":[],"sources":["../../../../package/common/listItem/listItem.tsx"],"sourcesContent":["import { useId, type ReactElement, type ReactNode } from 'react';\nimport cx from 'classnames';\nimport { faChevronRight } from '@fortawesome/free-solid-svg-icons';\n\nimport type { ListItemProps } from './listItem.types';\nimport styles from './listItem.module.pcss';\nimport { renderIcon } from '../utils/renderIcon';\nimport { useLinkClick } from '../utils/navigation';\n\n// `subtitle={isOverdue && 'Overdue'}` passes false, which renders nothing and needs no box.\nconst isShown = (node: ReactNode) => node != null && typeof node !== 'boolean' && node !== '';\n\nfunction ListItem({\n icon,\n title,\n subtitle,\n endContent,\n href,\n target,\n rel,\n download,\n onClick,\n selected = false,\n chevron = href !== undefined,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: ListItemProps): ReactElement {\n const followLink = useLinkClick();\n const id = useId();\n const hasSubtitle = isShown(subtitle);\n const hasEndContent = isShown(endContent);\n const isInteractive = href !== undefined || onClick !== undefined;\n // A status in endContent (\"Open\") is part of what the row says, so the link is described by it\n // too, where it is text: a control there would only read its own name a second time.\n const describedBy = [hasSubtitle && `${id}-subtitle`, typeof endContent === 'string' && `${id}-end`]\n .filter(Boolean)\n .join(' ');\n\n const titleElement = (\n <span className={cx(styles.listItemTitle, classNames?.title)} style={slotStyles?.title}>\n {title}\n </span>\n );\n // Only the title is the link or button: the rest of the row can then hold controls of its own,\n // which an <a> or <button> may not contain. Its ::after stretches over the whole row instead.\n const triggerProps = {\n className: cx(styles.listItemTrigger, classNames?.trigger),\n style: slotStyles?.trigger,\n 'aria-describedby': describedBy || undefined,\n };\n const trigger =\n href !== undefined ? (\n <a\n {...triggerProps}\n href={href}\n target={target}\n rel={rel}\n download={download}\n aria-current={selected ? 'page' : undefined}\n onClick={(event) => {\n onClick?.(event);\n followLink(event);\n }}\n >\n {titleElement}\n </a>\n ) : onClick ? (\n <button {...triggerProps} type='button' aria-pressed={selected || undefined} onClick={onClick}>\n {titleElement}\n </button>\n ) : (\n titleElement\n );\n\n return (\n <div\n {...rest}\n className={cx(\n styles.listItem,\n { [styles.listItemInteractive]: isInteractive, [styles.listItemSelected]: selected },\n className,\n classNames?.root,\n )}\n style={{ ...style, ...slotStyles?.root }}\n >\n {icon != null &&\n renderIcon(icon, { className: cx(styles.listItemIcon, classNames?.icon), style: slotStyles?.icon })}\n <div className={cx(styles.listItemLabels, classNames?.labels)} style={slotStyles?.labels}>\n {trigger}\n {hasSubtitle && (\n <div\n id={`${id}-subtitle`}\n className={cx(styles.listItemSubtitle, classNames?.subtitle)}\n style={slotStyles?.subtitle}\n >\n {subtitle}\n </div>\n )}\n </div>\n {hasEndContent && (\n <div\n id={`${id}-end`}\n className={cx(styles.listItemEndContent, classNames?.endContent)}\n style={slotStyles?.endContent}\n >\n {endContent}\n </div>\n )}\n {chevron &&\n renderIcon(faChevronRight, {\n className: cx(styles.listItemChevron, classNames?.chevron),\n style: slotStyles?.chevron,\n })}\n </div>\n );\n}\n\nexport default ListItem;\n"],"mappings":"2UAUA,IAAM,EAAW,GAAoB,GAAQ,MAAQ,OAAO,GAAS,WAAa,IAAS,GAE3F,SAAS,EAAS,CAChB,OACA,QACA,WACA,aACA,OACA,SACA,MACA,WACA,UACA,WAAW,GACX,UAAU,IAAS,IAAA,GACnB,YACA,QACA,aACA,OAAQ,EACR,GAAG,GAC2B,CAC9B,IAAM,EAAa,EAAa,EAC1B,EAAK,EAAM,EACX,EAAc,EAAQ,CAAQ,EAC9B,EAAgB,EAAQ,CAAU,EAClC,EAAgB,IAAS,IAAA,IAAa,IAAY,IAAA,GAGlD,EAAc,CAAC,GAAe,GAAG,EAAG,WAAY,OAAO,GAAe,UAAY,GAAG,EAAG,KAAK,CAAC,CACjG,OAAO,OAAO,CAAC,CACf,KAAK,GAAG,EAEL,EACJ,EAAC,OAAD,CAAM,UAAW,EAAG,EAAO,cAAe,GAAY,KAAK,EAAG,MAAO,GAAY,MAC9E,SAAA,CACG,CAAA,EAIF,EAAe,CACnB,UAAW,EAAG,EAAO,gBAAiB,GAAY,OAAO,EACzD,MAAO,GAAY,QACnB,mBAAoB,GAAe,IAAA,EACrC,EACM,EACJ,IAAS,IAAA,GAeL,EACF,EAAC,SAAD,CAAQ,GAAI,EAAc,KAAK,SAAS,eAAc,GAAY,IAAA,GAAoB,UACnF,SAAA,CACK,CAAA,EAER,EAnBA,EAAC,IAAD,CACE,GAAI,EACE,OACE,SACH,MACK,WACV,eAAc,EAAW,OAAS,IAAA,GAClC,QAAU,GAAU,CAClB,IAAU,CAAK,EACf,EAAW,CAAK,CAClB,EAEC,SAAA,CACA,CAAA,EASP,OACE,EAAC,MAAD,CACE,GAAI,EACJ,UAAW,EACT,EAAO,SACP,EAAG,EAAO,qBAAsB,GAAgB,EAAO,kBAAmB,CAAS,EACnF,EACA,GAAY,IACd,EACA,MAAO,CAAE,GAAG,EAAO,GAAG,GAAY,IAAK,EARzC,SAAA,CAUG,GAAQ,MACP,EAAW,EAAM,CAAE,UAAW,EAAG,EAAO,aAAc,GAAY,IAAI,EAAG,MAAO,GAAY,IAAK,CAAC,EACpG,EAAC,MAAD,CAAK,UAAW,EAAG,EAAO,eAAgB,GAAY,MAAM,EAAG,MAAO,GAAY,OAAlF,SAAA,CACG,EACA,GACC,EAAC,MAAD,CACE,GAAI,GAAG,EAAG,WACV,UAAW,EAAG,EAAO,iBAAkB,GAAY,QAAQ,EAC3D,MAAO,GAAY,SAElB,SAAA,CACE,CAAA,CAEJ,IACJ,GACC,EAAC,MAAD,CACE,GAAI,GAAG,EAAG,MACV,UAAW,EAAG,EAAO,mBAAoB,GAAY,UAAU,EAC/D,MAAO,GAAY,WAElB,SAAA,CACE,CAAA,EAEN,GACC,EAAW,EAAgB,CACzB,UAAW,EAAG,EAAO,gBAAiB,GAAY,OAAO,EACzD,MAAO,GAAY,OACrB,CAAC,CACA,GAET"}
@@ -0,0 +1,2 @@
1
+ "use client";var e=`listItem_i7EoH`,t=`listItem-icon_HEdQy`,n=`listItem-labels_dZXiH`,r=`listItem-title_zmlAW`,i=`listItem-trigger_07n1-`,a=`listItem-selected_zY4Ni`,o=`listItem-subtitle_-XwvP`,s=`listItem-endContent_cQoge`,c=`listItem-chevron_19GEH`,l=`listItem-interactive_GFbY-`,u={listItem:e,"listItem-icon":`listItem-icon_HEdQy`,listItemIcon:t,"listItem-labels":`listItem-labels_dZXiH`,listItemLabels:n,"listItem-title":`listItem-title_zmlAW`,listItemTitle:r,"listItem-trigger":`listItem-trigger_07n1-`,listItemTrigger:i,"listItem-selected":`listItem-selected_zY4Ni`,listItemSelected:a,"listItem-subtitle":`listItem-subtitle_-XwvP`,listItemSubtitle:o,"listItem-endContent":`listItem-endContent_cQoge`,listItemEndContent:s,"listItem-chevron":`listItem-chevron_19GEH`,listItemChevron:c,"listItem-interactive":`listItem-interactive_GFbY-`,listItemInteractive:l};export{u as default,e as listItem,c as listItemChevron,s as listItemEndContent,t as listItemIcon,l as listItemInteractive,n as listItemLabels,a as listItemSelected,o as listItemSubtitle,r as listItemTitle,i as listItemTrigger};
2
+ //# sourceMappingURL=listItem.module.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"listItem.module.mjs","names":[],"sources":["../../../../package/common/listItem/listItem.module.pcss"],"sourcesContent":["/* position: relative so the trigger's ::after can stretch over the whole row, and isolation so\n its z-index stays inside the row instead of rising over a sticky header of the page. */\n.listItem {\n position: relative;\n isolation: isolate;\n display: flex;\n align-items: center;\n gap: var(--spacing-m, 8px);\n box-sizing: border-box;\n width: 100%;\n min-height: var(--list-item-min-height, 48px);\n padding: var(--spacing-m, 8px);\n\n &-icon {\n /* FontAwesome's own rule is unlayered and outranks `width` from inside the library's layer. */\n --fa-width: 1.25em;\n\n flex-shrink: 0;\n }\n\n /* min-width: 0 lets the labels shrink, so a long title ellipses instead of pushing\n endContent and the chevron out of the row. */\n &-labels {\n display: flex;\n flex: 1 1 auto;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n }\n\n &-title {\n display: block;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n }\n\n /* The <a> or <button> around the title. */\n &-trigger {\n display: block;\n margin: 0;\n padding: 0;\n border: none;\n background: none;\n color: inherit;\n font: inherit;\n text-align: start;\n text-decoration: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n /* Over the whole row. It belongs to the link, so a middle click and a long press anywhere on\n the row act on the link too. */\n\n /* z-index above content that positions itself, a Chip among many, which would otherwise\n paint over it in tree order and swallow the click. */\n &::after {\n content: '';\n position: absolute;\n inset: 0;\n z-index: 1;\n transition: background-color 0.15s;\n }\n\n /* A tint of the text colour, so it shows on any surface the row sits on. (hover: hover)\n because on touch a tap latches :hover until the next tap elsewhere. */\n @media (hover: hover) {\n &:hover::after {\n background-color: color-mix(in srgb, currentcolor 6%, transparent);\n }\n }\n\n &:active::after {\n background-color: color-mix(in srgb, currentcolor 12%, transparent);\n }\n\n /* On the stretched area, to ring the row rather than the title. Inside the edge: a row\n usually fills a card that clips its overflow. */\n &:focus-visible {\n outline: none;\n }\n\n &:focus-visible::after {\n outline: 2px solid var(--focus-border-color, var(--primary-color));\n outline-offset: -2px;\n }\n }\n\n /* Under the trigger's hover tint, which still shows on top of it. */\n &-selected {\n background-color: var(--list-item-selected-background, color-mix(in srgb, var(--primary-color) 12%, transparent));\n }\n\n &-subtitle {\n display: -webkit-box;\n overflow: hidden;\n color: var(--text-dark);\n font-size: 0.85em;\n -webkit-box-orient: vertical;\n -webkit-line-clamp: 2;\n line-clamp: 2;\n }\n\n &-endContent {\n display: flex;\n flex-shrink: 0;\n align-items: center;\n gap: var(--spacing-s, 4px);\n }\n\n &-chevron {\n flex-shrink: 0;\n color: var(--text-dark);\n font-size: 0.85em;\n }\n}\n\n/* Controls elsewhere in the row sit above the stretched area, so they stay clickable while the\n text around them still opens the row. Any `a`, not `a[href]`: a disabled link Button drops its\n href, and a click on it must not open the row. All in :where(), for no specificity at all: a\n control's own position wins, so an input it positions absolutely stays absolute. */\n:where(.listItem-interactive)\n :where(a, button, input, select, textarea, label, [tabindex]):where(:not(.listItem-trigger)) {\n position: relative;\n z-index: 2;\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- "use client";import{isSelfActivation as e}from"../utils/activationKey.mjs";import{ariaKeyshortcuts as t,formatHotkey as n}from"../hooks/useHotkeys.mjs";import{PopoverAlign as r,PopoverPlacement as i}from"../popover/popover.types.mjs";import{useFocusBoundary as a}from"../hooks/useFocusBoundary.mjs";import o from"../popover/popover.mjs";import{isMenuAction as s,isMenuHeading as c,isMenuSeparator as l}from"./menu.types.mjs";import{hasAnyIcon as u,renderItemIcon as d}from"./menuItem.mjs";import f from"./menu.module.mjs";import{cloneElement as ee,isValidElement as p,useEffect as m,useId as h,useRef as g,useState as _}from"react";import v from"classnames";import{Fragment as te,jsx as y,jsxs as b}from"react/jsx-runtime";var x=600;function S(e,t,n){for(let r=1;r<=e.length;r++){let i=(t+n*r+e.length*r)%e.length,a=e[i];if(s(a)&&!a.disabled)return i}return-1}function C(e){return e.findIndex(e=>s(e)&&!e.disabled)}function w(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(s(n)&&!n.disabled)return t}return-1}function T({items:T,children:E,onAction:D,isOpen:O,onOpenChange:k,placement:A=i.Bottom,align:ne=r.Start,presentation:re,className:ie,style:ae,classNames:j,styles:M,...N}){let P=O!==void 0,[F,I]=_(!1),L=P?O:F,[R,z]=_(-1),B=g([]),V=g(null),H=g(null),{restoreFocusToTrigger:U,focusAfterTrigger:W}=a({triggerRef:V,contentRef:H}),G=h(),K=g(`first`),q=g({query:``,timer:void 0}),J=g(!1);function Y(e,t=!1){e&&(J.current=t),P||I(e),k?.(e)}let X=g(T);m(()=>{X.current=T}),m(()=>{if(!L)return;if(!J.current){z(-1);return}let e=X.current,t=K.current===`last`?w(e):C(e);z(t);let n=requestAnimationFrame(()=>{B.current[t]?.focus()});return()=>{cancelAnimationFrame(n),K.current=`first`}},[L]),m(()=>()=>clearTimeout(q.current.timer),[]);function Z(e){e<0||(z(e),B.current[e]?.focus())}function Q(e){Y(!1),e&&U()}function oe(e){if(e.length!==1||!e.trim())return!1;clearTimeout(q.current.timer),q.current.query+=e.toLowerCase(),q.current.timer=setTimeout(()=>{q.current.query=``},x);let t=q.current.query,n=t.length>1&&[...t].every(e=>e===t[0]),r=n?t[0]:t,i=n||t.length===1?R:R-1;for(let e=1;e<=T.length;e++){let t=(i+e+T.length)%T.length,n=T[t];if(s(n)&&!n.disabled&&(B.current[t]?.textContent?.trim().toLowerCase()??``).startsWith(r))return Z(t),!0}return!1}function se(e){if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),e.stopPropagation(),L){Z(e.key===`ArrowUp`?w(T):C(T));return}K.current=e.key===`ArrowUp`?`last`:`first`,Y(!0,!0)}}function ce(e){switch(e.key){case`ArrowDown`:Z(S(T,R,1));break;case`ArrowUp`:Z(R<0?w(T):S(T,R,-1));break;case`Home`:Z(C(T));break;case`End`:Z(w(T));break;case`Escape`:Q(!0);break;case`Tab`:Q(!1),e.shiftKey?U():W();break;default:if(!oe(e.key))return}e.preventDefault(),e.stopPropagation()}function le(e){let t=T[e];s(t)&&!t.disabled&&(t.onClick?.(),D?.(t.id),Q(!0))}let $=p(E)?ee(E,{"aria-haspopup":E.props[`aria-haspopup`]??`menu`,"aria-expanded":E.props[`aria-expanded`]??L,"aria-controls":L?E.props[`aria-controls`]??G:E.props[`aria-controls`]}):E,ue=u(T),de=y(`div`,{ref:H,id:G,role:`menu`,className:v(f.menu,j?.menu),style:M?.menu,onKeyDown:ce,children:T.map((r,i)=>{if(l(r))return y(`div`,{role:`separator`,className:v(f.menuSeparator,j?.separator),style:M?.separator},`separator-${i}`);if(c(r))return y(`div`,{role:`presentation`,className:v(f.menuHeading,j?.heading),style:M?.heading,children:r.heading},`heading-${i}`);let a={ref:e=>{B.current[i]=e},role:`menuitem`,"aria-keyshortcuts":t(r.shortcut),tabIndex:i===R?0:-1,className:v(f.menuItem,r.danger&&f.menuItemDanger,j?.item),style:M?.item,onClick:()=>le(i),onMouseEnter:()=>z(i)},o=b(te,{children:[d(r.icon,ue,{className:v(f.menuItemIcon,j?.itemIcon),style:M?.itemIcon}),y(`span`,{className:v(f.menuItemLabel,j?.itemLabel),style:M?.itemLabel,children:r.label}),r.shortcut!=null&&y(`span`,{"aria-hidden":!0,className:v(f.menuItemShortcut,j?.itemShortcut),style:M?.itemShortcut,children:n(r.shortcut)})]});return r.href&&!r.disabled?y(`a`,{href:r.href,...a,onKeyDown:t=>{t.key===` `&&e(t)&&(t.preventDefault(),t.currentTarget.click())},children:o},r.id):y(`button`,{type:`button`,disabled:r.disabled,...a,children:o},r.id)})});return y(o,{...N,isOpen:L,onOpenChange:(e,{fromKeyboard:t})=>Y(e,t),placement:A,align:ne,presentation:re,content:de,focusOnOpen:!1,constrainWidth:!1,classNames:{panel:f.menuPanel},className:v(ie,j?.root),style:{...ae,...M?.root},children:y(`span`,{ref:V,className:v(f.menuTrigger,j?.trigger),style:M?.trigger,onKeyDown:se,children:$})})}export{T as default};
1
+ "use client";import{isSelfActivation as e}from"../utils/activationKey.mjs";import{ariaKeyshortcuts as t,formatHotkey as n}from"../hooks/useHotkeys.mjs";import{useLinkClick as r}from"../utils/navigation.mjs";import{PopoverAlign as i,PopoverPlacement as a}from"../popover/popover.types.mjs";import{useFocusBoundary as o}from"../hooks/useFocusBoundary.mjs";import ee from"../popover/popover.mjs";import{isMenuAction as s,isMenuHeading as c,isMenuSeparator as te}from"./menu.types.mjs";import{hasAnyIcon as l,renderItemIcon as u}from"./menuItem.mjs";import d from"./menu.module.mjs";import{cloneElement as ne,isValidElement as re,useEffect as f,useId as ie,useRef as p,useState as m}from"react";import h from"classnames";import{Fragment as g,jsx as _,jsxs as ae}from"react/jsx-runtime";var oe=600;function v(e,t,n){for(let r=1;r<=e.length;r++){let i=(t+n*r+e.length*r)%e.length,a=e[i];if(s(a)&&!a.disabled)return i}return-1}function y(e){return e.findIndex(e=>s(e)&&!e.disabled)}function b(e){for(let t=e.length-1;t>=0;t--){let n=e[t];if(s(n)&&!n.disabled)return t}return-1}function x({items:x,children:S,onAction:C,isOpen:w,onOpenChange:T,placement:E=a.Bottom,align:D=i.Start,presentation:O,className:k,style:A,classNames:j,styles:M,...se}){let N=w!==void 0,[P,F]=m(!1),I=N?w:P,[L,R]=m(-1),z=p([]),B=p(null),V=p(null),{restoreFocusToTrigger:H,focusAfterTrigger:U}=o({triggerRef:B,contentRef:V}),W=ie(),G=r(),K=p(`first`),q=p({query:``,timer:void 0}),J=p(!1);function Y(e,t=!1){e&&(J.current=t),N||F(e),T?.(e)}let X=p(x);f(()=>{X.current=x}),f(()=>{if(!I)return;if(!J.current){R(-1);return}let e=X.current,t=K.current===`last`?b(e):y(e);R(t);let n=requestAnimationFrame(()=>{z.current[t]?.focus()});return()=>{cancelAnimationFrame(n),K.current=`first`}},[I]),f(()=>()=>clearTimeout(q.current.timer),[]);function Z(e){e<0||(R(e),z.current[e]?.focus())}function Q(e){Y(!1),e&&H()}function ce(e){if(e.length!==1||!e.trim())return!1;clearTimeout(q.current.timer),q.current.query+=e.toLowerCase(),q.current.timer=setTimeout(()=>{q.current.query=``},oe);let t=q.current.query,n=t.length>1&&[...t].every(e=>e===t[0]),r=n?t[0]:t,i=n||t.length===1?L:L-1;for(let e=1;e<=x.length;e++){let t=(i+e+x.length)%x.length,n=x[t];if(s(n)&&!n.disabled&&(z.current[t]?.textContent?.trim().toLowerCase()??``).startsWith(r))return Z(t),!0}return!1}function le(e){if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),e.stopPropagation(),I){Z(e.key===`ArrowUp`?b(x):y(x));return}K.current=e.key===`ArrowUp`?`last`:`first`,Y(!0,!0)}}function ue(e){switch(e.key){case`ArrowDown`:Z(v(x,L,1));break;case`ArrowUp`:Z(L<0?b(x):v(x,L,-1));break;case`Home`:Z(y(x));break;case`End`:Z(b(x));break;case`Escape`:Q(!0);break;case`Tab`:Q(!1),e.shiftKey?H():U();break;default:if(!ce(e.key))return}e.preventDefault(),e.stopPropagation()}function $(e){let t=x[e];s(t)&&!t.disabled&&(t.onClick?.(),C?.(t.id),Q(!0))}let de=re(S)?ne(S,{"aria-haspopup":S.props[`aria-haspopup`]??`menu`,"aria-expanded":S.props[`aria-expanded`]??I,"aria-controls":I?S.props[`aria-controls`]??W:S.props[`aria-controls`]}):S,fe=l(x),pe=_(`div`,{ref:V,id:W,role:`menu`,className:h(d.menu,j?.menu),style:M?.menu,onKeyDown:ue,children:x.map((r,i)=>{if(te(r))return _(`div`,{role:`separator`,className:h(d.menuSeparator,j?.separator),style:M?.separator},`separator-${i}`);if(c(r))return _(`div`,{role:`presentation`,className:h(d.menuHeading,j?.heading),style:M?.heading,children:r.heading},`heading-${i}`);let a={ref:e=>{z.current[i]=e},role:`menuitem`,"aria-keyshortcuts":t(r.shortcut),tabIndex:i===L?0:-1,className:h(d.menuItem,r.danger&&d.menuItemDanger,j?.item),style:M?.item,onClick:()=>$(i),onMouseEnter:()=>R(i)},o=ae(g,{children:[u(r.icon,fe,{className:h(d.menuItemIcon,j?.itemIcon),style:M?.itemIcon}),_(`span`,{className:h(d.menuItemLabel,j?.itemLabel),style:M?.itemLabel,children:r.label}),r.shortcut!=null&&_(`span`,{"aria-hidden":!0,className:h(d.menuItemShortcut,j?.itemShortcut),style:M?.itemShortcut,children:n(r.shortcut)})]});return r.href&&!r.disabled?_(`a`,{href:r.href,...a,onClick:e=>{$(i),G(e)},onKeyDown:t=>{t.key===` `&&e(t)&&(t.preventDefault(),t.currentTarget.click())},children:o},r.id):_(`button`,{type:`button`,disabled:r.disabled,...a,children:o},r.id)})});return _(ee,{...se,isOpen:I,onOpenChange:(e,{fromKeyboard:t})=>Y(e,t),placement:E,align:D,presentation:O,content:pe,focusOnOpen:!1,constrainWidth:!1,classNames:{panel:d.menuPanel},className:h(k,j?.root),style:{...A,...M?.root},children:_(`span`,{ref:B,className:h(d.menuTrigger,j?.trigger),style:M?.trigger,onKeyDown:le,children:de})})}export{x as default};
2
2
  //# sourceMappingURL=menu.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"menu.mjs","names":[],"sources":["../../../../package/common/menu/menu.tsx"],"sourcesContent":["import { cloneElement, isValidElement, useEffect, useId, useRef, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\n\nimport styles from './menu.module.pcss';\nimport Popover from '../popover';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { isSelfActivation } from '../utils/activationKey';\nimport { useFocusBoundary } from '../hooks/useFocusBoundary';\nimport { ariaKeyshortcuts, formatHotkey } from '../hooks/useHotkeys';\nimport { isMenuAction, isMenuHeading, isMenuSeparator, type MenuEntry, type MenuProps } from './menu.types';\nimport { hasAnyIcon, renderItemIcon } from './menuItem';\n\n/** How long a typed run stays one search before it starts over. */\nconst TYPEAHEAD_RESET_MS = 600;\n\n/** Index of the next action that can be focused, wrapping, or -1 if there is none. */\nfunction nextEnabled(items: MenuEntry[], from: number, step: 1 | -1): number {\n for (let i = 1; i <= items.length; i++) {\n // The `items.length * i` term only keeps the value positive for a backwards\n // step; JavaScript's `%` would otherwise return a negative index.\n const index = (from + step * i + items.length * i) % items.length;\n const entry = items[index];\n if (isMenuAction(entry) && !entry.disabled) return index;\n }\n return -1;\n}\n\nfunction firstEnabled(items: MenuEntry[]): number {\n return items.findIndex((entry) => isMenuAction(entry) && !entry.disabled);\n}\n\nfunction lastEnabled(items: MenuEntry[]): number {\n for (let i = items.length - 1; i >= 0; i--) {\n const entry = items[i];\n if (isMenuAction(entry) && !entry.disabled) return i;\n }\n return -1;\n}\n\n/**\n * A menu of actions on a trigger of your choosing.\n *\n * `Popover` does the anchoring, portalling and outside-click work but takes\n * arbitrary `content`, which leaves every consumer to write their own `ul`/`li`\n * and, in practice, to leave out the roles and the arrow keys. This is that list,\n * done once: `role=\"menu\"`, a roving focus that skips disabled entries, Escape\n * back to the trigger, and separators and headings that stay out of the keyboard\n * order.\n */\nfunction Menu({\n items,\n children,\n onAction,\n isOpen: controlledOpen,\n onOpenChange,\n placement = PopoverPlacement.Bottom,\n align = PopoverAlign.Start,\n presentation,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: MenuProps): ReactElement {\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const isOpen = isControlled ? controlledOpen : internalOpen;\n\n const [activeIndex, setActiveIndex] = useState(-1);\n const itemRefs = useRef<(HTMLElement | null)[]>([]);\n const triggerRef = useRef<HTMLSpanElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n // Tab leaves the panel in both directions, so the menu needs the same boundary\n // Popover uses: back to the trigger, or on to whatever follows it.\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({ triggerRef, contentRef: menuRef });\n const menuId = useId();\n // Which end to land on when the menu opens: `ArrowUp` on the trigger opens at\n // the bottom, everything else at the top.\n const openAtRef = useRef<'first' | 'last'>('first');\n const typeahead = useRef<{ query: string; timer: ReturnType<typeof setTimeout> | undefined }>({\n query: '',\n timer: undefined,\n });\n\n // Whether a key opened the menu, which decides between landing the focus on an\n // entry and leaving it on the trigger. Set from Popover, which is what sees the\n // trigger's events, or here when an arrow key did the opening.\n const openedByKeyboardRef = useRef(false);\n\n function setOpen(next: boolean, fromKeyboard = false) {\n if (next) openedByKeyboardRef.current = fromKeyboard;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }\n\n // The effect below needs the entries, but must not re-run when the array is rebuilt. A consumer\n // writes `items={[…]}` inline, so it is a new identity on every render of *their* component:\n // keyed off it, any parent re-render while the menu was open threw the focus back to the first\n // entry, mid-navigation. Declared above the effect that reads it, so it has already run.\n const itemsRef = useRef(items);\n useEffect(() => {\n itemsRef.current = items;\n });\n\n // Focus follows the active entry rather than the menu keeping focus and\n // pointing at it: the items are real buttons, so Enter and Space are theirs.\n // Popover's own `focusOnOpen` would take the first focusable and stop there;\n // the active index has to move with it, so the menu does it itself.\n useEffect(() => {\n if (!isOpen) return;\n // A pointer open leaves the focus where the pointer put it. A highlight on an\n // entry nobody pointed at reads as a selection, and the mouse is about to land\n // somewhere else anyway; the first arrow key moves in, see the trigger's keys.\n if (!openedByKeyboardRef.current) {\n setActiveIndex(-1);\n return;\n }\n const entries = itemsRef.current;\n const target = openAtRef.current === 'last' ? lastEnabled(entries) : firstEnabled(entries);\n setActiveIndex(target);\n // The panel is portalled and animated in, so its buttons exist a frame later.\n const frame = requestAnimationFrame(() => {\n itemRefs.current[target]?.focus();\n });\n return () => {\n cancelAnimationFrame(frame);\n openAtRef.current = 'first';\n };\n }, [isOpen]);\n\n useEffect(() => () => clearTimeout(typeahead.current.timer), []);\n\n function moveTo(index: number) {\n if (index < 0) return;\n setActiveIndex(index);\n itemRefs.current[index]?.focus();\n }\n\n function close(returnFocus: boolean) {\n setOpen(false);\n if (returnFocus) restoreFocusToTrigger();\n }\n\n /**\n * Jumps to the next entry whose label starts with what has been typed. The\n * text comes off the rendered button rather than the `label` prop, which is a\n * `ReactNode` and may be an icon, a badge or anything else.\n */\n function handleTypeahead(key: string): boolean {\n if (key.length !== 1 || !key.trim()) return false;\n clearTimeout(typeahead.current.timer);\n typeahead.current.query += key.toLowerCase();\n typeahead.current.timer = setTimeout(() => {\n typeahead.current.query = '';\n }, TYPEAHEAD_RESET_MS);\n\n const query = typeahead.current.query;\n // A repeated single character walks through the entries starting with it,\n // rather than sticking to the first one.\n const repeated = query.length > 1 && [...query].every((c) => c === query[0]);\n const needle = repeated ? query[0] : query;\n const from = repeated || query.length === 1 ? activeIndex : activeIndex - 1;\n\n for (let i = 1; i <= items.length; i++) {\n const index = (from + i + items.length) % items.length;\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) continue;\n const text = itemRefs.current[index]?.textContent?.trim().toLowerCase() ?? '';\n if (text.startsWith(needle)) {\n moveTo(index);\n return true;\n }\n }\n return false;\n }\n\n /** The trigger's own keys, which decide where the menu opens. */\n function handleTriggerKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n // Popover opens on these keys too; letting both act would be harmless but\n // this keeps the decision about where to land in one place.\n event.preventDefault();\n event.stopPropagation();\n // Already open means a pointer opened it and the focus never left the trigger,\n // since an entry's own keys never reach here. This is the key that moves in.\n if (isOpen) {\n moveTo(event.key === 'ArrowUp' ? lastEnabled(items) : firstEnabled(items));\n return;\n }\n openAtRef.current = event.key === 'ArrowUp' ? 'last' : 'first';\n setOpen(true, true);\n }\n\n function handleKeyDown(event: React.KeyboardEvent) {\n switch (event.key) {\n case 'ArrowDown':\n moveTo(nextEnabled(items, activeIndex, 1));\n break;\n case 'ArrowUp':\n // Stepping back from \"nothing active\" lands two short of the end, so the end is named.\n moveTo(activeIndex < 0 ? lastEnabled(items) : nextEnabled(items, activeIndex, -1));\n break;\n case 'Home':\n moveTo(firstEnabled(items));\n break;\n case 'End':\n moveTo(lastEnabled(items));\n break;\n // Popover handles both of these too, but only once the focus has actually\n // reached the panel: its Escape restores focus on that condition, and its\n // Tab handling acts at the first and last focusable. A menu focuses its\n // first entry a frame after opening, so a key pressed in between would\n // fall through. Here they are unconditional, which is also what a menu\n // wants from Tab: leave, whatever is focused.\n case 'Escape':\n close(true);\n break;\n case 'Tab':\n // Carry on from the trigger, as if the panel had never been in the tab\n // order. Closing and letting the browser take it from here would move on\n // from an entry that is about to be removed, which lands at the top of\n // the document.\n close(false);\n if (event.shiftKey) restoreFocusToTrigger();\n else focusAfterTrigger();\n break;\n default:\n if (!handleTypeahead(event.key)) return;\n }\n event.preventDefault();\n event.stopPropagation();\n }\n\n function handleAction(index: number) {\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) return;\n // Not runMenuAction: a link entry is an <a>, which the browser follows by itself.\n entry.onClick?.();\n onAction?.(entry.id);\n close(true);\n }\n\n // A screen reader has no way to tell that this button opens a menu unless the\n // button itself says so. Only filled in where the consumer has not, so a\n // trigger that describes itself keeps doing that.\n const triggerWithMenuSemantics = isValidElement<Record<string, unknown>>(children)\n ? cloneElement(children, {\n 'aria-haspopup': children.props['aria-haspopup'] ?? 'menu',\n 'aria-expanded': children.props['aria-expanded'] ?? isOpen,\n 'aria-controls': isOpen ? (children.props['aria-controls'] ?? menuId) : children.props['aria-controls'],\n })\n : children;\n\n const hasIcons = hasAnyIcon(items);\n\n const content = (\n <div\n ref={menuRef}\n id={menuId}\n role='menu'\n className={cx(styles.menu, classNames?.menu)}\n style={slotStyles?.menu}\n onKeyDown={handleKeyDown}\n >\n {items.map((entry, index) => {\n if (isMenuSeparator(entry))\n return (\n <div\n // Separators and headings carry no id of their own, and reordering\n // the list re-renders it wholesale anyway.\n key={`separator-${index}`}\n role='separator'\n className={cx(styles.menuSeparator, classNames?.separator)}\n style={slotStyles?.separator}\n />\n );\n\n if (isMenuHeading(entry))\n return (\n <div\n key={`heading-${index}`}\n role='presentation'\n className={cx(styles.menuHeading, classNames?.heading)}\n style={slotStyles?.heading}\n >\n {entry.heading}\n </div>\n );\n\n const itemProps = {\n ref: (el: HTMLElement | null) => {\n itemRefs.current[index] = el;\n },\n role: 'menuitem',\n 'aria-keyshortcuts': ariaKeyshortcuts(entry.shortcut),\n // One tab stop for the whole menu: the arrow keys move between items.\n tabIndex: index === activeIndex ? 0 : -1,\n className: cx(styles.menuItem, entry.danger && styles.menuItemDanger, classNames?.item),\n style: slotStyles?.item,\n onClick: () => handleAction(index),\n onMouseEnter: () => setActiveIndex(index),\n };\n const itemContent = (\n <>\n {renderItemIcon(entry.icon, hasIcons, {\n className: cx(styles.menuItemIcon, classNames?.itemIcon),\n style: slotStyles?.itemIcon,\n })}\n <span className={cx(styles.menuItemLabel, classNames?.itemLabel)} style={slotStyles?.itemLabel}>\n {entry.label}\n </span>\n {entry.shortcut != null && (\n <span\n aria-hidden\n className={cx(styles.menuItemShortcut, classNames?.itemShortcut)}\n style={slotStyles?.itemShortcut}\n >\n {formatHotkey(entry.shortcut)}\n </span>\n )}\n </>\n );\n\n // An <a> cannot be disabled, so a disabled link is a disabled button.\n return entry.href && !entry.disabled ? (\n <a\n key={entry.id}\n href={entry.href}\n {...itemProps}\n // A link takes Enter but not Space, which every other entry answers to.\n onKeyDown={(event) => {\n if (event.key !== ' ' || !isSelfActivation(event)) return;\n event.preventDefault();\n event.currentTarget.click();\n }}\n >\n {itemContent}\n </a>\n ) : (\n <button key={entry.id} type='button' disabled={entry.disabled} {...itemProps}>\n {itemContent}\n </button>\n );\n })}\n </div>\n );\n\n return (\n <Popover\n {...rest}\n isOpen={isOpen}\n onOpenChange={(next, { fromKeyboard }) => setOpen(next, fromKeyboard)}\n placement={placement}\n align={align}\n presentation={presentation}\n content={content}\n // The list pads its own rows, so a hover highlight reaches the panel edge,\n // and it sizes itself. Focus is the menu's own business, see above.\n focusOnOpen={false}\n constrainWidth={false}\n classNames={{ panel: styles.menuPanel }}\n className={cx(className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <span\n ref={triggerRef}\n className={cx(styles.menuTrigger, classNames?.trigger)}\n style={slotStyles?.trigger}\n onKeyDown={handleTriggerKeyDown}\n >\n {triggerWithMenuSemantics}\n </span>\n </Popover>\n );\n}\n\nexport default Menu;\n"],"mappings":"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"}
1
+ {"version":3,"file":"menu.mjs","names":[],"sources":["../../../../package/common/menu/menu.tsx"],"sourcesContent":["import { cloneElement, isValidElement, useEffect, useId, useRef, useState, type ReactElement } from 'react';\nimport cx from 'classnames';\n\nimport styles from './menu.module.pcss';\nimport Popover from '../popover';\nimport { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport { isSelfActivation } from '../utils/activationKey';\nimport { useLinkClick } from '../utils/navigation';\nimport { useFocusBoundary } from '../hooks/useFocusBoundary';\nimport { ariaKeyshortcuts, formatHotkey } from '../hooks/useHotkeys';\nimport { isMenuAction, isMenuHeading, isMenuSeparator, type MenuEntry, type MenuProps } from './menu.types';\nimport { hasAnyIcon, renderItemIcon } from './menuItem';\n\n/** How long a typed run stays one search before it starts over. */\nconst TYPEAHEAD_RESET_MS = 600;\n\n/** Index of the next action that can be focused, wrapping, or -1 if there is none. */\nfunction nextEnabled(items: MenuEntry[], from: number, step: 1 | -1): number {\n for (let i = 1; i <= items.length; i++) {\n // The `items.length * i` term only keeps the value positive for a backwards\n // step; JavaScript's `%` would otherwise return a negative index.\n const index = (from + step * i + items.length * i) % items.length;\n const entry = items[index];\n if (isMenuAction(entry) && !entry.disabled) return index;\n }\n return -1;\n}\n\nfunction firstEnabled(items: MenuEntry[]): number {\n return items.findIndex((entry) => isMenuAction(entry) && !entry.disabled);\n}\n\nfunction lastEnabled(items: MenuEntry[]): number {\n for (let i = items.length - 1; i >= 0; i--) {\n const entry = items[i];\n if (isMenuAction(entry) && !entry.disabled) return i;\n }\n return -1;\n}\n\n/**\n * A menu of actions on a trigger of your choosing.\n *\n * `Popover` does the anchoring, portalling and outside-click work but takes\n * arbitrary `content`, which leaves every consumer to write their own `ul`/`li`\n * and, in practice, to leave out the roles and the arrow keys. This is that list,\n * done once: `role=\"menu\"`, a roving focus that skips disabled entries, Escape\n * back to the trigger, and separators and headings that stay out of the keyboard\n * order.\n */\nfunction Menu({\n items,\n children,\n onAction,\n isOpen: controlledOpen,\n onOpenChange,\n placement = PopoverPlacement.Bottom,\n align = PopoverAlign.Start,\n presentation,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n}: MenuProps): ReactElement {\n const isControlled = controlledOpen !== undefined;\n const [internalOpen, setInternalOpen] = useState(false);\n const isOpen = isControlled ? controlledOpen : internalOpen;\n\n const [activeIndex, setActiveIndex] = useState(-1);\n const itemRefs = useRef<(HTMLElement | null)[]>([]);\n const triggerRef = useRef<HTMLSpanElement>(null);\n const menuRef = useRef<HTMLDivElement>(null);\n // Tab leaves the panel in both directions, so the menu needs the same boundary\n // Popover uses: back to the trigger, or on to whatever follows it.\n const { restoreFocusToTrigger, focusAfterTrigger } = useFocusBoundary({ triggerRef, contentRef: menuRef });\n const menuId = useId();\n const followLink = useLinkClick();\n // Which end to land on when the menu opens: `ArrowUp` on the trigger opens at\n // the bottom, everything else at the top.\n const openAtRef = useRef<'first' | 'last'>('first');\n const typeahead = useRef<{ query: string; timer: ReturnType<typeof setTimeout> | undefined }>({\n query: '',\n timer: undefined,\n });\n\n // Whether a key opened the menu, which decides between landing the focus on an\n // entry and leaving it on the trigger. Set from Popover, which is what sees the\n // trigger's events, or here when an arrow key did the opening.\n const openedByKeyboardRef = useRef(false);\n\n function setOpen(next: boolean, fromKeyboard = false) {\n if (next) openedByKeyboardRef.current = fromKeyboard;\n if (!isControlled) setInternalOpen(next);\n onOpenChange?.(next);\n }\n\n // The effect below needs the entries, but must not re-run when the array is rebuilt. A consumer\n // writes `items={[…]}` inline, so it is a new identity on every render of *their* component:\n // keyed off it, any parent re-render while the menu was open threw the focus back to the first\n // entry, mid-navigation. Declared above the effect that reads it, so it has already run.\n const itemsRef = useRef(items);\n useEffect(() => {\n itemsRef.current = items;\n });\n\n // Focus follows the active entry rather than the menu keeping focus and\n // pointing at it: the items are real buttons, so Enter and Space are theirs.\n // Popover's own `focusOnOpen` would take the first focusable and stop there;\n // the active index has to move with it, so the menu does it itself.\n useEffect(() => {\n if (!isOpen) return;\n // A pointer open leaves the focus where the pointer put it. A highlight on an\n // entry nobody pointed at reads as a selection, and the mouse is about to land\n // somewhere else anyway; the first arrow key moves in, see the trigger's keys.\n if (!openedByKeyboardRef.current) {\n setActiveIndex(-1);\n return;\n }\n const entries = itemsRef.current;\n const target = openAtRef.current === 'last' ? lastEnabled(entries) : firstEnabled(entries);\n setActiveIndex(target);\n // The panel is portalled and animated in, so its buttons exist a frame later.\n const frame = requestAnimationFrame(() => {\n itemRefs.current[target]?.focus();\n });\n return () => {\n cancelAnimationFrame(frame);\n openAtRef.current = 'first';\n };\n }, [isOpen]);\n\n useEffect(() => () => clearTimeout(typeahead.current.timer), []);\n\n function moveTo(index: number) {\n if (index < 0) return;\n setActiveIndex(index);\n itemRefs.current[index]?.focus();\n }\n\n function close(returnFocus: boolean) {\n setOpen(false);\n if (returnFocus) restoreFocusToTrigger();\n }\n\n /**\n * Jumps to the next entry whose label starts with what has been typed. The\n * text comes off the rendered button rather than the `label` prop, which is a\n * `ReactNode` and may be an icon, a badge or anything else.\n */\n function handleTypeahead(key: string): boolean {\n if (key.length !== 1 || !key.trim()) return false;\n clearTimeout(typeahead.current.timer);\n typeahead.current.query += key.toLowerCase();\n typeahead.current.timer = setTimeout(() => {\n typeahead.current.query = '';\n }, TYPEAHEAD_RESET_MS);\n\n const query = typeahead.current.query;\n // A repeated single character walks through the entries starting with it,\n // rather than sticking to the first one.\n const repeated = query.length > 1 && [...query].every((c) => c === query[0]);\n const needle = repeated ? query[0] : query;\n const from = repeated || query.length === 1 ? activeIndex : activeIndex - 1;\n\n for (let i = 1; i <= items.length; i++) {\n const index = (from + i + items.length) % items.length;\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) continue;\n const text = itemRefs.current[index]?.textContent?.trim().toLowerCase() ?? '';\n if (text.startsWith(needle)) {\n moveTo(index);\n return true;\n }\n }\n return false;\n }\n\n /** The trigger's own keys, which decide where the menu opens. */\n function handleTriggerKeyDown(event: React.KeyboardEvent) {\n if (event.key !== 'ArrowDown' && event.key !== 'ArrowUp') return;\n // Popover opens on these keys too; letting both act would be harmless but\n // this keeps the decision about where to land in one place.\n event.preventDefault();\n event.stopPropagation();\n // Already open means a pointer opened it and the focus never left the trigger,\n // since an entry's own keys never reach here. This is the key that moves in.\n if (isOpen) {\n moveTo(event.key === 'ArrowUp' ? lastEnabled(items) : firstEnabled(items));\n return;\n }\n openAtRef.current = event.key === 'ArrowUp' ? 'last' : 'first';\n setOpen(true, true);\n }\n\n function handleKeyDown(event: React.KeyboardEvent) {\n switch (event.key) {\n case 'ArrowDown':\n moveTo(nextEnabled(items, activeIndex, 1));\n break;\n case 'ArrowUp':\n // Stepping back from \"nothing active\" lands two short of the end, so the end is named.\n moveTo(activeIndex < 0 ? lastEnabled(items) : nextEnabled(items, activeIndex, -1));\n break;\n case 'Home':\n moveTo(firstEnabled(items));\n break;\n case 'End':\n moveTo(lastEnabled(items));\n break;\n // Popover handles both of these too, but only once the focus has actually\n // reached the panel: its Escape restores focus on that condition, and its\n // Tab handling acts at the first and last focusable. A menu focuses its\n // first entry a frame after opening, so a key pressed in between would\n // fall through. Here they are unconditional, which is also what a menu\n // wants from Tab: leave, whatever is focused.\n case 'Escape':\n close(true);\n break;\n case 'Tab':\n // Carry on from the trigger, as if the panel had never been in the tab\n // order. Closing and letting the browser take it from here would move on\n // from an entry that is about to be removed, which lands at the top of\n // the document.\n close(false);\n if (event.shiftKey) restoreFocusToTrigger();\n else focusAfterTrigger();\n break;\n default:\n if (!handleTypeahead(event.key)) return;\n }\n event.preventDefault();\n event.stopPropagation();\n }\n\n function handleAction(index: number) {\n const entry = items[index];\n if (!isMenuAction(entry) || entry.disabled) return;\n // Not runMenuAction: a link entry is an <a>, which the browser follows by itself.\n entry.onClick?.();\n onAction?.(entry.id);\n close(true);\n }\n\n // A screen reader has no way to tell that this button opens a menu unless the\n // button itself says so. Only filled in where the consumer has not, so a\n // trigger that describes itself keeps doing that.\n const triggerWithMenuSemantics = isValidElement<Record<string, unknown>>(children)\n ? cloneElement(children, {\n 'aria-haspopup': children.props['aria-haspopup'] ?? 'menu',\n 'aria-expanded': children.props['aria-expanded'] ?? isOpen,\n 'aria-controls': isOpen ? (children.props['aria-controls'] ?? menuId) : children.props['aria-controls'],\n })\n : children;\n\n const hasIcons = hasAnyIcon(items);\n\n const content = (\n <div\n ref={menuRef}\n id={menuId}\n role='menu'\n className={cx(styles.menu, classNames?.menu)}\n style={slotStyles?.menu}\n onKeyDown={handleKeyDown}\n >\n {items.map((entry, index) => {\n if (isMenuSeparator(entry))\n return (\n <div\n // Separators and headings carry no id of their own, and reordering\n // the list re-renders it wholesale anyway.\n key={`separator-${index}`}\n role='separator'\n className={cx(styles.menuSeparator, classNames?.separator)}\n style={slotStyles?.separator}\n />\n );\n\n if (isMenuHeading(entry))\n return (\n <div\n key={`heading-${index}`}\n role='presentation'\n className={cx(styles.menuHeading, classNames?.heading)}\n style={slotStyles?.heading}\n >\n {entry.heading}\n </div>\n );\n\n const itemProps = {\n ref: (el: HTMLElement | null) => {\n itemRefs.current[index] = el;\n },\n role: 'menuitem',\n 'aria-keyshortcuts': ariaKeyshortcuts(entry.shortcut),\n // One tab stop for the whole menu: the arrow keys move between items.\n tabIndex: index === activeIndex ? 0 : -1,\n className: cx(styles.menuItem, entry.danger && styles.menuItemDanger, classNames?.item),\n style: slotStyles?.item,\n onClick: () => handleAction(index),\n onMouseEnter: () => setActiveIndex(index),\n };\n const itemContent = (\n <>\n {renderItemIcon(entry.icon, hasIcons, {\n className: cx(styles.menuItemIcon, classNames?.itemIcon),\n style: slotStyles?.itemIcon,\n })}\n <span className={cx(styles.menuItemLabel, classNames?.itemLabel)} style={slotStyles?.itemLabel}>\n {entry.label}\n </span>\n {entry.shortcut != null && (\n <span\n aria-hidden\n className={cx(styles.menuItemShortcut, classNames?.itemShortcut)}\n style={slotStyles?.itemShortcut}\n >\n {formatHotkey(entry.shortcut)}\n </span>\n )}\n </>\n );\n\n // An <a> cannot be disabled, so a disabled link is a disabled button.\n return entry.href && !entry.disabled ? (\n <a\n key={entry.id}\n href={entry.href}\n {...itemProps}\n onClick={(event) => {\n handleAction(index);\n followLink(event);\n }}\n // A link takes Enter but not Space, which every other entry answers to.\n onKeyDown={(event) => {\n if (event.key !== ' ' || !isSelfActivation(event)) return;\n event.preventDefault();\n event.currentTarget.click();\n }}\n >\n {itemContent}\n </a>\n ) : (\n <button key={entry.id} type='button' disabled={entry.disabled} {...itemProps}>\n {itemContent}\n </button>\n );\n })}\n </div>\n );\n\n return (\n <Popover\n {...rest}\n isOpen={isOpen}\n onOpenChange={(next, { fromKeyboard }) => setOpen(next, fromKeyboard)}\n placement={placement}\n align={align}\n presentation={presentation}\n content={content}\n // The list pads its own rows, so a hover highlight reaches the panel edge,\n // and it sizes itself. Focus is the menu's own business, see above.\n focusOnOpen={false}\n constrainWidth={false}\n classNames={{ panel: styles.menuPanel }}\n className={cx(className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <span\n ref={triggerRef}\n className={cx(styles.menuTrigger, classNames?.trigger)}\n style={slotStyles?.trigger}\n onKeyDown={handleTriggerKeyDown}\n >\n {triggerWithMenuSemantics}\n </span>\n </Popover>\n );\n}\n\nexport default Menu;\n"],"mappings":"8wBAcA,IAAM,GAAqB,IAG3B,SAAS,EAAY,EAAoB,EAAc,EAAsB,CAC3E,IAAK,IAAI,EAAI,EAAG,GAAK,EAAM,OAAQ,IAAK,CAGtC,IAAM,GAAS,EAAO,EAAO,EAAI,EAAM,OAAS,GAAK,EAAM,OACrD,EAAQ,EAAM,GACpB,GAAI,EAAa,CAAK,GAAK,CAAC,EAAM,SAAU,OAAO,CACrD,CACA,MAAO,EACT,CAEA,SAAS,EAAa,EAA4B,CAChD,OAAO,EAAM,UAAW,GAAU,EAAa,CAAK,GAAK,CAAC,EAAM,QAAQ,CAC1E,CAEA,SAAS,EAAY,EAA4B,CAC/C,IAAK,IAAI,EAAI,EAAM,OAAS,EAAG,GAAK,EAAG,IAAK,CAC1C,IAAM,EAAQ,EAAM,GACpB,GAAI,EAAa,CAAK,GAAK,CAAC,EAAM,SAAU,OAAO,CACrD,CACA,MAAO,EACT,CAYA,SAAS,EAAK,CACZ,QACA,WACA,WACA,OAAQ,EACR,eACA,YAAY,EAAiB,OAC7B,QAAQ,EAAa,MACrB,eACA,YACA,QACA,aACA,OAAQ,EACR,GAAG,IACuB,CAC1B,IAAM,EAAe,IAAmB,IAAA,GAClC,CAAC,EAAc,GAAmB,EAAS,EAAK,EAChD,EAAS,EAAe,EAAiB,EAEzC,CAAC,EAAa,GAAkB,EAAS,EAAE,EAC3C,EAAW,EAA+B,CAAC,CAAC,EAC5C,EAAa,EAAwB,IAAI,EACzC,EAAU,EAAuB,IAAI,EAGrC,CAAE,wBAAuB,qBAAsB,EAAiB,CAAE,aAAY,WAAY,CAAQ,CAAC,EACnG,EAAS,GAAM,EACf,EAAa,EAAa,EAG1B,EAAY,EAAyB,OAAO,EAC5C,EAAY,EAA4E,CAC5F,MAAO,GACP,MAAO,IAAA,EACT,CAAC,EAKK,EAAsB,EAAO,EAAK,EAExC,SAAS,EAAQ,EAAe,EAAe,GAAO,CAChD,IAAM,EAAoB,QAAU,GACnC,GAAc,EAAgB,CAAI,EACvC,IAAe,CAAI,CACrB,CAMA,IAAM,EAAW,EAAO,CAAK,EAC7B,MAAgB,CACd,EAAS,QAAU,CACrB,CAAC,EAMD,MAAgB,CACd,GAAI,CAAC,EAAQ,OAIb,GAAI,CAAC,EAAoB,QAAS,CAChC,EAAe,EAAE,EACjB,MACF,CACA,IAAM,EAAU,EAAS,QACnB,EAAS,EAAU,UAAY,OAAS,EAAY,CAAO,EAAI,EAAa,CAAO,EACzF,EAAe,CAAM,EAErB,IAAM,EAAQ,0BAA4B,CACxC,EAAS,QAAQ,EAAO,EAAE,MAAM,CAClC,CAAC,EACD,UAAa,CACX,qBAAqB,CAAK,EAC1B,EAAU,QAAU,OACtB,CACF,EAAG,CAAC,CAAM,CAAC,EAEX,UAAsB,aAAa,EAAU,QAAQ,KAAK,EAAG,CAAC,CAAC,EAE/D,SAAS,EAAO,EAAe,CACzB,EAAQ,IACZ,EAAe,CAAK,EACpB,EAAS,QAAQ,EAAM,EAAE,MAAM,EACjC,CAEA,SAAS,EAAM,EAAsB,CACnC,EAAQ,EAAK,EACT,GAAa,EAAsB,CACzC,CAOA,SAAS,GAAgB,EAAsB,CAC7C,GAAI,EAAI,SAAW,GAAK,CAAC,EAAI,KAAK,EAAG,MAAO,GAC5C,aAAa,EAAU,QAAQ,KAAK,EACpC,EAAU,QAAQ,OAAS,EAAI,YAAY,EAC3C,EAAU,QAAQ,MAAQ,eAAiB,CACzC,EAAU,QAAQ,MAAQ,EAC5B,EAAG,EAAkB,EAErB,IAAM,EAAQ,EAAU,QAAQ,MAG1B,EAAW,EAAM,OAAS,GAAK,CAAC,GAAG,CAAK,CAAC,CAAC,MAAO,GAAM,IAAM,EAAM,EAAE,EACrE,EAAS,EAAW,EAAM,GAAK,EAC/B,EAAO,GAAY,EAAM,SAAW,EAAI,EAAc,EAAc,EAE1E,IAAK,IAAI,EAAI,EAAG,GAAK,EAAM,OAAQ,IAAK,CACtC,IAAM,GAAS,EAAO,EAAI,EAAM,QAAU,EAAM,OAC1C,EAAQ,EAAM,GAChB,GAAC,EAAa,CAAK,GAAK,GAAM,WACrB,EAAS,QAAQ,EAAM,EAAE,aAAa,KAAK,CAAC,CAAC,YAAY,GAAK,GAAA,CAClE,WAAW,CAAM,EAExB,OADA,EAAO,CAAK,EACL,EAEX,CACA,MAAO,EACT,CAGA,SAAS,GAAqB,EAA4B,CACpD,KAAM,MAAQ,aAAe,EAAM,MAAQ,UAO/C,IAJA,EAAM,eAAe,EACrB,EAAM,gBAAgB,EAGlB,EAAQ,CACV,EAAO,EAAM,MAAQ,UAAY,EAAY,CAAK,EAAI,EAAa,CAAK,CAAC,EACzE,MACF,CACA,EAAU,QAAU,EAAM,MAAQ,UAAY,OAAS,QACvD,EAAQ,GAAM,EAAI,CAFlB,CAGF,CAEA,SAAS,GAAc,EAA4B,CACjD,OAAQ,EAAM,IAAd,CACE,IAAK,YACH,EAAO,EAAY,EAAO,EAAa,CAAC,CAAC,EACzC,MACF,IAAK,UAEH,EAAO,EAAc,EAAI,EAAY,CAAK,EAAI,EAAY,EAAO,EAAa,EAAE,CAAC,EACjF,MACF,IAAK,OACH,EAAO,EAAa,CAAK,CAAC,EAC1B,MACF,IAAK,MACH,EAAO,EAAY,CAAK,CAAC,EACzB,MAOF,IAAK,SACH,EAAM,EAAI,EACV,MACF,IAAK,MAKH,EAAM,EAAK,EACP,EAAM,SAAU,EAAsB,EACrC,EAAkB,EACvB,MACF,QACE,GAAI,CAAC,GAAgB,EAAM,GAAG,EAAG,MACrC,CACA,EAAM,eAAe,EACrB,EAAM,gBAAgB,CACxB,CAEA,SAAS,EAAa,EAAe,CACnC,IAAM,EAAQ,EAAM,GACf,EAAa,CAAK,GAAK,GAAM,WAElC,EAAM,UAAU,EAChB,IAAW,EAAM,EAAE,EACnB,EAAM,EAAI,EACZ,CAKA,IAAM,GAA2B,GAAwC,CAAQ,EAC7E,GAAa,EAAU,CACrB,gBAAiB,EAAS,MAAM,kBAAoB,OACpD,gBAAiB,EAAS,MAAM,kBAAoB,EACpD,gBAAiB,EAAU,EAAS,MAAM,kBAAoB,EAAU,EAAS,MAAM,gBACzF,CAAC,EACD,EAEE,GAAW,EAAW,CAAK,EAE3B,GACJ,EAAC,MAAD,CACE,IAAK,EACL,GAAI,EACJ,KAAK,OACL,UAAW,EAAG,EAAO,KAAM,GAAY,IAAI,EAC3C,MAAO,GAAY,KACnB,UAAW,GAEV,SAAA,EAAM,KAAK,EAAO,IAAU,CAC3B,GAAI,GAAgB,CAAK,EACvB,OACE,EAAC,MAAD,CAIE,KAAK,YACL,UAAW,EAAG,EAAO,cAAe,GAAY,SAAS,EACzD,MAAO,GAAY,SACpB,EAJM,aAAa,GAInB,EAGL,GAAI,EAAc,CAAK,EACrB,OACE,EAAC,MAAD,CAEE,KAAK,eACL,UAAW,EAAG,EAAO,YAAa,GAAY,OAAO,EACrD,MAAO,GAAY,QAElB,SAAA,EAAM,OACJ,EANE,WAAW,GAMb,EAGT,IAAM,EAAY,CAChB,IAAM,GAA2B,CAC/B,EAAS,QAAQ,GAAS,CAC5B,EACA,KAAM,WACN,oBAAqB,EAAiB,EAAM,QAAQ,EAEpD,SAAU,IAAU,EAAc,EAAI,GACtC,UAAW,EAAG,EAAO,SAAU,EAAM,QAAU,EAAO,eAAgB,GAAY,IAAI,EACtF,MAAO,GAAY,KACnB,YAAe,EAAa,CAAK,EACjC,iBAAoB,EAAe,CAAK,CAC1C,EACM,EACJ,GAAA,EAAA,CAAA,SAAA,CACG,EAAe,EAAM,KAAM,GAAU,CACpC,UAAW,EAAG,EAAO,aAAc,GAAY,QAAQ,EACvD,MAAO,GAAY,QACrB,CAAC,EACD,EAAC,OAAD,CAAM,UAAW,EAAG,EAAO,cAAe,GAAY,SAAS,EAAG,MAAO,GAAY,UAClF,SAAA,EAAM,KACH,CAAA,EACL,EAAM,UAAY,MACjB,EAAC,OAAD,CACE,cAAA,GACA,UAAW,EAAG,EAAO,iBAAkB,GAAY,YAAY,EAC/D,MAAO,GAAY,aAElB,SAAA,EAAa,EAAM,QAAQ,CACxB,CAAA,CAER,CAAA,CAAA,EAIJ,OAAO,EAAM,MAAQ,CAAC,EAAM,SAC1B,EAAC,IAAD,CAEE,KAAM,EAAM,KACZ,GAAI,EACJ,QAAU,GAAU,CAClB,EAAa,CAAK,EAClB,EAAW,CAAK,CAClB,EAEA,UAAY,GAAU,CAChB,EAAM,MAAQ,KAAQ,EAAiB,CAAK,IAChD,EAAM,eAAe,EACrB,EAAM,cAAc,MAAM,EAC5B,EAEC,SAAA,CACA,EAfI,EAAM,EAeV,EAEH,EAAC,SAAD,CAAuB,KAAK,SAAS,SAAU,EAAM,SAAU,GAAI,EAChE,SAAA,CACK,EAFK,EAAM,EAEX,CAEZ,CAAC,CACE,CAAA,EAGP,OACE,EAAC,GAAD,CACE,GAAI,GACI,SACR,cAAe,EAAM,CAAE,kBAAmB,EAAQ,EAAM,CAAY,EACzD,YACJ,QACO,eACL,WAGT,YAAa,GACb,eAAgB,GAChB,WAAY,CAAE,MAAO,EAAO,SAAU,EACtC,UAAW,EAAG,EAAW,GAAY,IAAI,EACzC,MAAO,CAAE,GAAG,EAAO,GAAG,GAAY,IAAK,EAEvC,SAAA,EAAC,OAAD,CACE,IAAK,EACL,UAAW,EAAG,EAAO,YAAa,GAAY,OAAO,EACrD,MAAO,GAAY,QACnB,UAAW,GAEV,SAAA,EACG,CAAA,CACC,CAAA,CAEb"}
@@ -1 +1 @@
1
- {"version":3,"file":"menu.types.mjs","names":[],"sources":["../../../../package/common/menu/menu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\nimport type { IconContent } from '../types/icon.types';\nimport type { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport type { Presentation } from '../configProvider/presentation.types';\n\n/** One thing the menu can do. */\nexport interface MenuAction {\n /** Stable id, also what `onAction` reports. */\n id: string;\n label: ReactNode;\n icon?: IconContent;\n /**\n * A keyboard shortcut for this action, in `useHotkeys` spelling: `'mod+k'`,\n * `'shift+f2'`, `'delete'`. Shown on the trailing edge written for the\n * platform: `⌘K` on an Apple one, `Ctrl+K` elsewhere.\n *\n * The menu draws it and nothing more. Binding is yours, because only the app\n * knows what else is listening and whether the shortcut should work at all\n * times or only while the menu is open. `menuHotkeys` turns these entries\n * into a `useHotkeys` map, so the one spelling covers both ends.\n */\n shortcut?: string;\n /** Extra search terms for `CommandPalette`, which also matches a string `label`. `Menu` ignores them. */\n keywords?: string[];\n disabled?: boolean;\n /** Renders in the destructive colour. For deleting, discarding, revoking. */\n danger?: boolean;\n /**\n * Followed after `onClick` and `onAction`. In `Menu` a real `<a>`, so Ctrl/⌘-click opens a new tab.\n * Loads the whole page: with a client-side router, navigate in `onClick` instead.\n */\n href?: string;\n onClick?: () => void;\n}\n\n/** A line between groups of actions. */\nexport interface MenuSeparator {\n separator: true;\n}\n\n/** A label over the actions that follow it. */\nexport interface MenuHeading {\n heading: ReactNode;\n}\n\nexport type MenuEntry = MenuAction | MenuSeparator | MenuHeading;\n\nexport function isMenuSeparator(entry: MenuEntry): entry is MenuSeparator {\n return 'separator' in entry;\n}\n\nexport function isMenuHeading(entry: MenuEntry): entry is MenuHeading {\n return 'heading' in entry;\n}\n\nexport function isMenuAction(entry: MenuEntry): entry is MenuAction {\n return !isMenuSeparator(entry) && !isMenuHeading(entry);\n}\n\nexport type MenuSlots =\n | 'root'\n | 'trigger'\n | 'menu'\n | 'item'\n | 'itemIcon'\n | 'itemLabel'\n | 'itemShortcut'\n | 'separator'\n | 'heading';\n\nexport interface MenuProps extends Omit<HtmlProps, 'onSelect'> {\n /** What the menu offers, in the order it is read. */\n items: MenuEntry[];\n /** The element that opens the menu. */\n children?: ReactNode;\n /** Called with the id of the action that was picked, after its own `onClick`. */\n onAction?: (id: string) => void;\n /** Controlled open state. Leave it out to let the menu manage its own. */\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n /** Which side of the trigger the menu opens on (default `Bottom`). */\n placement?: PopoverPlacement;\n /** Which edge it lines up with on the cross axis (default `Start`). */\n align?: PopoverAlign;\n /** Anchored to the trigger, pinned to the bottom of the screen, or the latter only on touch. */\n presentation?: Presentation;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<MenuSlots>;\n styles?: SlotStyles<MenuSlots>;\n}\n"],"mappings":"aAgDA,SAAgB,EAAgB,EAA0C,CACxE,MAAO,cAAe,CACxB,CAEA,SAAgB,EAAc,EAAwC,CACpE,MAAO,YAAa,CACtB,CAEA,SAAgB,EAAa,EAAuC,CAClE,MAAO,CAAC,EAAgB,CAAK,GAAK,CAAC,EAAc,CAAK,CACxD"}
1
+ {"version":3,"file":"menu.types.mjs","names":[],"sources":["../../../../package/common/menu/menu.types.ts"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\nimport type { SlotClassNames, SlotStyles, HtmlProps } from '../types/slots.types';\nimport type { IconContent } from '../types/icon.types';\nimport type { PopoverAlign, PopoverPlacement } from '../popover/popover.types';\nimport type { Presentation } from '../configProvider/presentation.types';\n\n/** One thing the menu can do. */\nexport interface MenuAction {\n /** Stable id, also what `onAction` reports. */\n id: string;\n label: ReactNode;\n icon?: IconContent;\n /**\n * A keyboard shortcut for this action, in `useHotkeys` spelling: `'mod+k'`,\n * `'shift+f2'`, `'delete'`. Shown on the trailing edge written for the\n * platform: `⌘K` on an Apple one, `Ctrl+K` elsewhere.\n *\n * The menu draws it and nothing more. Binding is yours, because only the app\n * knows what else is listening and whether the shortcut should work at all\n * times or only while the menu is open. `menuHotkeys` turns these entries\n * into a `useHotkeys` map, so the one spelling covers both ends.\n */\n shortcut?: string;\n /** Extra search terms for `CommandPalette`, which also matches a string `label`. `Menu` ignores them. */\n keywords?: string[];\n disabled?: boolean;\n /** Renders in the destructive colour. For deleting, discarding, revoking. */\n danger?: boolean;\n /**\n * Followed after `onClick` and `onAction`, through `ConfigProvider`'s `navigate` when it is set.\n * In `Menu` a real `<a>`, so Ctrl/⌘-click opens a new tab.\n */\n href?: string;\n onClick?: () => void;\n}\n\n/** A line between groups of actions. */\nexport interface MenuSeparator {\n separator: true;\n}\n\n/** A label over the actions that follow it. */\nexport interface MenuHeading {\n heading: ReactNode;\n}\n\nexport type MenuEntry = MenuAction | MenuSeparator | MenuHeading;\n\nexport function isMenuSeparator(entry: MenuEntry): entry is MenuSeparator {\n return 'separator' in entry;\n}\n\nexport function isMenuHeading(entry: MenuEntry): entry is MenuHeading {\n return 'heading' in entry;\n}\n\nexport function isMenuAction(entry: MenuEntry): entry is MenuAction {\n return !isMenuSeparator(entry) && !isMenuHeading(entry);\n}\n\nexport type MenuSlots =\n | 'root'\n | 'trigger'\n | 'menu'\n | 'item'\n | 'itemIcon'\n | 'itemLabel'\n | 'itemShortcut'\n | 'separator'\n | 'heading';\n\nexport interface MenuProps extends Omit<HtmlProps, 'onSelect'> {\n /** What the menu offers, in the order it is read. */\n items: MenuEntry[];\n /** The element that opens the menu. */\n children?: ReactNode;\n /** Called with the id of the action that was picked, after its own `onClick`. */\n onAction?: (id: string) => void;\n /** Controlled open state. Leave it out to let the menu manage its own. */\n isOpen?: boolean;\n onOpenChange?: (isOpen: boolean) => void;\n /** Which side of the trigger the menu opens on (default `Bottom`). */\n placement?: PopoverPlacement;\n /** Which edge it lines up with on the cross axis (default `Start`). */\n align?: PopoverAlign;\n /** Anchored to the trigger, pinned to the bottom of the screen, or the latter only on touch. */\n presentation?: Presentation;\n className?: string;\n style?: CSSProperties;\n classNames?: SlotClassNames<MenuSlots>;\n styles?: SlotStyles<MenuSlots>;\n}\n"],"mappings":"aAgDA,SAAgB,EAAgB,EAA0C,CACxE,MAAO,cAAe,CACxB,CAEA,SAAgB,EAAc,EAAwC,CACpE,MAAO,YAAa,CACtB,CAEA,SAAgB,EAAa,EAAuC,CAClE,MAAO,CAAC,EAAgB,CAAK,GAAK,CAAC,EAAc,CAAK,CACxD"}
@@ -1,2 +1,2 @@
1
- "use client";import{renderIcon as e}from"../utils/renderIcon.mjs";import{isMenuAction as t}from"./menu.types.mjs";import{jsx as n}from"react/jsx-runtime";function r(e){return e.some(e=>t(e)&&e.icon!=null)}function i(t,r,i){return t==null?r?n(`span`,{"aria-hidden":!0,...i}):null:e(t,i)}function a(e,t){e.onClick?.(),t?.(e.id),e.href&&o(e.href)}function o(e){let t;try{t=new URL(e,document.baseURI)}catch{return}t.protocol!==`javascript:`&&window.location.assign(t)}export{r as hasAnyIcon,i as renderItemIcon,a as runMenuAction};
1
+ "use client";import{renderIcon as e}from"../utils/renderIcon.mjs";import{followHref as t}from"../utils/navigation.mjs";import{isMenuAction as n}from"./menu.types.mjs";import{jsx as r}from"react/jsx-runtime";function i(e){return e.some(e=>n(e)&&e.icon!=null)}function a(t,n,i){return t==null?n?r(`span`,{"aria-hidden":!0,...i}):null:e(t,i)}function o(e,n,r=t){e.onClick?.(),n?.(e.id),e.href&&r(e.href)}export{i as hasAnyIcon,a as renderItemIcon,o as runMenuAction};
2
2
  //# sourceMappingURL=menuItem.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"menuItem.mjs","names":[],"sources":["../../../../package/common/menu/menuItem.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\n\nimport { renderIcon } from '../utils/renderIcon';\nimport { isMenuAction, type MenuAction, type MenuEntry } from './menu.types';\n\nexport function hasAnyIcon(items: MenuEntry[]): boolean {\n return items.some((entry) => isMenuAction(entry) && entry.icon != null);\n}\n\n/** The action's icon, or an empty cell as wide when another action has one, so the labels line up. */\nexport function renderItemIcon(\n icon: MenuAction['icon'],\n reserveCell: boolean,\n props: { className: string; style?: CSSProperties },\n): ReactNode {\n if (icon != null) return renderIcon(icon, props);\n return reserveCell ? <span aria-hidden {...props} /> : null;\n}\n\n/** Runs an action the way clicking it does: its own `onClick`, then `onAction`, then its `href`. */\nexport function runMenuAction(action: MenuAction, onAction?: (id: string) => void): void {\n action.onClick?.();\n onAction?.(action.id);\n if (action.href) followHref(action.href);\n}\n\nfunction followHref(href: string) {\n let url: URL;\n try {\n url = new URL(href, document.baseURI);\n } catch {\n return;\n }\n // React refuses a javascript: URL on Menu's <a>, so the same entry must not run one here. Parsed,\n // not matched, because the parser strips the spaces and control characters that can hide one.\n if (url.protocol === 'javascript:') return;\n window.location.assign(url);\n}\n"],"mappings":"0JAKA,SAAgB,EAAW,EAA6B,CACtD,OAAO,EAAM,KAAM,GAAU,EAAa,CAAK,GAAK,EAAM,MAAQ,IAAI,CACxE,CAGA,SAAgB,EACd,EACA,EACA,EACW,CAEX,OADI,GAAQ,KACL,EAAc,EAAC,OAAD,CAAM,cAAA,GAAY,GAAI,CAAQ,CAAA,EAAI,KAD9B,EAAW,EAAM,CAAK,CAEjD,CAGA,SAAgB,EAAc,EAAoB,EAAuC,CACvF,EAAO,UAAU,EACjB,IAAW,EAAO,EAAE,EAChB,EAAO,MAAM,EAAW,EAAO,IAAI,CACzC,CAEA,SAAS,EAAW,EAAc,CAChC,IAAI,EACJ,GAAI,CACF,EAAM,IAAI,IAAI,EAAM,SAAS,OAAO,CACtC,MAAQ,CACN,MACF,CAGI,EAAI,WAAa,eACrB,OAAO,SAAS,OAAO,CAAG,CAC5B"}
1
+ {"version":3,"file":"menuItem.mjs","names":[],"sources":["../../../../package/common/menu/menuItem.tsx"],"sourcesContent":["import type { CSSProperties, ReactNode } from 'react';\n\nimport { followHref } from '../utils/navigation';\nimport { renderIcon } from '../utils/renderIcon';\nimport { isMenuAction, type MenuAction, type MenuEntry } from './menu.types';\n\nexport function hasAnyIcon(items: MenuEntry[]): boolean {\n return items.some((entry) => isMenuAction(entry) && entry.icon != null);\n}\n\n/** The action's icon, or an empty cell as wide when another action has one, so the labels line up. */\nexport function renderItemIcon(\n icon: MenuAction['icon'],\n reserveCell: boolean,\n props: { className: string; style?: CSSProperties },\n): ReactNode {\n if (icon != null) return renderIcon(icon, props);\n return reserveCell ? <span aria-hidden {...props} /> : null;\n}\n\n/**\n * Runs an action the way clicking it does: its own `onClick`, then `onAction`, then its `href`.\n * `follow` is `useFollowHref()` where the caller can reach the router; `menuHotkeys` cannot.\n */\nexport function runMenuAction(\n action: MenuAction,\n onAction?: (id: string) => void,\n follow: (href: string) => void = followHref,\n): void {\n action.onClick?.();\n onAction?.(action.id);\n if (action.href) follow(action.href);\n}\n"],"mappings":"+MAMA,SAAgB,EAAW,EAA6B,CACtD,OAAO,EAAM,KAAM,GAAU,EAAa,CAAK,GAAK,EAAM,MAAQ,IAAI,CACxE,CAGA,SAAgB,EACd,EACA,EACA,EACW,CAEX,OADI,GAAQ,KACL,EAAc,EAAC,OAAD,CAAM,cAAA,GAAY,GAAI,CAAQ,CAAA,EAAI,KAD9B,EAAW,EAAM,CAAK,CAEjD,CAMA,SAAgB,EACd,EACA,EACA,EAAiC,EAC3B,CACN,EAAO,UAAU,EACjB,IAAW,EAAO,EAAE,EAChB,EAAO,MAAM,EAAO,EAAO,IAAI,CACrC"}
@@ -0,0 +1,2 @@
1
+ "use client";import{NavigateContext as e}from"../configProvider/configProvider.mjs";import{useContext as t}from"react";function n(e){try{return new URL(e,document.baseURI)}catch{return null}}function r(e){return e.protocol!==`http:`&&e.protocol!==`https:`||e.origin!==window.location.origin||e.pathname===window.location.pathname&&e.search===window.location.search&&e.href.includes(`#`)?null:e.pathname+e.search+e.hash}function i(e){let t=e.currentTarget;return!e.defaultPrevented&&e.button===0&&!(e.metaKey||e.ctrlKey||e.shiftKey||e.altKey)&&(!t.target||t.target===`_self`)&&!t.hasAttribute(`download`)}function a(){let a=t(e);return e=>{if(!a||!i(e))return;let t=n(e.currentTarget.href),o=t&&r(t);o!==null&&(e.preventDefault(),a(o))}}function o(e,t){let i=n(e);if(!i||i.protocol===`javascript:`)return;let a=t?r(i):null;t&&a!==null?t(a):window.location.assign(i)}function s(){let n=t(e);return e=>o(e,n)}export{o as followHref,s as useFollowHref,a as useLinkClick};
2
+ //# sourceMappingURL=navigation.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"navigation.mjs","names":[],"sources":["../../../../package/common/utils/navigation.ts"],"sourcesContent":["import { useContext, type MouseEvent } from 'react';\n\nimport { NavigateContext } from '../configProvider/configProvider';\n\ntype Navigate = (path: string) => void;\n\nfunction parseUrl(href: string): URL | null {\n try {\n return new URL(href, document.baseURI);\n } catch {\n return null;\n }\n}\n\n/**\n * The path to hand to the router, or null where the browser has to take the URL: another site, or\n * another protocol. Protocol and origin are both checked because a `blob:` URL, which an app opens\n * a generated PDF through, carries the page's own origin. A jump to an anchor on the current page\n * stays with the browser too, which scrolls to it.\n */\nfunction routerPath(url: URL): string | null {\n if (url.protocol !== 'http:' && url.protocol !== 'https:') return null;\n if (url.origin !== window.location.origin) return null;\n const samePage = url.pathname === window.location.pathname && url.search === window.location.search;\n // Not `url.hash`, which is empty for a bare `#` that still jumps to the top.\n if (samePage && url.href.includes('#')) return null;\n return url.pathname + url.search + url.hash;\n}\n\n/** The checks react-router's own `<Link>` makes, plus `download`, which it leaves to the browser. */\nfunction isPlainClick(event: MouseEvent<HTMLAnchorElement>): boolean {\n const anchor = event.currentTarget;\n return (\n !event.defaultPrevented &&\n event.button === 0 &&\n !(event.metaKey || event.ctrlKey || event.shiftKey || event.altKey) &&\n (!anchor.target || anchor.target === '_self') &&\n !anchor.hasAttribute('download')\n );\n}\n\n/**\n * The click handler for an `<a>` a component renders: a plain click on a link within the app goes\n * to `ConfigProvider`'s `navigate`, everything else to the browser. Call it after the consumer's own\n * `onClick`, so a `preventDefault()` there still wins.\n */\nexport function useLinkClick(): (event: MouseEvent<HTMLAnchorElement>) => void {\n const navigate = useContext(NavigateContext);\n return (event) => {\n if (!navigate || !isPlainClick(event)) return;\n // `.href` rather than the attribute: the browser has already resolved a relative link against\n // the page, as it does for a middle click, which the router would resolve against the route.\n const url = parseUrl(event.currentTarget.href);\n const path = url && routerPath(url);\n if (path === null) return;\n event.preventDefault();\n navigate(path);\n };\n}\n\n/** Follows a link from code, where no anchor was clicked: through the router where it can. */\nexport function followHref(href: string, navigate?: Navigate): void {\n const url = parseUrl(href);\n if (!url) return;\n // React refuses a javascript: URL on an <a>, so the same link must not run one here. Parsed,\n // not matched, because the parser strips the spaces and control characters that can hide one.\n if (url.protocol === 'javascript:') return;\n const path = navigate ? routerPath(url) : null;\n if (navigate && path !== null) navigate(path);\n else window.location.assign(url);\n}\n\nexport function useFollowHref(): (href: string) => void {\n const navigate = useContext(NavigateContext);\n return (href) => followHref(href, navigate);\n}\n"],"mappings":"uHAMA,SAAS,EAAS,EAA0B,CAC1C,GAAI,CACF,OAAO,IAAI,IAAI,EAAM,SAAS,OAAO,CACvC,MAAQ,CACN,OAAO,IACT,CACF,CAQA,SAAS,EAAW,EAAyB,CAM3C,OALI,EAAI,WAAa,SAAW,EAAI,WAAa,UAC7C,EAAI,SAAW,OAAO,SAAS,QAClB,EAAI,WAAa,OAAO,SAAS,UAAY,EAAI,SAAW,OAAO,SAAS,QAE7E,EAAI,KAAK,SAAS,GAAG,EAAU,KACxC,EAAI,SAAW,EAAI,OAAS,EAAI,IACzC,CAGA,SAAS,EAAa,EAA+C,CACnE,IAAM,EAAS,EAAM,cACrB,MACE,CAAC,EAAM,kBACP,EAAM,SAAW,GACjB,EAAE,EAAM,SAAW,EAAM,SAAW,EAAM,UAAY,EAAM,UAC3D,CAAC,EAAO,QAAU,EAAO,SAAW,UACrC,CAAC,EAAO,aAAa,UAAU,CAEnC,CAOA,SAAgB,GAA+D,CAC7E,IAAM,EAAW,EAAW,CAAe,EAC3C,MAAQ,IAAU,CAChB,GAAI,CAAC,GAAY,CAAC,EAAa,CAAK,EAAG,OAGvC,IAAM,EAAM,EAAS,EAAM,cAAc,IAAI,EACvC,EAAO,GAAO,EAAW,CAAG,EAC9B,IAAS,OACb,EAAM,eAAe,EACrB,EAAS,CAAI,EACf,CACF,CAGA,SAAgB,EAAW,EAAc,EAA2B,CAClE,IAAM,EAAM,EAAS,CAAI,EAIzB,GAHI,CAAC,GAGD,EAAI,WAAa,cAAe,OACpC,IAAM,EAAO,EAAW,EAAW,CAAG,EAAI,KACtC,GAAY,IAAS,KAAM,EAAS,CAAI,EACvC,OAAO,SAAS,OAAO,CAAG,CACjC,CAEA,SAAgB,GAAwC,CACtD,IAAM,EAAW,EAAW,CAAe,EAC3C,MAAQ,IAAS,EAAW,EAAM,CAAQ,CAC5C"}
@@ -1 +1 @@
1
- "use client";import{AccordionStyleType as e}from"./common/accordion/accordion.types.mjs";import t from"./common/configProvider/configProvider.mjs";import{useComponentDefaults as n}from"./common/configProvider/useComponentDefaults.mjs";import{useLabels as r}from"./common/configProvider/useLabels.mjs";import{usePresentationDefault as i}from"./common/configProvider/usePresentationDefault.mjs";import{Presentation as a}from"./common/configProvider/presentation.types.mjs";import{ThemeColor as o}from"./common/themeProvider/color.types.mjs";import s from"./common/accordion/accordion.mjs";import{LoaderType as c}from"./common/loader/loader.types.mjs";import l from"./common/loader/loader.mjs";import{ButtonSize as u,ButtonStyleType as d,ButtonType as f}from"./common/button/button.types.mjs";import p from"./common/ripple/ripple.mjs";import m,{formatHotkey as h}from"./common/hooks/useHotkeys.mjs";import g from"./common/button/button.mjs";import _ from"./common/actionButtons/actionButtons.mjs";import v from"./common/actionIcon/actionIcon.mjs";import y from"./common/scrollbarProvider/index.mjs";import{defaultTheme as b}from"./common/themeProvider/defaultTheme.mjs";import x from"./common/themeProvider/themeProvider.mjs";import{lightTheme as S}from"./common/themeProvider/lightTheme.mjs";import C from"./common/bodyEnd/bodyEnd.mjs";import w from"./common/hooks/useMediaQuery.mjs";import T from"./common/hooks/useCoarsePointer.mjs";import{useSwipeDismiss as E}from"./common/hooks/useSwipeDismiss.mjs";import{showToast as D}from"./common/toast/toastService.mjs";import O from"./common/ahroweProvider/ahroweProvider.mjs";import k from"./common/alert/alert.mjs";import A from"./common/animatedLogo/animatedLogo.mjs";import{AnimatedTextUnit as j,AnimatedTextVariant as M}from"./common/animatedText/animatedText.types.mjs";import N from"./common/animatedText/animatedText.mjs";import{BadgePosition as P,BadgeStyleType as F}from"./common/badge/badge.types.mjs";import I from"./common/badge/badge.mjs";import L from"./common/avatar/avatar.mjs";import R from"./common/avatar/avatarGroup.mjs";import z from"./common/interactableDiv/index.mjs";import{PopoverAlign as B,PopoverPlacement as V,PopoverTrigger as H}from"./common/popover/popover.types.mjs";import{tabbablesIn as U}from"./common/hooks/useFocusBoundary.mjs";import{useVisualViewportSize as W}from"./common/hooks/useVisualViewportSize.mjs";import{useOverlay as G}from"./common/hooks/useOverlay.mjs";import K from"./common/popover/popover.mjs";import q from"./common/breadcrumb/breadcrumb.mjs";import{ButtonGroupOrientation as J}from"./common/buttonGroup/buttonGroup.types.mjs";import Y from"./common/buttonGroup/buttonGroup.mjs";import{dateToDay as X,dateToTime as Z,dayTimeToDate as Q,dayToDate as $}from"./common/utils/day.mjs";import{CalendarView as ee}from"./common/calendar/calendar.types.mjs";import te from"./common/emptyState/emptyState.mjs";import ne from"./common/optionPicker/optionPicker.mjs";import re from"./common/calendar/calendar.mjs";import{CardStyleType as ie}from"./common/card/card.types.mjs";import ae from"./common/card/Card.mjs";import oe from"./common/card/CardHeader.mjs";import se from"./common/card/CardMedia.mjs";import ce from"./common/card/CardContent.mjs";import le from"./common/card/CardActions.mjs";import ue from"./common/carousel/carousel.mjs";import de from"./common/chatComposer/chatComposer.mjs";import{ChatMessageStatus as fe,ChatMessageStyleType as pe}from"./common/chatMessage/chatMessage.types.mjs";import me from"./common/chatMessage/chatMessage.mjs";import he from"./common/chatMessageList/chatMessageList.mjs";import ge from"./common/checkbox/checkbox.mjs";import{ChipStyleType as _e}from"./common/chip/chip.types.mjs";import ve from"./common/chip/chip.mjs";import ye from"./common/chip/chipContainer.mjs";import be from"./common/tooltip/tooltip.mjs";import{InputIconPosition as xe,InputType as Se}from"./common/input/input.types.mjs";import Ce from"./common/input/input.mjs";import we from"./common/colorPicker/colorPicker.mjs";import{useScrollEdges as Te}from"./common/hooks/useScrollEdges.mjs";import Ee from"./common/modal/modal.mjs";import{isMenuAction as De,isMenuHeading as Oe,isMenuSeparator as ke}from"./common/menu/menu.types.mjs";import Ae from"./common/commandPalette/commandPalette.mjs";import je from"./common/confirmModal/confirmModal.mjs";import Me from"./common/hooks/useClipboard.mjs";import Ne from"./common/copyButton/copyButton.mjs";import{getLocale as Pe,mapLocale as Fe,setLocale as Ie}from"./services/localization.mjs";import Le from"./common/dropdown/dropdown.mjs";import Re from"./common/datePicker/datePicker.mjs";import{DividerOrientation as ze,DividerTextPosition as Be}from"./common/divider/divider.types.mjs";import Ve from"./common/divider/divider.mjs";import He from"./common/drawer/drawer.mjs";import{DropZoneReturnType as Ue,DropZoneStatus as We}from"./common/dropZone/dropZone.types.mjs";import Ge from"./common/dropZone/dropZone.mjs";import Ke from"./common/errorBoundary/errorBoundary.mjs";import qe from"./common/fab/fab.mjs";import Je from"./common/flip/flip.mjs";import{DoorSwing as Ye,OpeningKind as Xe,PlanIssueKind as Ze,PlanUnitSystem as Qe,WallType as $e}from"./common/floorPlan/floorPlan.types.mjs";import{MIN_OPENING_WIDTH as et,MIN_WALL_LENGTH as tt}from"./common/floorPlan/floorPlan.geometry.mjs";import{DEFAULT_WALL_ATTRS as nt,addOpening as rt,addRect as it,addWall as at,cleanupPlan as ot,detachWall as st,dissolveNode as ct,mergeNodes as lt,moveNode as ut,removeOpening as dt,removeWall as ft,scalePlan as pt,splitWall as mt,transformPlan as ht,updateOpening as gt,validatePlan as _t,wallLength as vt,weldShortWalls as yt}from"./common/floorPlan/floorPlan.graph.mjs";import{MIN_FLOOR_HEIGHT as bt,addFloor as xt,duplicateFloor as St,emptyFloor as Ct,emptyFloorPlan as wt,floorBelow as Tt,floorBounds as Et,floorIndex as Dt,getFloor as Ot,moveFloor as kt,removeFloor as At,renameFloor as jt,setFloor as Mt,setFloorHeight as Nt,updateFloor as Pt}from"./common/floorPlan/floorPlan.plan.mjs";import{deriveFaces as Ft,nodeDegrees as It}from"./common/floorPlan/floorPlan.faces.mjs";import{commitDerivation as Lt,derivePlan as Rt,pruneUnmatchedRooms as zt,roomAtPoint as Bt}from"./common/floorPlan/floorPlan.rooms.mjs";import{buildWallPaths as Vt,openingGeometry as Ht,wallCentrelineSpans as Ut}from"./common/floorPlan/floorPlan.path.mjs";import{HIT_PX as Wt,HIT_PX_COARSE as Gt,hitTest as Kt,selectionsEqual as qt,worldTolerances as Jt}from"./common/floorPlan/floorPlan.hit.mjs";import{DEFAULT_SNAP_OPTIONS as Yt,SnapKind as Xt,clientToWorld as Zt,resolveSnap as Qt}from"./common/floorPlan/floorPlan.snap.mjs";import{PLAN_FORMAT_VERSION as $t,planFromJson as en,planToJson as tn}from"./common/floorPlan/floorPlan.json.mjs";import{buildPlanMesh as nn}from"./common/floorPlan/floorPlan.mesh.mjs";import rn from"./common/iconPicker/iconPicker.mjs";import an from"./common/idleManager/idleManager.mjs";import on from"./common/inputDropdown/inputDropdown.mjs";import sn from"./common/kanbanBoard/KanbanColumn.mjs";import cn from"./common/kanbanBoard/KanbanBoard.mjs";import ln from"./common/searchInput/searchInput.mjs";import un from"./common/klipyPicker/klipyPicker.mjs";import dn from"./common/loadingOverlay/loadingOverlay.mjs";import fn from"./common/menu/menu.mjs";import{menuHotkeys as pn}from"./common/menu/menuHotkeys.mjs";import mn from"./common/multiSelect/multiSelect.mjs";import hn from"./common/numberInput/index.mjs";import{OtpInputCharset as gn}from"./common/otpInput/otpInput.types.mjs";import _n from"./common/otpInput/otpInput.mjs";import vn from"./common/overscroll/overscroll.mjs";import yn from"./common/pagination/pagination.mjs";import bn from"./common/progressBar/progressBar.mjs";import{RadioGroupOrientation as xn}from"./common/radioGroup/radioGroup.types.mjs";import Sn from"./common/radioGroup/radioGroup.mjs";import Cn from"./common/rating/rating.mjs";import wn from"./common/revealLens/revealLens.mjs";import Tn from"./common/roomDrawer/roomDrawer.mjs";import En from"./common/roomViewer/roomViewer.mjs";import{ScrollFadeAxis as Dn}from"./common/scrollFade/scrollFade.types.mjs";import On from"./common/scrollFade/scrollFade.mjs";import{SectionHeaderSize as kn}from"./common/sectionHeader/sectionHeader.types.mjs";import An from"./common/sectionHeader/sectionHeader.mjs";import{SkeletonAnimation as jn,SkeletonVariant as Mn}from"./common/skeleton/skeleton.types.mjs";import Nn from"./common/skeleton/skeleton.mjs";import Pn from"./common/slider/slider.mjs";import Fn from"./common/splitButton/splitButton.mjs";import{StepperCollapse as In,StepperLabelPlacement as Ln,StepperOrientation as Rn,StepperStyleType as zn}from"./common/stepper/stepper.types.mjs";import Bn from"./common/stepper/stepper.mjs";import Vn from"./common/sticky/sticky.mjs";import Hn from"./common/switch/switch.mjs";import Un from"./common/tabHeader/tabHeader.mjs";import Wn from"./common/textarea/textarea.mjs";import{useTheme as Gn}from"./common/themeProvider/useTheme.mjs";import Kn,{TiltGroupContext as qn,useTiltGroup as Jn}from"./common/tiltGroup/tiltGroup.mjs";import{defaultTiltEasing as Yn}from"./common/tilt/tiltMath.mjs";import Xn from"./common/tilt/tilt.mjs";import Zn from"./common/timeInput/timeInput.mjs";import{TimelineAlignment as Qn}from"./common/timeline/timeline.types.mjs";import $n from"./common/timeline/timeline.mjs";import er from"./common/timer/timer.mjs";import tr from"./common/virtualList/virtualList.mjs";import{flattenTree as nr}from"./common/tree/flattenTree.mjs";import rr from"./common/tree/tree.mjs";import{WeatherType as ir}from"./common/weatherIcon/weatherIcon.types.mjs";import ar from"./common/weatherIcon/weatherIcon.mjs";import or from"./common/wizard/wizard.mjs";import sr from"./services/formValidation/FormValidatorGroupWithForm.mjs";import cr from"./services/formValidation/validatableComponent.mjs";import{useFormValidatorGroup as lr}from"./services/formValidation/useFormValidatorGroup.mjs";import{FormValidator as ur,Validators as dr,useFormValidator as fr}from"./services/formValidation/index.mjs";import{hasEightPasswordChars as pr,hasOnePasswordDigit as mr,hasOnePasswordLetter as hr,isBic as gr,isDate as _r,isDay as vr,isEmail as yr,isISODate as br,isNumber as xr,isPassword as Sr,isURL as Cr}from"@ahrowe/form-validation";export{s as Accordion,e as AccordionStyleType,_ as ActionButtons,v as ActionIcon,O as AhroweProvider,k as Alert,A as AnimatedLogo,N as AnimatedText,j as AnimatedTextUnit,M as AnimatedTextVariant,L as Avatar,R as AvatarGroup,I as Badge,P as BadgePosition,F as BadgeStyleType,C as BodyEnd,q as Breadcrumb,g as Button,Y as ButtonGroup,J as ButtonGroupOrientation,u as ButtonSize,d as ButtonStyleType,f as ButtonType,re as Calendar,ee as CalendarView,ae as Card,le as CardActions,ce as CardContent,oe as CardHeader,se as CardMedia,ie as CardStyleType,ue as Carousel,de as ChatComposer,me as ChatMessage,he as ChatMessageList,fe as ChatMessageStatus,pe as ChatMessageStyleType,ge as Checkbox,ve as Chip,ye as ChipContainer,_e as ChipStyleType,we as ColorPicker,Ae as CommandPalette,t as ConfigProvider,je as ConfirmModal,Ne as CopyButton,Yt as DEFAULT_SNAP_OPTIONS,nt as DEFAULT_WALL_ATTRS,Re as DatePicker,Ve as Divider,ze as DividerOrientation,Be as DividerTextPosition,Ye as DoorSwing,He as Drawer,Ge as DropZone,Ue as DropZoneReturnType,We as DropZoneStatus,Le as Dropdown,te as EmptyState,Ke as ErrorBoundary,qe as Fab,Je as Flip,ur as FormValidator,sr as FormValidatorGroup,Wt as HIT_PX,Gt as HIT_PX_COARSE,rn as IconPicker,an as IdleManager,Ce as Input,on as InputDropdown,xe as InputIconPosition,Se as InputType,z as InteractableDiv,cn as KanbanBoard,sn as KanbanColumn,un as KlipyPicker,l as Loader,c as LoaderType,dn as LoadingOverlay,bt as MIN_FLOOR_HEIGHT,et as MIN_OPENING_WIDTH,tt as MIN_WALL_LENGTH,fn as Menu,Ee as Modal,mn as MultiSelect,hn as NumberInput,Xe as OpeningKind,ne as OptionPicker,_n as OtpInput,gn as OtpInputCharset,vn as Overscroll,$t as PLAN_FORMAT_VERSION,yn as Pagination,Ze as PlanIssueKind,Qe as PlanUnitSystem,K as Popover,B as PopoverAlign,V as PopoverPlacement,H as PopoverTrigger,a as Presentation,bn as ProgressBar,Sn as RadioGroup,xn as RadioGroupOrientation,Cn as Rating,wn as RevealLens,p as Ripple,Tn as RoomDrawer,En as RoomViewer,On as ScrollFade,Dn as ScrollFadeAxis,y as ScrollbarProvider,ln as SearchInput,An as SectionHeader,kn as SectionHeaderSize,Nn as Skeleton,jn as SkeletonAnimation,Mn as SkeletonVariant,Pn as Slider,Xt as SnapKind,Fn as SplitButton,Bn as Stepper,In as StepperCollapse,Ln as StepperLabelPlacement,Rn as StepperOrientation,zn as StepperStyleType,Vn as Sticky,Hn as Switch,Un as TabHeader,Wn as Textarea,o as ThemeColor,x as ThemeProvider,Xn as Tilt,Kn as TiltGroup,qn as TiltGroupContext,Zn as TimeInput,$n as Timeline,Qn as TimelineAlignment,er as Timer,be as Tooltip,rr as Tree,cr as ValidatableComponent,dr as Validators,tr as VirtualList,$e as WallType,ar as WeatherIcon,ir as WeatherType,or as Wizard,xt as addFloor,rt as addOpening,it as addRect,at as addWall,nn as buildPlanMesh,Vt as buildWallPaths,ot as cleanupPlan,Zt as clientToWorld,Lt as commitDerivation,X as dateToDay,Z as dateToTime,Q as dayTimeToDate,$ as dayToDate,b as defaultTheme,Yn as defaultTiltEasing,Ft as deriveFaces,Rt as derivePlan,st as detachWall,ct as dissolveNode,St as duplicateFloor,Ct as emptyFloor,wt as emptyFloorPlan,nr as flattenTree,Tt as floorBelow,Et as floorBounds,Dt as floorIndex,h as formatHotkey,Ot as getFloor,Pe as getLocale,pr as hasEightPasswordChars,mr as hasOnePasswordDigit,hr as hasOnePasswordLetter,Kt as hitTest,gr as isBic,_r as isDate,vr as isDay,yr as isEmail,br as isISODate,De as isMenuAction,Oe as isMenuHeading,ke as isMenuSeparator,xr as isNumber,Sr as isPassword,Cr as isURL,S as lightTheme,Fe as mapLocale,pn as menuHotkeys,lt as mergeNodes,kt as moveFloor,ut as moveNode,It as nodeDegrees,Ht as openingGeometry,en as planFromJson,tn as planToJson,zt as pruneUnmatchedRooms,At as removeFloor,dt as removeOpening,ft as removeWall,jt as renameFloor,Qt as resolveSnap,Bt as roomAtPoint,pt as scalePlan,qt as selectionsEqual,Mt as setFloor,Nt as setFloorHeight,Ie as setLocale,D as showToast,mt as splitWall,U as tabbablesIn,ht as transformPlan,Pt as updateFloor,gt as updateOpening,Me as useClipboard,T as useCoarsePointer,n as useComponentDefaults,fr as useFormValidator,lr as useFormValidatorGroup,m as useHotkeys,r as useLabels,w as useMediaQuery,G as useOverlay,i as usePresentationDefault,Te as useScrollEdges,E as useSwipeDismiss,Gn as useTheme,Jn as useTiltGroup,W as useVisualViewportSize,_t as validatePlan,Ut as wallCentrelineSpans,vt as wallLength,yt as weldShortWalls,Jt as worldTolerances};
1
+ "use client";import{AccordionStyleType as e}from"./common/accordion/accordion.types.mjs";import t from"./common/configProvider/configProvider.mjs";import{useComponentDefaults as n}from"./common/configProvider/useComponentDefaults.mjs";import{useLabels as r}from"./common/configProvider/useLabels.mjs";import{usePresentationDefault as i}from"./common/configProvider/usePresentationDefault.mjs";import{Presentation as a}from"./common/configProvider/presentation.types.mjs";import{ThemeColor as o}from"./common/themeProvider/color.types.mjs";import s from"./common/accordion/accordion.mjs";import{LoaderType as c}from"./common/loader/loader.types.mjs";import l from"./common/loader/loader.mjs";import{ButtonSize as u,ButtonStyleType as d,ButtonType as f}from"./common/button/button.types.mjs";import p from"./common/ripple/ripple.mjs";import m,{formatHotkey as h}from"./common/hooks/useHotkeys.mjs";import g from"./common/button/button.mjs";import _ from"./common/actionButtons/actionButtons.mjs";import v from"./common/actionIcon/actionIcon.mjs";import y from"./common/scrollbarProvider/index.mjs";import{defaultTheme as b}from"./common/themeProvider/defaultTheme.mjs";import x from"./common/themeProvider/themeProvider.mjs";import{lightTheme as S}from"./common/themeProvider/lightTheme.mjs";import C from"./common/bodyEnd/bodyEnd.mjs";import w from"./common/hooks/useMediaQuery.mjs";import T from"./common/hooks/useCoarsePointer.mjs";import{useSwipeDismiss as E}from"./common/hooks/useSwipeDismiss.mjs";import{showToast as D}from"./common/toast/toastService.mjs";import O from"./common/ahroweProvider/ahroweProvider.mjs";import k from"./common/alert/alert.mjs";import A from"./common/animatedLogo/animatedLogo.mjs";import{AnimatedTextUnit as j,AnimatedTextVariant as M}from"./common/animatedText/animatedText.types.mjs";import N from"./common/animatedText/animatedText.mjs";import{BadgePosition as P,BadgeStyleType as F}from"./common/badge/badge.types.mjs";import I from"./common/badge/badge.mjs";import L from"./common/avatar/avatar.mjs";import R from"./common/avatar/avatarGroup.mjs";import z from"./common/interactableDiv/index.mjs";import{PopoverAlign as B,PopoverPlacement as V,PopoverTrigger as H}from"./common/popover/popover.types.mjs";import{tabbablesIn as U}from"./common/hooks/useFocusBoundary.mjs";import{useVisualViewportSize as W}from"./common/hooks/useVisualViewportSize.mjs";import{useOverlay as G}from"./common/hooks/useOverlay.mjs";import K from"./common/popover/popover.mjs";import q from"./common/breadcrumb/breadcrumb.mjs";import{ButtonGroupOrientation as J}from"./common/buttonGroup/buttonGroup.types.mjs";import Y from"./common/buttonGroup/buttonGroup.mjs";import{dateToDay as X,dateToTime as Z,dayTimeToDate as Q,dayToDate as $}from"./common/utils/day.mjs";import{CalendarView as ee}from"./common/calendar/calendar.types.mjs";import te from"./common/emptyState/emptyState.mjs";import ne from"./common/optionPicker/optionPicker.mjs";import re from"./common/calendar/calendar.mjs";import{CardStyleType as ie}from"./common/card/card.types.mjs";import ae from"./common/card/Card.mjs";import oe from"./common/card/CardHeader.mjs";import se from"./common/card/CardMedia.mjs";import ce from"./common/card/CardContent.mjs";import le from"./common/card/CardActions.mjs";import ue from"./common/carousel/carousel.mjs";import de from"./common/chatComposer/chatComposer.mjs";import{ChatMessageStatus as fe,ChatMessageStyleType as pe}from"./common/chatMessage/chatMessage.types.mjs";import me from"./common/chatMessage/chatMessage.mjs";import he from"./common/chatMessageList/chatMessageList.mjs";import ge from"./common/checkbox/checkbox.mjs";import{ChipStyleType as _e}from"./common/chip/chip.types.mjs";import ve from"./common/chip/chip.mjs";import ye from"./common/chip/chipContainer.mjs";import be from"./common/tooltip/tooltip.mjs";import{InputIconPosition as xe,InputType as Se}from"./common/input/input.types.mjs";import Ce from"./common/input/input.mjs";import we from"./common/colorPicker/colorPicker.mjs";import{useScrollEdges as Te}from"./common/hooks/useScrollEdges.mjs";import Ee from"./common/modal/modal.mjs";import{isMenuAction as De,isMenuHeading as Oe,isMenuSeparator as ke}from"./common/menu/menu.types.mjs";import Ae from"./common/commandPalette/commandPalette.mjs";import je from"./common/confirmModal/confirmModal.mjs";import Me from"./common/hooks/useClipboard.mjs";import Ne from"./common/copyButton/copyButton.mjs";import{getLocale as Pe,mapLocale as Fe,setLocale as Ie}from"./services/localization.mjs";import Le from"./common/dropdown/dropdown.mjs";import Re from"./common/datePicker/datePicker.mjs";import{DividerOrientation as ze,DividerTextPosition as Be}from"./common/divider/divider.types.mjs";import Ve from"./common/divider/divider.mjs";import He from"./common/drawer/drawer.mjs";import{DropZoneReturnType as Ue,DropZoneStatus as We}from"./common/dropZone/dropZone.types.mjs";import Ge from"./common/dropZone/dropZone.mjs";import Ke from"./common/errorBoundary/errorBoundary.mjs";import qe from"./common/fab/fab.mjs";import Je from"./common/flip/flip.mjs";import{DoorSwing as Ye,OpeningKind as Xe,PlanIssueKind as Ze,PlanUnitSystem as Qe,WallType as $e}from"./common/floorPlan/floorPlan.types.mjs";import{MIN_OPENING_WIDTH as et,MIN_WALL_LENGTH as tt}from"./common/floorPlan/floorPlan.geometry.mjs";import{DEFAULT_WALL_ATTRS as nt,addOpening as rt,addRect as it,addWall as at,cleanupPlan as ot,detachWall as st,dissolveNode as ct,mergeNodes as lt,moveNode as ut,removeOpening as dt,removeWall as ft,scalePlan as pt,splitWall as mt,transformPlan as ht,updateOpening as gt,validatePlan as _t,wallLength as vt,weldShortWalls as yt}from"./common/floorPlan/floorPlan.graph.mjs";import{MIN_FLOOR_HEIGHT as bt,addFloor as xt,duplicateFloor as St,emptyFloor as Ct,emptyFloorPlan as wt,floorBelow as Tt,floorBounds as Et,floorIndex as Dt,getFloor as Ot,moveFloor as kt,removeFloor as At,renameFloor as jt,setFloor as Mt,setFloorHeight as Nt,updateFloor as Pt}from"./common/floorPlan/floorPlan.plan.mjs";import{deriveFaces as Ft,nodeDegrees as It}from"./common/floorPlan/floorPlan.faces.mjs";import{commitDerivation as Lt,derivePlan as Rt,pruneUnmatchedRooms as zt,roomAtPoint as Bt}from"./common/floorPlan/floorPlan.rooms.mjs";import{buildWallPaths as Vt,openingGeometry as Ht,wallCentrelineSpans as Ut}from"./common/floorPlan/floorPlan.path.mjs";import{HIT_PX as Wt,HIT_PX_COARSE as Gt,hitTest as Kt,selectionsEqual as qt,worldTolerances as Jt}from"./common/floorPlan/floorPlan.hit.mjs";import{DEFAULT_SNAP_OPTIONS as Yt,SnapKind as Xt,clientToWorld as Zt,resolveSnap as Qt}from"./common/floorPlan/floorPlan.snap.mjs";import{PLAN_FORMAT_VERSION as $t,planFromJson as en,planToJson as tn}from"./common/floorPlan/floorPlan.json.mjs";import{buildPlanMesh as nn}from"./common/floorPlan/floorPlan.mesh.mjs";import rn from"./common/iconPicker/iconPicker.mjs";import an from"./common/idleManager/idleManager.mjs";import on from"./common/inputDropdown/inputDropdown.mjs";import sn from"./common/kanbanBoard/KanbanColumn.mjs";import cn from"./common/kanbanBoard/KanbanBoard.mjs";import ln from"./common/searchInput/searchInput.mjs";import un from"./common/klipyPicker/klipyPicker.mjs";import dn from"./common/listItem/listItem.mjs";import fn from"./common/loadingOverlay/loadingOverlay.mjs";import pn from"./common/menu/menu.mjs";import{menuHotkeys as mn}from"./common/menu/menuHotkeys.mjs";import hn from"./common/multiSelect/multiSelect.mjs";import gn from"./common/numberInput/index.mjs";import{OtpInputCharset as _n}from"./common/otpInput/otpInput.types.mjs";import vn from"./common/otpInput/otpInput.mjs";import yn from"./common/overscroll/overscroll.mjs";import bn from"./common/pagination/pagination.mjs";import xn from"./common/progressBar/progressBar.mjs";import{RadioGroupOrientation as Sn}from"./common/radioGroup/radioGroup.types.mjs";import Cn from"./common/radioGroup/radioGroup.mjs";import wn from"./common/rating/rating.mjs";import Tn from"./common/revealLens/revealLens.mjs";import En from"./common/roomDrawer/roomDrawer.mjs";import Dn from"./common/roomViewer/roomViewer.mjs";import{ScrollFadeAxis as On}from"./common/scrollFade/scrollFade.types.mjs";import kn from"./common/scrollFade/scrollFade.mjs";import{SectionHeaderSize as An}from"./common/sectionHeader/sectionHeader.types.mjs";import jn from"./common/sectionHeader/sectionHeader.mjs";import{SkeletonAnimation as Mn,SkeletonVariant as Nn}from"./common/skeleton/skeleton.types.mjs";import Pn from"./common/skeleton/skeleton.mjs";import Fn from"./common/slider/slider.mjs";import In from"./common/splitButton/splitButton.mjs";import{StepperCollapse as Ln,StepperLabelPlacement as Rn,StepperOrientation as zn,StepperStyleType as Bn}from"./common/stepper/stepper.types.mjs";import Vn from"./common/stepper/stepper.mjs";import Hn from"./common/sticky/sticky.mjs";import Un from"./common/switch/switch.mjs";import Wn from"./common/tabHeader/tabHeader.mjs";import Gn from"./common/textarea/textarea.mjs";import{useTheme as Kn}from"./common/themeProvider/useTheme.mjs";import qn,{TiltGroupContext as Jn,useTiltGroup as Yn}from"./common/tiltGroup/tiltGroup.mjs";import{defaultTiltEasing as Xn}from"./common/tilt/tiltMath.mjs";import Zn from"./common/tilt/tilt.mjs";import Qn from"./common/timeInput/timeInput.mjs";import{TimelineAlignment as $n}from"./common/timeline/timeline.types.mjs";import er from"./common/timeline/timeline.mjs";import tr from"./common/timer/timer.mjs";import nr from"./common/virtualList/virtualList.mjs";import{flattenTree as rr}from"./common/tree/flattenTree.mjs";import ir from"./common/tree/tree.mjs";import{WeatherType as ar}from"./common/weatherIcon/weatherIcon.types.mjs";import or from"./common/weatherIcon/weatherIcon.mjs";import sr from"./common/wizard/wizard.mjs";import cr from"./services/formValidation/FormValidatorGroupWithForm.mjs";import lr from"./services/formValidation/validatableComponent.mjs";import{useFormValidatorGroup as ur}from"./services/formValidation/useFormValidatorGroup.mjs";import{FormValidator as dr,Validators as fr,useFormValidator as pr}from"./services/formValidation/index.mjs";import{hasEightPasswordChars as mr,hasOnePasswordDigit as hr,hasOnePasswordLetter as gr,isBic as _r,isDate as vr,isDay as yr,isEmail as br,isISODate as xr,isNumber as Sr,isPassword as Cr,isURL as wr}from"@ahrowe/form-validation";export{s as Accordion,e as AccordionStyleType,_ as ActionButtons,v as ActionIcon,O as AhroweProvider,k as Alert,A as AnimatedLogo,N as AnimatedText,j as AnimatedTextUnit,M as AnimatedTextVariant,L as Avatar,R as AvatarGroup,I as Badge,P as BadgePosition,F as BadgeStyleType,C as BodyEnd,q as Breadcrumb,g as Button,Y as ButtonGroup,J as ButtonGroupOrientation,u as ButtonSize,d as ButtonStyleType,f as ButtonType,re as Calendar,ee as CalendarView,ae as Card,le as CardActions,ce as CardContent,oe as CardHeader,se as CardMedia,ie as CardStyleType,ue as Carousel,de as ChatComposer,me as ChatMessage,he as ChatMessageList,fe as ChatMessageStatus,pe as ChatMessageStyleType,ge as Checkbox,ve as Chip,ye as ChipContainer,_e as ChipStyleType,we as ColorPicker,Ae as CommandPalette,t as ConfigProvider,je as ConfirmModal,Ne as CopyButton,Yt as DEFAULT_SNAP_OPTIONS,nt as DEFAULT_WALL_ATTRS,Re as DatePicker,Ve as Divider,ze as DividerOrientation,Be as DividerTextPosition,Ye as DoorSwing,He as Drawer,Ge as DropZone,Ue as DropZoneReturnType,We as DropZoneStatus,Le as Dropdown,te as EmptyState,Ke as ErrorBoundary,qe as Fab,Je as Flip,dr as FormValidator,cr as FormValidatorGroup,Wt as HIT_PX,Gt as HIT_PX_COARSE,rn as IconPicker,an as IdleManager,Ce as Input,on as InputDropdown,xe as InputIconPosition,Se as InputType,z as InteractableDiv,cn as KanbanBoard,sn as KanbanColumn,un as KlipyPicker,dn as ListItem,l as Loader,c as LoaderType,fn as LoadingOverlay,bt as MIN_FLOOR_HEIGHT,et as MIN_OPENING_WIDTH,tt as MIN_WALL_LENGTH,pn as Menu,Ee as Modal,hn as MultiSelect,gn as NumberInput,Xe as OpeningKind,ne as OptionPicker,vn as OtpInput,_n as OtpInputCharset,yn as Overscroll,$t as PLAN_FORMAT_VERSION,bn as Pagination,Ze as PlanIssueKind,Qe as PlanUnitSystem,K as Popover,B as PopoverAlign,V as PopoverPlacement,H as PopoverTrigger,a as Presentation,xn as ProgressBar,Cn as RadioGroup,Sn as RadioGroupOrientation,wn as Rating,Tn as RevealLens,p as Ripple,En as RoomDrawer,Dn as RoomViewer,kn as ScrollFade,On as ScrollFadeAxis,y as ScrollbarProvider,ln as SearchInput,jn as SectionHeader,An as SectionHeaderSize,Pn as Skeleton,Mn as SkeletonAnimation,Nn as SkeletonVariant,Fn as Slider,Xt as SnapKind,In as SplitButton,Vn as Stepper,Ln as StepperCollapse,Rn as StepperLabelPlacement,zn as StepperOrientation,Bn as StepperStyleType,Hn as Sticky,Un as Switch,Wn as TabHeader,Gn as Textarea,o as ThemeColor,x as ThemeProvider,Zn as Tilt,qn as TiltGroup,Jn as TiltGroupContext,Qn as TimeInput,er as Timeline,$n as TimelineAlignment,tr as Timer,be as Tooltip,ir as Tree,lr as ValidatableComponent,fr as Validators,nr as VirtualList,$e as WallType,or as WeatherIcon,ar as WeatherType,sr as Wizard,xt as addFloor,rt as addOpening,it as addRect,at as addWall,nn as buildPlanMesh,Vt as buildWallPaths,ot as cleanupPlan,Zt as clientToWorld,Lt as commitDerivation,X as dateToDay,Z as dateToTime,Q as dayTimeToDate,$ as dayToDate,b as defaultTheme,Xn as defaultTiltEasing,Ft as deriveFaces,Rt as derivePlan,st as detachWall,ct as dissolveNode,St as duplicateFloor,Ct as emptyFloor,wt as emptyFloorPlan,rr as flattenTree,Tt as floorBelow,Et as floorBounds,Dt as floorIndex,h as formatHotkey,Ot as getFloor,Pe as getLocale,mr as hasEightPasswordChars,hr as hasOnePasswordDigit,gr as hasOnePasswordLetter,Kt as hitTest,_r as isBic,vr as isDate,yr as isDay,br as isEmail,xr as isISODate,De as isMenuAction,Oe as isMenuHeading,ke as isMenuSeparator,Sr as isNumber,Cr as isPassword,wr as isURL,S as lightTheme,Fe as mapLocale,mn as menuHotkeys,lt as mergeNodes,kt as moveFloor,ut as moveNode,It as nodeDegrees,Ht as openingGeometry,en as planFromJson,tn as planToJson,zt as pruneUnmatchedRooms,At as removeFloor,dt as removeOpening,ft as removeWall,jt as renameFloor,Qt as resolveSnap,Bt as roomAtPoint,pt as scalePlan,qt as selectionsEqual,Mt as setFloor,Nt as setFloorHeight,Ie as setLocale,D as showToast,mt as splitWall,U as tabbablesIn,ht as transformPlan,Pt as updateFloor,gt as updateOpening,Me as useClipboard,T as useCoarsePointer,n as useComponentDefaults,pr as useFormValidator,ur as useFormValidatorGroup,m as useHotkeys,r as useLabels,w as useMediaQuery,G as useOverlay,i as usePresentationDefault,Te as useScrollEdges,E as useSwipeDismiss,Kn as useTheme,Yn as useTiltGroup,W as useVisualViewportSize,_t as validatePlan,Ut as wallCentrelineSpans,vt as wallLength,yt as weldShortWalls,Jt as worldTolerances};