@tensor_1/react 2.47.0 → 2.49.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 (204) hide show
  1. package/README.md +540 -2
  2. package/dist/{SchedulingCalendar-B6TakO2h.d.ts → SchedulingCalendar-WWyFL3Eo.d.ts} +51 -2
  3. package/dist/announce.d.ts +10 -0
  4. package/dist/announce.js +30 -0
  5. package/dist/chart-analytic.cjs +33 -25
  6. package/dist/chart-preset.cjs +23 -15
  7. package/dist/chart.cjs +23 -15
  8. package/dist/combobox-model.d.ts +10 -1
  9. package/dist/combobox-model.js +15 -0
  10. package/dist/command-palette-model.d.ts +44 -0
  11. package/dist/command-palette-model.js +36 -0
  12. package/dist/components/AccountMenu.d.ts +44 -0
  13. package/dist/components/AccountMenu.js +43 -0
  14. package/dist/components/AppShell.d.ts +45 -2
  15. package/dist/components/AppShell.js +116 -5
  16. package/dist/components/AuditLog.d.ts +128 -0
  17. package/dist/components/AuditLog.js +196 -0
  18. package/dist/components/BrandProfiles.js +4 -3
  19. package/dist/components/Breadcrumbs.d.ts +9 -2
  20. package/dist/components/Breadcrumbs.js +3 -2
  21. package/dist/components/Button.d.ts +12 -5
  22. package/dist/components/Button.js +7 -3
  23. package/dist/components/Card.d.ts +18 -1
  24. package/dist/components/Card.js +5 -1
  25. package/dist/components/ChangeHighlight.d.ts +30 -0
  26. package/dist/components/ChangeHighlight.js +21 -0
  27. package/dist/components/ChartCore.js +2 -1
  28. package/dist/components/Checkbox.d.ts +27 -1
  29. package/dist/components/Checkbox.js +31 -2
  30. package/dist/components/Chip.d.ts +7 -3
  31. package/dist/components/Chip.js +2 -2
  32. package/dist/components/CodeDisplay.d.ts +65 -0
  33. package/dist/components/CodeDisplay.js +124 -0
  34. package/dist/components/Combobox.d.ts +27 -6
  35. package/dist/components/Combobox.js +195 -58
  36. package/dist/components/CommandPalette.d.ts +36 -1
  37. package/dist/components/CommandPalette.js +254 -2
  38. package/dist/components/ContactCard.d.ts +66 -0
  39. package/dist/components/ContactCard.js +74 -0
  40. package/dist/components/Count.d.ts +24 -0
  41. package/dist/components/Count.js +32 -0
  42. package/dist/components/DashboardCanvas.js +14 -0
  43. package/dist/components/DataWorkspace.d.ts +167 -0
  44. package/dist/components/DataWorkspace.js +380 -0
  45. package/dist/components/DateFieldParts.d.ts +2 -1
  46. package/dist/components/DateFieldParts.js +7 -0
  47. package/dist/components/DatePicker.d.ts +9 -2
  48. package/dist/components/DatePicker.js +67 -28
  49. package/dist/components/DateRangePicker.d.ts +12 -2
  50. package/dist/components/DateRangePicker.js +13 -12
  51. package/dist/components/DetailPage.d.ts +7 -1
  52. package/dist/components/DetailPage.js +2 -1
  53. package/dist/components/Dialogs.d.ts +71 -10
  54. package/dist/components/Dialogs.js +130 -30
  55. package/dist/components/DiffViewer.d.ts +23 -3
  56. package/dist/components/DiffViewer.js +26 -12
  57. package/dist/components/DiscardPrompt.js +16 -0
  58. package/dist/components/DisplayPreferences.d.ts +83 -0
  59. package/dist/components/DisplayPreferences.js +185 -0
  60. package/dist/components/EditorialHome.d.ts +23 -3
  61. package/dist/components/EditorialHome.js +16 -11
  62. package/dist/components/EntityPicker.d.ts +20 -3
  63. package/dist/components/EntityPicker.js +32 -13
  64. package/dist/components/FilterEditor.d.ts +18 -4
  65. package/dist/components/FilterEditor.js +141 -19
  66. package/dist/components/FocusOnMount.d.ts +282 -0
  67. package/dist/components/FocusOnMount.js +12 -0
  68. package/dist/components/InfoTip.js +11 -12
  69. package/dist/components/InlineEdit.d.ts +87 -20
  70. package/dist/components/InlineEdit.js +197 -54
  71. package/dist/components/Input.d.ts +12 -2
  72. package/dist/components/Input.js +5 -3
  73. package/dist/components/Kanban.d.ts +14 -3
  74. package/dist/components/Kanban.js +9 -4
  75. package/dist/components/Kbd.d.ts +6 -1
  76. package/dist/components/Kbd.js +6 -6
  77. package/dist/components/Lightbox.d.ts +41 -5
  78. package/dist/components/Lightbox.js +95 -9
  79. package/dist/components/MatchReview.d.ts +40 -1
  80. package/dist/components/MatchReview.js +130 -4
  81. package/dist/components/MetricInput.js +3 -2
  82. package/dist/components/Modal.d.ts +2 -1
  83. package/dist/components/Modal.js +13 -4
  84. package/dist/components/MotionList.d.ts +303 -0
  85. package/dist/components/MotionList.js +175 -0
  86. package/dist/components/NavFavourites.d.ts +5 -0
  87. package/dist/components/NavFavourites.js +7 -7
  88. package/dist/components/OtpInput.d.ts +33 -0
  89. package/dist/components/OtpInput.js +123 -0
  90. package/dist/components/PageHeader.d.ts +7 -1
  91. package/dist/components/PageHeader.js +2 -2
  92. package/dist/components/Pagination.js +6 -5
  93. package/dist/components/PasswordInput.d.ts +34 -0
  94. package/dist/components/PasswordInput.js +101 -0
  95. package/dist/components/Peek.js +3 -3
  96. package/dist/components/Popover.js +11 -0
  97. package/dist/components/PrintLayout.d.ts +63 -0
  98. package/dist/components/PrintLayout.js +114 -0
  99. package/dist/components/QrCode.d.ts +47 -0
  100. package/dist/components/QrCode.js +55 -0
  101. package/dist/components/QrScanner.d.ts +95 -0
  102. package/dist/components/QrScanner.js +266 -0
  103. package/dist/components/RelationshipGraph.d.ts +32 -1
  104. package/dist/components/RelationshipGraph.js +22 -6
  105. package/dist/components/RelationshipGraphLayered.d.ts +1 -1
  106. package/dist/components/RelationshipGraphLayered.js +268 -118
  107. package/dist/components/RelationshipGraphList.js +33 -6
  108. package/dist/components/RuleBuilder.js +39 -7
  109. package/dist/components/SchedulingAgenda.d.ts +3 -1
  110. package/dist/components/SchedulingCalendar.d.ts +3 -1
  111. package/dist/components/SchedulingCalendar.js +43 -4
  112. package/dist/components/SchedulingResourceDay.d.ts +57 -0
  113. package/dist/components/SchedulingResourceDay.js +287 -0
  114. package/dist/components/SchedulingTimeGrid.d.ts +3 -1
  115. package/dist/components/SchedulingTimeline.d.ts +3 -1
  116. package/dist/components/SearchSuggest.d.ts +23 -3
  117. package/dist/components/SearchSuggest.js +56 -18
  118. package/dist/components/Segmented.d.ts +39 -4
  119. package/dist/components/Segmented.js +39 -5
  120. package/dist/components/Select.d.ts +3 -2
  121. package/dist/components/Select.js +7 -1
  122. package/dist/components/ShortcutHint.d.ts +11 -10
  123. package/dist/components/ShortcutHint.js +44 -38
  124. package/dist/components/Sidebar.d.ts +36 -4
  125. package/dist/components/Sidebar.js +37 -12
  126. package/dist/components/SortableList.d.ts +45 -0
  127. package/dist/components/SortableList.js +147 -0
  128. package/dist/components/Stat.d.ts +28 -3
  129. package/dist/components/Stat.js +13 -3
  130. package/dist/components/States.d.ts +33 -1
  131. package/dist/components/States.js +43 -1
  132. package/dist/components/StatusPill.d.ts +14 -3
  133. package/dist/components/StatusPill.js +11 -3
  134. package/dist/components/Steps.js +2 -1
  135. package/dist/components/Table.d.ts +9 -2
  136. package/dist/components/Table.js +4 -2
  137. package/dist/components/TableControls.js +18 -58
  138. package/dist/components/TableOverflowProbe.d.ts +12 -0
  139. package/dist/components/TableOverflowProbe.js +27 -0
  140. package/dist/components/Tabs.d.ts +2 -1
  141. package/dist/components/Tabs.js +10 -2
  142. package/dist/components/TagInput.d.ts +67 -0
  143. package/dist/components/TagInput.js +342 -0
  144. package/dist/components/Textarea.d.ts +5 -0
  145. package/dist/components/Textarea.js +2 -2
  146. package/dist/components/TimePicker.d.ts +80 -0
  147. package/dist/components/TimePicker.js +347 -0
  148. package/dist/components/Toast.d.ts +1 -1
  149. package/dist/components/Toast.js +109 -4
  150. package/dist/components/Tooltip.d.ts +8 -4
  151. package/dist/components/Tooltip.js +86 -28
  152. package/dist/components/Tree.d.ts +8 -0
  153. package/dist/components/Tree.js +11 -5
  154. package/dist/display-preferences-model.d.ts +53 -0
  155. package/dist/display-preferences-model.js +64 -0
  156. package/dist/emoji.cjs +143 -49
  157. package/dist/filter-model.d.ts +59 -3
  158. package/dist/filter-model.js +67 -2
  159. package/dist/hooks/useAnchoredPosition.js +14 -2
  160. package/dist/hooks/useChangeHighlight.d.ts +33 -0
  161. package/dist/hooks/useChangeHighlight.js +44 -0
  162. package/dist/hooks/useDeferredReorder.d.ts +32 -0
  163. package/dist/hooks/useDeferredReorder.js +47 -0
  164. package/dist/hooks/useDialog.d.ts +5 -0
  165. package/dist/hooks/useDialog.js +17 -3
  166. package/dist/hooks/useKeyboardGrab.d.ts +58 -0
  167. package/dist/hooks/useKeyboardGrab.js +118 -0
  168. package/dist/hooks/useOptimisticValue.d.ts +51 -0
  169. package/dist/hooks/useOptimisticValue.js +61 -0
  170. package/dist/hooks/useReducedMotion.d.ts +4 -1
  171. package/dist/hooks/useReducedMotion.js +7 -1
  172. package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
  173. package/dist/hooks/useResolvedFilterLabels.js +34 -0
  174. package/dist/hooks/useSlidingIndicator.d.ts +18 -0
  175. package/dist/hooks/useSlidingIndicator.js +80 -0
  176. package/dist/hooks/useVirtualRows.d.ts +21 -2
  177. package/dist/hooks/useVirtualRows.js +30 -3
  178. package/dist/icons/Icon.d.ts +1 -1
  179. package/dist/index.cjs +19687 -13423
  180. package/dist/index.d.cts +3419 -651
  181. package/dist/index.d.ts +48 -18
  182. package/dist/index.js +153 -9
  183. package/dist/labels-context.d.ts +93 -3
  184. package/dist/motion.d.ts +11 -0
  185. package/dist/motion.js +35 -0
  186. package/dist/overlay-stack.d.ts +6 -0
  187. package/dist/overlay-stack.js +13 -0
  188. package/dist/qr-model.d.ts +65 -0
  189. package/dist/qr-model.js +323 -0
  190. package/dist/relationship-graph-model.d.ts +92 -3
  191. package/dist/relationship-graph-model.js +134 -15
  192. package/dist/reorder.d.ts +30 -0
  193. package/dist/reorder.js +74 -0
  194. package/dist/rich-text.cjs +46 -4
  195. package/dist/scheduling-resource-model.d.ts +76 -0
  196. package/dist/scheduling-resource-model.js +74 -0
  197. package/dist/search-suggest-model.js +3 -1
  198. package/dist/shell-context.d.ts +11 -0
  199. package/dist/shell-context.js +7 -0
  200. package/dist/time-field-model.d.ts +46 -0
  201. package/dist/time-field-model.js +152 -0
  202. package/dist/toast-store.d.ts +22 -3
  203. package/dist/toast-store.js +26 -9
  204. package/package.json +2 -1
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { TextFilterOperator, NumberFilterOperator, FilterField, FilterValue } from '../filter-model.js';
2
+ import { TextFilterOperator, NumberFilterOperator, DateFilterOperator, FilterField, FilterValue } from '../filter-model.js';
3
3
 
4
4
  interface FilterEditorLabels {
5
5
  apply: string;
@@ -26,7 +26,15 @@ interface FilterEditorLabels {
26
26
  remove: string;
27
27
  /** Names the row of `field.presets` chips. Optional so existing label objects still type-check; default "Presets". */
28
28
  presets?: string;
29
+ /** `tags` (HAR-1832): the field that takes a new value, and its hint. Optional, like `presets`. */
30
+ addTag?: string;
31
+ /** `tags`: how to add one, read with the field. */
32
+ addTagHint?: string;
33
+ /** `date` (HAR-1832): the date of on / before / after. Optional, like `presets`. */
34
+ date?: string;
29
35
  operators: Record<TextFilterOperator | NumberFilterOperator, string>;
36
+ /** `date` conditions (HAR-1832). Optional, like `presets`. */
37
+ dateOperators?: Partial<Record<DateFilterOperator, string>>;
30
38
  }
31
39
  declare const DEFAULT_FILTER_EDITOR_LABELS: FilterEditorLabels;
32
40
  interface FilterEditorProps {
@@ -34,7 +42,12 @@ interface FilterEditorProps {
34
42
  /** Undefined means "not filtered yet". */
35
43
  value: FilterValue | undefined;
36
44
  onValueChange: (value: FilterValue) => void;
37
- onApply: () => void;
45
+ /**
46
+ * Apply the filter: the Apply button, or Enter in any field (HAR-1832). Gets the value to
47
+ * apply, which already holds a tag still being typed: read it rather than your state, which
48
+ * has not caught up when Enter applies in the same event.
49
+ */
50
+ onApply: (value: FilterValue) => void;
38
51
  onClear: () => void;
39
52
  labels?: Partial<FilterEditorLabels>;
40
53
  /** Show an option filter above an enum list once it has more options than this. Default 8. */
@@ -44,8 +57,9 @@ interface FilterEditorProps {
44
57
  }
45
58
  /**
46
59
  * Editor content for one typed column filter (HAR-1365; TENSOR C6, MOTUS C-1): an enum
47
- * multi-select, text or number with a condition, a date range, yes/no, or records found by
48
- * an async search. The product owns the popover trigger and the query; `summarizeFilter`
60
+ * multi-select, text or number with a condition, a date range, a date with a condition
61
+ * (on / before / after / between), yes/no, free-text tags, or records found by an async search
62
+ * (restored ids get their labels from `field.resolveLabels`). Enter applies in every kind. The product owns the popover trigger and the query; `summarizeFilter`
49
63
  * turns the applied value into the chip text. `FilterPopover` stays for the one-string case.
50
64
  * An enum field's `presets` (HAR-1505) render as toggle chips above its options. Words come
51
65
  * from `labels`, or from `UixLabelsProvider`'s `filterEditor` entry.
@@ -1,6 +1,6 @@
1
1
  "use client";
2
2
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useId, useMemo, useRef, useState } from "react";
3
+ import { Fragment as Fragment2, useEffect, useId, useMemo, useRef, useState } from "react";
4
4
  import { Button } from "./Button.js";
5
5
  import { Checkbox } from "./Checkbox.js";
6
6
  import { Input } from "./Input.js";
@@ -8,9 +8,11 @@ import { Radio, RadioGroup } from "./Radio.js";
8
8
  import { Select } from "./Select.js";
9
9
  import { Chip } from "./Chip.js";
10
10
  import { fillLabel } from "../fill-label.js";
11
+ import { cx } from "../cx.js";
11
12
  import { useUixLabels } from "../labels-context.js";
13
+ import { useDelayedPending } from "../hooks/useDelayedPending.js";
12
14
  import { foldForSearch } from "../search-suggest-model.js";
13
- import { NUMBER_FILTER_OPERATORS, TEXT_FILTER_OPERATORS, emptyFilterValue, matchFilterPreset } from "../filter-model.js";
15
+ import { DATE_FILTER_OPERATORS, NUMBER_FILTER_OPERATORS, TEXT_FILTER_OPERATORS, emptyFilterValue, isUnresolvedChoice, matchFilterPreset, orderFilterRange } from "../filter-model.js";
14
16
  const DEFAULT_FILTER_EDITOR_LABELS = {
15
17
  apply: "Apply",
16
18
  clear: "Clear",
@@ -32,6 +34,10 @@ const DEFAULT_FILTER_EDITOR_LABELS = {
32
34
  selected: "{count} selected",
33
35
  remove: "Remove {label}",
34
36
  presets: "Presets",
37
+ addTag: "Add a value",
38
+ addTagHint: "Enter or a comma adds it.",
39
+ date: "Date",
40
+ dateOperators: { on: "on", before: "before", after: "after", between: "between" },
35
41
  operators: {
36
42
  contains: "contains",
37
43
  "not-contains": "does not contain",
@@ -53,10 +59,21 @@ function FilterEditor({ field, value: valueProp, onValueChange, onApply, onClear
53
59
  ...DEFAULT_FILTER_EDITOR_LABELS,
54
60
  ...provided,
55
61
  ...labelOverrides,
56
- operators: { ...DEFAULT_FILTER_EDITOR_LABELS.operators, ...provided?.operators, ...labelOverrides?.operators }
62
+ operators: { ...DEFAULT_FILTER_EDITOR_LABELS.operators, ...provided?.operators, ...labelOverrides?.operators },
63
+ dateOperators: { ...DEFAULT_FILTER_EDITOR_LABELS.dateOperators, ...provided?.dateOperators, ...labelOverrides?.dateOperators }
57
64
  };
58
65
  const id = useId();
59
- const value = valueProp?.kind === field.kind ? valueProp : emptyFilterValue(field.kind);
66
+ let value = valueProp?.kind === field.kind ? valueProp : emptyFilterValue(field.kind);
67
+ if (value.kind === "date" && field.dateOperators?.length && !field.dateOperators.includes(value.operator)) value = { ...value, operator: field.dateOperators[0] };
68
+ const pendingTag = useRef(() => void 0);
69
+ const apply = () => onApply(orderFilterRange((value.kind === "tags" ? pendingTag.current() : void 0) ?? value));
70
+ const onKeyDown = (event) => {
71
+ if (event.key !== "Enter" || event.defaultPrevented || event.nativeEvent.isComposing || event.keyCode === 229) return;
72
+ const target = event.target;
73
+ if (target.closest('button, a, textarea, [role="option"], [role="listbox"], [aria-expanded="true"]')) return;
74
+ event.preventDefault();
75
+ apply();
76
+ };
60
77
  let body = null;
61
78
  switch (value.kind) {
62
79
  case "enum":
@@ -65,13 +82,31 @@ function FilterEditor({ field, value: valueProp, onValueChange, onApply, onClear
65
82
  case "reference":
66
83
  body = /* @__PURE__ */ jsx(ReferenceBody, { field, value, onChange: onValueChange, labels, delay: searchDelay });
67
84
  break;
85
+ case "tags":
86
+ body = /* @__PURE__ */ jsx(TagsBody, { value, onChange: onValueChange, labels, pending: pendingTag, id });
87
+ break;
88
+ case "date": {
89
+ const ops = field.dateOperators ?? DATE_FILTER_OPERATORS;
90
+ const words = labels.dateOperators ?? {};
91
+ const between = value.operator === "between";
92
+ body = /* @__PURE__ */ jsxs("div", { className: "uix-filter-editor__row", children: [
93
+ ops.length > 1 && /* @__PURE__ */ jsx(Select, { size: "sm", "aria-label": labels.operator, value: value.operator, onChange: (e) => onValueChange({ ...value, operator: e.currentTarget.value, ...e.currentTarget.value === "between" ? {} : { to: void 0 } }), children: ops.map((op) => /* @__PURE__ */ jsx("option", { value: op, children: words[op] ?? DEFAULT_FILTER_EDITOR_LABELS.dateOperators[op] }, op)) }),
94
+ /* @__PURE__ */ jsxs("label", { className: "uix-filter-editor__date", children: [
95
+ /* @__PURE__ */ jsx("span", { children: between ? labels.from : labels.date ?? DEFAULT_FILTER_EDITOR_LABELS.date }),
96
+ /* @__PURE__ */ jsx(Input, { type: "date", value: value.from ?? "", max: between ? value.to : void 0, onChange: (e) => onValueChange({ ...value, from: e.currentTarget.value || void 0 }), autoFocus: true })
97
+ ] }),
98
+ between && /* @__PURE__ */ jsxs("label", { className: "uix-filter-editor__date", children: [
99
+ /* @__PURE__ */ jsx("span", { children: labels.to }),
100
+ /* @__PURE__ */ jsx(Input, { type: "date", value: value.to ?? "", min: value.from, onChange: (e) => onValueChange({ ...value, to: e.currentTarget.value || void 0 }) })
101
+ ] })
102
+ ] });
103
+ break;
104
+ }
68
105
  case "text": {
69
106
  const ops = field.operators ?? TEXT_FILTER_OPERATORS;
70
107
  body = /* @__PURE__ */ jsxs("div", { className: "uix-filter-editor__row", children: [
71
108
  ops.length > 1 && /* @__PURE__ */ jsx(Select, { size: "sm", "aria-label": labels.operator, value: value.operator, onChange: (e) => onValueChange({ ...value, operator: e.currentTarget.value }), children: ops.map((op) => /* @__PURE__ */ jsx("option", { value: op, children: labels.operators[op] }, op)) }),
72
- /* @__PURE__ */ jsx(Input, { "aria-label": labels.value, value: value.text, onChange: (e) => onValueChange({ ...value, text: e.currentTarget.value }), onKeyDown: (e) => {
73
- if (e.key === "Enter") onApply();
74
- }, autoFocus: true })
109
+ /* @__PURE__ */ jsx(Input, { "aria-label": labels.value, value: value.text, onChange: (e) => onValueChange({ ...value, text: e.currentTarget.value }), autoFocus: true })
75
110
  ] });
76
111
  break;
77
112
  }
@@ -111,12 +146,12 @@ function FilterEditor({ field, value: valueProp, onValueChange, onApply, onClear
111
146
  break;
112
147
  }
113
148
  }
114
- return /* @__PURE__ */ jsxs("div", { className: "uix-filter-popover uix-filter-editor", role: "group", "aria-labelledby": `${id}-label`, "data-kind": field.kind, children: [
149
+ return /* @__PURE__ */ jsxs("div", { className: "uix-filter-popover uix-filter-editor", role: "group", "aria-labelledby": `${id}-label`, "data-kind": field.kind, onKeyDown, children: [
115
150
  /* @__PURE__ */ jsx("div", { id: `${id}-label`, className: "uix-filter-editor__label", children: field.label }),
116
- body,
151
+ /* @__PURE__ */ jsx(Fragment2, { children: body }, `${field.kind}:${field.id}`),
117
152
  /* @__PURE__ */ jsxs("div", { className: "uix-filter-popover__actions", children: [
118
153
  /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", onClick: onClear, children: labels.clear }),
119
- /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", variant: "primary", onClick: onApply, children: labels.apply })
154
+ /* @__PURE__ */ jsx(Button, { type: "button", size: "sm", variant: "primary", onClick: apply, children: labels.apply })
120
155
  ] })
121
156
  ] });
122
157
  }
@@ -146,13 +181,18 @@ function ReferenceBody({ field, value, onChange, labels, delay }) {
146
181
  const [query, setQuery] = useState("");
147
182
  const [state, setState] = useState({ status: "idle", results: [] });
148
183
  const [attempt, setAttempt] = useState(0);
184
+ const slow = useDelayedPending(state.status === "loading");
149
185
  const latest = useRef(0);
186
+ const search = useRef(field.onSearch);
187
+ search.current = field.onSearch;
188
+ const resolve = useRef(field.resolveLabels);
189
+ resolve.current = field.resolveLabels;
150
190
  useEffect(() => {
151
- if (!field.onSearch) return;
191
+ if (!search.current) return;
152
192
  const run = ++latest.current;
153
193
  const timer = window.setTimeout(() => {
154
194
  setState((s) => ({ ...s, status: "loading" }));
155
- field.onSearch(query.trim()).then(
195
+ search.current(query.trim()).then(
156
196
  (results) => {
157
197
  if (run === latest.current) setState({ status: "done", results });
158
198
  },
@@ -162,22 +202,104 @@ function ReferenceBody({ field, value, onChange, labels, delay }) {
162
202
  );
163
203
  }, delay);
164
204
  return () => window.clearTimeout(timer);
165
- }, [query, attempt, field, delay]);
166
- const chosen = new Map(value.values.map((v) => [v.value, v]));
167
- const toggle = (choice, on) => onChange({ kind: "reference", values: on ? [...value.values, choice] : value.values.filter((v) => v.value !== choice.value) });
205
+ }, [query, attempt, field.id, delay]);
206
+ const [known, setKnown] = useState(/* @__PURE__ */ new Map());
207
+ const answered = useRef(/* @__PURE__ */ new Set());
208
+ const requests = useRef(/* @__PURE__ */ new Map());
209
+ const unresolved = value.values.filter((v) => isUnresolvedChoice(v) && !known.has(v.value) && !answered.current.has(v.value)).map((v) => v.value);
210
+ const unresolvedKey = unresolved.join("\0");
211
+ useEffect(() => {
212
+ if (!unresolvedKey || !resolve.current) return;
213
+ let live = true;
214
+ const ids = unresolvedKey.split("\0");
215
+ let request = requests.current.get(unresolvedKey);
216
+ if (!request) {
217
+ request = resolve.current(ids);
218
+ requests.current.set(unresolvedKey, request);
219
+ }
220
+ const settle = (choices) => {
221
+ for (const id of ids) answered.current.add(id);
222
+ if (live) setKnown((prev) => new Map([...prev, ...choices.map((c) => [c.value, c.label])]));
223
+ };
224
+ request.then(settle, () => settle([]));
225
+ return () => {
226
+ live = false;
227
+ };
228
+ }, [unresolvedKey, field.id]);
229
+ const labelled = (v) => isUnresolvedChoice(v) && known.has(v.value) ? { value: v.value, label: known.get(v.value) } : v;
230
+ const values = value.values.map(labelled);
231
+ const chosen = new Map(values.map((v) => [v.value, v]));
232
+ const toggle = (choice, on) => onChange({ kind: "reference", values: on ? [...values, choice] : values.filter((v) => v.value !== choice.value) });
233
+ const showResults = state.status === "done" || state.status === "loading" && state.results.length > 0;
168
234
  return /* @__PURE__ */ jsxs(Fragment, { children: [
169
- value.values.length > 0 && /* @__PURE__ */ jsx("div", { className: "uix-chip-group", role: "group", "aria-label": fillLabel(labels.selected, { count: value.values.length }), children: value.values.map((v) => /* @__PURE__ */ jsx(Chip, { removeLabel: fillLabel(labels.remove, { label: v.label }), onRemove: () => toggle(v, false), children: v.label }, v.value)) }),
235
+ values.length > 0 && /* @__PURE__ */ jsx("div", { className: "uix-chip-group", role: "group", "aria-label": fillLabel(labels.selected, { count: values.length }), children: values.map((v) => /* @__PURE__ */ jsx(Chip, { removeLabel: fillLabel(labels.remove, { label: v.label }), onRemove: () => toggle(v, false), children: v.label }, v.value)) }),
170
236
  /* @__PURE__ */ jsx(Input, { type: "search", size: "sm", "aria-label": labels.search, placeholder: labels.search, value: query, onChange: (e) => setQuery(e.currentTarget.value), autoFocus: true }),
171
237
  /* @__PURE__ */ jsxs("div", { className: "uix-filter-editor__list", "aria-busy": state.status === "loading" || void 0, children: [
172
- state.status === "loading" && /* @__PURE__ */ jsx("p", { className: "uix-filter-editor__note", role: "status", children: labels.searching }),
173
238
  state.status === "error" && /* @__PURE__ */ jsxs("p", { className: "uix-filter-editor__note", role: "alert", children: [
174
239
  labels.searchFailed,
175
240
  " ",
176
241
  /* @__PURE__ */ jsx(Button, { type: "button", variant: "link", size: "sm", onClick: () => setAttempt((n) => n + 1), children: labels.retry })
177
242
  ] }),
178
243
  state.status === "done" && state.results.length === 0 && /* @__PURE__ */ jsx("p", { className: "uix-filter-editor__note", children: labels.noMatches }),
179
- state.status === "done" && state.results.map((r) => /* @__PURE__ */ jsx(Checkbox, { label: r.label, checked: chosen.has(r.value), onChange: (e) => toggle(r, e.currentTarget.checked) }, r.value))
180
- ] })
244
+ showResults && state.results.map((r) => /* @__PURE__ */ jsx(Checkbox, { label: r.label, checked: chosen.has(r.value), onChange: (e) => toggle(r, e.currentTarget.checked) }, r.value))
245
+ ] }),
246
+ /* @__PURE__ */ jsx("p", { className: cx("uix-filter-editor__note", "uix-filter-editor__searching", !slow && "uix-visually-hidden"), role: "status", "data-shown": slow || void 0, children: slow ? labels.searching : "" })
247
+ ] });
248
+ }
249
+ const splitTags = (text) => text.split(/[,\n]/).map((t) => t.trim()).filter(Boolean);
250
+ function TagsBody({ value, onChange, labels, pending, id }) {
251
+ const [draft, setDraft] = useState("");
252
+ const field = useRef(null);
253
+ const withTags = (tags) => ({ kind: "tags", values: [...value.values, ...tags.filter((t, i) => !value.values.includes(t) && tags.indexOf(t) === i)] });
254
+ pending.current = () => splitTags(draft).length ? withTags(splitTags(draft)) : void 0;
255
+ const commit = (text) => {
256
+ const tags = splitTags(text);
257
+ if (tags.length) onChange(withTags(tags));
258
+ setDraft("");
259
+ };
260
+ const remove = (tag) => {
261
+ onChange({ kind: "tags", values: value.values.filter((t) => t !== tag) });
262
+ field.current?.focus();
263
+ };
264
+ const onKeyDown = (event) => {
265
+ if (event.nativeEvent.isComposing || event.keyCode === 229) return;
266
+ if ((event.key === "Enter" || event.key === ",") && draft.trim()) {
267
+ event.preventDefault();
268
+ commit(draft);
269
+ } else if (event.key === ",") {
270
+ event.preventDefault();
271
+ } else if (event.key === "Backspace" && draft === "" && value.values.length > 0) {
272
+ onChange({ kind: "tags", values: value.values.slice(0, -1) });
273
+ }
274
+ };
275
+ const onPaste = (event) => {
276
+ const text = event.clipboardData.getData("text");
277
+ if (!/[,\n]/.test(text)) return;
278
+ event.preventDefault();
279
+ commit(`${draft}${text}`);
280
+ };
281
+ return /* @__PURE__ */ jsxs("div", { className: "uix-taginput uix-filter-editor__tags", children: [
282
+ value.values.map((tag) => /* @__PURE__ */ jsxs("span", { className: "uix-tag", children: [
283
+ tag,
284
+ /* @__PURE__ */ jsx("button", { type: "button", className: "uix-tag__remove", "aria-label": fillLabel(labels.remove, { label: tag }), onClick: () => remove(tag), children: /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2.5, strokeLinecap: "round", "aria-hidden": "true", children: /* @__PURE__ */ jsx("path", { d: "M18 6 6 18M6 6l12 12" }) }) })
285
+ ] }, tag)),
286
+ /* @__PURE__ */ jsx(
287
+ "input",
288
+ {
289
+ ref: field,
290
+ className: "uix-taginput__field",
291
+ "aria-label": labels.addTag ?? DEFAULT_FILTER_EDITOR_LABELS.addTag,
292
+ "aria-describedby": `${id}-tags-hint`,
293
+ placeholder: labels.addTag ?? DEFAULT_FILTER_EDITOR_LABELS.addTag,
294
+ value: draft,
295
+ enterKeyHint: "enter",
296
+ onChange: (e) => setDraft(e.currentTarget.value),
297
+ onKeyDown,
298
+ onPaste,
299
+ autoFocus: true
300
+ }
301
+ ),
302
+ /* @__PURE__ */ jsx("span", { id: `${id}-tags-hint`, className: "uix-visually-hidden", children: labels.addTagHint ?? DEFAULT_FILTER_EDITOR_LABELS.addTagHint })
181
303
  ] });
182
304
  }
183
305
  export {
@@ -0,0 +1,282 @@
1
+ import * as react from 'react';
2
+ import { ReactNode, HTMLAttributes } from 'react';
3
+
4
+ /**
5
+ * A heading (or any element) that takes focus once, when it mounts — so a page that replaces
6
+ * a form with its outcome (SuccessState) reads the outcome first. `tabIndex={-1}`: focusable
7
+ * by script, not a tab stop. The client half of server-renderable states.
8
+ */
9
+ declare function FocusOnMount({ as, enabled, children, ...props }: {
10
+ as: keyof HTMLElementTagNameMap;
11
+ enabled?: boolean;
12
+ children?: ReactNode;
13
+ } & HTMLAttributes<HTMLElement>): react.DetailedReactHTMLElement<{
14
+ ref: react.RefObject<HTMLElement>;
15
+ tabIndex: number;
16
+ defaultChecked?: boolean | undefined;
17
+ defaultValue?: string | number | readonly string[] | undefined;
18
+ suppressContentEditableWarning?: boolean | undefined;
19
+ suppressHydrationWarning?: boolean | undefined;
20
+ accessKey?: string | undefined;
21
+ autoCapitalize?: "off" | "none" | "on" | "sentences" | "words" | "characters" | undefined | (string & {});
22
+ autoFocus?: boolean | undefined;
23
+ className?: string | undefined;
24
+ contentEditable?: (boolean | "false" | "true") | "inherit" | "plaintext-only" | undefined;
25
+ contextMenu?: string | undefined;
26
+ dir?: string | undefined;
27
+ draggable?: (boolean | "false" | "true") | undefined;
28
+ enterKeyHint?: "enter" | "done" | "go" | "next" | "previous" | "search" | "send" | undefined;
29
+ hidden?: boolean | undefined;
30
+ id?: string | undefined;
31
+ lang?: string | undefined;
32
+ nonce?: string | undefined;
33
+ slot?: string | undefined;
34
+ spellCheck?: (boolean | "false" | "true") | undefined;
35
+ style?: react.CSSProperties | undefined;
36
+ title?: string | undefined;
37
+ translate?: "yes" | "no" | undefined;
38
+ radioGroup?: string | undefined;
39
+ role?: react.AriaRole | undefined;
40
+ about?: string | undefined;
41
+ content?: string | undefined;
42
+ datatype?: string | undefined;
43
+ inlist?: any;
44
+ prefix?: string | undefined;
45
+ property?: string | undefined;
46
+ rel?: string | undefined;
47
+ resource?: string | undefined;
48
+ rev?: string | undefined;
49
+ typeof?: string | undefined;
50
+ vocab?: string | undefined;
51
+ autoCorrect?: string | undefined;
52
+ autoSave?: string | undefined;
53
+ color?: string | undefined;
54
+ itemProp?: string | undefined;
55
+ itemScope?: boolean | undefined;
56
+ itemType?: string | undefined;
57
+ itemID?: string | undefined;
58
+ itemRef?: string | undefined;
59
+ results?: number | undefined;
60
+ security?: string | undefined;
61
+ unselectable?: "on" | "off" | undefined;
62
+ inputMode?: "none" | "text" | "tel" | "url" | "email" | "numeric" | "decimal" | "search" | undefined;
63
+ is?: string | undefined;
64
+ exportparts?: string | undefined;
65
+ part?: string | undefined;
66
+ "aria-activedescendant"?: string | undefined;
67
+ "aria-atomic"?: (boolean | "false" | "true") | undefined;
68
+ "aria-autocomplete"?: "none" | "inline" | "list" | "both" | undefined;
69
+ "aria-braillelabel"?: string | undefined;
70
+ "aria-brailleroledescription"?: string | undefined;
71
+ "aria-busy"?: (boolean | "false" | "true") | undefined;
72
+ "aria-checked"?: boolean | "false" | "mixed" | "true" | undefined;
73
+ "aria-colcount"?: number | undefined;
74
+ "aria-colindex"?: number | undefined;
75
+ "aria-colindextext"?: string | undefined;
76
+ "aria-colspan"?: number | undefined;
77
+ "aria-controls"?: string | undefined;
78
+ "aria-current"?: boolean | "false" | "true" | "page" | "step" | "location" | "date" | "time" | undefined;
79
+ "aria-describedby"?: string | undefined;
80
+ "aria-description"?: string | undefined;
81
+ "aria-details"?: string | undefined;
82
+ "aria-disabled"?: (boolean | "false" | "true") | undefined;
83
+ "aria-dropeffect"?: "none" | "copy" | "execute" | "link" | "move" | "popup" | undefined;
84
+ "aria-errormessage"?: string | undefined;
85
+ "aria-expanded"?: (boolean | "false" | "true") | undefined;
86
+ "aria-flowto"?: string | undefined;
87
+ "aria-grabbed"?: (boolean | "false" | "true") | undefined;
88
+ "aria-haspopup"?: boolean | "false" | "true" | "menu" | "listbox" | "tree" | "grid" | "dialog" | undefined;
89
+ "aria-hidden"?: (boolean | "false" | "true") | undefined;
90
+ "aria-invalid"?: boolean | "false" | "true" | "grammar" | "spelling" | undefined;
91
+ "aria-keyshortcuts"?: string | undefined;
92
+ "aria-label"?: string | undefined;
93
+ "aria-labelledby"?: string | undefined;
94
+ "aria-level"?: number | undefined;
95
+ "aria-live"?: "off" | "assertive" | "polite" | undefined;
96
+ "aria-modal"?: (boolean | "false" | "true") | undefined;
97
+ "aria-multiline"?: (boolean | "false" | "true") | undefined;
98
+ "aria-multiselectable"?: (boolean | "false" | "true") | undefined;
99
+ "aria-orientation"?: "horizontal" | "vertical" | undefined;
100
+ "aria-owns"?: string | undefined;
101
+ "aria-placeholder"?: string | undefined;
102
+ "aria-posinset"?: number | undefined;
103
+ "aria-pressed"?: boolean | "false" | "mixed" | "true" | undefined;
104
+ "aria-readonly"?: (boolean | "false" | "true") | undefined;
105
+ "aria-relevant"?: "additions" | "additions removals" | "additions text" | "all" | "removals" | "removals additions" | "removals text" | "text" | "text additions" | "text removals" | undefined;
106
+ "aria-required"?: (boolean | "false" | "true") | undefined;
107
+ "aria-roledescription"?: string | undefined;
108
+ "aria-rowcount"?: number | undefined;
109
+ "aria-rowindex"?: number | undefined;
110
+ "aria-rowindextext"?: string | undefined;
111
+ "aria-rowspan"?: number | undefined;
112
+ "aria-selected"?: (boolean | "false" | "true") | undefined;
113
+ "aria-setsize"?: number | undefined;
114
+ "aria-sort"?: "none" | "ascending" | "descending" | "other" | undefined;
115
+ "aria-valuemax"?: number | undefined;
116
+ "aria-valuemin"?: number | undefined;
117
+ "aria-valuenow"?: number | undefined;
118
+ "aria-valuetext"?: string | undefined;
119
+ dangerouslySetInnerHTML?: {
120
+ __html: string | TrustedHTML;
121
+ } | undefined;
122
+ onCopy?: react.ClipboardEventHandler<HTMLElement> | undefined;
123
+ onCopyCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
124
+ onCut?: react.ClipboardEventHandler<HTMLElement> | undefined;
125
+ onCutCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
126
+ onPaste?: react.ClipboardEventHandler<HTMLElement> | undefined;
127
+ onPasteCapture?: react.ClipboardEventHandler<HTMLElement> | undefined;
128
+ onCompositionEnd?: react.CompositionEventHandler<HTMLElement> | undefined;
129
+ onCompositionEndCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
130
+ onCompositionStart?: react.CompositionEventHandler<HTMLElement> | undefined;
131
+ onCompositionStartCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
132
+ onCompositionUpdate?: react.CompositionEventHandler<HTMLElement> | undefined;
133
+ onCompositionUpdateCapture?: react.CompositionEventHandler<HTMLElement> | undefined;
134
+ onFocus?: react.FocusEventHandler<HTMLElement> | undefined;
135
+ onFocusCapture?: react.FocusEventHandler<HTMLElement> | undefined;
136
+ onBlur?: react.FocusEventHandler<HTMLElement> | undefined;
137
+ onBlurCapture?: react.FocusEventHandler<HTMLElement> | undefined;
138
+ onChange?: react.FormEventHandler<HTMLElement> | undefined;
139
+ onChangeCapture?: react.FormEventHandler<HTMLElement> | undefined;
140
+ onBeforeInput?: react.InputEventHandler<HTMLElement> | undefined;
141
+ onBeforeInputCapture?: react.FormEventHandler<HTMLElement> | undefined;
142
+ onInput?: react.FormEventHandler<HTMLElement> | undefined;
143
+ onInputCapture?: react.FormEventHandler<HTMLElement> | undefined;
144
+ onReset?: react.FormEventHandler<HTMLElement> | undefined;
145
+ onResetCapture?: react.FormEventHandler<HTMLElement> | undefined;
146
+ onSubmit?: react.FormEventHandler<HTMLElement> | undefined;
147
+ onSubmitCapture?: react.FormEventHandler<HTMLElement> | undefined;
148
+ onInvalid?: react.FormEventHandler<HTMLElement> | undefined;
149
+ onInvalidCapture?: react.FormEventHandler<HTMLElement> | undefined;
150
+ onLoad?: react.ReactEventHandler<HTMLElement> | undefined;
151
+ onLoadCapture?: react.ReactEventHandler<HTMLElement> | undefined;
152
+ onError?: react.ReactEventHandler<HTMLElement> | undefined;
153
+ onErrorCapture?: react.ReactEventHandler<HTMLElement> | undefined;
154
+ onKeyDown?: react.KeyboardEventHandler<HTMLElement> | undefined;
155
+ onKeyDownCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
156
+ onKeyPress?: react.KeyboardEventHandler<HTMLElement> | undefined;
157
+ onKeyPressCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
158
+ onKeyUp?: react.KeyboardEventHandler<HTMLElement> | undefined;
159
+ onKeyUpCapture?: react.KeyboardEventHandler<HTMLElement> | undefined;
160
+ onAbort?: react.ReactEventHandler<HTMLElement> | undefined;
161
+ onAbortCapture?: react.ReactEventHandler<HTMLElement> | undefined;
162
+ onCanPlay?: react.ReactEventHandler<HTMLElement> | undefined;
163
+ onCanPlayCapture?: react.ReactEventHandler<HTMLElement> | undefined;
164
+ onCanPlayThrough?: react.ReactEventHandler<HTMLElement> | undefined;
165
+ onCanPlayThroughCapture?: react.ReactEventHandler<HTMLElement> | undefined;
166
+ onDurationChange?: react.ReactEventHandler<HTMLElement> | undefined;
167
+ onDurationChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
168
+ onEmptied?: react.ReactEventHandler<HTMLElement> | undefined;
169
+ onEmptiedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
170
+ onEncrypted?: react.ReactEventHandler<HTMLElement> | undefined;
171
+ onEncryptedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
172
+ onEnded?: react.ReactEventHandler<HTMLElement> | undefined;
173
+ onEndedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
174
+ onLoadedData?: react.ReactEventHandler<HTMLElement> | undefined;
175
+ onLoadedDataCapture?: react.ReactEventHandler<HTMLElement> | undefined;
176
+ onLoadedMetadata?: react.ReactEventHandler<HTMLElement> | undefined;
177
+ onLoadedMetadataCapture?: react.ReactEventHandler<HTMLElement> | undefined;
178
+ onLoadStart?: react.ReactEventHandler<HTMLElement> | undefined;
179
+ onLoadStartCapture?: react.ReactEventHandler<HTMLElement> | undefined;
180
+ onPause?: react.ReactEventHandler<HTMLElement> | undefined;
181
+ onPauseCapture?: react.ReactEventHandler<HTMLElement> | undefined;
182
+ onPlay?: react.ReactEventHandler<HTMLElement> | undefined;
183
+ onPlayCapture?: react.ReactEventHandler<HTMLElement> | undefined;
184
+ onPlaying?: react.ReactEventHandler<HTMLElement> | undefined;
185
+ onPlayingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
186
+ onProgress?: react.ReactEventHandler<HTMLElement> | undefined;
187
+ onProgressCapture?: react.ReactEventHandler<HTMLElement> | undefined;
188
+ onRateChange?: react.ReactEventHandler<HTMLElement> | undefined;
189
+ onRateChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
190
+ onSeeked?: react.ReactEventHandler<HTMLElement> | undefined;
191
+ onSeekedCapture?: react.ReactEventHandler<HTMLElement> | undefined;
192
+ onSeeking?: react.ReactEventHandler<HTMLElement> | undefined;
193
+ onSeekingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
194
+ onStalled?: react.ReactEventHandler<HTMLElement> | undefined;
195
+ onStalledCapture?: react.ReactEventHandler<HTMLElement> | undefined;
196
+ onSuspend?: react.ReactEventHandler<HTMLElement> | undefined;
197
+ onSuspendCapture?: react.ReactEventHandler<HTMLElement> | undefined;
198
+ onTimeUpdate?: react.ReactEventHandler<HTMLElement> | undefined;
199
+ onTimeUpdateCapture?: react.ReactEventHandler<HTMLElement> | undefined;
200
+ onVolumeChange?: react.ReactEventHandler<HTMLElement> | undefined;
201
+ onVolumeChangeCapture?: react.ReactEventHandler<HTMLElement> | undefined;
202
+ onWaiting?: react.ReactEventHandler<HTMLElement> | undefined;
203
+ onWaitingCapture?: react.ReactEventHandler<HTMLElement> | undefined;
204
+ onAuxClick?: react.MouseEventHandler<HTMLElement> | undefined;
205
+ onAuxClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
206
+ onClick?: react.MouseEventHandler<HTMLElement> | undefined;
207
+ onClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
208
+ onContextMenu?: react.MouseEventHandler<HTMLElement> | undefined;
209
+ onContextMenuCapture?: react.MouseEventHandler<HTMLElement> | undefined;
210
+ onDoubleClick?: react.MouseEventHandler<HTMLElement> | undefined;
211
+ onDoubleClickCapture?: react.MouseEventHandler<HTMLElement> | undefined;
212
+ onDrag?: react.DragEventHandler<HTMLElement> | undefined;
213
+ onDragCapture?: react.DragEventHandler<HTMLElement> | undefined;
214
+ onDragEnd?: react.DragEventHandler<HTMLElement> | undefined;
215
+ onDragEndCapture?: react.DragEventHandler<HTMLElement> | undefined;
216
+ onDragEnter?: react.DragEventHandler<HTMLElement> | undefined;
217
+ onDragEnterCapture?: react.DragEventHandler<HTMLElement> | undefined;
218
+ onDragExit?: react.DragEventHandler<HTMLElement> | undefined;
219
+ onDragExitCapture?: react.DragEventHandler<HTMLElement> | undefined;
220
+ onDragLeave?: react.DragEventHandler<HTMLElement> | undefined;
221
+ onDragLeaveCapture?: react.DragEventHandler<HTMLElement> | undefined;
222
+ onDragOver?: react.DragEventHandler<HTMLElement> | undefined;
223
+ onDragOverCapture?: react.DragEventHandler<HTMLElement> | undefined;
224
+ onDragStart?: react.DragEventHandler<HTMLElement> | undefined;
225
+ onDragStartCapture?: react.DragEventHandler<HTMLElement> | undefined;
226
+ onDrop?: react.DragEventHandler<HTMLElement> | undefined;
227
+ onDropCapture?: react.DragEventHandler<HTMLElement> | undefined;
228
+ onMouseDown?: react.MouseEventHandler<HTMLElement> | undefined;
229
+ onMouseDownCapture?: react.MouseEventHandler<HTMLElement> | undefined;
230
+ onMouseEnter?: react.MouseEventHandler<HTMLElement> | undefined;
231
+ onMouseLeave?: react.MouseEventHandler<HTMLElement> | undefined;
232
+ onMouseMove?: react.MouseEventHandler<HTMLElement> | undefined;
233
+ onMouseMoveCapture?: react.MouseEventHandler<HTMLElement> | undefined;
234
+ onMouseOut?: react.MouseEventHandler<HTMLElement> | undefined;
235
+ onMouseOutCapture?: react.MouseEventHandler<HTMLElement> | undefined;
236
+ onMouseOver?: react.MouseEventHandler<HTMLElement> | undefined;
237
+ onMouseOverCapture?: react.MouseEventHandler<HTMLElement> | undefined;
238
+ onMouseUp?: react.MouseEventHandler<HTMLElement> | undefined;
239
+ onMouseUpCapture?: react.MouseEventHandler<HTMLElement> | undefined;
240
+ onSelect?: react.ReactEventHandler<HTMLElement> | undefined;
241
+ onSelectCapture?: react.ReactEventHandler<HTMLElement> | undefined;
242
+ onTouchCancel?: react.TouchEventHandler<HTMLElement> | undefined;
243
+ onTouchCancelCapture?: react.TouchEventHandler<HTMLElement> | undefined;
244
+ onTouchEnd?: react.TouchEventHandler<HTMLElement> | undefined;
245
+ onTouchEndCapture?: react.TouchEventHandler<HTMLElement> | undefined;
246
+ onTouchMove?: react.TouchEventHandler<HTMLElement> | undefined;
247
+ onTouchMoveCapture?: react.TouchEventHandler<HTMLElement> | undefined;
248
+ onTouchStart?: react.TouchEventHandler<HTMLElement> | undefined;
249
+ onTouchStartCapture?: react.TouchEventHandler<HTMLElement> | undefined;
250
+ onPointerDown?: react.PointerEventHandler<HTMLElement> | undefined;
251
+ onPointerDownCapture?: react.PointerEventHandler<HTMLElement> | undefined;
252
+ onPointerMove?: react.PointerEventHandler<HTMLElement> | undefined;
253
+ onPointerMoveCapture?: react.PointerEventHandler<HTMLElement> | undefined;
254
+ onPointerUp?: react.PointerEventHandler<HTMLElement> | undefined;
255
+ onPointerUpCapture?: react.PointerEventHandler<HTMLElement> | undefined;
256
+ onPointerCancel?: react.PointerEventHandler<HTMLElement> | undefined;
257
+ onPointerCancelCapture?: react.PointerEventHandler<HTMLElement> | undefined;
258
+ onPointerEnter?: react.PointerEventHandler<HTMLElement> | undefined;
259
+ onPointerLeave?: react.PointerEventHandler<HTMLElement> | undefined;
260
+ onPointerOver?: react.PointerEventHandler<HTMLElement> | undefined;
261
+ onPointerOverCapture?: react.PointerEventHandler<HTMLElement> | undefined;
262
+ onPointerOut?: react.PointerEventHandler<HTMLElement> | undefined;
263
+ onPointerOutCapture?: react.PointerEventHandler<HTMLElement> | undefined;
264
+ onGotPointerCapture?: react.PointerEventHandler<HTMLElement> | undefined;
265
+ onGotPointerCaptureCapture?: react.PointerEventHandler<HTMLElement> | undefined;
266
+ onLostPointerCapture?: react.PointerEventHandler<HTMLElement> | undefined;
267
+ onLostPointerCaptureCapture?: react.PointerEventHandler<HTMLElement> | undefined;
268
+ onScroll?: react.UIEventHandler<HTMLElement> | undefined;
269
+ onScrollCapture?: react.UIEventHandler<HTMLElement> | undefined;
270
+ onWheel?: react.WheelEventHandler<HTMLElement> | undefined;
271
+ onWheelCapture?: react.WheelEventHandler<HTMLElement> | undefined;
272
+ onAnimationStart?: react.AnimationEventHandler<HTMLElement> | undefined;
273
+ onAnimationStartCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
274
+ onAnimationEnd?: react.AnimationEventHandler<HTMLElement> | undefined;
275
+ onAnimationEndCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
276
+ onAnimationIteration?: react.AnimationEventHandler<HTMLElement> | undefined;
277
+ onAnimationIterationCapture?: react.AnimationEventHandler<HTMLElement> | undefined;
278
+ onTransitionEnd?: react.TransitionEventHandler<HTMLElement> | undefined;
279
+ onTransitionEndCapture?: react.TransitionEventHandler<HTMLElement> | undefined;
280
+ }, HTMLElement>;
281
+
282
+ export { FocusOnMount };
@@ -0,0 +1,12 @@
1
+ "use client";
2
+ import { createElement, useEffect, useRef } from "react";
3
+ function FocusOnMount({ as, enabled = true, children, ...props }) {
4
+ const ref = useRef(null);
5
+ useEffect(() => {
6
+ if (enabled) ref.current?.focus({ preventScroll: false });
7
+ }, [enabled]);
8
+ return createElement(as, { ...props, ref, tabIndex: -1 }, children);
9
+ }
10
+ export {
11
+ FocusOnMount
12
+ };
@@ -1,11 +1,12 @@
1
1
  "use client";
2
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
- import { useEffect, useId, useRef, useState } from "react";
3
+ import { useEffect, useId, useLayoutEffect, useRef, useState } from "react";
4
4
  import { cx } from "../cx.js";
5
5
  import { helpParagraphs } from "../info-tip-model.js";
6
6
  import { Popover } from "./Popover.js";
7
7
  const OPEN_DELAY = 300;
8
8
  const CLOSE_DELAY = 100;
9
+ const useIsomorphicLayoutEffect = typeof document !== "undefined" ? useLayoutEffect : useEffect;
9
10
  const QuestionMark = () => /* @__PURE__ */ jsx("svg", { viewBox: "262 -840 436 760", fill: "currentColor", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M424-320q0-81 14.5-116.5T500-514q41-36 62.5-62.5T584-637q0-41-27.5-68T480-732q-51 0-77.5 31T365-638l-103-44q21-64 77-111t141-47q105 0 161.5 58.5T698-641q0 50-21.5 85.5T609-475q-49 47-59.5 71.5T539-320H424Zm56 240q-33 0-56.5-23.5T400-160q0-33 23.5-56.5T480-240q33 0 56.5 23.5T560-160q0 33-23.5 56.5T480-80Z" }) });
10
11
  const isShown = (el) => {
11
12
  try {
@@ -93,18 +94,21 @@ function InfoTipControl({
93
94
  refocusing.current = false;
94
95
  }
95
96
  };
96
- useEffect(() => {
97
- if (!open) return;
97
+ useIsomorphicLayoutEffect(() => {
98
+ if (!open) return void 0;
98
99
  const onKey = (e) => {
99
- if (e.key === "Escape") escape();
100
+ if (e.key !== "Escape" || !openRef.current) return;
101
+ e.preventDefault();
102
+ e.stopPropagation();
103
+ escape();
100
104
  };
101
105
  const onPointer = (e) => {
102
106
  if (!wrapRef.current?.contains(e.target)) hide();
103
107
  };
104
- document.addEventListener("keydown", onKey);
108
+ document.addEventListener("keydown", onKey, true);
105
109
  document.addEventListener("pointerdown", onPointer, true);
106
110
  return () => {
107
- document.removeEventListener("keydown", onKey);
111
+ document.removeEventListener("keydown", onKey, true);
108
112
  document.removeEventListener("pointerdown", onPointer, true);
109
113
  };
110
114
  }, [open]);
@@ -148,13 +152,8 @@ function InfoTipControl({
148
152
  pinned.current = true;
149
153
  }
150
154
  },
151
- onKeyDown: (e) => {
155
+ onKeyDown: () => {
152
156
  pressing.current = false;
153
- if (e.key === "Escape" && openRef.current) {
154
- e.preventDefault();
155
- e.stopPropagation();
156
- hide();
157
- }
158
157
  },
159
158
  children: /* @__PURE__ */ jsx(QuestionMark, {})
160
159
  }