@ahrowe/ui 0.36.0 → 0.38.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 (176) hide show
  1. package/README.md +6 -2
  2. package/dist/cjs-types/common/commandPalette/commandPalette.d.ts +4 -0
  3. package/dist/cjs-types/common/commandPalette/commandPalette.types.d.ts +42 -0
  4. package/dist/cjs-types/common/commandPalette/filterCommands.d.ts +15 -0
  5. package/dist/cjs-types/common/commandPalette/index.d.ts +2 -0
  6. package/dist/cjs-types/common/configProvider/configProvider.types.d.ts +6 -0
  7. package/dist/cjs-types/common/copyButton/copyButton.d.ts +4 -0
  8. package/dist/cjs-types/common/copyButton/copyButton.types.d.ts +36 -0
  9. package/dist/cjs-types/common/copyButton/index.d.ts +2 -0
  10. package/dist/cjs-types/common/errorBoundary/errorBoundary.d.ts +0 -3
  11. package/dist/cjs-types/common/errorBoundary/errorBoundary.types.d.ts +2 -3
  12. package/dist/cjs-types/common/hooks/index.d.ts +15 -0
  13. package/dist/cjs-types/common/hooks/useClipboard.d.ts +16 -0
  14. package/dist/cjs-types/common/hooks/useHotkeys.d.ts +45 -0
  15. package/dist/cjs-types/common/hooks/useSwipeDismiss.d.ts +6 -2
  16. package/dist/cjs-types/common/inputDropdown/inputDropdown.types.d.ts +7 -1
  17. package/dist/cjs-types/common/loading/index.d.ts +0 -1
  18. package/dist/cjs-types/common/menu/index.d.ts +1 -0
  19. package/dist/cjs-types/common/menu/menu.types.d.ts +11 -3
  20. package/dist/cjs-types/common/menu/menuHotkeys.d.ts +20 -0
  21. package/dist/cjs-types/common/popover/usePopoverPosition.d.ts +1 -0
  22. package/dist/cjs-types/common/sticky/sticky.d.ts +1 -1
  23. package/dist/cjs-types/common/sticky/sticky.types.d.ts +15 -0
  24. package/dist/cjs-types/common/sticky/stickyStack.d.ts +5 -0
  25. package/dist/cjs-types/common/themeProvider/themeProvider.d.ts +8 -7
  26. package/dist/cjs-types/common/utils/scrollAncestors.d.ts +10 -0
  27. package/dist/cjs-types/common/virtualList/scroller.d.ts +33 -0
  28. package/dist/cjs-types/common/virtualList/useRowDrag.d.ts +6 -1
  29. package/dist/cjs-types/common/virtualList/useRowNavigation.d.ts +11 -1
  30. package/dist/cjs-types/common/virtualList/useVirtualWindow.d.ts +22 -3
  31. package/dist/cjs-types/common/virtualList/virtualList.d.ts +1 -1
  32. package/dist/cjs-types/common/virtualList/virtualList.types.d.ts +43 -3
  33. package/dist/cjs-types/common/weatherIcon/index.d.ts +3 -0
  34. package/dist/cjs-types/common/weatherIcon/parts.d.ts +26 -0
  35. package/dist/cjs-types/common/weatherIcon/weatherIcon.d.ts +4 -0
  36. package/dist/cjs-types/common/weatherIcon/weatherIcon.types.d.ts +44 -0
  37. package/dist/cjs-types/index.d.ts +7 -0
  38. package/dist/esm/common/buttonGroup/buttonGroup.module.mjs.map +1 -1
  39. package/dist/esm/common/commandPalette/commandPalette.mjs +2 -0
  40. package/dist/esm/common/commandPalette/commandPalette.mjs.map +1 -0
  41. package/dist/esm/common/commandPalette/commandPalette.module.mjs +2 -0
  42. package/dist/esm/common/commandPalette/commandPalette.module.mjs.map +1 -0
  43. package/dist/esm/common/commandPalette/filterCommands.mjs +2 -0
  44. package/dist/esm/common/commandPalette/filterCommands.mjs.map +1 -0
  45. package/dist/esm/common/copyButton/copyButton.mjs +2 -0
  46. package/dist/esm/common/copyButton/copyButton.mjs.map +1 -0
  47. package/dist/esm/common/copyButton/copyButton.module.mjs +2 -0
  48. package/dist/esm/common/copyButton/copyButton.module.mjs.map +1 -0
  49. package/dist/esm/common/dropdown/dropdown.mjs +1 -1
  50. package/dist/esm/common/dropdown/dropdown.module.mjs.map +1 -1
  51. package/dist/esm/common/errorBoundary/errorBoundary.mjs +2 -2
  52. package/dist/esm/common/errorBoundary/errorBoundary.mjs.map +1 -1
  53. package/dist/esm/common/errorBoundary/errorBoundary.module.mjs +1 -1
  54. package/dist/esm/common/errorBoundary/errorBoundary.module.mjs.map +1 -1
  55. package/dist/esm/common/hooks/useClipboard.mjs +2 -0
  56. package/dist/esm/common/hooks/useClipboard.mjs.map +1 -0
  57. package/dist/esm/common/hooks/useHotkeys.mjs +2 -0
  58. package/dist/esm/common/hooks/useHotkeys.mjs.map +1 -0
  59. package/dist/esm/common/hooks/useSwipeDismiss.mjs +1 -1
  60. package/dist/esm/common/hooks/useSwipeDismiss.mjs.map +1 -1
  61. package/dist/esm/common/input/input.mjs +1 -1
  62. package/dist/esm/common/input/input.mjs.map +1 -1
  63. package/dist/esm/common/input/input.module.mjs +1 -1
  64. package/dist/esm/common/input/input.module.mjs.map +1 -1
  65. package/dist/esm/common/inputDropdown/inputDropdown.mjs +1 -1
  66. package/dist/esm/common/inputDropdown/inputDropdown.mjs.map +1 -1
  67. package/dist/esm/common/inputDropdown/inputDropdown.module.mjs +1 -1
  68. package/dist/esm/common/inputDropdown/inputDropdown.module.mjs.map +1 -1
  69. package/dist/esm/common/menu/menu.mjs +1 -1
  70. package/dist/esm/common/menu/menu.mjs.map +1 -1
  71. package/dist/esm/common/menu/menu.types.mjs.map +1 -1
  72. package/dist/esm/common/menu/menuHotkeys.mjs +2 -0
  73. package/dist/esm/common/menu/menuHotkeys.mjs.map +1 -0
  74. package/dist/esm/common/multiSelect/multiSelect.mjs +1 -1
  75. package/dist/esm/common/multiSelect/multiSelect.mjs.map +1 -1
  76. package/dist/esm/common/multiSelect/multiSelect.module.mjs +1 -1
  77. package/dist/esm/common/multiSelect/multiSelect.module.mjs.map +1 -1
  78. package/dist/esm/common/otpInput/otpInput.module.mjs.map +1 -1
  79. package/dist/esm/common/popover/usePopoverPosition.mjs +1 -1
  80. package/dist/esm/common/popover/usePopoverPosition.mjs.map +1 -1
  81. package/dist/esm/common/sticky/sticky.mjs +1 -1
  82. package/dist/esm/common/sticky/sticky.mjs.map +1 -1
  83. package/dist/esm/common/sticky/stickyStack.mjs +1 -1
  84. package/dist/esm/common/sticky/stickyStack.mjs.map +1 -1
  85. package/dist/esm/common/themeProvider/themeProvider.mjs +1 -1
  86. package/dist/esm/common/themeProvider/themeProvider.mjs.map +1 -1
  87. package/dist/esm/common/timer/timer.mjs +1 -1
  88. package/dist/esm/common/timer/timer.mjs.map +1 -1
  89. package/dist/esm/common/utils/scrollAncestors.mjs +1 -1
  90. package/dist/esm/common/utils/scrollAncestors.mjs.map +1 -1
  91. package/dist/esm/common/virtualList/scroller.mjs +2 -0
  92. package/dist/esm/common/virtualList/scroller.mjs.map +1 -0
  93. package/dist/esm/common/virtualList/useRowDrag.mjs +1 -1
  94. package/dist/esm/common/virtualList/useRowDrag.mjs.map +1 -1
  95. package/dist/esm/common/virtualList/useRowNavigation.mjs +1 -1
  96. package/dist/esm/common/virtualList/useRowNavigation.mjs.map +1 -1
  97. package/dist/esm/common/virtualList/useVirtualWindow.mjs +1 -1
  98. package/dist/esm/common/virtualList/useVirtualWindow.mjs.map +1 -1
  99. package/dist/esm/common/virtualList/virtualList.mjs +1 -1
  100. package/dist/esm/common/virtualList/virtualList.mjs.map +1 -1
  101. package/dist/esm/common/virtualList/virtualList.module.mjs +1 -1
  102. package/dist/esm/common/virtualList/virtualList.module.mjs.map +1 -1
  103. package/dist/esm/common/weatherIcon/parts.mjs +2 -0
  104. package/dist/esm/common/weatherIcon/parts.mjs.map +1 -0
  105. package/dist/esm/common/weatherIcon/weatherIcon.mjs +2 -0
  106. package/dist/esm/common/weatherIcon/weatherIcon.mjs.map +1 -0
  107. package/dist/esm/common/weatherIcon/weatherIcon.module.mjs +2 -0
  108. package/dist/esm/common/weatherIcon/weatherIcon.module.mjs.map +1 -0
  109. package/dist/esm/common/weatherIcon/weatherIcon.types.mjs +2 -0
  110. package/dist/esm/common/weatherIcon/weatherIcon.types.mjs.map +1 -0
  111. package/dist/esm/index.mjs +1 -1
  112. package/dist/index.cjs +3 -3
  113. package/dist/index.cjs.map +1 -1
  114. package/dist/style.css +1 -1
  115. package/dist/types/common/commandPalette/commandPalette.d.ts +4 -0
  116. package/dist/types/common/commandPalette/commandPalette.types.d.ts +42 -0
  117. package/dist/types/common/commandPalette/filterCommands.d.ts +15 -0
  118. package/dist/types/common/commandPalette/index.d.ts +2 -0
  119. package/dist/types/common/configProvider/configProvider.types.d.ts +6 -0
  120. package/dist/types/common/copyButton/copyButton.d.ts +4 -0
  121. package/dist/types/common/copyButton/copyButton.types.d.ts +36 -0
  122. package/dist/types/common/copyButton/index.d.ts +2 -0
  123. package/dist/types/common/errorBoundary/errorBoundary.d.ts +0 -3
  124. package/dist/types/common/errorBoundary/errorBoundary.types.d.ts +2 -3
  125. package/dist/types/common/hooks/index.d.ts +15 -0
  126. package/dist/types/common/hooks/useClipboard.d.ts +16 -0
  127. package/dist/types/common/hooks/useHotkeys.d.ts +45 -0
  128. package/dist/types/common/hooks/useSwipeDismiss.d.ts +6 -2
  129. package/dist/types/common/inputDropdown/inputDropdown.types.d.ts +7 -1
  130. package/dist/types/common/loading/index.d.ts +0 -1
  131. package/dist/types/common/menu/index.d.ts +1 -0
  132. package/dist/types/common/menu/menu.types.d.ts +11 -3
  133. package/dist/types/common/menu/menuHotkeys.d.ts +20 -0
  134. package/dist/types/common/popover/usePopoverPosition.d.ts +1 -0
  135. package/dist/types/common/sticky/sticky.d.ts +1 -1
  136. package/dist/types/common/sticky/sticky.types.d.ts +15 -0
  137. package/dist/types/common/sticky/stickyStack.d.ts +5 -0
  138. package/dist/types/common/themeProvider/themeProvider.d.ts +8 -7
  139. package/dist/types/common/utils/scrollAncestors.d.ts +10 -0
  140. package/dist/types/common/virtualList/scroller.d.ts +33 -0
  141. package/dist/types/common/virtualList/useRowDrag.d.ts +6 -1
  142. package/dist/types/common/virtualList/useRowNavigation.d.ts +11 -1
  143. package/dist/types/common/virtualList/useVirtualWindow.d.ts +22 -3
  144. package/dist/types/common/virtualList/virtualList.d.ts +1 -1
  145. package/dist/types/common/virtualList/virtualList.types.d.ts +43 -3
  146. package/dist/types/common/weatherIcon/index.d.ts +3 -0
  147. package/dist/types/common/weatherIcon/parts.d.ts +26 -0
  148. package/dist/types/common/weatherIcon/weatherIcon.d.ts +4 -0
  149. package/dist/types/common/weatherIcon/weatherIcon.types.d.ts +44 -0
  150. package/dist/types/index.d.ts +7 -0
  151. package/docs/ButtonGroup.md +2 -0
  152. package/docs/CLAUDE.md +6 -2
  153. package/docs/CommandPalette.md +84 -0
  154. package/docs/ConfigProvider.md +2 -2
  155. package/docs/CopyButton.md +45 -0
  156. package/docs/ErrorBoundary.md +4 -4
  157. package/docs/Fab.md +1 -2
  158. package/docs/Hooks.md +268 -0
  159. package/docs/InputDropdown.md +9 -4
  160. package/docs/Loading.md +56 -15
  161. package/docs/Menu.md +30 -6
  162. package/docs/Popover.md +2 -0
  163. package/docs/Sticky.md +22 -1
  164. package/docs/VirtualList.md +44 -4
  165. package/docs/WeatherIcon.md +49 -0
  166. package/package.json +1 -2
  167. package/dist/cjs-types/common/loading/iconLoading/iconLoading.d.ts +0 -5
  168. package/dist/cjs-types/common/loading/iconLoading/index.d.ts +0 -2
  169. package/dist/esm/common/loading/iconLoading/iconLoading.mjs +0 -2
  170. package/dist/esm/common/loading/iconLoading/iconLoading.mjs.map +0 -1
  171. package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs +0 -2
  172. package/dist/esm/common/loading/iconLoading/iconLoading.module.mjs.map +0 -1
  173. package/dist/esm/common/loading/iconLoading/index.mjs +0 -2
  174. package/dist/esm/common/loading/iconLoading/index.mjs.map +0 -1
  175. package/dist/types/common/loading/iconLoading/iconLoading.d.ts +0 -5
  176. package/dist/types/common/loading/iconLoading/index.d.ts +0 -2
@@ -1,5 +1,5 @@
1
1
  import { default as React } from 'react';
2
2
  import { VirtualListProps } from './virtualList.types.js';
3
3
  export { buildOffsets, findStartIndex, getVisibleRange, resolveReorderTarget, resolveTreeDropTarget, lastDescendantIndex, buildColumnTemplate, compareSortValues, isColumnSortable, isEmptySortValue, nextSort, sortItems, } from './virtualList.utils.js';
4
- declare function VirtualList<T>({ ref, items, renderRow, ariaRoles, columns, height, estimatedRowHeight, overscan, rowGap, rowPadding, selectedKey, getItemKey, onRowClick, keyboardNavigation, visibleColumnKeys, onVisibleColumnsChange, persistColumnsKey, resizableColumns, columnWidths, onColumnWidthsChange, labels, sort, defaultSort, onSortChange, showColumnToggle, onLoadMore, loadMoreThreshold, isLoading, multiSelect, selectedKeys, onSelectionChange, reorderable, onReorder, longPressDelay, treeReorder, getItemDepth, isGroup, onTreeDrop, treeIndentPx, dragHandle, showDivider, rowHover, className, style, classNames, styles: slotStyles, ...rest }: VirtualListProps<T>): React.JSX.Element;
4
+ declare function VirtualList<T>(props: VirtualListProps<T>): React.JSX.Element;
5
5
  export default VirtualList;
@@ -74,6 +74,13 @@ export interface VirtualListColumn<T> {
74
74
  */
75
75
  sortable?: boolean;
76
76
  }
77
+ /**
78
+ * What scrolls, when the list is not to scroll itself. `'nearest'` is the first
79
+ * ancestor set to scroll, the same one `Sticky` pins to; `'window'` is the page;
80
+ * an element (or a getter for one, for a ref that fills after the first render)
81
+ * names it outright.
82
+ */
83
+ export type VirtualListScrollParent = 'nearest' | 'window' | HTMLElement | (() => HTMLElement | null);
77
84
  export interface VirtualListScrollOptions {
78
85
  /** Where the target row lands in the viewport. Default: 'start'. */
79
86
  align?: 'start' | 'center' | 'end';
@@ -88,8 +95,18 @@ export interface VirtualListHandle {
88
95
  scrollToKey: (key: string | number, options?: VirtualListScrollOptions) => void;
89
96
  /** Scroll back to the top. */
90
97
  scrollToTop: (options?: Pick<VirtualListScrollOptions, 'behavior'>) => void;
91
- /** The underlying scroll container element, for advanced use. */
92
- getScrollElement: () => HTMLDivElement | null;
98
+ /**
99
+ * The element that scrolls: the list itself, or the `scrollParent` it was
100
+ * given. `null` for `scrollParent='window'`, where the page scrolls.
101
+ */
102
+ getScrollElement: () => HTMLElement | null;
103
+ /**
104
+ * Re-read where the list sits in its `scrollParent`. Only needed in that mode,
105
+ * and only when something *above* the list changed height without the list
106
+ * re-rendering: an element moving fires no event of its own, and the list
107
+ * would keep rendering the window it had before.
108
+ */
109
+ remeasure: () => void;
93
110
  /**
94
111
  * Re-measure `fit` columns on the next layout. Call this after an out-of-band
95
112
  * content change that doesn't flow through a new `items` array or `columns`
@@ -143,8 +160,22 @@ export interface VirtualListProps<T> extends HtmlProps {
143
160
  container: string;
144
161
  row: string;
145
162
  };
146
- /** Height of the scroll viewport. Defaults to '100%' to fill the parent container. */
163
+ /** Height of the scroll viewport. Defaults to '100%' to fill the parent container. Ignored with `scrollParent`. */
147
164
  height?: number | string;
165
+ /**
166
+ * Drops the list's own scrollbar: it renders at its full height in the page
167
+ * flow and virtualizes against whatever is given here, so a long list at the
168
+ * end of a scrolling page doesn't put a second scrollbar inside the first.
169
+ * `height` no longer applies. `'nearest'` covers most cases: it walks up to
170
+ * the first ancestor whose `overflow-y` is set to scroll, whether or not it
171
+ * currently does, and falls back to the page.
172
+ *
173
+ * The header still sticks, now to the top of that scrollport; give the list
174
+ * `--vl-header-top` to clear a fixed app bar. Rows of uneven height move the
175
+ * page's own scrollbar as they are measured, so set `estimatedRowHeight` to
176
+ * the real height where the rows have one.
177
+ */
178
+ scrollParent?: VirtualListScrollParent;
148
179
  /** Estimated row height before measurement. Default: 40. */
149
180
  estimatedRowHeight?: number;
150
181
  /** Extra rows to render above/below the visible window. Default: 3. */
@@ -187,6 +218,15 @@ export interface VirtualListProps<T> extends HtmlProps {
187
218
  * `Tree` does.
188
219
  */
189
220
  keyboardNavigation?: boolean;
221
+ /**
222
+ * Lets Tab carry on into the next row instead of leaving the list at the end
223
+ * of the current one, for a grid of inputs a user fills in field by field.
224
+ * Shift+Tab walks back the same way, and Tab out of the last row (or back out
225
+ * of the first) leaves the list as it always did. Default: false, because for
226
+ * a list that is read rather than filled in, one tab stop and the arrow keys
227
+ * are the expected behaviour, and 5000 rows of tab stops are a trap.
228
+ */
229
+ tabAcrossRows?: boolean;
190
230
  /** Controlled visible column keys. When provided, internal state is ignored. */
191
231
  visibleColumnKeys?: string[];
192
232
  /** Called when the user toggles a column in the popover. */
@@ -0,0 +1,3 @@
1
+ export { default } from './weatherIcon.js';
2
+ export { WeatherType } from './weatherIcon.types.js';
3
+ export type { WeatherIconLabels, WeatherIconProps } from './weatherIcon.types.js';
@@ -0,0 +1,26 @@
1
+ import { ReactElement } from 'react';
2
+ import { WeatherPartProps } from './weatherIcon.types.js';
3
+ /** Exported so a scene can clip what sits behind the cloud to this same silhouette. */
4
+ export declare const CLOUD_PATH = "M 26.3 62.9 C 15.4 65.0 15.0 48.5 27.8 49.8 C 23.9 43.9 34.2 34.0 43.0 39.6 C 46.0 26.2 73.9 32.0 68.9 46.3 C 85.0 44.3 84.6 64.2 72.4 62.5 Z";
5
+ export declare function Cloud({ className, delayed }: {
6
+ className?: string;
7
+ delayed?: boolean;
8
+ }): ReactElement;
9
+ export declare function Sun({ className }: {
10
+ className?: string;
11
+ }): ReactElement;
12
+ export declare function Moon({ className }: {
13
+ className?: string;
14
+ }): ReactElement;
15
+ export declare enum RainIntensity {
16
+ Light = "light",
17
+ Medium = "medium",
18
+ Heavy = "heavy"
19
+ }
20
+ export declare function Rain({ animated, intensity, }: WeatherPartProps & {
21
+ intensity?: RainIntensity;
22
+ }): ReactElement;
23
+ export declare function Snow({ animated }: WeatherPartProps): ReactElement;
24
+ export declare function Hail({ animated }: WeatherPartProps): ReactElement;
25
+ export declare function Fog(): ReactElement;
26
+ export declare function Lightning(): ReactElement;
@@ -0,0 +1,4 @@
1
+ import { ReactElement } from 'react';
2
+ import { WeatherIconProps } from './weatherIcon.types.js';
3
+ declare function WeatherIcon(props: WeatherIconProps): ReactElement;
4
+ export default WeatherIcon;
@@ -0,0 +1,44 @@
1
+ import { CSSProperties, SVGAttributes } from 'react';
2
+ import { DataProps } from '../types/slots.types.js';
3
+ export declare enum WeatherType {
4
+ Sunny = "sunny",
5
+ ClearNight = "clearNight",
6
+ Cloudy = "cloudy",
7
+ PartlyCloudy = "partlyCloudy",
8
+ PartlyCloudyNight = "partlyCloudyNight",
9
+ RainyLight = "rainyLight",
10
+ Rainy = "rainy",
11
+ RainyHeavy = "rainyHeavy",
12
+ Snowy = "snowy",
13
+ Hail = "hail",
14
+ Foggy = "foggy",
15
+ Thunderstorm = "thunderstorm"
16
+ }
17
+ /** The accessible name of each weather, read out by screen readers. */
18
+ export type WeatherIconLabels = Partial<Record<`${WeatherType}`, string>>;
19
+ /**
20
+ * The root is an `<svg>`, so the native attributes come from `SVGAttributes` rather than
21
+ * `HtmlProps`. Its `type` is the attribute of `<script>` and `<style>`, not of an `<svg>`.
22
+ */
23
+ export interface WeatherIconProps extends DataProps, Omit<SVGAttributes<SVGSVGElement>, 'type'> {
24
+ /**
25
+ * The weather to draw. Takes the enum or its string value, so an API's own enum with the same
26
+ * values passes as it is.
27
+ */
28
+ type: WeatherType | `${WeatherType}`;
29
+ /** Width and height, any CSS size. Default `64`. */
30
+ size?: number | string;
31
+ /**
32
+ * Default `true`. `false` draws a still frame, for small or repeated icons where the motion is
33
+ * too small to see but costs the same. Always still under `prefers-reduced-motion`.
34
+ */
35
+ animated?: boolean;
36
+ /** Text this component renders of its own. */
37
+ labels?: WeatherIconLabels;
38
+ className?: string;
39
+ style?: CSSProperties;
40
+ }
41
+ /** What a falling part needs to know to pick its still frame. */
42
+ export interface WeatherPartProps {
43
+ animated: boolean;
44
+ }
@@ -31,10 +31,14 @@ export { default as Chip } from './common/chip/index.js';
31
31
  export * from './common/chip/index.js';
32
32
  export { default as ColorPicker } from './common/colorPicker/index.js';
33
33
  export * from './common/colorPicker/index.js';
34
+ export { default as CommandPalette } from './common/commandPalette/index.js';
35
+ export * from './common/commandPalette/index.js';
34
36
  export { default as ConfigProvider } from './common/configProvider/index.js';
35
37
  export * from './common/configProvider/index.js';
36
38
  export { default as ConfirmModal } from './common/confirmModal/index.js';
37
39
  export * from './common/confirmModal/index.js';
40
+ export { default as CopyButton } from './common/copyButton/index.js';
41
+ export * from './common/copyButton/index.js';
38
42
  export { default as DatePicker } from './common/datePicker/index.js';
39
43
  export * from './common/datePicker/index.js';
40
44
  export { default as Divider } from './common/divider/index.js';
@@ -146,8 +150,11 @@ export { default as Tree } from './common/tree/index.js';
146
150
  export * from './common/tree/index.js';
147
151
  export { default as VirtualList } from './common/virtualList/index.js';
148
152
  export * from './common/virtualList/index.js';
153
+ export { default as WeatherIcon } from './common/weatherIcon/index.js';
154
+ export * from './common/weatherIcon/index.js';
149
155
  export { default as Wizard } from './common/wizard/index.js';
150
156
  export * from './common/wizard/index.js';
157
+ export * from './common/hooks/index.js';
151
158
  export { FormValidator, FormValidatorGroup, Validators, ValidatableComponent, useFormValidator, useFormValidatorGroup, } from './services/formValidation/index.js';
152
159
  export type { ValidationError, ValidatorFunction, ErrorParser, FormValidatorGroupOptions, InferGroupValues, MergedValues, } from './services/formValidation/index.js';
153
160
  export { mapLocale, setLocale, getLocale } from './services/localization.js';
@@ -1 +1 @@
1
- {"version":3,"file":"buttonGroup.module.mjs","names":[],"sources":["../../../../package/common/buttonGroup/buttonGroup.module.pcss"],"sourcesContent":[".buttonGroup {\n display: inline-flex;\n align-items: stretch;\n\n /* Each rule below targets its position with a pseudo-class (:first-child, :last-child, or\n :not()), which contributes extra specificity beyond a plain class selector. That's what\n reliably beats a child component's own base border-radius rule (e.g. Button's), regardless\n of which CSS module happens to load first in the final bundle — a plain \".buttonGroup > *\"\n reset would tie on specificity with Button's own class and depend on load order.\n\n Alongside the direct border-radius reset (for a child whose visible border lives right on\n its own root, e.g. Button), each rule also sets --group-radius-* custom properties. Unlike\n border-radius itself, custom properties inherit through every descendant regardless of\n nesting depth, so a child whose actual border lives on a nested element (e.g. Input's\n `fieldset`, buried inside a `<label>`) can flatten correctly too, as long as that nested\n element's own border-radius reads `var(--group-radius-tl, var(--default-border-radius))`\n etc. instead of hardcoding `var(--default-border-radius)` — see input.module.pcss.\n\n A nested ButtonGroup (role=\"group\") is excluded throughout: it manages its own corners and\n spacing internally, so the outer group only arranges it as a self-contained unit rather than\n reaching into it. */\n > *:not(:first-child):not(:last-child):not([role='group']) {\n border-radius: 0;\n\n --group-radius-tl: 0;\n --group-radius-tr: 0;\n --group-radius-br: 0;\n --group-radius-bl: 0;\n }\n\n > *:hover,\n > *:focus-within {\n z-index: 1;\n }\n\n &:not(&-vertical) {\n /* A separator (e.g. a vertical Divider) is meant to stay visible between two buttons, not\n merge into one of them, so it's excluded from the border-collapsing overlap below — and\n so is whatever comes right after one, since that overlap is only meant to collapse two\n adjacent button borders, not eat into the separator itself. A nested ButtonGroup is\n excluded the same way, and given real spacing instead, rather than being squeezed 1px\n into whatever's next to it. */\n > *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-left: -1px;\n }\n\n /* Matches the specificity of the collapse rule above (three :not()s deep, not two) so this\n reliably wins the override regardless of source order — the collapse rule's own three\n :not()s (:first-child, [role=separator], [role=group]) outweigh an adjacency selector with\n only one, so a fourth, redundant :not() is added here purely to close that gap. The\n trailing :not([role='group']) on both lines also keeps this from matching when the\n following element is itself a nested group — that case must fall through to the dedicated\n 8px group-spacing rule below, not get zeroed. */\n > [role='separator'] + *:not(:first-child):not([role='group']),\n > [role='group'] + *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-left: 0;\n }\n\n > [role='group']:not(:first-child) {\n margin-left: 8px;\n }\n\n > *:first-child:not(:last-child):not([role='group']) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n\n --group-radius-tr: 0;\n --group-radius-br: 0;\n }\n\n > *:last-child:not(:first-child):not([role='group']) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n\n --group-radius-tl: 0;\n --group-radius-bl: 0;\n }\n }\n\n &-vertical {\n flex-direction: column;\n\n > *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-top: -1px;\n }\n\n > [role='separator'] + *:not(:first-child):not([role='group']),\n > [role='group'] + *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-top: 0;\n }\n\n > [role='group']:not(:first-child) {\n margin-top: 8px;\n }\n\n > *:first-child:not(:last-child):not([role='group']) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n\n --group-radius-bl: 0;\n --group-radius-br: 0;\n }\n\n > *:last-child:not(:first-child):not([role='group']) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n\n --group-radius-tl: 0;\n --group-radius-tr: 0;\n }\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"buttonGroup.module.mjs","names":[],"sources":["../../../../package/common/buttonGroup/buttonGroup.module.pcss"],"sourcesContent":[".buttonGroup {\n display: inline-flex;\n align-items: stretch;\n\n /* At a fractional scale two overlapping borders round to different device pixels, so each seam\n keeps one: the earlier child clips its shared 1px, or the next one does while the earlier has\n the focus (docs/ButtonGroup.md). Reset per group so a nested one starts clean. */\n --group-clip-start: initial;\n --group-clip-end: initial;\n\n /* Each rule below targets its position with a pseudo-class (:first-child, :last-child, or\n :not()), which contributes extra specificity beyond a plain class selector. That's what\n reliably beats a child component's own base border-radius rule (e.g. Button's), regardless\n of which CSS module happens to load first in the final bundle — a plain \".buttonGroup > *\"\n reset would tie on specificity with Button's own class and depend on load order.\n\n Alongside the direct border-radius reset (for a child whose visible border lives right on\n its own root, e.g. Button), each rule also sets --group-radius-* custom properties. Unlike\n border-radius itself, custom properties inherit through every descendant regardless of\n nesting depth, so a child whose actual border lives on a nested element (e.g. Input's\n `fieldset`, buried inside a `<label>`) can flatten correctly too, as long as that nested\n element's own border-radius reads `var(--group-radius-tl, var(--default-border-radius))`\n etc. instead of hardcoding `var(--default-border-radius)` — see input.module.pcss.\n\n A nested ButtonGroup (role=\"group\") is excluded throughout: it manages its own corners and\n spacing internally, so the outer group only arranges it as a self-contained unit rather than\n reaching into it. */\n > *:not(:first-child):not(:last-child):not([role='group']) {\n border-radius: 0;\n\n --group-radius-tl: 0;\n --group-radius-tr: 0;\n --group-radius-br: 0;\n --group-radius-bl: 0;\n }\n\n > *:hover,\n > *:focus-within {\n z-index: 1;\n }\n\n &:not(&-vertical) {\n /* A separator (e.g. a vertical Divider) is meant to stay visible between two buttons, not\n merge into one of them, so it's excluded from the border-collapsing overlap below — and\n so is whatever comes right after one, since that overlap is only meant to collapse two\n adjacent button borders, not eat into the separator itself. A nested ButtonGroup is\n excluded the same way, and given real spacing instead, rather than being squeezed 1px\n into whatever's next to it. */\n > *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-left: -1px;\n }\n\n > *:not([role='separator']):not([role='group']):has(+ :not([role='separator']):not([role='group'])) {\n --group-clip-end: 1px;\n\n clip-path: inset(-100vmax var(--group-clip-end, -100vmax) -100vmax var(--group-clip-start, -100vmax));\n }\n\n > *:not([role='separator']):not([role='group']):has(+ :not([role='separator']):not([role='group'])):focus-within {\n --group-clip-end: initial;\n }\n\n > :focus-within:not([role='separator']):not([role='group']) + *:not([role='separator']):not([role='group']) {\n --group-clip-start: 1px;\n\n clip-path: inset(-100vmax var(--group-clip-end, -100vmax) -100vmax var(--group-clip-start, -100vmax));\n }\n\n /* Matches the specificity of the collapse rule above (three :not()s deep, not two) so this\n reliably wins the override regardless of source order — the collapse rule's own three\n :not()s (:first-child, [role=separator], [role=group]) outweigh an adjacency selector with\n only one, so a fourth, redundant :not() is added here purely to close that gap. The\n trailing :not([role='group']) on both lines also keeps this from matching when the\n following element is itself a nested group — that case must fall through to the dedicated\n 8px group-spacing rule below, not get zeroed. */\n > [role='separator'] + *:not(:first-child):not([role='group']),\n > [role='group'] + *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-left: 0;\n }\n\n > [role='group']:not(:first-child) {\n margin-left: 8px;\n }\n\n > *:first-child:not(:last-child):not([role='group']) {\n border-top-right-radius: 0;\n border-bottom-right-radius: 0;\n\n --group-radius-tr: 0;\n --group-radius-br: 0;\n }\n\n > *:last-child:not(:first-child):not([role='group']) {\n border-top-left-radius: 0;\n border-bottom-left-radius: 0;\n\n --group-radius-tl: 0;\n --group-radius-bl: 0;\n }\n }\n\n &-vertical {\n flex-direction: column;\n\n > *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-top: -1px;\n }\n\n > *:not([role='separator']):not([role='group']):has(+ :not([role='separator']):not([role='group'])) {\n --group-clip-end: 1px;\n\n clip-path: inset(var(--group-clip-start, -100vmax) -100vmax var(--group-clip-end, -100vmax) -100vmax);\n }\n\n > *:not([role='separator']):not([role='group']):has(+ :not([role='separator']):not([role='group'])):focus-within {\n --group-clip-end: initial;\n }\n\n > :focus-within:not([role='separator']):not([role='group']) + *:not([role='separator']):not([role='group']) {\n --group-clip-start: 1px;\n\n clip-path: inset(var(--group-clip-start, -100vmax) -100vmax var(--group-clip-end, -100vmax) -100vmax);\n }\n\n > [role='separator'] + *:not(:first-child):not([role='group']),\n > [role='group'] + *:not(:first-child):not([role='separator']):not([role='group']) {\n margin-top: 0;\n }\n\n > [role='group']:not(:first-child) {\n margin-top: 8px;\n }\n\n > *:first-child:not(:last-child):not([role='group']) {\n border-bottom-left-radius: 0;\n border-bottom-right-radius: 0;\n\n --group-radius-bl: 0;\n --group-radius-br: 0;\n }\n\n > *:last-child:not(:first-child):not([role='group']) {\n border-top-left-radius: 0;\n border-top-right-radius: 0;\n\n --group-radius-tl: 0;\n --group-radius-tr: 0;\n }\n }\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{renderIcon as n}from"../utils/renderIcon.mjs";import r from"../modal/modal.mjs";import{formatHotkey as ee}from"../hooks/useHotkeys.mjs";import{edgeIndex as i,nextIndex as a,scrollOptionIntoView as o}from"../utils/listNavigation.mjs";import{filterCommands as s,groupCommands as c}from"./filterCommands.mjs";import l from"./commandPalette.module.mjs";import{useEffect as u,useId as te,useRef as d,useState as f}from"react";import p from"classnames";import{faMagnifyingGlass as m}from"@fortawesome/free-solid-svg-icons";import{jsx as h,jsxs as g}from"react/jsx-runtime";var _={label:`Search commands`,placeholder:`Type a command or search…`,empty:`No results`,loading:`Searching…`,results:e=>e===1?`1 result`:`${e} results`};function v(v){let{items:y,isOpen:b,onClose:x,onAction:S,onQueryChange:C,filter:w=!0,isLoading:T=!1,presentation:E,labels:D,className:O,style:k,classNames:A,styles:j,...ne}=e(`CommandPalette`,v),M=t(`CommandPalette`,D,_),N=te(),P=d(null),[F,I]=f(``),[L,R]=f(null),[z,B]=f(b);b!==z&&(B(b),b&&(I(``),R(null)));let V=d(C);u(()=>{V.current=C}),u(()=>{b&&V.current?.(``)},[b]);let H=w?s(c(y),F):c(y),U=H.flatMap(e=>e.actions),W=e=>!!U[e]?.disabled,G=U.findIndex(e=>e.id===L&&!e.disabled),K=G>=0?G:i(`first`,U.length,{isDisabled:W}),q=e=>`${N}-${encodeURIComponent(e.id)}`,J=K===null?void 0:q(U[K]);u(()=>{J&&o(P.current,document.getElementById(J))},[J]);function Y(e){e&&!e.disabled&&(e.onClick?.(),S?.(e.id),x())}function X(e){if(!e.nativeEvent.isComposing){if(e.key===`ArrowDown`||e.key===`ArrowUp`){let t=a(K,e.key===`ArrowDown`?1:-1,U.length,{isDisabled:W});R(t===null?null:U[t].id)}else if(e.key===`Enter`)Y(K===null?void 0:U[K]);else return;e.preventDefault()}}let Z=F.trim()!==``,Q=T?M.loading:M.empty,$=-1;return g(r,{...ne,"aria-label":M.label,isOpen:b,onClose:x,hideHeader:!0,presentation:E,className:p(l.commandPalette,O,A?.root),style:{...k,...j?.root},children:[g(`div`,{className:p(l.commandPaletteSearch,A?.search),style:j?.search,children:[n(m,{className:l.commandPaletteSearchIcon}),h(`input`,{type:`text`,role:`combobox`,"aria-label":M.label,"aria-expanded":`true`,"aria-controls":N,"aria-autocomplete":`list`,"aria-activedescendant":J,autoComplete:`off`,spellCheck:!1,placeholder:M.placeholder,value:F,onChange:e=>{I(e.target.value),R(null),C?.(e.target.value)},onKeyDown:X,className:p(l.commandPaletteInput,A?.input),style:j?.input})]}),h(`div`,{ref:P,id:N,role:`listbox`,"aria-label":M.label,className:p(l.commandPaletteList,A?.list),style:j?.list,children:H.map((e,t)=>{let r=`${N}-heading-${t}`;return g(`div`,{role:e.heading===void 0?`presentation`:`group`,"aria-labelledby":e.heading===void 0?void 0:r,children:[e.separated&&t>0&&h(`div`,{"aria-hidden":!0,className:p(l.commandPaletteSeparator,A?.separator),style:j?.separator}),e.heading!==void 0&&h(`div`,{id:r,role:`presentation`,className:p(l.commandPaletteHeading,A?.heading),style:j?.heading,children:e.heading}),e.actions.map(e=>{$+=1;let t=$;return g(`div`,{id:q(e),role:`option`,"aria-selected":t===K,"aria-disabled":e.disabled||void 0,className:p(l.commandPaletteItem,t===K&&l.commandPaletteItemActive,e.danger&&l.commandPaletteItemDanger,e.disabled&&l.commandPaletteItemDisabled,A?.item),style:j?.item,onMouseDown:e=>e.preventDefault(),onMouseMove:()=>!e.disabled&&R(e.id),onClick:()=>Y(e),children:[e.icon!=null&&n(e.icon,{className:p(l.commandPaletteItemIcon,A?.itemIcon),style:j?.itemIcon}),h(`span`,{className:p(l.commandPaletteItemLabel,A?.itemLabel),style:j?.itemLabel,children:e.label}),e.shortcut!=null&&h(`span`,{className:p(l.commandPaletteItemShortcut,A?.itemShortcut),style:j?.itemShortcut,children:ee(e.shortcut)})]},e.id)})]},t)})}),Z&&U.length===0&&h(`div`,{className:p(l.commandPaletteEmpty,A?.empty),style:j?.empty,children:Q}),h(`span`,{className:l.commandPaletteStatus,role:`status`,"aria-live":`polite`,children:Z?U.length>0?M.results(U.length):Q:``})]})}export{v as default};
2
+ //# sourceMappingURL=commandPalette.mjs.map
@@ -0,0 +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 { formatHotkey } from '../hooks/useHotkeys';\nimport { edgeIndex, nextIndex, scrollOptionIntoView } from '../utils/listNavigation';\nimport { renderIcon } from '../utils/renderIcon';\nimport type { MenuAction } from '../menu/menu.types';\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 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 action.onClick?.();\n onAction?.(action.id);\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 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 {action.icon != null &&\n renderIcon(action.icon, {\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 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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"}
@@ -0,0 +1,2 @@
1
+ "use client";var e=`commandPalette_YtQdV`,t=`commandPalette-search_FII6k`,n=`commandPalette-search-icon_acfcm`,r=`commandPalette-input_Vb3da`,i=`commandPalette-list_93yGm`,a=`commandPalette-item_oa2PX`,o=`commandPalette-item-active_9KaV-`,s=`commandPalette-item-danger_VP4If`,c=`commandPalette-item-disabled_hiHzA`,l=`commandPalette-item-icon_N4L26`,u=`commandPalette-item-label_cy-ke`,d=`commandPalette-item-shortcut_G2KPh`,f=`commandPalette-heading_ONebI`,p=`commandPalette-separator_Yu8TJ`,m=`commandPalette-empty_LqVAt`,h=`commandPalette-status_rft-N`,g={commandPalette:e,"commandPalette-search":`commandPalette-search_FII6k`,commandPaletteSearch:t,"commandPalette-search-icon":`commandPalette-search-icon_acfcm`,commandPaletteSearchIcon:n,"commandPalette-input":`commandPalette-input_Vb3da`,commandPaletteInput:r,"commandPalette-list":`commandPalette-list_93yGm`,commandPaletteList:i,"commandPalette-item":`commandPalette-item_oa2PX`,commandPaletteItem:a,"commandPalette-item-active":`commandPalette-item-active_9KaV-`,commandPaletteItemActive:o,"commandPalette-item-danger":`commandPalette-item-danger_VP4If`,commandPaletteItemDanger:s,"commandPalette-item-disabled":`commandPalette-item-disabled_hiHzA`,commandPaletteItemDisabled:c,"commandPalette-item-icon":`commandPalette-item-icon_N4L26`,commandPaletteItemIcon:l,"commandPalette-item-label":`commandPalette-item-label_cy-ke`,commandPaletteItemLabel:u,"commandPalette-item-shortcut":`commandPalette-item-shortcut_G2KPh`,commandPaletteItemShortcut:d,"commandPalette-heading":`commandPalette-heading_ONebI`,commandPaletteHeading:f,"commandPalette-separator":`commandPalette-separator_Yu8TJ`,commandPaletteSeparator:p,"commandPalette-empty":`commandPalette-empty_LqVAt`,commandPaletteEmpty:m,"commandPalette-status":`commandPalette-status_rft-N`,commandPaletteStatus:h};export{e as commandPalette,m as commandPaletteEmpty,f as commandPaletteHeading,r as commandPaletteInput,a as commandPaletteItem,o as commandPaletteItemActive,s as commandPaletteItemDanger,c as commandPaletteItemDisabled,l as commandPaletteItemIcon,u as commandPaletteItemLabel,d as commandPaletteItemShortcut,i as commandPaletteList,t as commandPaletteSearch,n as commandPaletteSearchIcon,p as commandPaletteSeparator,h as commandPaletteStatus,g as default};
2
+ //# sourceMappingURL=commandPalette.module.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"commandPalette.module.mjs","names":[],"sources":["../../../../package/common/commandPalette/commandPalette.module.pcss"],"sourcesContent":[".commandPalette {\n --modal-padding: var(--spacing-s);\n --modal-body-bleed: 0;\n\n width: 640px;\n\n /* Near the top rather than centred, so the panel does not jump as the list shrinks while\n typing. A sheet overrides both with its own doubled selector. */\n align-self: flex-start;\n margin-top: 12vh;\n\n &-search {\n display: flex;\n align-items: center;\n gap: var(--spacing-s);\n padding: var(--spacing-s) var(--spacing-m);\n border-bottom: 1px solid var(--border-color);\n\n &-icon {\n flex: none;\n color: var(--text-light);\n }\n }\n\n &-input {\n flex: 1;\n min-width: 0;\n padding: 4px 0;\n border: none;\n outline: none;\n background: transparent;\n font: inherit;\n font-size: 1.1em;\n color: var(--text-color);\n\n &::placeholder {\n color: var(--text-light);\n }\n }\n\n &-list {\n max-height: min(24rem, 60vh);\n max-height: min(24rem, 60dvh);\n overflow-y: auto;\n padding: 4px 0;\n\n &:empty {\n display: none;\n }\n }\n\n &-item {\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 8px 12px;\n border-radius: var(--default-border-radius);\n color: var(--text-color);\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n /* Same token as Menu's highlight: `--background-accent-light` matches the modal surface in\n the default theme. */\n &-active {\n background: var(--background-accent);\n }\n\n &-danger {\n color: var(--error-color);\n }\n\n &-disabled {\n opacity: 0.45;\n cursor: default;\n }\n\n &-icon {\n flex: none;\n width: 1em;\n text-align: center;\n }\n\n &-label {\n flex: 1;\n overflow: hidden;\n text-overflow: ellipsis;\n }\n\n &-shortcut {\n flex: none;\n margin-left: 16px;\n font-size: 0.85em;\n color: var(--text-light);\n }\n }\n\n &-heading {\n padding: 10px 12px 4px;\n font-size: 0.8em;\n font-weight: 600;\n text-transform: uppercase;\n letter-spacing: 0.04em;\n color: var(--text-light);\n }\n\n &-separator {\n height: 1px;\n margin: 4px 0;\n background: var(--border-color);\n }\n\n &-empty {\n padding: var(--spacing-l) var(--spacing-m);\n text-align: center;\n color: var(--text-light);\n }\n\n &-status {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ "use client";import{isMenuAction as e,isMenuHeading as t}from"../menu/menu.types.mjs";function n(e){return e.normalize(`NFD`).replace(/\p{Diacritic}/gu,``).toLowerCase()}function r(n){let r=[],i={separated:!1,actions:[]},a=()=>{(i.heading!==void 0||i.actions.length>0)&&r.push(i)};for(let r of n){if(e(r)){i.actions.push(r);continue}a(),i=t(r)?{heading:r.heading,separated:i.separated&&i.actions.length===0,actions:[]}:{separated:!0,actions:[]}}return a(),r.filter(e=>e.actions.length>0)}function i(e,t,r){let i=typeof e.label==`string`?n(e.label):``,a=(e.keywords??[]).map(n),o=[i,...a].join(` `);if(!t.every(e=>o.includes(e)))return null;if(i.startsWith(r))return 0;let s=e=>e.split(/\s+/).some(e=>e.startsWith(t[0]));return s(i)||a.some(s)?1:2}function a(e,t){let r=n(t.trim());if(!r)return e;let a=r.split(/\s+/);return e.map(e=>{let t=e.actions.map(e=>({action:e,rank:i(e,a,r)})).filter(e=>e.rank!==null).sort((e,t)=>e.rank-t.rank);return t.length===0?null:{group:{...e,separated:!1,actions:t.map(e=>e.action)},best:t[0].rank}}).filter(e=>e!==null).sort((e,t)=>e.best-t.best).map(e=>e.group)}export{a as filterCommands,r as groupCommands};
2
+ //# sourceMappingURL=filterCommands.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"filterCommands.mjs","names":[],"sources":["../../../../package/common/commandPalette/filterCommands.ts"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { isMenuAction, isMenuHeading, type MenuAction, type MenuEntry } from '../menu/menu.types';\n\nexport interface CommandGroup {\n heading?: ReactNode;\n /** Whether a separator started this group, so the divider can be drawn above it. */\n separated: boolean;\n actions: MenuAction[];\n}\n\n// Lower-cased and stripped of accents, so \"uber\" finds \"Übersicht\".\nfunction normalize(text: string): string {\n return text\n .normalize('NFD')\n .replace(/\\p{Diacritic}/gu, '')\n .toLowerCase();\n}\n\n/** Splits entries into groups at each heading and separator, keeping their order. */\nexport function groupCommands(items: MenuEntry[]): CommandGroup[] {\n const groups: CommandGroup[] = [];\n let current: CommandGroup = { separated: false, actions: [] };\n const flush = () => {\n if (current.heading !== undefined || current.actions.length > 0) groups.push(current);\n };\n for (const entry of items) {\n if (isMenuAction(entry)) {\n current.actions.push(entry);\n continue;\n }\n flush();\n current = isMenuHeading(entry)\n ? { heading: entry.heading, separated: current.separated && current.actions.length === 0, actions: [] }\n : { separated: true, actions: [] };\n }\n flush();\n return groups.filter((group) => group.actions.length > 0);\n}\n\n/**\n * 0 when the label starts with the query, 1 when a word of the label or a keyword does, 2 for any\n * other match, `null` when a query word is missing from both the label and the keywords.\n *\n * A label that is not a string cannot be read, so such an action is found through its keywords only.\n */\nfunction rank(action: MenuAction, words: string[], query: string): number | null {\n const label = typeof action.label === 'string' ? normalize(action.label) : '';\n const keywords = (action.keywords ?? []).map(normalize);\n const haystack = [label, ...keywords].join(' ');\n if (!words.every((word) => haystack.includes(word))) return null;\n if (label.startsWith(query)) return 0;\n const hasWordStartingWith = (text: string) => text.split(/\\s+/).some((word) => word.startsWith(words[0]));\n if (hasWordStartingWith(label) || keywords.some(hasWordStartingWith)) return 1;\n return 2;\n}\n\ninterface RankedGroup {\n group: CommandGroup;\n best: number;\n}\n\n/**\n * The groups with only the actions matching `query`, best matches first within each group, and\n * the group holding the best match first. A heading moves with its group, never away from it.\n */\nexport function filterCommands(groups: CommandGroup[], query: string): CommandGroup[] {\n const normalized = normalize(query.trim());\n if (!normalized) return groups;\n const words = normalized.split(/\\s+/);\n\n // Both sorts rely on `Array.prototype.sort` being stable, so ties keep the order they were given in.\n return groups\n .map((group): RankedGroup | null => {\n const matches = group.actions\n .map((action) => ({ action, rank: rank(action, words, normalized) }))\n .filter((match): match is { action: MenuAction; rank: number } => match.rank !== null)\n .sort((a, b) => a.rank - b.rank);\n if (matches.length === 0) return null;\n return {\n // Separators are dropped while filtering: the headings still say where one group ends.\n group: { ...group, separated: false, actions: matches.map((match) => match.action) },\n best: matches[0].rank,\n };\n })\n .filter((ranked): ranked is RankedGroup => ranked !== null)\n .sort((a, b) => a.best - b.best)\n .map((ranked) => ranked.group);\n}\n"],"mappings":"sFAWA,SAAS,EAAU,EAAsB,CACvC,OAAO,EACJ,UAAU,KAAK,CAAC,CAChB,QAAQ,kBAAmB,EAAE,CAAC,CAC9B,YAAY,CACjB,CAGA,SAAgB,EAAc,EAAoC,CAChE,IAAM,EAAyB,CAAC,EAC5B,EAAwB,CAAE,UAAW,GAAO,QAAS,CAAC,CAAE,EACtD,MAAc,EACd,EAAQ,UAAY,IAAA,IAAa,EAAQ,QAAQ,OAAS,IAAG,EAAO,KAAK,CAAO,CACtF,EACA,IAAK,IAAM,KAAS,EAAO,CACzB,GAAI,EAAa,CAAK,EAAG,CACvB,EAAQ,QAAQ,KAAK,CAAK,EAC1B,QACF,CACA,EAAM,EACN,EAAU,EAAc,CAAK,EACzB,CAAE,QAAS,EAAM,QAAS,UAAW,EAAQ,WAAa,EAAQ,QAAQ,SAAW,EAAG,QAAS,CAAC,CAAE,EACpG,CAAE,UAAW,GAAM,QAAS,CAAC,CAAE,CACrC,CAEA,OADA,EAAM,EACC,EAAO,OAAQ,GAAU,EAAM,QAAQ,OAAS,CAAC,CAC1D,CAQA,SAAS,EAAK,EAAoB,EAAiB,EAA8B,CAC/E,IAAM,EAAQ,OAAO,EAAO,OAAU,SAAW,EAAU,EAAO,KAAK,EAAI,GACrE,GAAY,EAAO,UAAY,CAAC,EAAA,CAAG,IAAI,CAAS,EAChD,EAAW,CAAC,EAAO,GAAG,CAAQ,CAAC,CAAC,KAAK,GAAG,EAC9C,GAAI,CAAC,EAAM,MAAO,GAAS,EAAS,SAAS,CAAI,CAAC,EAAG,OAAO,KAC5D,GAAI,EAAM,WAAW,CAAK,EAAG,MAAO,GACpC,IAAM,EAAuB,GAAiB,EAAK,MAAM,KAAK,CAAC,CAAC,KAAM,GAAS,EAAK,WAAW,EAAM,EAAE,CAAC,EAExG,OADI,EAAoB,CAAK,GAAK,EAAS,KAAK,CAAmB,EAAU,EACtE,CACT,CAWA,SAAgB,EAAe,EAAwB,EAA+B,CACpF,IAAM,EAAa,EAAU,EAAM,KAAK,CAAC,EACzC,GAAI,CAAC,EAAY,OAAO,EACxB,IAAM,EAAQ,EAAW,MAAM,KAAK,EAGpC,OAAO,EACJ,IAAK,GAA8B,CAClC,IAAM,EAAU,EAAM,QACnB,IAAK,IAAY,CAAE,SAAQ,KAAM,EAAK,EAAQ,EAAO,CAAU,CAAE,EAAE,CAAC,CACpE,OAAQ,GAAyD,EAAM,OAAS,IAAI,CAAC,CACrF,MAAM,EAAG,IAAM,EAAE,KAAO,EAAE,IAAI,EAEjC,OADI,EAAQ,SAAW,EAAU,KAC1B,CAEL,MAAO,CAAE,GAAG,EAAO,UAAW,GAAO,QAAS,EAAQ,IAAK,GAAU,EAAM,MAAM,CAAE,EACnF,KAAM,EAAQ,EAAE,CAAC,IACnB,CACF,CAAC,CAAC,CACD,OAAQ,GAAkC,IAAW,IAAI,CAAC,CAC1D,MAAM,EAAG,IAAM,EAAE,KAAO,EAAE,IAAI,CAAC,CAC/B,IAAK,GAAW,EAAO,KAAK,CACjC"}
@@ -0,0 +1,2 @@
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{useLabels as t}from"../configProvider/useLabels.mjs";import{isIconDefinition as n,renderIcon as r}from"../utils/renderIcon.mjs";import i from"../actionIcon/actionIcon.mjs";import a from"../animatedIcon/animatedIcon.mjs";import o from"../hooks/useClipboard.mjs";import s from"./copyButton.module.mjs";import c from"classnames";import{faCheck as l,faCopy as u}from"@fortawesome/free-solid-svg-icons";import{Fragment as d,jsx as f,jsxs as p}from"react/jsx-runtime";var m={copy:`Copy`,copied:`Copied`,failed:`Could not copy`};function h(h){let{value:g,timeout:_=2e3,icon:v=u,copiedIcon:y=l,onCopy:b,onError:x,onClick:S,labels:C,className:w,style:T,classNames:E,styles:D,...O}=e(`CopyButton`,h),k=t(`CopyButton`,C,m),{copy:A,copied:j,error:M}=o({timeout:_}),N=j?k.copied:k.copy,P=j?y:v,F=n(v)&&n(y)?f(a,{icon:j?y:v,classNames:{icon:E?.icon},styles:{icon:D?.icon}}):r(P,{className:E?.icon,style:D?.icon});return p(d,{children:[f(i,{...O,icon:f(d,{children:F}),title:N,"aria-label":N,className:c(s.copyButton,j&&s.copyButtonCopied,w),style:T,classNames:{root:E?.root},styles:{root:D?.root},onClick:async e=>{S?.(e),await A(g)?b?.(g):x?.()}}),f(`span`,{className:s.copyButtonStatus,role:`status`,"aria-live":`polite`,children:j?k.copied:M?k.failed:``})]})}export{h as default};
2
+ //# sourceMappingURL=copyButton.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyButton.mjs","names":[],"sources":["../../../../package/common/copyButton/copyButton.tsx"],"sourcesContent":["import type { ReactElement } from 'react';\nimport cx from 'classnames';\nimport { faCheck, faCopy } from '@fortawesome/free-solid-svg-icons';\n\nimport ActionIcon from '../actionIcon';\nimport AnimatedIcon from '../animatedIcon';\nimport { useComponentDefaults, useLabels } from '../configProvider';\nimport { useClipboard } from '../hooks/useClipboard';\nimport { isIconDefinition, renderIcon } from '../utils/renderIcon';\nimport type { CopyButtonLabels, CopyButtonProps } from './copyButton.types';\nimport styles from './copyButton.module.pcss';\n\nconst DEFAULT_LABELS: Required<CopyButtonLabels> = {\n copy: 'Copy',\n copied: 'Copied',\n failed: 'Could not copy',\n};\n\nfunction CopyButton(props: CopyButtonProps): ReactElement {\n const {\n value,\n timeout = 2000,\n icon = faCopy,\n copiedIcon = faCheck,\n onCopy,\n onError,\n onClick,\n labels,\n className,\n style,\n classNames,\n styles: slotStyles,\n ...rest\n } = useComponentDefaults('CopyButton', props);\n const text = useLabels('CopyButton', labels, DEFAULT_LABELS);\n const { copy, copied, error } = useClipboard({ timeout });\n\n const label = copied ? text.copied : text.copy;\n const current = copied ? copiedIcon : icon;\n const iconElement =\n isIconDefinition(icon) && isIconDefinition(copiedIcon) ? (\n <AnimatedIcon\n icon={copied ? copiedIcon : icon}\n classNames={{ icon: classNames?.icon }}\n styles={{ icon: slotStyles?.icon }}\n />\n ) : (\n renderIcon(current, { className: classNames?.icon, style: slotStyles?.icon })\n );\n\n return (\n <>\n <ActionIcon\n {...rest}\n icon={<>{iconElement}</>}\n title={label}\n aria-label={label}\n className={cx(styles.copyButton, copied && styles.copyButtonCopied, className)}\n style={style}\n classNames={{ root: classNames?.root }}\n styles={{ root: slotStyles?.root }}\n onClick={async (event) => {\n onClick?.(event);\n if (await copy(value)) onCopy?.(value);\n else onError?.();\n }}\n />\n {/* Beside the button, not in it: a live region inside role=\"button\" is not reliably announced. */}\n <span className={styles.copyButtonStatus} role='status' aria-live='polite'>\n {copied ? text.copied : error ? text.failed : ''}\n </span>\n </>\n );\n}\n\nexport default CopyButton;\n"],"mappings":"ojBAYA,IAAM,EAA6C,CACjD,KAAM,OACN,OAAQ,SACR,OAAQ,gBACV,EAEA,SAAS,EAAW,EAAsC,CACxD,GAAM,CACJ,QACA,UAAU,IACV,OAAO,EACP,aAAa,EACb,SACA,UACA,UACA,SACA,YACA,QACA,aACA,OAAQ,EACR,GAAG,GACD,EAAqB,aAAc,CAAK,EACtC,EAAO,EAAU,aAAc,EAAQ,CAAc,EACrD,CAAE,OAAM,SAAQ,SAAU,EAAa,CAAE,SAAQ,CAAC,EAElD,EAAQ,EAAS,EAAK,OAAS,EAAK,KACpC,EAAU,EAAS,EAAa,EAChC,EACJ,EAAiB,CAAI,GAAK,EAAiB,CAAU,EACnD,EAAC,EAAD,CACE,KAAM,EAAS,EAAa,EAC5B,WAAY,CAAE,KAAM,GAAY,IAAK,EACrC,OAAQ,CAAE,KAAM,GAAY,IAAK,CAClC,CAAA,EAED,EAAW,EAAS,CAAE,UAAW,GAAY,KAAM,MAAO,GAAY,IAAK,CAAC,EAGhF,OACE,EAAA,EAAA,CAAA,SAAA,CACE,EAAC,EAAD,CACE,GAAI,EACJ,KAAM,EAAA,EAAA,CAAA,SAAG,CAAc,CAAA,EACvB,MAAO,EACP,aAAY,EACZ,UAAW,EAAG,EAAO,WAAY,GAAU,EAAO,iBAAkB,CAAS,EACtE,QACP,WAAY,CAAE,KAAM,GAAY,IAAK,EACrC,OAAQ,CAAE,KAAM,GAAY,IAAK,EACjC,QAAS,KAAO,IAAU,CACxB,IAAU,CAAK,EACX,MAAM,EAAK,CAAK,EAAG,IAAS,CAAK,EAChC,IAAU,CACjB,CACD,CAAA,EAED,EAAC,OAAD,CAAM,UAAW,EAAO,iBAAkB,KAAK,SAAS,YAAU,SAC/D,SAAA,EAAS,EAAK,OAAS,EAAQ,EAAK,OAAS,EAC1C,CAAA,CACN,CAAA,CAAA,CAEN"}
@@ -0,0 +1,2 @@
1
+ "use client";var e=`copyButton_HEd1K`,t=`copyButton-copied_HL1zN`,n=`copyButton-status_QdwYf`,r={copyButton:e,"copyButton-copied":`copyButton-copied_HL1zN`,copyButtonCopied:t,"copyButton-status":`copyButton-status_QdwYf`,copyButtonStatus:n};export{e as copyButton,t as copyButtonCopied,n as copyButtonStatus,r as default};
2
+ //# sourceMappingURL=copyButton.module.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copyButton.module.mjs","names":[],"sources":["../../../../package/common/copyButton/copyButton.module.pcss"],"sourcesContent":[".copyButton {\n /* As a block, AnimatedIcon's inline-block box sits on a text baseline and rides high. */\n display: inline-flex;\n\n &-copied {\n color: var(--success-color);\n }\n\n &-status {\n position: absolute;\n width: 1px;\n height: 1px;\n padding: 0;\n border: 0;\n clip-path: inset(50%);\n overflow: hidden;\n white-space: nowrap;\n }\n}\n"],"mappings":""}
@@ -1,2 +1,2 @@
1
- "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import{Presentation as n}from"../configProvider/presentation.types.mjs";import r from"../loading/spinnerLoading/index.mjs";import i from"../styles/sheet.module.mjs";import{PopoverAlign as ee,PopoverPlacement as te}from"../popover/popover.types.mjs";import ne from"../hooks/useSheet.mjs";import re from"../popover/popover.mjs";import ie from"../tooltip/tooltip.mjs";import{useInfiniteScroll as ae}from"../infiniteBlock/useInfiniteScroll.mjs";import{edgeIndex as oe,nextIndex as se,scrollOptionIntoView as ce}from"../utils/listNavigation.mjs";import a from"./dropdown.module.mjs";import{useEffect as o,useId as le,useLayoutEffect as ue,useRef as s,useState as c}from"react";import l from"classnames";import{FontAwesomeIcon as de}from"@fortawesome/react-fontawesome";import{faChevronDown as fe}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var pe=500;function f(f){let{errorMessage:p=``,className:me=``,style:he,label:m=``,value:ge=``,isValid:_e=!0,tabIndex:ve=0,isRequired:ye=!1,customProps:h={},isRow:be=!1,disabled:g=!1,readOnly:_=!1,onScroll:xe=()=>Promise.resolve(),onClick:v,onChange:y,onFocus:Se=null,onBlur:Ce=null,onMouseEnter:we=null,onMouseLeave:Te=null,dropdownLabel:Ee,isDropdownListWider:b=!1,formValidator:x=null,classNames:S,styles:C,items:w=[],useMatLabelStyle:T=!0,alwaysFloatLabel:E=!1,placeholder:D=``,plainStyle:O=!1,scrollToSelected:De=!1,presentation:Oe,reactRef:ke,...Ae}=e(`Dropdown`,f),[je,Me]=c(!1),[Ne,Pe]=c(!1),[,Fe]=c(0),k=s(x),A=s(null),j=s(null),M=s(null),[Ie,Le]=c(!1),[N,P]=c(null),F=s({buffer:``,at:0}),I=le(),L=`${I}-listbox`,R=`${I}-label`,z=e=>`${I}-option-${e}`,B=!g&&!_,V=Ie&&B,{isLoading:Re,sentinelRef:ze}=ae(M,xe,!1),Be=t(),H=Oe??Be??n.Default,{isSheet:U}=ne(H);ue(()=>{let e=A.current,t=j.current;V&&!U&&e&&t&&(t.style.fontSize=window.getComputedStyle(e).fontSize)},[V,U]),o(()=>{if(k.current=x,!k.current)return;k.current.label=m??``,k.current.validate();let e=()=>Fe(e=>e+1);return k.current.registerOnUpdateListener(e),()=>k.current?.removeOnUpdateListener(e)},[x,m]);let W=x?x.value:ge,G=w.findIndex(e=>e.key===W);o(()=>{V&&N!==null&&ce(M.current,document.getElementById(z(N)))},[V,N]);let Ve=e=>{Pe(!0),we?.(e)},He=e=>{Pe(!1),Te?.(e)},Ue=e=>{Me(!0),Se?.(e)},We=e=>{k.current&&(k.current.touched=!0),Me(!1),Ce?.(e)},Ge=()=>x?x.touched&&x.hasError():!_e||!!p,K=()=>!!(ye||x?.validators.find(e=>e.validatorId===`required`)),Ke=e=>{x?(x.set(e),y?.(x.value,h)):y?.(e,h)};function q(e){(!e||B)&&(Le(e),e?P(De&&G>=0?G:null):F.current={buffer:``,at:0})}function J(e){e.disabled||(Ke(e.key),q(!1))}let qe={isDisabled:e=>!!w[e].disabled};function Je(e){let t=Date.now(),n=t-F.current.at>pe?e:F.current.buffer+e;F.current={buffer:n,at:t};let r=n.toLowerCase(),i=w.findIndex(e=>!e.disabled&&typeof e.label==`string`&&e.label.toLowerCase().startsWith(r));i!==-1&&(V?P(i):J(w[i]))}function Ye(e){if(B){if(!V){e.key===`ArrowDown`||e.key===`ArrowUp`||e.key===`Enter`||e.key===` `?(e.preventDefault(),q(!0)):e.key.length===1&&Je(e.key);return}if(e.key===`ArrowDown`||e.key===`ArrowUp`)e.preventDefault(),P(se(N,e.key===`ArrowDown`?1:-1,w.length,qe));else if(e.key===`Home`||e.key===`End`)e.preventDefault(),P(oe(e.key===`Home`?`first`:`last`,w.length,qe));else if(e.key===`Enter`||e.key===` `){e.preventDefault();let t=N===null?void 0:w[N];t?J(t):q(!1)}else e.key===`Escape`||e.key===`Tab`?q(!1):e.key.length===1&&Je(e.key)}}let Y=Ee,X=Ge();w.forEach(e=>{e.key===W&&(Y=e.label)});let Z=Y||W,Q=Z==null||typeof Z==`string`&&Z.trim()===``,Xe=K()?u(`span`,{className:a.requiredMark,children:`*`}):null,Ze=m&&K()?`${m} *`:m,$=je&&!_;return d(`div`,{...Ae,className:l(me,S?.root,a.dropdownLabel,a.dropdown,{[a.dropdownLabelColumn]:!be}),style:{...he,...C?.root},onMouseEnter:Ve,onMouseLeave:He,children:[u(`div`,{children:u(re,{isOpen:V,onOpenChange:q,disabled:!B,placement:te.Bottom,align:ee.Start,offset:0,withArrow:!1,constrainWidth:!1,width:`trigger`,focusOnOpen:!1,presentation:H,classNames:{panel:a.dropdownPanel},content:u(`div`,{ref:j,className:l(!U&&a.dropdownInputListAnim,{[a.dropdownInputListAnimWider]:b&&!U}),children:d(`div`,{ref:M,id:L,role:`listbox`,"aria-label":m||D||void 0,className:l(a.dropdownInputList,U&&i.sheetScroll,S?.list),style:C?.list,children:[w.map((e,t)=>u(`div`,{id:z(t),role:`option`,"aria-selected":e.key===W,"aria-disabled":e.disabled||void 0,style:C?.option,className:l(a.dropdownInputListItem,S?.option,{[a.dropdownInputListItemActive]:N===t,[a.dropdownInputListItemSelected]:e.key===W,[a.dropdownInputListItemDisabled]:!!e.disabled}),onMouseDown:e=>e.preventDefault(),onMouseEnter:()=>P(t),onClick:()=>J(e),children:e.label},e.key)),u(`div`,{ref:ze,className:a.dropdownSentinel,"aria-hidden":`true`}),Re&&u(`div`,{className:a.dropdownLoadMore,"aria-hidden":`true`,children:u(r,{className:a.dropdownLoadMoreSpinner})})]})}),children:d(`div`,{ref:A,onFocus:Ue,onBlur:We,className:l(a.dropdownInput,{[a.dropdownInputPlain]:O,[a.dropdownInputReadOnly]:_&&!g},S?.field),style:C?.field,children:[u(`button`,{tabIndex:ve,type:`button`,disabled:g,role:`combobox`,"aria-haspopup":`listbox`,"aria-expanded":V,"aria-controls":L,"aria-activedescendant":V&&N!==null?z(N):void 0,"aria-labelledby":m?R:void 0,"aria-label":m?void 0:D||void 0,"aria-readonly":_||void 0,className:l(a.dropdownInputButton,{[a.dropdownInputButtonDisabled]:g,[a.dropdownInputButtonReadOnly]:_&&!g},S?.control),style:{...b?{padding:`6px`,border:`none`}:{},...C?.control},onKeyDown:Ye,onClick:v,ref:ke,children:Q?`\xA0`:Z}),u(`button`,{type:`button`,tabIndex:-1,disabled:g,"aria-hidden":`true`,className:l(a.dropdownInputButtonIcon,S?.icon),style:C?.icon,onMouseDown:e=>e.preventDefault(),onClick:v,children:!g&&!_&&u(de,{icon:fe,className:l(a.dropdownInputButtonIconArrow,{[a.dropdownInputButtonIconArrowOpen]:V})})}),u(`fieldset`,{className:l(a.dropdownFieldset,{[a.dropdownBorderPlain]:O,[a.dropdownBorderFocused]:$,[a.dropdownBorderInvalid]:X,[a.dropdownBorderError]:X}),children:u(`legend`,{className:l(a.dropdownFieldsetLegend,{[a.dropdownFieldsetLegendActive]:T&&(E||$||!Q)}),children:u(`span`,{children:Ze})})}),T&&m&&d(`div`,{id:R,className:l(a.dropdownMatLabel,{[a.dropdownMatLabelFloating]:E||$||!Q},S?.label),style:C?.label,children:[m,Xe]}),T&&D&&u(`div`,{className:l(a.dropdownPlaceholder,$&&!Y&&a.dropdownPlaceholderShown),children:D})]})})}),m&&!T&&d(`div`,{id:R,className:l(a.dropdownLabelText,S?.label),style:C?.label,children:[m,Xe]}),u(ie,{variant:`error`,message:x?x.getCurrentErrorMessage():p||``,isVisible:X&&(je||Ne)})]})}export{f as default};
1
+ "use client";import{useComponentDefaults as e}from"../configProvider/useComponentDefaults.mjs";import{usePresentationDefault as t}from"../configProvider/usePresentationDefault.mjs";import{Presentation as n}from"../configProvider/presentation.types.mjs";import r from"../loading/spinnerLoading/index.mjs";import i from"../styles/sheet.module.mjs";import{PopoverAlign as ee,PopoverPlacement as te}from"../popover/popover.types.mjs";import ne from"../hooks/useSheet.mjs";import re from"../popover/popover.mjs";import ie from"../tooltip/tooltip.mjs";import{edgeIndex as ae,nextIndex as oe,scrollOptionIntoView as se}from"../utils/listNavigation.mjs";import{useInfiniteScroll as ce}from"../infiniteBlock/useInfiniteScroll.mjs";import a from"./dropdown.module.mjs";import{useEffect as o,useId as le,useLayoutEffect as ue,useRef as s,useState as c}from"react";import l from"classnames";import{FontAwesomeIcon as de}from"@fortawesome/react-fontawesome";import{faChevronDown as fe}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var pe=500;function f(f){let{errorMessage:p=``,className:me=``,style:he,label:m=``,value:ge=``,isValid:_e=!0,tabIndex:ve=0,isRequired:ye=!1,customProps:h={},isRow:be=!1,disabled:g=!1,readOnly:_=!1,onScroll:xe=()=>Promise.resolve(),onClick:v,onChange:y,onFocus:Se=null,onBlur:Ce=null,onMouseEnter:we=null,onMouseLeave:Te=null,dropdownLabel:Ee,isDropdownListWider:b=!1,formValidator:x=null,classNames:S,styles:C,items:w=[],useMatLabelStyle:T=!0,alwaysFloatLabel:E=!1,placeholder:D=``,plainStyle:O=!1,scrollToSelected:De=!1,presentation:Oe,reactRef:ke,...Ae}=e(`Dropdown`,f),[je,Me]=c(!1),[Ne,Pe]=c(!1),[,Fe]=c(0),k=s(x),A=s(null),j=s(null),M=s(null),[Ie,Le]=c(!1),[N,P]=c(null),F=s({buffer:``,at:0}),I=le(),L=`${I}-listbox`,R=`${I}-label`,z=e=>`${I}-option-${e}`,B=!g&&!_,V=Ie&&B,{isLoading:Re,sentinelRef:ze}=ce(M,xe,!1),Be=t(),H=Oe??Be??n.Default,{isSheet:U}=ne(H);ue(()=>{let e=A.current,t=j.current;V&&!U&&e&&t&&(t.style.fontSize=window.getComputedStyle(e).fontSize)},[V,U]),o(()=>{if(k.current=x,!k.current)return;k.current.label=m??``,k.current.validate();let e=()=>Fe(e=>e+1);return k.current.registerOnUpdateListener(e),()=>k.current?.removeOnUpdateListener(e)},[x,m]);let W=x?x.value:ge,G=w.findIndex(e=>e.key===W);o(()=>{V&&N!==null&&se(M.current,document.getElementById(z(N)))},[V,N]);let Ve=e=>{Pe(!0),we?.(e)},He=e=>{Pe(!1),Te?.(e)},Ue=e=>{Me(!0),Se?.(e)},We=e=>{k.current&&(k.current.touched=!0),Me(!1),Ce?.(e)},Ge=()=>x?x.touched&&x.hasError():!_e||!!p,K=()=>!!(ye||x?.validators.find(e=>e.validatorId===`required`)),Ke=e=>{x?(x.set(e),y?.(x.value,h)):y?.(e,h)};function q(e){(!e||B)&&(Le(e),e?P(De&&G>=0?G:null):F.current={buffer:``,at:0})}function J(e){e.disabled||(Ke(e.key),q(!1))}let qe={isDisabled:e=>!!w[e].disabled};function Je(e){let t=Date.now(),n=t-F.current.at>pe?e:F.current.buffer+e;F.current={buffer:n,at:t};let r=n.toLowerCase(),i=w.findIndex(e=>!e.disabled&&typeof e.label==`string`&&e.label.toLowerCase().startsWith(r));i!==-1&&(V?P(i):J(w[i]))}function Ye(e){if(B){if(!V){e.key===`ArrowDown`||e.key===`ArrowUp`||e.key===`Enter`||e.key===` `?(e.preventDefault(),q(!0)):e.key.length===1&&Je(e.key);return}if(e.key===`ArrowDown`||e.key===`ArrowUp`)e.preventDefault(),P(oe(N,e.key===`ArrowDown`?1:-1,w.length,qe));else if(e.key===`Home`||e.key===`End`)e.preventDefault(),P(ae(e.key===`Home`?`first`:`last`,w.length,qe));else if(e.key===`Enter`||e.key===` `){e.preventDefault();let t=N===null?void 0:w[N];t?J(t):q(!1)}else e.key===`Escape`||e.key===`Tab`?q(!1):e.key.length===1&&Je(e.key)}}let Y=Ee,X=Ge();w.forEach(e=>{e.key===W&&(Y=e.label)});let Z=Y||W,Q=Z==null||typeof Z==`string`&&Z.trim()===``,Xe=K()?u(`span`,{className:a.requiredMark,children:`*`}):null,Ze=m&&K()?`${m} *`:m,$=je&&!_;return d(`div`,{...Ae,className:l(me,S?.root,a.dropdownLabel,a.dropdown,{[a.dropdownLabelColumn]:!be}),style:{...he,...C?.root},onMouseEnter:Ve,onMouseLeave:He,children:[u(`div`,{children:u(re,{isOpen:V,onOpenChange:q,disabled:!B,placement:te.Bottom,align:ee.Start,offset:0,withArrow:!1,constrainWidth:!1,width:`trigger`,focusOnOpen:!1,presentation:H,classNames:{panel:a.dropdownPanel},content:u(`div`,{ref:j,className:l(!U&&a.dropdownInputListAnim,{[a.dropdownInputListAnimWider]:b&&!U}),children:d(`div`,{ref:M,id:L,role:`listbox`,"aria-label":m||D||void 0,className:l(a.dropdownInputList,U&&i.sheetScroll,S?.list),style:C?.list,children:[w.map((e,t)=>u(`div`,{id:z(t),role:`option`,"aria-selected":e.key===W,"aria-disabled":e.disabled||void 0,style:C?.option,className:l(a.dropdownInputListItem,S?.option,{[a.dropdownInputListItemActive]:N===t,[a.dropdownInputListItemSelected]:e.key===W,[a.dropdownInputListItemDisabled]:!!e.disabled}),onMouseDown:e=>e.preventDefault(),onMouseEnter:()=>P(t),onClick:()=>J(e),children:e.label},e.key)),u(`div`,{ref:ze,className:a.dropdownSentinel,"aria-hidden":`true`}),Re&&u(`div`,{className:a.dropdownLoadMore,"aria-hidden":`true`,children:u(r,{className:a.dropdownLoadMoreSpinner})})]})}),children:d(`div`,{ref:A,onFocus:Ue,onBlur:We,className:l(a.dropdownInput,{[a.dropdownInputPlain]:O,[a.dropdownInputReadOnly]:_&&!g},S?.field),style:C?.field,children:[u(`button`,{tabIndex:ve,type:`button`,disabled:g,role:`combobox`,"aria-haspopup":`listbox`,"aria-expanded":V,"aria-controls":L,"aria-activedescendant":V&&N!==null?z(N):void 0,"aria-labelledby":m?R:void 0,"aria-label":m?void 0:D||void 0,"aria-readonly":_||void 0,className:l(a.dropdownInputButton,{[a.dropdownInputButtonDisabled]:g,[a.dropdownInputButtonReadOnly]:_&&!g},S?.control),style:{...b?{padding:`6px`,border:`none`}:{},...C?.control},onKeyDown:Ye,onClick:v,ref:ke,children:Q?`\xA0`:Z}),u(`button`,{type:`button`,tabIndex:-1,disabled:g,"aria-hidden":`true`,className:l(a.dropdownInputButtonIcon,S?.icon),style:C?.icon,onMouseDown:e=>e.preventDefault(),onClick:v,children:!g&&!_&&u(de,{icon:fe,className:l(a.dropdownInputButtonIconArrow,{[a.dropdownInputButtonIconArrowOpen]:V})})}),u(`fieldset`,{className:l(a.dropdownFieldset,{[a.dropdownBorderPlain]:O,[a.dropdownBorderFocused]:$,[a.dropdownBorderInvalid]:X,[a.dropdownBorderError]:X}),children:u(`legend`,{className:l(a.dropdownFieldsetLegend,{[a.dropdownFieldsetLegendActive]:T&&(E||$||!Q)}),children:u(`span`,{children:Ze})})}),T&&m&&d(`div`,{id:R,className:l(a.dropdownMatLabel,{[a.dropdownMatLabelFloating]:E||$||!Q},S?.label),style:C?.label,children:[m,Xe]}),T&&D&&u(`div`,{className:l(a.dropdownPlaceholder,$&&!Y&&a.dropdownPlaceholderShown),children:D})]})})}),m&&!T&&d(`div`,{id:R,className:l(a.dropdownLabelText,S?.label),style:C?.label,children:[m,Xe]}),u(ie,{variant:`error`,message:x?x.getCurrentErrorMessage():p||``,isVisible:X&&(je||Ne)})]})}export{f as default};
2
2
  //# sourceMappingURL=dropdown.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"dropdown.module.mjs","names":[],"sources":["../../../../package/common/dropdown/dropdown.module.pcss"],"sourcesContent":[".required-mark {\n padding: 0 0 0 4px;\n color: var(--required-mark-color, var(--error-color));\n}\n\n.dropdown {\n position: relative;\n\n /* Nothing inside gives the root a width, so as a flex or grid item it collapsed to the chevron\n and drew its border through the label. `input` and `multiSelect` say the same. */\n width: 100%;\n\n --dropdown-notch-height: 1.75em;\n\n /* See input.module.pcss for why this exists: the visible border lives on `-input`/`-fieldset`\n below, not this root, so a wrapping ButtonGroup's --group-radius-* custom properties (which\n inherit through any nesting depth, unlike border-radius itself) are what let this component\n flatten correctly when it sits inside a ButtonGroup. */\n --dropdown-radius: var(--group-radius-tl, var(--default-border-radius))\n var(--group-radius-tr, var(--default-border-radius)) var(--group-radius-br, var(--default-border-radius))\n var(--group-radius-bl, var(--default-border-radius));\n\n &-label {\n display: flex;\n\n &-column {\n flex-direction: column;\n }\n\n &-text {\n white-space: nowrap;\n margin-right: 5px;\n margin-bottom: 5px;\n display: flex;\n align-items: center;\n color: var(--text-color);\n font-size: 12px;\n position: absolute;\n top: -15px;\n }\n }\n\n &-input {\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--input-background);\n border-radius: var(--dropdown-radius);\n\n &-plain {\n background: transparent;\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus-within {\n outline: none;\n }\n\n &-button {\n padding: 7px 20% 7px 7.5px !important;\n background-color: transparent;\n border: none;\n font-family: inherit;\n font-size: inherit;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n text-align: left;\n width: 100%;\n line-height: 1.25;\n color: var(--text-color);\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n border-radius: var(--dropdown-radius);\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus {\n outline: none;\n }\n\n &-icon {\n float: right;\n background-color: transparent;\n border: none;\n position: absolute;\n outline: none;\n right: var(--spacing-s);\n top: 50%;\n transform: translateY(-50%);\n color: var(--text-color);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &-arrow {\n transition: transform 0.25s;\n pointer-events: none;\n\n &-open {\n transform: rotate(180deg);\n }\n }\n }\n }\n\n /* Chrome, placement and the portal come from the Popover this renders inside.\n What is left is the clipping that keeps the first and last row inside the\n panel's rounded corners. */\n &-list-anim {\n overflow: hidden;\n border-radius: inherit;\n\n &-wider {\n width: max-content !important;\n }\n }\n\n &-list {\n width: 100%;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n max-height: 10em;\n list-style-type: none;\n\n &-item {\n border: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--background-modal);\n padding: 0.5em;\n text-align: left;\n border-radius: 0;\n transition: background-color 0.3s;\n\n &-active {\n background-color: var(--background-accent);\n }\n\n &-selected {\n font-weight: 500;\n }\n\n &:focus {\n outline: none;\n }\n\n &:hover {\n background-color: var(--background-accent);\n }\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n cursor: not-allowed;\n\n &:hover {\n background-color: var(--disabled-input-color);\n }\n }\n }\n }\n }\n\n &-fieldset {\n position: absolute;\n width: 100%;\n margin: 0;\n box-sizing: border-box;\n border-radius: var(--dropdown-radius);\n font-size: 0.8em;\n inset: calc(var(--dropdown-notch-height) / -2) 0 0;\n padding-left: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: var(--border-color);\n pointer-events: none;\n user-select: none;\n\n &-legend {\n display: block;\n max-width: 0;\n transition: max-width 0.2s;\n white-space: nowrap;\n padding: 0;\n\n &-active {\n max-width: 300px;\n }\n\n span {\n line-height: var(--dropdown-notch-height);\n padding: 0 5px;\n opacity: 0;\n }\n\n /* With an empty label the span would still reserve its padding, leaving a gap in\n the fieldset's top border. Collapse it so the notch closes when there's no label. */\n span:empty {\n padding: 0.000001px;\n }\n }\n }\n\n &-placeholder {\n position: absolute;\n top: 50%;\n left: 7px;\n transform: translateY(-50%);\n transition: all 0.2s;\n opacity: 0;\n\n &-shown {\n animation: 0.2s fadeIn 0.3s forwards;\n }\n }\n\n &-matLabel {\n position: absolute;\n transition: all 0.3s;\n left: 7px;\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1em;\n color: var(--input-label-resting-color, var(--text-light));\n pointer-events: none;\n user-select: none;\n\n &-floating {\n inset: 0 0 auto 14px;\n font-size: 0.8em;\n color: var(--input-label-floating-color, var(--text-color));\n transform: translateY(-50%);\n }\n }\n\n @keyframes fadeIn {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 0.5;\n }\n }\n\n &-border {\n &-focused {\n outline-color: var(--focus-border-color, var(--primary-color));\n border-color: var(--focus-border-color, var(--primary-color));\n }\n\n &-plain:not(&-focused) {\n border-color: transparent;\n outline-color: transparent;\n }\n\n &-invalid {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-invalid:hover {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-error {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n }\n}\n\n/* The list brings its own padding and its rows reach the panel edge. */\n.dropdownPanel {\n padding: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dropdown-matLabel,\n .dropdown-placeholder,\n .dropdown-input-button-icon-arrow {\n transition: none;\n }\n}\n\n/* The sentinel the infinite-scroll hook watches, and the spinner shown while a page loads.\n These came with `InfiniteBlock` when the list rendered through it; the list is its own scroll\n container now, so they live here. */\n.dropdown-sentinel {\n height: 1px;\n}\n\n.dropdown-load-more {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 4px 0;\n\n &-spinner {\n width: 32px;\n height: 32px;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"dropdown.module.mjs","names":[],"sources":["../../../../package/common/dropdown/dropdown.module.pcss"],"sourcesContent":[".required-mark {\n padding: 0 0 0 4px;\n color: var(--required-mark-color, var(--error-color));\n}\n\n.dropdown {\n position: relative;\n\n /* Nothing inside gives the root a width, so as a flex or grid item it collapsed to the chevron\n and drew its border through the label. `input` and `multiSelect` say the same. */\n width: 100%;\n\n --dropdown-notch-height: 1.75em;\n\n /* See input.module.pcss for why this exists: the visible border lives on `-input`/`-fieldset`\n below, not this root, so a wrapping ButtonGroup's --group-radius-* custom properties (which\n inherit through any nesting depth, unlike border-radius itself) are what let this component\n flatten correctly when it sits inside a ButtonGroup. */\n --dropdown-radius: var(--group-radius-tl, var(--default-border-radius))\n var(--group-radius-tr, var(--default-border-radius)) var(--group-radius-br, var(--default-border-radius))\n var(--group-radius-bl, var(--default-border-radius));\n\n &-label {\n display: flex;\n\n &-column {\n flex-direction: column;\n }\n\n &-text {\n white-space: nowrap;\n margin-right: 5px;\n margin-bottom: 5px;\n display: flex;\n align-items: center;\n color: var(--text-color);\n font-size: 12px;\n position: absolute;\n top: -15px;\n }\n }\n\n &-input {\n position: relative;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--input-background);\n border-radius: var(--dropdown-radius);\n\n &-plain {\n background: transparent;\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus-within {\n outline: none;\n }\n\n &-button {\n padding: 8px 20% 6px 7.5px !important;\n background-color: transparent;\n border: none;\n font-family: inherit;\n font-size: inherit;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n text-align: left;\n width: 100%;\n line-height: 1.25;\n color: var(--text-color);\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n border-radius: var(--dropdown-radius);\n }\n\n &-readOnly {\n cursor: default;\n }\n\n &:focus {\n outline: none;\n }\n\n &-icon {\n float: right;\n background-color: transparent;\n border: none;\n position: absolute;\n outline: none;\n right: var(--spacing-s);\n top: 50%;\n transform: translateY(-50%);\n color: var(--text-color);\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n\n &-arrow {\n transition: transform 0.25s;\n pointer-events: none;\n\n &-open {\n transform: rotate(180deg);\n }\n }\n }\n }\n\n /* Chrome, placement and the portal come from the Popover this renders inside.\n What is left is the clipping that keeps the first and last row inside the\n panel's rounded corners. */\n &-list-anim {\n overflow: hidden;\n border-radius: inherit;\n\n &-wider {\n width: max-content !important;\n }\n }\n\n &-list {\n width: 100%;\n display: flex;\n flex-direction: column;\n overflow-y: auto;\n max-height: 10em;\n list-style-type: none;\n\n &-item {\n border: none;\n cursor: pointer;\n -webkit-tap-highlight-color: transparent;\n background-color: var(--background-modal);\n padding: 0.5em;\n text-align: left;\n border-radius: 0;\n transition: background-color 0.3s;\n\n &-active {\n background-color: var(--background-accent);\n }\n\n &-selected {\n font-weight: 500;\n }\n\n &:focus {\n outline: none;\n }\n\n &:hover {\n background-color: var(--background-accent);\n }\n\n &-disabled {\n background-color: var(--disabled-input-color);\n color: var(--disabled-font-color);\n cursor: not-allowed;\n\n &:hover {\n background-color: var(--disabled-input-color);\n }\n }\n }\n }\n }\n\n &-fieldset {\n position: absolute;\n width: 100%;\n margin: 0;\n box-sizing: border-box;\n border-radius: var(--dropdown-radius);\n font-size: 0.8em;\n inset: calc(var(--dropdown-notch-height) / -2) 0 0;\n padding-left: 8px;\n border-width: 1px;\n border-style: solid;\n border-color: var(--border-color);\n pointer-events: none;\n user-select: none;\n\n &-legend {\n display: block;\n\n /* Not taken from the text: an empty span gets no line box, which raised a label-less\n field's border half a notch. */\n height: var(--dropdown-notch-height);\n max-width: 0;\n transition: max-width 0.2s;\n white-space: nowrap;\n padding: 0;\n\n &-active {\n max-width: 300px;\n }\n\n span {\n line-height: var(--dropdown-notch-height);\n padding: 0 5px;\n opacity: 0;\n }\n\n /* With an empty label the span would still reserve its padding, leaving a gap in\n the fieldset's top border. Collapse it so the notch closes when there's no label. */\n span:empty {\n padding: 0;\n }\n }\n }\n\n &-placeholder {\n position: absolute;\n top: 50%;\n left: 7px;\n transform: translateY(-50%);\n transition: all 0.2s;\n opacity: 0;\n\n &-shown {\n animation: 0.2s fadeIn 0.3s forwards;\n }\n }\n\n &-matLabel {\n position: absolute;\n transition: all 0.3s;\n left: 7px;\n right: 0;\n top: 50%;\n transform: translateY(-50%);\n font-size: 1em;\n color: var(--input-label-resting-color, var(--text-light));\n pointer-events: none;\n user-select: none;\n\n &-floating {\n inset: 0 0 auto 14px;\n font-size: 0.8em;\n color: var(--input-label-floating-color, var(--text-color));\n transform: translateY(-50%);\n }\n }\n\n @keyframes fadeIn {\n from {\n opacity: 0;\n }\n\n to {\n opacity: 0.5;\n }\n }\n\n &-border {\n &-focused {\n outline-color: var(--focus-border-color, var(--primary-color));\n border-color: var(--focus-border-color, var(--primary-color));\n }\n\n &-plain:not(&-focused) {\n border-color: transparent;\n outline-color: transparent;\n }\n\n &-invalid {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-invalid:hover {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n\n &-error {\n outline-color: var(--error-border-color);\n border-color: var(--error-border-color);\n }\n }\n}\n\n/* The list brings its own padding and its rows reach the panel edge. */\n.dropdownPanel {\n padding: 0;\n}\n\n@media (prefers-reduced-motion: reduce) {\n .dropdown-matLabel,\n .dropdown-placeholder,\n .dropdown-input-button-icon-arrow {\n transition: none;\n }\n}\n\n/* The sentinel the infinite-scroll hook watches, and the spinner shown while a page loads.\n These came with `InfiniteBlock` when the list rendered through it; the list is its own scroll\n container now, so they live here. */\n.dropdown-sentinel {\n height: 1px;\n}\n\n.dropdown-load-more {\n display: flex;\n justify-content: center;\n align-items: center;\n padding: 4px 0;\n\n &-spinner {\n width: 32px;\n height: 32px;\n }\n}\n"],"mappings":""}
@@ -1,4 +1,4 @@
1
- "use client";import e from"../accordion/accordion.mjs";import{ButtonSize as t}from"../button/button.types.mjs";import n from"../button/button.mjs";import{showToast as r}from"../toast/toastService.mjs";import i from"./errorBoundary.module.mjs";import a from"react";import o from"classnames";import{FontAwesomeIcon as s}from"@fortawesome/react-fontawesome";import{faArrowRotateRight as c,faCheck as l,faCopy as u,faTriangleExclamation as d}from"@fortawesome/free-solid-svg-icons";import{jsx as f,jsxs as p}from"react/jsx-runtime";var m=2e3,h={stackTrace:`Stack trace`,copy:`Copy`,copied:`Copied`,reset:`Try again`,copySuccessToast:`Stack trace copied to clipboard`,copyErrorToast:`Could not copy stack trace`};function g(e,t){let n=[e.stack??`${e.name}: ${e.message}`];return t?.componentStack&&n.push(`Component stack:${t.componentStack}`),n.join(`
1
+ "use client";import e from"../accordion/accordion.mjs";import t from"../button/button.mjs";import n from"../copyButton/copyButton.mjs";import{showToast as r}from"../toast/toastService.mjs";import i from"./errorBoundary.module.mjs";import a from"react";import o from"classnames";import{FontAwesomeIcon as s}from"@fortawesome/react-fontawesome";import{faArrowRotateRight as c,faTriangleExclamation as l}from"@fortawesome/free-solid-svg-icons";import{jsx as u,jsxs as d}from"react/jsx-runtime";var f={stackTrace:`Stack trace`,copy:`Copy`,copied:`Copied`,reset:`Try again`,copySuccessToast:`Stack trace copied to clipboard`,copyErrorToast:`Could not copy stack trace`};function p(e,t){let n=[e.stack??`${e.name}: ${e.message}`];return t?.componentStack&&n.push(`Component stack:${t.componentStack}`),n.join(`
2
2
 
3
- `)}var _=class extends a.Component{constructor(...e){super(...e),this.state={error:null,errorInfo:null,copied:!1},this.copyResetTimeout=null,this.reset=()=>{this.setState({error:null,errorInfo:null,copied:!1}),this.props.onReset?.()},this.copyStackTrace=async()=>{let{error:e,errorInfo:t}=this.state;if(!e)return;let n={...h,...this.props.labels};try{await navigator.clipboard.writeText(g(e,t)),this.setState({copied:!0}),this.copyResetTimeout&&clearTimeout(this.copyResetTimeout),this.copyResetTimeout=setTimeout(()=>this.setState({copied:!1}),m),r(n.copySuccessToast,{type:`success`})}catch{r(n.copyErrorToast,{type:`error`})}}}static getDerivedStateFromError(e){return{error:e}}componentDidCatch(e,t){this.setState({errorInfo:t}),this.props.onError?.(e,t)}componentDidUpdate(e){if(!this.state.error)return;let t=e.resetKeys??[],n=this.props.resetKeys??[];(n.length!==t.length||n.some((e,n)=>e!==t[n]))&&this.reset()}componentWillUnmount(){this.copyResetTimeout&&clearTimeout(this.copyResetTimeout)}render(){let{error:r,errorInfo:a,copied:m}=this.state,{children:_=null,title:v=`Something went wrong`,description:y,labels:b,fallback:x,hideStack:S=!1,className:C,style:w,classNames:T,styles:E,onError:D,onReset:O,resetKeys:k,role:A=`alert`,...j}=this.props;if(!r)return _;let M={...h,...b};return x?typeof x==`function`?x({error:r,errorInfo:a,resetErrorBoundary:this.reset}):x:p(`div`,{...j,role:A,className:o(i.errorBoundary,C,T?.root),style:{...w,...E?.root},children:[p(`div`,{className:o(i.errorBoundaryHeader,T?.header),style:E?.header,children:[f(`div`,{className:o(i.errorBoundaryBadge,T?.badge),style:E?.badge,children:f(s,{icon:d,className:o(i.errorBoundaryIcon,T?.icon),style:E?.icon})}),f(`div`,{className:o(i.errorBoundaryTitle,T?.title),style:E?.title,children:v}),f(`div`,{className:o(i.errorBoundaryDescription,T?.description),style:E?.description,children:y??r.message})]}),!S&&p(e,{title:M.stackTrace,className:o(i.errorBoundaryStack,T?.stack),style:E?.stack,children:[p(`div`,{className:o(i.errorBoundaryStackHeader,T?.stackHeader),style:E?.stackHeader,children:[f(`span`,{className:o(i.errorBoundaryStackLabel,T?.stackLabel),style:E?.stackLabel,children:r.name||`Error`}),f(n,{size:t.Small,icon:m?l:u,onClick:this.copyStackTrace,className:o(i.errorBoundaryCopyButton,m&&i.errorBoundaryCopyButtonActive,T?.copyButton),style:E?.copyButton,children:m?M.copied:M.copy})]}),f(`pre`,{className:o(i.errorBoundaryStackTrace,T?.stackTrace),style:E?.stackTrace,children:g(r,a)})]}),f(`div`,{className:o(i.errorBoundaryActions,T?.actions),style:E?.actions,children:f(n,{onClick:this.reset,icon:c,className:o(i.errorBoundaryResetButton,T?.resetButton),style:E?.resetButton,children:M.reset})})]})}};export{_ as default};
3
+ `)}var m=class extends a.Component{constructor(...e){super(...e),this.state={error:null,errorInfo:null},this.reset=()=>{this.setState({error:null,errorInfo:null}),this.props.onReset?.()}}static getDerivedStateFromError(e){return{error:e}}componentDidCatch(e,t){this.setState({errorInfo:t}),this.props.onError?.(e,t)}componentDidUpdate(e){if(!this.state.error)return;let t=e.resetKeys??[],n=this.props.resetKeys??[];(n.length!==t.length||n.some((e,n)=>e!==t[n]))&&this.reset()}render(){let{error:a,errorInfo:m}=this.state,{children:h=null,title:g=`Something went wrong`,description:_,labels:v,fallback:y,hideStack:b=!1,className:x,style:S,classNames:C,styles:w,onError:T,onReset:E,resetKeys:D,role:O=`alert`,...k}=this.props;if(!a)return h;let A={...f,...v};return y?typeof y==`function`?y({error:a,errorInfo:m,resetErrorBoundary:this.reset}):y:d(`div`,{...k,role:O,className:o(i.errorBoundary,x,C?.root),style:{...S,...w?.root},children:[d(`div`,{className:o(i.errorBoundaryHeader,C?.header),style:w?.header,children:[u(`div`,{className:o(i.errorBoundaryBadge,C?.badge),style:w?.badge,children:u(s,{icon:l,className:o(i.errorBoundaryIcon,C?.icon),style:w?.icon})}),u(`div`,{className:o(i.errorBoundaryTitle,C?.title),style:w?.title,children:g}),u(`div`,{className:o(i.errorBoundaryDescription,C?.description),style:w?.description,children:_??a.message})]}),!b&&d(e,{title:A.stackTrace,className:o(i.errorBoundaryStack,C?.stack),style:w?.stack,children:[d(`div`,{className:o(i.errorBoundaryStackHeader,C?.stackHeader),style:w?.stackHeader,children:[u(`span`,{className:o(i.errorBoundaryStackLabel,C?.stackLabel),style:w?.stackLabel,children:a.name||`Error`}),u(n,{value:p(a,m),labels:{copy:A.copy,copied:A.copied},onCopy:()=>r(A.copySuccessToast,{type:`success`}),onError:()=>r(A.copyErrorToast,{type:`error`}),className:o(i.errorBoundaryCopyButton,C?.copyButton),style:w?.copyButton})]}),u(`pre`,{className:o(i.errorBoundaryStackTrace,C?.stackTrace),style:w?.stackTrace,children:p(a,m)})]}),u(`div`,{className:o(i.errorBoundaryActions,C?.actions),style:w?.actions,children:u(t,{onClick:this.reset,icon:c,className:o(i.errorBoundaryResetButton,C?.resetButton),style:w?.resetButton,children:A.reset})})]})}};export{m as default};
4
4
  //# sourceMappingURL=errorBoundary.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorBoundary.mjs","names":[],"sources":["../../../../package/common/errorBoundary/errorBoundary.tsx"],"sourcesContent":["import React from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faTriangleExclamation, faCopy, faCheck, faArrowRotateRight } from '@fortawesome/free-solid-svg-icons';\n\nimport Button, { ButtonSize } from '../button';\nimport Accordion from '../accordion';\nimport { showToast } from '../toast';\nimport type { ErrorBoundaryLabels, ErrorBoundaryProps, ErrorBoundaryState } from './errorBoundary.types';\nimport styles from './errorBoundary.module.pcss';\n\nconst COPY_FEEDBACK_DURATION = 2000;\n\nconst DEFAULT_LABELS: Required<ErrorBoundaryLabels> = {\n stackTrace: 'Stack trace',\n copy: 'Copy',\n copied: 'Copied',\n reset: 'Try again',\n copySuccessToast: 'Stack trace copied to clipboard',\n copyErrorToast: 'Could not copy stack trace',\n};\n\nfunction formatStackTrace(error: Error, errorInfo: React.ErrorInfo | null): string {\n const parts = [error.stack ?? `${error.name}: ${error.message}`];\n if (errorInfo?.componentStack) parts.push(`Component stack:${errorInfo.componentStack}`);\n return parts.join('\\n\\n');\n}\n\nclass ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state: ErrorBoundaryState = { error: null, errorInfo: null, copied: false };\n\n private copyResetTimeout: ReturnType<typeof setTimeout> | null = null;\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.setState({ errorInfo });\n this.props.onError?.(error, errorInfo);\n }\n\n componentDidUpdate(prevProps: ErrorBoundaryProps): void {\n if (!this.state.error) return;\n const prevKeys = prevProps.resetKeys ?? [];\n const nextKeys = this.props.resetKeys ?? [];\n const changed = nextKeys.length !== prevKeys.length || nextKeys.some((key, i) => key !== prevKeys[i]);\n if (changed) this.reset();\n }\n\n componentWillUnmount(): void {\n if (this.copyResetTimeout) clearTimeout(this.copyResetTimeout);\n }\n\n private reset = (): void => {\n this.setState({ error: null, errorInfo: null, copied: false });\n this.props.onReset?.();\n };\n\n private copyStackTrace = async (): Promise<void> => {\n const { error, errorInfo } = this.state;\n if (!error) return;\n const labels = { ...DEFAULT_LABELS, ...this.props.labels };\n try {\n await navigator.clipboard.writeText(formatStackTrace(error, errorInfo));\n this.setState({ copied: true });\n if (this.copyResetTimeout) clearTimeout(this.copyResetTimeout);\n this.copyResetTimeout = setTimeout(() => this.setState({ copied: false }), COPY_FEEDBACK_DURATION);\n showToast(labels.copySuccessToast, { type: 'success' });\n } catch {\n showToast(labels.copyErrorToast, { type: 'error' });\n }\n };\n\n render(): React.ReactNode {\n const { error, errorInfo, copied } = this.state;\n // onError/onReset/resetKeys are consumed elsewhere (getDerivedStateFromError,\n // componentDidCatch, componentDidUpdate) and must not land on the root element via `rest`.\n /* eslint-disable @typescript-eslint/no-unused-vars */\n const {\n children = null,\n title = 'Something went wrong',\n description,\n labels: labelOverrides,\n fallback,\n hideStack = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n onError,\n onReset,\n resetKeys,\n role = 'alert',\n ...rest\n } = this.props;\n\n if (!error) return children;\n\n const labels = { ...DEFAULT_LABELS, ...labelOverrides };\n\n if (fallback) {\n return typeof fallback === 'function' ? fallback({ error, errorInfo, resetErrorBoundary: this.reset }) : fallback;\n }\n\n return (\n <div\n {...rest}\n role={role}\n className={cx(styles.errorBoundary, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <div className={cx(styles.errorBoundaryHeader, classNames?.header)} style={slotStyles?.header}>\n <div className={cx(styles.errorBoundaryBadge, classNames?.badge)} style={slotStyles?.badge}>\n <FontAwesomeIcon\n icon={faTriangleExclamation}\n className={cx(styles.errorBoundaryIcon, classNames?.icon)}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n </div>\n <div className={cx(styles.errorBoundaryTitle, classNames?.title)} style={slotStyles?.title}>\n {title}\n </div>\n <div className={cx(styles.errorBoundaryDescription, classNames?.description)} style={slotStyles?.description}>\n {description ?? error.message}\n </div>\n </div>\n\n {!hideStack && (\n <Accordion\n title={labels.stackTrace}\n className={cx(styles.errorBoundaryStack, classNames?.stack)}\n style={slotStyles?.stack}\n >\n <div\n className={cx(styles.errorBoundaryStackHeader, classNames?.stackHeader)}\n style={slotStyles?.stackHeader}\n >\n <span\n className={cx(styles.errorBoundaryStackLabel, classNames?.stackLabel)}\n style={slotStyles?.stackLabel}\n >\n {error.name || 'Error'}\n </span>\n <Button\n size={ButtonSize.Small}\n icon={copied ? faCheck : faCopy}\n onClick={this.copyStackTrace}\n className={cx(\n styles.errorBoundaryCopyButton,\n copied && styles.errorBoundaryCopyButtonActive,\n classNames?.copyButton,\n )}\n style={slotStyles?.copyButton}\n >\n {copied ? labels.copied : labels.copy}\n </Button>\n </div>\n <pre className={cx(styles.errorBoundaryStackTrace, classNames?.stackTrace)} style={slotStyles?.stackTrace}>\n {formatStackTrace(error, errorInfo)}\n </pre>\n </Accordion>\n )}\n\n <div className={cx(styles.errorBoundaryActions, classNames?.actions)} style={slotStyles?.actions}>\n <Button\n onClick={this.reset}\n icon={faArrowRotateRight}\n className={cx(styles.errorBoundaryResetButton, classNames?.resetButton)}\n style={slotStyles?.resetButton}\n >\n {labels.reset}\n </Button>\n </div>\n </div>\n );\n }\n}\n\nexport default ErrorBoundary;\n"],"mappings":"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"}
1
+ {"version":3,"file":"errorBoundary.mjs","names":[],"sources":["../../../../package/common/errorBoundary/errorBoundary.tsx"],"sourcesContent":["import React from 'react';\nimport cx from 'classnames';\nimport { FontAwesomeIcon } from '@fortawesome/react-fontawesome';\nimport { faTriangleExclamation, faArrowRotateRight } from '@fortawesome/free-solid-svg-icons';\n\nimport Button from '../button';\nimport Accordion from '../accordion';\nimport { showToast } from '../toast';\nimport CopyButton from '../copyButton';\nimport type { ErrorBoundaryLabels, ErrorBoundaryProps, ErrorBoundaryState } from './errorBoundary.types';\nimport styles from './errorBoundary.module.pcss';\n\nconst DEFAULT_LABELS: Required<ErrorBoundaryLabels> = {\n stackTrace: 'Stack trace',\n copy: 'Copy',\n copied: 'Copied',\n reset: 'Try again',\n copySuccessToast: 'Stack trace copied to clipboard',\n copyErrorToast: 'Could not copy stack trace',\n};\n\nfunction formatStackTrace(error: Error, errorInfo: React.ErrorInfo | null): string {\n const parts = [error.stack ?? `${error.name}: ${error.message}`];\n if (errorInfo?.componentStack) parts.push(`Component stack:${errorInfo.componentStack}`);\n return parts.join('\\n\\n');\n}\n\nclass ErrorBoundary extends React.Component<ErrorBoundaryProps, ErrorBoundaryState> {\n state: ErrorBoundaryState = { error: null, errorInfo: null };\n\n static getDerivedStateFromError(error: Error): Partial<ErrorBoundaryState> {\n return { error };\n }\n\n componentDidCatch(error: Error, errorInfo: React.ErrorInfo): void {\n this.setState({ errorInfo });\n this.props.onError?.(error, errorInfo);\n }\n\n componentDidUpdate(prevProps: ErrorBoundaryProps): void {\n if (!this.state.error) return;\n const prevKeys = prevProps.resetKeys ?? [];\n const nextKeys = this.props.resetKeys ?? [];\n const changed = nextKeys.length !== prevKeys.length || nextKeys.some((key, i) => key !== prevKeys[i]);\n if (changed) this.reset();\n }\n\n private reset = (): void => {\n this.setState({ error: null, errorInfo: null });\n this.props.onReset?.();\n };\n\n render(): React.ReactNode {\n const { error, errorInfo } = this.state;\n // onError/onReset/resetKeys are consumed elsewhere (getDerivedStateFromError,\n // componentDidCatch, componentDidUpdate) and must not land on the root element via `rest`.\n /* eslint-disable @typescript-eslint/no-unused-vars */\n const {\n children = null,\n title = 'Something went wrong',\n description,\n labels: labelOverrides,\n fallback,\n hideStack = false,\n className,\n style,\n classNames,\n styles: slotStyles,\n onError,\n onReset,\n resetKeys,\n role = 'alert',\n ...rest\n } = this.props;\n\n if (!error) return children;\n\n const labels = { ...DEFAULT_LABELS, ...labelOverrides };\n\n if (fallback) {\n return typeof fallback === 'function' ? fallback({ error, errorInfo, resetErrorBoundary: this.reset }) : fallback;\n }\n\n return (\n <div\n {...rest}\n role={role}\n className={cx(styles.errorBoundary, className, classNames?.root)}\n style={{ ...style, ...slotStyles?.root }}\n >\n <div className={cx(styles.errorBoundaryHeader, classNames?.header)} style={slotStyles?.header}>\n <div className={cx(styles.errorBoundaryBadge, classNames?.badge)} style={slotStyles?.badge}>\n <FontAwesomeIcon\n icon={faTriangleExclamation}\n className={cx(styles.errorBoundaryIcon, classNames?.icon)}\n style={slotStyles?.icon as React.CSSProperties & Record<`--fa-font-${string}`, string>}\n />\n </div>\n <div className={cx(styles.errorBoundaryTitle, classNames?.title)} style={slotStyles?.title}>\n {title}\n </div>\n <div className={cx(styles.errorBoundaryDescription, classNames?.description)} style={slotStyles?.description}>\n {description ?? error.message}\n </div>\n </div>\n\n {!hideStack && (\n <Accordion\n title={labels.stackTrace}\n className={cx(styles.errorBoundaryStack, classNames?.stack)}\n style={slotStyles?.stack}\n >\n <div\n className={cx(styles.errorBoundaryStackHeader, classNames?.stackHeader)}\n style={slotStyles?.stackHeader}\n >\n <span\n className={cx(styles.errorBoundaryStackLabel, classNames?.stackLabel)}\n style={slotStyles?.stackLabel}\n >\n {error.name || 'Error'}\n </span>\n <CopyButton\n value={formatStackTrace(error, errorInfo)}\n labels={{ copy: labels.copy, copied: labels.copied }}\n onCopy={() => showToast(labels.copySuccessToast, { type: 'success' })}\n onError={() => showToast(labels.copyErrorToast, { type: 'error' })}\n className={cx(styles.errorBoundaryCopyButton, classNames?.copyButton)}\n style={slotStyles?.copyButton}\n />\n </div>\n <pre className={cx(styles.errorBoundaryStackTrace, classNames?.stackTrace)} style={slotStyles?.stackTrace}>\n {formatStackTrace(error, errorInfo)}\n </pre>\n </Accordion>\n )}\n\n <div className={cx(styles.errorBoundaryActions, classNames?.actions)} style={slotStyles?.actions}>\n <Button\n onClick={this.reset}\n icon={faArrowRotateRight}\n className={cx(styles.errorBoundaryResetButton, classNames?.resetButton)}\n style={slotStyles?.resetButton}\n >\n {labels.reset}\n </Button>\n </div>\n </div>\n );\n }\n}\n\nexport default ErrorBoundary;\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- "use client";var e=`errorBoundary_XdPM0`,t=`errorBoundaryHeader_2PdRz`,n=`errorBoundaryBadge_TyXdO`,r=`errorBoundaryBadgeIn_Q-MMB`,i=`errorBoundaryIcon_PcZ4H`,a=`errorBoundaryTitle_X9tEE`,o=`errorBoundaryFadeUp_2qx5d`,s=`errorBoundaryDescription_NELdD`,c=`errorBoundaryStack_BUkBD`,l=`errorBoundaryStackHeader_uimLH`,u=`errorBoundaryStackLabel_D-19W`,d=`errorBoundaryCopyButton_e09KC`,f=`errorBoundaryCopyButtonActive_OBPiV`,p=`errorBoundaryStackTrace_DskzG`,m=`errorBoundaryActions_h3GMQ`,h={errorBoundary:e,errorBoundaryHeader:t,errorBoundaryBadge:n,errorBoundaryBadgeIn:r,errorBoundaryIcon:i,errorBoundaryTitle:a,errorBoundaryFadeUp:o,errorBoundaryDescription:s,errorBoundaryStack:c,errorBoundaryStackHeader:l,errorBoundaryStackLabel:u,errorBoundaryCopyButton:d,errorBoundaryCopyButtonActive:f,errorBoundaryStackTrace:p,errorBoundaryActions:m};export{h as default,e as errorBoundary,m as errorBoundaryActions,n as errorBoundaryBadge,r as errorBoundaryBadgeIn,d as errorBoundaryCopyButton,f as errorBoundaryCopyButtonActive,s as errorBoundaryDescription,o as errorBoundaryFadeUp,t as errorBoundaryHeader,i as errorBoundaryIcon,c as errorBoundaryStack,l as errorBoundaryStackHeader,u as errorBoundaryStackLabel,p as errorBoundaryStackTrace,a as errorBoundaryTitle};
1
+ "use client";var e=`errorBoundary_XdPM0`,t=`errorBoundaryHeader_2PdRz`,n=`errorBoundaryBadge_TyXdO`,r=`errorBoundaryBadgeIn_Q-MMB`,i=`errorBoundaryIcon_PcZ4H`,a=`errorBoundaryTitle_X9tEE`,o=`errorBoundaryFadeUp_2qx5d`,s=`errorBoundaryDescription_NELdD`,c=`errorBoundaryStack_BUkBD`,l=`errorBoundaryStackHeader_uimLH`,u=`errorBoundaryStackLabel_D-19W`,d=`errorBoundaryCopyButton_e09KC`,f=`errorBoundaryStackTrace_DskzG`,p=`errorBoundaryActions_h3GMQ`,m={errorBoundary:e,errorBoundaryHeader:t,errorBoundaryBadge:n,errorBoundaryBadgeIn:r,errorBoundaryIcon:i,errorBoundaryTitle:a,errorBoundaryFadeUp:o,errorBoundaryDescription:s,errorBoundaryStack:c,errorBoundaryStackHeader:l,errorBoundaryStackLabel:u,errorBoundaryCopyButton:d,errorBoundaryStackTrace:f,errorBoundaryActions:p};export{m as default,e as errorBoundary,p as errorBoundaryActions,n as errorBoundaryBadge,r as errorBoundaryBadgeIn,d as errorBoundaryCopyButton,s as errorBoundaryDescription,o as errorBoundaryFadeUp,t as errorBoundaryHeader,i as errorBoundaryIcon,c as errorBoundaryStack,l as errorBoundaryStackHeader,u as errorBoundaryStackLabel,f as errorBoundaryStackTrace,a as errorBoundaryTitle};
2
2
  //# sourceMappingURL=errorBoundary.module.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"errorBoundary.module.mjs","names":[],"sources":["../../../../package/common/errorBoundary/errorBoundary.module.pcss"],"sourcesContent":["@keyframes errorBoundaryBadgeIn {\n from {\n opacity: 0;\n transform: scale(0.6);\n }\n\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes errorBoundaryFadeUp {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.errorBoundary {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 20px;\n padding: 36px 28px;\n border-radius: var(--default-border-radius);\n background: var(--background-accent);\n border: 1px solid var(--border-color);\n box-shadow: var(--card-shadow);\n color: var(--text-color);\n font-family: var(--default-font);\n box-sizing: border-box;\n overflow: hidden;\n isolation: isolate;\n\n &::before {\n content: '';\n position: absolute;\n top: -30px;\n left: 50%;\n width: 260px;\n height: 180px;\n transform: translateX(-50%);\n background: radial-gradient(closest-side, color-mix(in srgb, var(--error-color) 16%, transparent), transparent);\n pointer-events: none;\n z-index: -1;\n }\n\n &Header {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n text-align: center;\n max-width: 420px;\n }\n\n &Badge {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 52px;\n height: 52px;\n border-radius: 50%;\n background: var(--error-lighter);\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--error-color) 8%, transparent);\n margin-bottom: 4px;\n animation: errorBoundaryBadgeIn 0.35s ease-out;\n }\n\n &Icon {\n font-size: 20px;\n color: var(--error-color, #ef4444);\n }\n\n &Title {\n font-weight: var(--header-font-weight, 700);\n font-size: 17px;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.05s backwards;\n }\n\n &Description {\n color: var(--text-dark);\n font-size: 14px;\n line-height: 1.5;\n word-break: break-word;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.1s backwards;\n }\n\n &Stack {\n align-self: stretch;\n width: 100%;\n text-align: left;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.15s backwards;\n }\n\n &StackHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n margin-bottom: 10px;\n }\n\n &StackLabel {\n font-family: var(--monospace-font, monospace);\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--error-color, #ef4444);\n background: var(--error-lighter);\n padding: 3px 8px;\n border-radius: 999px;\n }\n\n &CopyButton {\n flex-shrink: 0;\n\n &Active {\n color: var(--success-color) !important;\n }\n }\n\n &StackTrace {\n margin: 0;\n padding: 12px;\n border-radius: var(--default-border-radius);\n background: var(--background);\n color: var(--text-dark);\n font-family: var(--monospace-font, monospace);\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-wrap;\n word-break: break-word;\n max-height: 320px;\n overflow: auto;\n }\n\n &Actions {\n display: flex;\n justify-content: center;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.2s backwards;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .errorBoundaryBadge,\n .errorBoundaryTitle,\n .errorBoundaryDescription,\n .errorBoundaryStack,\n .errorBoundaryActions {\n animation: none;\n }\n}\n"],"mappings":""}
1
+ {"version":3,"file":"errorBoundary.module.mjs","names":[],"sources":["../../../../package/common/errorBoundary/errorBoundary.module.pcss"],"sourcesContent":["@keyframes errorBoundaryBadgeIn {\n from {\n opacity: 0;\n transform: scale(0.6);\n }\n\n to {\n opacity: 1;\n transform: scale(1);\n }\n}\n\n@keyframes errorBoundaryFadeUp {\n from {\n opacity: 0;\n transform: translateY(6px);\n }\n\n to {\n opacity: 1;\n transform: translateY(0);\n }\n}\n\n.errorBoundary {\n position: relative;\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 20px;\n padding: 36px 28px;\n border-radius: var(--default-border-radius);\n background: var(--background-accent);\n border: 1px solid var(--border-color);\n box-shadow: var(--card-shadow);\n color: var(--text-color);\n font-family: var(--default-font);\n box-sizing: border-box;\n overflow: hidden;\n isolation: isolate;\n\n &::before {\n content: '';\n position: absolute;\n top: -30px;\n left: 50%;\n width: 260px;\n height: 180px;\n transform: translateX(-50%);\n background: radial-gradient(closest-side, color-mix(in srgb, var(--error-color) 16%, transparent), transparent);\n pointer-events: none;\n z-index: -1;\n }\n\n &Header {\n display: flex;\n flex-direction: column;\n align-items: center;\n gap: 8px;\n text-align: center;\n max-width: 420px;\n }\n\n &Badge {\n display: flex;\n align-items: center;\n justify-content: center;\n width: 52px;\n height: 52px;\n border-radius: 50%;\n background: var(--error-lighter);\n box-shadow: 0 0 0 6px color-mix(in srgb, var(--error-color) 8%, transparent);\n margin-bottom: 4px;\n animation: errorBoundaryBadgeIn 0.35s ease-out;\n }\n\n &Icon {\n font-size: 20px;\n color: var(--error-color, #ef4444);\n }\n\n &Title {\n font-weight: var(--header-font-weight, 700);\n font-size: 17px;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.05s backwards;\n }\n\n &Description {\n color: var(--text-dark);\n font-size: 14px;\n line-height: 1.5;\n word-break: break-word;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.1s backwards;\n }\n\n &Stack {\n align-self: stretch;\n width: 100%;\n text-align: left;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.15s backwards;\n }\n\n &StackHeader {\n display: flex;\n align-items: center;\n justify-content: space-between;\n gap: 10px;\n margin-bottom: 10px;\n }\n\n &StackLabel {\n font-family: var(--monospace-font, monospace);\n font-size: 11px;\n font-weight: 700;\n letter-spacing: 0.02em;\n text-transform: uppercase;\n color: var(--error-color, #ef4444);\n background: var(--error-lighter);\n padding: 3px 8px;\n border-radius: 999px;\n }\n\n &CopyButton {\n flex-shrink: 0;\n }\n\n &StackTrace {\n margin: 0;\n padding: 12px;\n border-radius: var(--default-border-radius);\n background: var(--background);\n color: var(--text-dark);\n font-family: var(--monospace-font, monospace);\n font-size: 12px;\n line-height: 1.6;\n white-space: pre-wrap;\n word-break: break-word;\n max-height: 320px;\n overflow: auto;\n }\n\n &Actions {\n display: flex;\n justify-content: center;\n animation: errorBoundaryFadeUp 0.3s ease-out 0.2s backwards;\n }\n}\n\n@media (prefers-reduced-motion: reduce) {\n .errorBoundaryBadge,\n .errorBoundaryTitle,\n .errorBoundaryDescription,\n .errorBoundaryStack,\n .errorBoundaryActions {\n animation: none;\n }\n}\n"],"mappings":""}
@@ -0,0 +1,2 @@
1
+ "use client";import{useCallback as e,useEffect as t,useRef as n,useState as r}from"react";function i({timeout:i=2e3}={}){let[a,o]=r(!1),[s,c]=r(null),l=n(null),u=e(()=>{l.current&&clearTimeout(l.current),l.current=null},[]);t(()=>u,[u]);let d=e(()=>{u(),o(!1),c(null)},[u]);return{copy:e(async e=>{u();try{if(!navigator.clipboard?.writeText)throw Error(`Clipboard API unavailable`);return await navigator.clipboard.writeText(e),c(null),o(!0),l.current=setTimeout(()=>o(!1),i),!0}catch(e){return o(!1),c(e instanceof Error?e:Error(String(e))),!1}},[u,i]),copied:a,error:s,reset:d}}export{i as default,i as useClipboard};
2
+ //# sourceMappingURL=useClipboard.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useClipboard.mjs","names":[],"sources":["../../../../package/common/hooks/useClipboard.ts"],"sourcesContent":["import { useCallback, useEffect, useRef, useState } from 'react';\n\nexport interface UseClipboardOptions {\n /** How long `copied` stays `true` after a successful copy, in ms. Default: 2000. */\n timeout?: number;\n}\n\nexport interface UseClipboardResult {\n /** Writes `text` to the clipboard. Resolves `true` on success, `false` on failure. */\n copy: (text: string) => Promise<boolean>;\n /** `true` for `timeout` ms after a successful copy. */\n copied: boolean;\n /** Why the last copy failed, until the next attempt. */\n error: Error | null;\n /** Clears `copied` and `error` early. */\n reset: () => void;\n}\n\n// No `execCommand('copy')` fallback: it is deprecated, and where the async API is missing the\n// caller is better served by `error` than by a copy that may silently do nothing.\nexport function useClipboard({ timeout = 2000 }: UseClipboardOptions = {}): UseClipboardResult {\n const [copied, setCopied] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n const clearTimer = useCallback(() => {\n if (timerRef.current) clearTimeout(timerRef.current);\n timerRef.current = null;\n }, []);\n\n useEffect(() => clearTimer, [clearTimer]);\n\n const reset = useCallback(() => {\n clearTimer();\n setCopied(false);\n setError(null);\n }, [clearTimer]);\n\n const copy = useCallback(\n async (text: string) => {\n clearTimer();\n try {\n if (!navigator.clipboard?.writeText) throw new Error('Clipboard API unavailable');\n await navigator.clipboard.writeText(text);\n setError(null);\n setCopied(true);\n timerRef.current = setTimeout(() => setCopied(false), timeout);\n return true;\n } catch (e) {\n setCopied(false);\n setError(e instanceof Error ? e : new Error(String(e)));\n return false;\n }\n },\n [clearTimer, timeout],\n );\n\n return { copy, copied, error, reset };\n}\n\nexport default useClipboard;\n"],"mappings":"0FAoBA,SAAgB,EAAa,CAAE,UAAU,KAA8B,CAAC,EAAuB,CAC7F,GAAM,CAAC,EAAQ,GAAa,EAAS,EAAK,EACpC,CAAC,EAAO,GAAY,EAAuB,IAAI,EAC/C,EAAW,EAA6C,IAAI,EAE5D,EAAa,MAAkB,CAC/B,EAAS,SAAS,aAAa,EAAS,OAAO,EACnD,EAAS,QAAU,IACrB,EAAG,CAAC,CAAC,EAEL,MAAgB,EAAY,CAAC,CAAU,CAAC,EAExC,IAAM,EAAQ,MAAkB,CAC9B,EAAW,EACX,EAAU,EAAK,EACf,EAAS,IAAI,CACf,EAAG,CAAC,CAAU,CAAC,EAqBf,MAAO,CAAE,KAnBI,EACX,KAAO,IAAiB,CACtB,EAAW,EACX,GAAI,CACF,GAAI,CAAC,UAAU,WAAW,UAAW,MAAU,MAAM,2BAA2B,EAKhF,OAJA,MAAM,UAAU,UAAU,UAAU,CAAI,EACxC,EAAS,IAAI,EACb,EAAU,EAAI,EACd,EAAS,QAAU,eAAiB,EAAU,EAAK,EAAG,CAAO,EACtD,EACT,OAAS,EAAG,CAGV,OAFA,EAAU,EAAK,EACf,EAAS,aAAa,MAAQ,EAAQ,MAAM,OAAO,CAAC,CAAC,CAAC,EAC/C,EACT,CACF,EACA,CAAC,EAAY,CAAO,CAGb,EAAM,SAAQ,QAAO,OAAM,CACtC"}
@@ -0,0 +1,2 @@
1
+ "use client";import{useEffect as e,useRef as t}from"react";var n=`input, textarea, select, [contenteditable=""], [contenteditable="true"]`,r={esc:`escape`,space:` `,spacebar:` `,plus:`+`,up:`arrowup`,down:`arrowdown`,left:`arrowleft`,right:`arrowright`};function i(){return typeof navigator<`u`&&/Mac|iPhone|iPad|iPod/i.test(navigator.userAgent)}function a(e){let t=e.split(`+`).map(e=>e.trim().toLowerCase()).filter(Boolean);if(t.length===0)return null;let n={key:``,ctrl:!1,meta:!1,alt:!1,shift:!1,shiftNamed:!1},a=i();for(let e of t)switch(e){case`mod`:a?n.meta=!0:n.ctrl=!0;break;case`ctrl`:case`control`:n.ctrl=!0;break;case`meta`:case`cmd`:case`command`:n.meta=!0;break;case`alt`:case`option`:n.alt=!0;break;case`shift`:n.shift=!0,n.shiftNamed=!0;break;default:n.key=r[e]??e}return n.key?n:null}function o(e){let t=[e.key.toLowerCase()],n=/^(?:Key|Digit)(.)$/.exec(e.code);return n&&t.push(n[1].toLowerCase()),t}function s(e,t){return e.ctrl!==t.ctrlKey||e.meta!==t.metaKey||e.alt!==t.altKey||e.shiftNamed&&e.shift!==t.shiftKey?!1:o(t).includes(e.key)}function c(e){return e instanceof Element&&!!e.closest(n)}var l=new Set([`arrowup`,`arrowdown`,`arrowleft`,`arrowright`,`home`,`end`,`pageup`,`pagedown`,`backspace`,`delete`,`enter`,`tab`]);function u(e){return e.ctrl||e.meta||e.alt?!1:e.key.length===1||l.has(e.key)}var d={" ":`Space`,arrowup:`↑`,arrowdown:`↓`,arrowleft:`←`,arrowright:`→`,escape:`Esc`,enter:`↵`,backspace:`⌫`,delete:`Del`,pageup:`PgUp`,pagedown:`PgDn`};function f(e){let t=a(e);if(!t)return e;let n=d[t.key]??(t.key.length===1?t.key.toUpperCase():p(t.key));return i()?[t.ctrl&&`⌃`,t.alt&&`⌥`,t.shift&&`⇧`,t.meta&&`⌘`].filter(Boolean).join(``)+n:[...[t.ctrl&&`Ctrl`,t.meta&&`Win`,t.alt&&`Alt`,t.shift&&`Shift`].filter(Boolean),n].join(`+`)}function p(e){return e[0].toUpperCase()+e.slice(1)}function m(n,r={}){let{enabled:i=!0,target:o,enableInFields:l=!1,preventDefault:d=!0}=r,f=t(n);e(()=>{f.current=n}),e(()=>{if(!i)return;let e=o?o.current:window;if(!e)return;function t(e){let t=e;if(!t.isComposing)for(let[e,n]of Object.entries(f.current)){let r=a(e);if(r&&s(r,t)&&!(u(r)&&!l&&c(t.target))){d&&t.preventDefault(),n(t);return}}}return e.addEventListener(`keydown`,t),()=>e.removeEventListener(`keydown`,t)},[i,o,l,d])}export{m as default,m as useHotkeys,f as formatHotkey};
2
+ //# sourceMappingURL=useHotkeys.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useHotkeys.mjs","names":[],"sources":["../../../../package/common/hooks/useHotkeys.ts"],"sourcesContent":["import { useEffect, useRef, type RefObject } from 'react';\n\nexport type HotkeyHandler = (event: KeyboardEvent) => void;\n\n/** Combo → handler, e.g. `{ 'mod+k': open, Escape: close }`. */\nexport type HotkeyMap = Record<string, HotkeyHandler>;\n\nexport interface UseHotkeysOptions {\n /** Attach the listener at all. Default `true`; pass `false` to suspend every combo at once. */\n enabled?: boolean;\n /** Scope the shortcuts to one element instead of the whole window. */\n target?: RefObject<HTMLElement | null>;\n /**\n * Let plain-key combos fire while a text field or `contenteditable` has focus. Default `false`,\n * so `'n'` does not fire for every `n` typed into an input. Combos carrying Ctrl, Cmd or Alt\n * are never suppressed — they cannot be confused with typing.\n */\n enableInFields?: boolean;\n /**\n * Call `preventDefault()` on a match, so `mod+s` does not also open the browser's save dialog.\n * Default `true`.\n */\n preventDefault?: boolean;\n}\n\ninterface Combo {\n key: string;\n ctrl: boolean;\n meta: boolean;\n alt: boolean;\n shift: boolean;\n /** Set when the combo named Shift itself — see `matches`. */\n shiftNamed: boolean;\n}\n\nconst FIELD_SELECTOR = 'input, textarea, select, [contenteditable=\"\"], [contenteditable=\"true\"]';\n\n/** Spellings accepted for keys whose `event.key` is awkward to write inside a `+`-separated combo. */\nconst KEY_ALIASES: Record<string, string> = {\n esc: 'escape',\n space: ' ',\n spacebar: ' ',\n plus: '+',\n up: 'arrowup',\n down: 'arrowdown',\n left: 'arrowleft',\n right: 'arrowright',\n};\n\n/** `mod` is Cmd where Cmd is the command modifier, and Ctrl everywhere else. */\nfunction isApplePlatform(): boolean {\n return typeof navigator !== 'undefined' && /Mac|iPhone|iPad|iPod/i.test(navigator.userAgent);\n}\n\nfunction parseCombo(combo: string): Combo | null {\n const parts = combo\n .split('+')\n .map((part) => part.trim().toLowerCase())\n .filter(Boolean);\n // A trailing separator (`'mod+'`) loses its key to the filter above, so the whole combo is\n // dropped rather than matching on the modifier alone. `'mod+plus'` is how to mean `+` itself.\n if (parts.length === 0) return null;\n\n const parsed: Combo = { key: '', ctrl: false, meta: false, alt: false, shift: false, shiftNamed: false };\n const apple = isApplePlatform();\n\n for (const part of parts) {\n switch (part) {\n case 'mod':\n if (apple) parsed.meta = true;\n else parsed.ctrl = true;\n break;\n case 'ctrl':\n case 'control':\n parsed.ctrl = true;\n break;\n case 'meta':\n case 'cmd':\n case 'command':\n parsed.meta = true;\n break;\n case 'alt':\n case 'option':\n parsed.alt = true;\n break;\n case 'shift':\n parsed.shift = true;\n parsed.shiftNamed = true;\n break;\n default:\n parsed.key = KEY_ALIASES[part] ?? part;\n }\n }\n\n return parsed.key ? parsed : null;\n}\n\n/**\n * The key the event carries, plus the one its physical position would produce unshifted.\n *\n * Both are needed: Alt+K on a Mac arrives as `key: '˚'` and Shift+1 as `key: '!'`, so a combo\n * written against the letter or digit on the keycap only matches through `code`.\n */\nfunction pressedKeys(event: KeyboardEvent): string[] {\n const keys = [event.key.toLowerCase()];\n const physical = /^(?:Key|Digit)(.)$/.exec(event.code);\n if (physical) keys.push(physical[1].toLowerCase());\n return keys;\n}\n\nfunction matches(combo: Combo, event: KeyboardEvent): boolean {\n if (combo.ctrl !== event.ctrlKey || combo.meta !== event.metaKey || combo.alt !== event.altKey) return false;\n // Shift is only compared when the combo named it. A symbol is typed *with* Shift on most\n // layouts, so requiring `shiftKey === false` would make `'?'` and `'mod+/'` unreachable.\n if (combo.shiftNamed && combo.shift !== event.shiftKey) return false;\n return pressedKeys(event).includes(combo.key);\n}\n\nfunction isInField(target: EventTarget | null): boolean {\n return target instanceof Element && !!target.closest(FIELD_SELECTOR);\n}\n\n/** Keys a text field uses for itself, beyond the characters it inserts. */\nconst FIELD_KEYS = new Set([\n 'arrowup',\n 'arrowdown',\n 'arrowleft',\n 'arrowright',\n 'home',\n 'end',\n 'pageup',\n 'pagedown',\n 'backspace',\n 'delete',\n 'enter',\n 'tab',\n]);\n\n/**\n * Whether a combo would be taken out of a focused field's mouth.\n *\n * Ctrl, Cmd and Alt take a key out of the field's hands whatever it is. Without one, a single\n * character is typing and the listed keys are editing, but `F2` and `Escape` are neither, and\n * suppressing those made a menu's `F2` do nothing the moment the page had a focused input.\n */\nfunction isFieldKey(combo: Combo): boolean {\n if (combo.ctrl || combo.meta || combo.alt) return false;\n return combo.key.length === 1 || FIELD_KEYS.has(combo.key);\n}\n\n/** Keys whose name is not what a keycap says. Anything else is capitalised, so `f2` reads `F2`. */\nconst KEY_LABELS: Record<string, string> = {\n ' ': 'Space',\n arrowup: '↑',\n arrowdown: '↓',\n arrowleft: '←',\n arrowright: '→',\n escape: 'Esc',\n enter: '↵',\n backspace: '⌫',\n delete: 'Del',\n pageup: 'PgUp',\n pagedown: 'PgDn',\n};\n\n/**\n * A combo written for the reader: `'mod+shift+k'` reads `⇧⌘K` on an Apple platform and\n * `Ctrl+Shift+K` everywhere else.\n *\n * So a shortcut is written once, in one spelling, and the hint beside it cannot contradict what\n * the binding actually listens for. Hand-written `'⌘K'` hints are wrong on every other platform,\n * silently, because nothing compares the label to the binding.\n *\n * Resolved from the platform at call time, so a server-rendered page renders the non-Apple form.\n */\nexport function formatHotkey(combo: string): string {\n const parsed = parseCombo(combo);\n if (!parsed) return combo;\n\n const key = KEY_LABELS[parsed.key] ?? (parsed.key.length === 1 ? parsed.key.toUpperCase() : capitalise(parsed.key));\n\n // Apple orders modifier symbols ⌃⌥⇧⌘ and runs them into the key; everywhere else they are\n // words joined by `+`.\n if (isApplePlatform()) {\n const symbols = [parsed.ctrl && '⌃', parsed.alt && '⌥', parsed.shift && '⇧', parsed.meta && '⌘'];\n return symbols.filter(Boolean).join('') + key;\n }\n const words = [parsed.ctrl && 'Ctrl', parsed.meta && 'Win', parsed.alt && 'Alt', parsed.shift && 'Shift'];\n return [...words.filter(Boolean), key].join('+');\n}\n\nfunction capitalise(value: string): string {\n return value[0].toUpperCase() + value.slice(1);\n}\n\n/**\n * Keyboard shortcuts, for a whole app or for one element.\n *\n * ```tsx\n * useHotkeys({ 'mod+k': () => setPaletteOpen(true), '?': () => setHelpOpen(true) });\n * ```\n *\n * The map is read through a ref at event time, so an inline object literal is fine and no handler\n * needs memoising. Shortcuts keep firing while a Modal or Drawer is open — pass `enabled` for the\n * ones that should not.\n */\nexport function useHotkeys(hotkeys: HotkeyMap, options: UseHotkeysOptions = {}): void {\n const { enabled = true, target, enableInFields = false, preventDefault = true } = options;\n\n const hotkeysRef = useRef(hotkeys);\n useEffect(() => {\n hotkeysRef.current = hotkeys;\n });\n\n useEffect(() => {\n if (!enabled) return;\n const node: HTMLElement | Window | null = target ? target.current : window;\n if (!node) return;\n\n function onKeyDown(event: Event) {\n const keyboardEvent = event as KeyboardEvent;\n // A key pressed to compose a character in an IME is not a shortcut.\n if (keyboardEvent.isComposing) return;\n\n for (const [spelling, handler] of Object.entries(hotkeysRef.current)) {\n const combo = parseCombo(spelling);\n if (!combo || !matches(combo, keyboardEvent)) continue;\n if (isFieldKey(combo) && !enableInFields && isInField(keyboardEvent.target)) continue;\n if (preventDefault) keyboardEvent.preventDefault();\n handler(keyboardEvent);\n return;\n }\n }\n\n node.addEventListener('keydown', onKeyDown);\n return () => node.removeEventListener('keydown', onKeyDown);\n }, [enabled, target, enableInFields, preventDefault]);\n}\n\nexport default useHotkeys;\n"],"mappings":"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"}