@tensor_1/react 2.46.0 → 2.48.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 +509 -1
  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/BusyBar.d.ts +13 -0
  22. package/dist/components/BusyBar.js +10 -0
  23. package/dist/components/BusyRegion.d.ts +18 -0
  24. package/dist/components/BusyRegion.js +12 -0
  25. package/dist/components/Button.d.ts +33 -5
  26. package/dist/components/Button.js +12 -6
  27. package/dist/components/ButtonFeedback.d.ts +30 -0
  28. package/dist/components/ButtonFeedback.js +78 -0
  29. package/dist/components/Card.d.ts +18 -1
  30. package/dist/components/Card.js +5 -1
  31. package/dist/components/ChangeHighlight.d.ts +30 -0
  32. package/dist/components/ChangeHighlight.js +21 -0
  33. package/dist/components/ChartCore.js +2 -1
  34. package/dist/components/Checkbox.d.ts +27 -1
  35. package/dist/components/Checkbox.js +31 -2
  36. package/dist/components/CodeDisplay.d.ts +65 -0
  37. package/dist/components/CodeDisplay.js +124 -0
  38. package/dist/components/Combobox.d.ts +27 -6
  39. package/dist/components/Combobox.js +195 -58
  40. package/dist/components/CommandPalette.d.ts +36 -1
  41. package/dist/components/CommandPalette.js +254 -2
  42. package/dist/components/ContactCard.d.ts +66 -0
  43. package/dist/components/ContactCard.js +74 -0
  44. package/dist/components/Count.d.ts +24 -0
  45. package/dist/components/Count.js +32 -0
  46. package/dist/components/DataWorkspace.d.ts +167 -0
  47. package/dist/components/DataWorkspace.js +383 -0
  48. package/dist/components/DateFieldParts.d.ts +2 -1
  49. package/dist/components/DateFieldParts.js +7 -0
  50. package/dist/components/DatePicker.d.ts +9 -2
  51. package/dist/components/DatePicker.js +67 -28
  52. package/dist/components/DateRangePicker.d.ts +12 -2
  53. package/dist/components/DateRangePicker.js +13 -12
  54. package/dist/components/DelayedRender.d.ts +15 -0
  55. package/dist/components/DelayedRender.js +10 -0
  56. package/dist/components/DetailPage.d.ts +7 -1
  57. package/dist/components/DetailPage.js +2 -1
  58. package/dist/components/Dialogs.d.ts +71 -10
  59. package/dist/components/Dialogs.js +130 -30
  60. package/dist/components/DiffViewer.d.ts +23 -3
  61. package/dist/components/DiffViewer.js +26 -12
  62. package/dist/components/DiscardPrompt.d.ts +1 -0
  63. package/dist/components/DiscardPrompt.js +16 -0
  64. package/dist/components/DisplayPreferences.d.ts +83 -0
  65. package/dist/components/DisplayPreferences.js +185 -0
  66. package/dist/components/Drawer.d.ts +1 -0
  67. package/dist/components/EditorialHome.d.ts +23 -3
  68. package/dist/components/EditorialHome.js +16 -11
  69. package/dist/components/EntityPicker.d.ts +20 -3
  70. package/dist/components/EntityPicker.js +32 -13
  71. package/dist/components/FilterEditor.d.ts +18 -4
  72. package/dist/components/FilterEditor.js +141 -19
  73. package/dist/components/InfoTip.js +11 -12
  74. package/dist/components/InlineEdit.d.ts +87 -20
  75. package/dist/components/InlineEdit.js +197 -54
  76. package/dist/components/Input.d.ts +12 -2
  77. package/dist/components/Input.js +5 -3
  78. package/dist/components/Kbd.d.ts +6 -1
  79. package/dist/components/Kbd.js +6 -6
  80. package/dist/components/Lightbox.d.ts +41 -5
  81. package/dist/components/Lightbox.js +95 -9
  82. package/dist/components/MatchReview.d.ts +40 -1
  83. package/dist/components/MatchReview.js +130 -4
  84. package/dist/components/MetricInput.js +3 -2
  85. package/dist/components/Modal.d.ts +3 -1
  86. package/dist/components/Modal.js +13 -4
  87. package/dist/components/NavFavourites.d.ts +5 -0
  88. package/dist/components/NavFavourites.js +7 -7
  89. package/dist/components/OtpInput.d.ts +33 -0
  90. package/dist/components/OtpInput.js +123 -0
  91. package/dist/components/PageHeader.d.ts +7 -1
  92. package/dist/components/PageHeader.js +2 -2
  93. package/dist/components/Pagination.js +6 -5
  94. package/dist/components/PasswordInput.d.ts +34 -0
  95. package/dist/components/PasswordInput.js +101 -0
  96. package/dist/components/Peek.js +3 -3
  97. package/dist/components/Popover.js +2 -0
  98. package/dist/components/PrintLayout.d.ts +63 -0
  99. package/dist/components/PrintLayout.js +114 -0
  100. package/dist/components/QrCode.d.ts +47 -0
  101. package/dist/components/QrCode.js +55 -0
  102. package/dist/components/QrScanner.d.ts +95 -0
  103. package/dist/components/QrScanner.js +266 -0
  104. package/dist/components/RelationshipGraph.d.ts +32 -1
  105. package/dist/components/RelationshipGraph.js +18 -5
  106. package/dist/components/RelationshipGraphLayered.d.ts +1 -1
  107. package/dist/components/RelationshipGraphLayered.js +190 -115
  108. package/dist/components/RelationshipGraphList.js +33 -6
  109. package/dist/components/RuleBuilder.js +39 -7
  110. package/dist/components/SaveStatus.d.ts +7 -1
  111. package/dist/components/SaveStatus.js +13 -4
  112. package/dist/components/SchedulingAgenda.d.ts +3 -1
  113. package/dist/components/SchedulingCalendar.d.ts +3 -1
  114. package/dist/components/SchedulingCalendar.js +43 -4
  115. package/dist/components/SchedulingResourceDay.d.ts +57 -0
  116. package/dist/components/SchedulingResourceDay.js +287 -0
  117. package/dist/components/SchedulingTimeGrid.d.ts +3 -1
  118. package/dist/components/SchedulingTimeline.d.ts +3 -1
  119. package/dist/components/SearchBar.d.ts +1 -0
  120. package/dist/components/SearchSuggest.d.ts +23 -3
  121. package/dist/components/SearchSuggest.js +48 -17
  122. package/dist/components/Segmented.d.ts +39 -4
  123. package/dist/components/Segmented.js +31 -3
  124. package/dist/components/Select.d.ts +3 -2
  125. package/dist/components/Select.js +1 -1
  126. package/dist/components/ShortcutHint.d.ts +11 -10
  127. package/dist/components/ShortcutHint.js +44 -38
  128. package/dist/components/Sidebar.d.ts +36 -4
  129. package/dist/components/Sidebar.js +37 -12
  130. package/dist/components/SortableList.d.ts +45 -0
  131. package/dist/components/SortableList.js +134 -0
  132. package/dist/components/Spinner.d.ts +7 -1
  133. package/dist/components/Spinner.js +7 -1
  134. package/dist/components/Stat.d.ts +28 -3
  135. package/dist/components/Stat.js +13 -3
  136. package/dist/components/States.d.ts +7 -1
  137. package/dist/components/States.js +7 -1
  138. package/dist/components/StatusPill.d.ts +14 -3
  139. package/dist/components/StatusPill.js +11 -3
  140. package/dist/components/Steps.js +2 -1
  141. package/dist/components/Table.d.ts +16 -2
  142. package/dist/components/Table.js +8 -4
  143. package/dist/components/TableControls.js +18 -58
  144. package/dist/components/TableOverflowProbe.d.ts +12 -0
  145. package/dist/components/TableOverflowProbe.js +27 -0
  146. package/dist/components/Tabs.d.ts +2 -1
  147. package/dist/components/Tabs.js +1 -0
  148. package/dist/components/TagInput.d.ts +67 -0
  149. package/dist/components/TagInput.js +342 -0
  150. package/dist/components/Textarea.d.ts +5 -0
  151. package/dist/components/Textarea.js +2 -2
  152. package/dist/components/TimePicker.d.ts +80 -0
  153. package/dist/components/TimePicker.js +347 -0
  154. package/dist/components/Toast.js +3 -2
  155. package/dist/components/Tooltip.d.ts +8 -4
  156. package/dist/components/Tooltip.js +24 -21
  157. package/dist/components/Tree.d.ts +8 -0
  158. package/dist/components/Tree.js +11 -5
  159. package/dist/display-preferences-model.d.ts +53 -0
  160. package/dist/display-preferences-model.js +64 -0
  161. package/dist/emoji.cjs +28 -35
  162. package/dist/filter-model.d.ts +59 -3
  163. package/dist/filter-model.js +67 -2
  164. package/dist/hooks/useChangeHighlight.d.ts +33 -0
  165. package/dist/hooks/useChangeHighlight.js +44 -0
  166. package/dist/hooks/useDelayedPending.d.ts +22 -0
  167. package/dist/hooks/useDelayedPending.js +35 -0
  168. package/dist/hooks/useDialog.d.ts +5 -0
  169. package/dist/hooks/useDialog.js +3 -2
  170. package/dist/hooks/useOptimisticValue.d.ts +51 -0
  171. package/dist/hooks/useOptimisticValue.js +61 -0
  172. package/dist/hooks/useReducedMotion.d.ts +4 -1
  173. package/dist/hooks/useReducedMotion.js +7 -1
  174. package/dist/hooks/useResolvedFilterLabels.d.ts +15 -0
  175. package/dist/hooks/useResolvedFilterLabels.js +34 -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 +18977 -13378
  180. package/dist/index.d.cts +3065 -664
  181. package/dist/index.d.ts +46 -16
  182. package/dist/index.js +149 -7
  183. package/dist/labels-context.d.ts +93 -3
  184. package/dist/motion-timing.d.ts +8 -0
  185. package/dist/motion-timing.js +8 -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 +78 -3
  191. package/dist/relationship-graph-model.js +112 -5
  192. package/dist/reorder.d.ts +30 -0
  193. package/dist/reorder.js +74 -0
  194. package/dist/rich-text.cjs +4 -2
  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 +17 -1
  203. package/dist/toast-store.js +23 -7
  204. package/package.json +2 -1
@@ -0,0 +1,383 @@
1
+ "use client";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
+ import { useEffect, useId, useMemo, useRef, useState } from "react";
4
+ import { cx } from "../cx.js";
5
+ import { fillLabel } from "../fill-label.js";
6
+ import { useUixLabels } from "../labels-context.js";
7
+ import { renderUixLink } from "../link.js";
8
+ import { isFilterEmpty, summarizeFilter } from "../filter-model.js";
9
+ import { useResolvedFilterLabels } from "../hooks/useResolvedFilterLabels.js";
10
+ import { BusyRegion } from "./BusyRegion.js";
11
+ import { Button } from "./Button.js";
12
+ import { Checkbox } from "./Checkbox.js";
13
+ import { Chip } from "./Chip.js";
14
+ import { FilterEditor } from "./FilterEditor.js";
15
+ import { Menu, MenuItem } from "./Menu.js";
16
+ import { Pagination } from "./Pagination.js";
17
+ import { Popover } from "./Popover.js";
18
+ import { SearchBar } from "./SearchBar.js";
19
+ import { Select } from "./Select.js";
20
+ import { EmptyState, ErrorState, FilteredEmptyState, LoadingState } from "./States.js";
21
+ import { BulkBar, RowActions, Table, TableWrap, Td, Th, Tr } from "./Table.js";
22
+ import { SavedViewMenu, ViewMenu } from "./TableControls.js";
23
+ const DEFAULT_DATA_WORKSPACE_LABELS = {
24
+ search: "Search",
25
+ searchPlaceholder: "Search\u2026",
26
+ addFilter: "Filter",
27
+ clearFilters: "Clear filters",
28
+ savedView: "View: {name}",
29
+ view: "View",
30
+ saveView: "Save changes",
31
+ saveViewAs: "Save as\u2026",
32
+ maximize: "Maximize",
33
+ restore: "Restore size",
34
+ selectAll: "Select all rows on this page",
35
+ selectRow: "Select {label}",
36
+ selected: "{count} selected",
37
+ bulkActions: "Bulk actions",
38
+ open: "Open {label}",
39
+ rowActions: "Actions",
40
+ range: "{from}\u2013{to} of {total}",
41
+ rowsPerPage: "Rows per page",
42
+ loading: "Loading",
43
+ empty: "Nothing here yet",
44
+ emptyDetail: "Records show here as soon as they exist.",
45
+ filteredEmpty: "Nothing matches",
46
+ filteredEmptyDetail: "Change the search or clear a filter.",
47
+ error: "The list could not be loaded",
48
+ retry: "Try again"
49
+ };
50
+ const ArrowUpRight = () => /* @__PURE__ */ jsx("svg", { className: "uix-id-cell__arrow", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M7 17 17 7M8 7h9v9" }) });
51
+ const PlusIcon = () => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: "M12 5v14M5 12h14" }) });
52
+ const MaximizeIcon = ({ restore }) => /* @__PURE__ */ jsx("svg", { viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: 2, strokeLinecap: "round", strokeLinejoin: "round", "aria-hidden": "true", focusable: "false", children: /* @__PURE__ */ jsx("path", { d: restore ? "M4 14h6v6M20 10h-6V4M14 10l7-7M3 21l7-7" : "M15 3h6v6M9 21H3v-6M21 3l-7 7M3 21l7-7" }) });
53
+ function DataWorkspace({
54
+ label,
55
+ rows,
56
+ getRowId,
57
+ columns,
58
+ idColumn,
59
+ sort,
60
+ onSortChange,
61
+ selection,
62
+ onSelectionChange,
63
+ bulkActions,
64
+ rowActions,
65
+ getRowProps,
66
+ density,
67
+ search,
68
+ filters,
69
+ savedViews,
70
+ viewMenu,
71
+ viewChanged = false,
72
+ onSaveView,
73
+ onSaveViewAs,
74
+ maximized = false,
75
+ onMaximizedChange,
76
+ toolbarEnd,
77
+ pagination,
78
+ status = "ready",
79
+ refreshing = false,
80
+ onRetry,
81
+ labels: labelOverrides,
82
+ className,
83
+ ...props
84
+ }) {
85
+ const labels = { ...DEFAULT_DATA_WORKSPACE_LABELS, ...useUixLabels().dataWorkspace, ...labelOverrides };
86
+ const id = useId();
87
+ const searchRef = useRef(null);
88
+ const rootRef = useRef(null);
89
+ const anchor = useRef(null);
90
+ useEffect(() => {
91
+ if (!search) return;
92
+ const onKey = (event) => {
93
+ if (event.key !== "/" || !(event.ctrlKey || event.metaKey) || event.altKey || event.defaultPrevented) return;
94
+ const root = rootRef.current;
95
+ const target = event.target;
96
+ const inside = root != null && target != null && root.contains(target);
97
+ const unfocused = target === document.body || target === document.documentElement || target === document;
98
+ if (inside || unfocused && root != null && document.querySelector(".uix-data-workspace") === root) {
99
+ event.preventDefault();
100
+ searchRef.current?.focus();
101
+ searchRef.current?.select();
102
+ }
103
+ };
104
+ window.addEventListener("keydown", onKey);
105
+ return () => window.removeEventListener("keydown", onKey);
106
+ }, [search != null]);
107
+ useEffect(() => {
108
+ if (!maximized || !onMaximizedChange) return;
109
+ const onKey = (event) => {
110
+ if (event.key !== "Escape" || event.defaultPrevented) return;
111
+ const root = rootRef.current;
112
+ const target = event.target;
113
+ const owner = target?.closest?.('[popover], [role="dialog"], [role="menu"], [role="listbox"], [aria-expanded="true"]');
114
+ if (owner && root?.contains(owner)) return;
115
+ if (root && openInside(root)) return;
116
+ onMaximizedChange(false);
117
+ };
118
+ window.addEventListener("keydown", onKey);
119
+ return () => window.removeEventListener("keydown", onKey);
120
+ }, [maximized, onMaximizedChange]);
121
+ const filtered = (filters ? filters.fields.some((field) => !isFilterEmpty(filters.values[field.id])) : false) || (search?.value.trim() ?? "") !== "";
122
+ const [settled, setSettled] = useState({ rows, filtered });
123
+ if (!refreshing && rows !== settled.rows) setSettled({ rows, filtered });
124
+ const view = rows.length > 0 ? { rows, filtered } : refreshing || rows === settled.rows ? settled : { rows, filtered };
125
+ const shownRows = view.rows;
126
+ const ids = useMemo(() => shownRows.map(getRowId), [shownRows, getRowId]);
127
+ const selected = selection ?? /* @__PURE__ */ new Set();
128
+ const selectable = onSelectionChange != null;
129
+ const onPage = ids.filter((rowId) => selected.has(rowId)).length;
130
+ const toggleRow = (rowId, on, event) => {
131
+ if (!onSelectionChange) return;
132
+ const next = new Set(selected);
133
+ const from = anchor.current ? ids.indexOf(anchor.current) : -1;
134
+ const to = ids.indexOf(rowId);
135
+ if (event?.shiftKey && from >= 0 && to >= 0) {
136
+ for (let i = Math.min(from, to); i <= Math.max(from, to); i += 1) {
137
+ if (on) next.add(ids[i]);
138
+ else next.delete(ids[i]);
139
+ }
140
+ } else {
141
+ if (on) next.add(rowId);
142
+ else next.delete(rowId);
143
+ anchor.current = rowId;
144
+ }
145
+ onSelectionChange(next);
146
+ };
147
+ const toggleAll = (on) => {
148
+ if (!onSelectionChange) return;
149
+ const next = new Set(selected);
150
+ for (const rowId of ids) {
151
+ if (on) next.add(rowId);
152
+ else next.delete(rowId);
153
+ }
154
+ onSelectionChange(next);
155
+ };
156
+ const actionsByRow = useMemo(() => rowActions ? shownRows.map((row) => rowActions(row)) : [], [shownRows, rowActions]);
157
+ const hasActions = actionsByRow.some((node) => node != null && node !== false);
158
+ const activeFilters = filters ? filters.fields.filter((field) => !isFilterEmpty(filters.values[field.id])) : [];
159
+ const searching = (search?.value.trim() ?? "") !== "";
160
+ const clearAll = () => {
161
+ for (const field of activeFilters) filters?.onChange(field.id, void 0);
162
+ if (searching) search?.onChange("");
163
+ };
164
+ const sortFor = (column) => sort?.columnId === column.id ? sort.direction : "none";
165
+ const cycleSort = (column) => {
166
+ const current = sortFor(column);
167
+ onSortChange?.(current === "none" ? { columnId: column.id, direction: "ascending" } : current === "ascending" ? { columnId: column.id, direction: "descending" } : null);
168
+ };
169
+ const toolbar = /* @__PURE__ */ jsxs("div", { className: "uix-toolbar uix-data-workspace__toolbar", role: "toolbar", "aria-label": label, children: [
170
+ savedViews && /* @__PURE__ */ jsx(PopoverButton, { id: `${id}-views`, label: savedViews.current, title: typeof savedViews.current === "string" ? fillLabel(labels.savedView, { name: savedViews.current }) : void 0, variant: "secondary", children: (close) => /* @__PURE__ */ jsx(SavedViewMenu, { ...savedViews.menu, onSelect: (viewId) => {
171
+ savedViews.menu.onSelect(viewId);
172
+ close();
173
+ } }) }),
174
+ viewChanged && onSaveView && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "secondary", onClick: onSaveView, children: labels.saveView }),
175
+ viewChanged && onSaveViewAs && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", onClick: onSaveViewAs, children: labels.saveViewAs }),
176
+ filters && /* @__PURE__ */ jsx(FilterChips, { filters, labels, baseId: id }),
177
+ /* @__PURE__ */ jsx("span", { className: "uix-toolbar__spacer" }),
178
+ search && /* @__PURE__ */ jsx(
179
+ SearchBar,
180
+ {
181
+ className: "uix-data-workspace__search",
182
+ landmark: false,
183
+ label: search.label ?? labels.search,
184
+ placeholder: search.placeholder ?? labels.searchPlaceholder,
185
+ value: search.value,
186
+ onValueChange: search.onChange,
187
+ inputRef: searchRef
188
+ }
189
+ ),
190
+ viewMenu && /* @__PURE__ */ jsx(PopoverButton, { id: `${id}-view`, label: labels.view, variant: "ghost", children: () => /* @__PURE__ */ jsx(ViewMenu, { ...viewMenu }) }),
191
+ onMaximizedChange && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "ghost", icon: true, "aria-label": maximized ? labels.restore : labels.maximize, "aria-pressed": maximized, onClick: () => onMaximizedChange(!maximized), children: /* @__PURE__ */ jsx(MaximizeIcon, { restore: maximized }) }),
192
+ toolbarEnd
193
+ ] });
194
+ let body;
195
+ if (status === "loading") body = /* @__PURE__ */ jsx(LoadingState, { rows: 6, label: labels.loading, className: "uix-data-workspace__loading" });
196
+ else if (status === "error") body = /* @__PURE__ */ jsx(ErrorState, { title: labels.error, action: onRetry && /* @__PURE__ */ jsx(Button, { size: "sm", onClick: onRetry, children: labels.retry }) });
197
+ else if (shownRows.length === 0) {
198
+ body = /* @__PURE__ */ jsx(BusyRegion, { busy: refreshing, className: "uix-data-workspace__state", children: view.filtered ? /* @__PURE__ */ jsx(FilteredEmptyState, { title: labels.filteredEmpty, action: /* @__PURE__ */ jsx(Button, { size: "sm", onClick: clearAll, children: labels.clearFilters }), children: labels.filteredEmptyDetail }) : /* @__PURE__ */ jsx(EmptyState, { title: labels.empty, children: labels.emptyDetail }) });
199
+ } else {
200
+ body = /* @__PURE__ */ jsx(TableWrap, { refreshing, className: "uix-data-workspace__table", children: /* @__PURE__ */ jsxs(Table, { density, pinnedCol: idColumn != null, pinnedActions: hasActions, className: cx(selectable && idColumn && "uix-data-workspace__grid--pin-id"), "aria-label": label, children: [
201
+ /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsxs("tr", { children: [
202
+ selectable && /* @__PURE__ */ jsx("th", { className: "uix-table__selcol", scope: "col", children: /* @__PURE__ */ jsx(Checkbox, { "aria-label": labels.selectAll, checked: onPage > 0 && onPage === ids.length, indeterminate: onPage > 0 && onPage < ids.length, onChange: (event) => toggleAll(event.currentTarget.checked) }) }),
203
+ idColumn && /* @__PURE__ */ jsx(Th, { scope: "col", children: idColumn.header }),
204
+ columns.map((column) => /* @__PURE__ */ jsx(
205
+ Th,
206
+ {
207
+ scope: "col",
208
+ className: column.align === "end" ? "uix-col--num" : void 0,
209
+ style: column.width ? { width: column.width } : void 0,
210
+ sortable: column.sortable && onSortChange != null,
211
+ sortDirection: sortFor(column),
212
+ onSort: () => cycleSort(column),
213
+ children: column.header
214
+ },
215
+ column.id
216
+ )),
217
+ hasActions && /* @__PURE__ */ jsx("th", { scope: "col", className: "uix-table__actions", children: /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: labels.rowActions }) })
218
+ ] }) }),
219
+ /* @__PURE__ */ jsx("tbody", { children: shownRows.map((row, index) => {
220
+ const rowId = ids[index];
221
+ const text = idColumn?.text(row) ?? rowId;
222
+ const isSelected = selected.has(rowId);
223
+ return /* @__PURE__ */ jsxs(Tr, { selected: isSelected, ...getRowProps?.(row), children: [
224
+ selectable && /* @__PURE__ */ jsx("td", { className: "uix-table__selcell", children: /* @__PURE__ */ jsx(
225
+ Checkbox,
226
+ {
227
+ "aria-label": fillLabel(labels.selectRow, { label: text }),
228
+ checked: isSelected,
229
+ onClick: (event) => toggleRow(rowId, event.currentTarget.checked, event),
230
+ onChange: () => {
231
+ }
232
+ }
233
+ ) }),
234
+ idColumn && /* @__PURE__ */ jsx(Td, { className: "uix-id-cell", children: /* @__PURE__ */ jsxs("span", { className: "uix-data-workspace__id", children: [
235
+ idColumn.onPeek ? /* @__PURE__ */ jsx("button", { type: "button", className: "uix-id-cell__btn", "aria-haspopup": "dialog", onClick: () => idColumn.onPeek?.(row), children: text }) : /* @__PURE__ */ jsx("span", { className: "uix-cell-strong", children: text }),
236
+ idColumn.href && renderUixLink(idColumn.renderLink, {
237
+ href: idColumn.href(row),
238
+ className: "uix-data-workspace__open",
239
+ "aria-label": fillLabel(labels.open, { label: text }),
240
+ children: /* @__PURE__ */ jsx(ArrowUpRight, {})
241
+ })
242
+ ] }) }),
243
+ columns.map((column) => /* @__PURE__ */ jsx(Td, { className: column.align === "end" ? "uix-col--num" : void 0, children: column.cell(row) }, column.id)),
244
+ hasActions && /* @__PURE__ */ jsx(RowActions, { children: actionsByRow[index] })
245
+ ] }, rowId);
246
+ }) })
247
+ ] }) });
248
+ }
249
+ const selectedIds = [...selected];
250
+ return /* @__PURE__ */ jsxs(
251
+ "section",
252
+ {
253
+ ref: rootRef,
254
+ className: cx("uix-data-workspace", maximized && "uix-data-workspace--maximized", className),
255
+ "aria-label": label,
256
+ ...props,
257
+ children: [
258
+ toolbar,
259
+ bulkActions && selectedIds.length > 0 && /* @__PURE__ */ jsx(BulkBar, { count: selectedIds.length, label: labels.bulkActions, selectedLabel: (n) => fillLabel(labels.selected, { count: n }), children: bulkActions(selectedIds) }),
260
+ body,
261
+ pagination && status === "ready" && shownRows.length > 0 && /* @__PURE__ */ jsx(Footer, { pagination, labels, rowCount: shownRows.length })
262
+ ]
263
+ }
264
+ );
265
+ }
266
+ function Footer({ pagination, labels, rowCount }) {
267
+ const sizes = pagination.pageSizes;
268
+ const size = pagination.mode === "offset" ? pagination.pageSize : pagination.pageSize;
269
+ const rangeText = pagination.mode === "offset" ? fillLabel(labels.range, {
270
+ from: pagination.total === 0 ? 0 : (pagination.page - 1) * pagination.pageSize + 1,
271
+ to: Math.min(pagination.total, (pagination.page - 1) * pagination.pageSize + rowCount),
272
+ total: pagination.total
273
+ }) : null;
274
+ return /* @__PURE__ */ jsxs("div", { className: "uix-data-workspace__footer", children: [
275
+ rangeText != null && /* @__PURE__ */ jsx("span", { className: "uix-data-workspace__range", children: rangeText }),
276
+ sizes && sizes.length > 1 && size != null && pagination.onPageSizeChange && /* @__PURE__ */ jsxs("label", { className: "uix-data-workspace__size", children: [
277
+ /* @__PURE__ */ jsx("span", { children: labels.rowsPerPage }),
278
+ /* @__PURE__ */ jsx(Select, { size: "sm", value: String(size), onValueChange: (v) => pagination.onPageSizeChange?.(Number(v)), options: sizes.map((s) => ({ value: String(s), label: String(s) })) })
279
+ ] }),
280
+ /* @__PURE__ */ jsx("span", { className: "uix-toolbar__spacer" }),
281
+ pagination.mode === "offset" ? /* @__PURE__ */ jsx(Pagination, { mode: "offset", page: pagination.page, pageCount: Math.max(1, Math.ceil(pagination.total / pagination.pageSize)), onChange: pagination.onPageChange }) : /* @__PURE__ */ jsx(Pagination, { mode: "cursor", hasPrevious: pagination.hasPrevious, hasNext: pagination.hasNext, onFirst: pagination.onFirst, onPrevious: pagination.onPrevious, onNext: pagination.onNext, summary: pagination.summary })
282
+ ] });
283
+ }
284
+ function PopoverButton({ id, label, title, variant, children }) {
285
+ const anchor = useRef(null);
286
+ const [open, setOpen] = useState(false);
287
+ const popover = () => document.getElementById(id);
288
+ const close = () => {
289
+ popover()?.hidePopover?.();
290
+ anchor.current?.querySelector("button")?.focus();
291
+ };
292
+ useEffect(() => {
293
+ const el = popover();
294
+ if (!el) return;
295
+ const onToggle = (event) => setOpen(event.newState === "open");
296
+ el.addEventListener("toggle", onToggle);
297
+ return () => el.removeEventListener("toggle", onToggle);
298
+ });
299
+ return /* @__PURE__ */ jsxs("span", { ref: anchor, className: "uix-data-workspace__menu", children: [
300
+ /* @__PURE__ */ jsx(Button, { size: "sm", variant, title, "aria-haspopup": "dialog", "aria-expanded": open, "aria-controls": id, onClick: () => popover()?.togglePopover?.(), children: label }),
301
+ /* @__PURE__ */ jsx(Popover, { id, anchor, role: "dialog", "aria-label": title ?? (typeof label === "string" ? label : void 0), children: children(close) })
302
+ ] });
303
+ }
304
+ function ChipSummary({ field, value, options }) {
305
+ const resolved = useResolvedFilterLabels(field, value);
306
+ return /* @__PURE__ */ jsx(Fragment, { children: summarizeFilter(resolved.field, resolved.value, options) });
307
+ }
308
+ function openInside(root) {
309
+ try {
310
+ if (root.querySelector(":popover-open")) return true;
311
+ } catch {
312
+ }
313
+ return root.querySelector('dialog[open], [aria-expanded="true"]') != null;
314
+ }
315
+ function FilterChips({ filters, labels, baseId }) {
316
+ const [editing, setEditing] = useState(null);
317
+ const [draft, setDraft] = useState();
318
+ const [focusChip, setFocusChip] = useState(null);
319
+ const popId = `${baseId}-filter`;
320
+ const anchors = useRef(/* @__PURE__ */ new Map());
321
+ const addRef = useRef(null);
322
+ const set = filters.fields.filter((f) => !isFilterEmpty(filters.values[f.id]));
323
+ const unset = filters.fields.filter((f) => isFilterEmpty(filters.values[f.id]));
324
+ const edit = (field, anchor) => {
325
+ if (!anchor) return;
326
+ setDraft(filters.values[field.id]);
327
+ setEditing({ field, anchor });
328
+ };
329
+ useEffect(() => {
330
+ const el = document.getElementById(popId);
331
+ if (!el || !editing) return;
332
+ if (!el.matches(":popover-open")) el.showPopover?.();
333
+ const onToggle = (event) => {
334
+ if (event.newState === "closed") setEditing(null);
335
+ };
336
+ el.addEventListener("toggle", onToggle);
337
+ return () => el.removeEventListener("toggle", onToggle);
338
+ }, [editing, popId]);
339
+ const finish = (value) => {
340
+ if (!editing) return;
341
+ const applied = value && !isFilterEmpty(value) ? value : void 0;
342
+ filters.onChange(editing.field.id, applied);
343
+ const back = anchors.current.get(editing.field.id) ?? addRef.current?.querySelector("button");
344
+ document.getElementById(popId)?.hidePopover?.();
345
+ (back?.querySelector?.("button") ?? back)?.focus?.();
346
+ if (applied && !anchors.current.get(editing.field.id)) setFocusChip(editing.field.id);
347
+ };
348
+ useEffect(() => {
349
+ if (!focusChip) return;
350
+ const chip = anchors.current.get(focusChip)?.querySelector("button");
351
+ if (chip) {
352
+ chip.focus();
353
+ setFocusChip(null);
354
+ }
355
+ });
356
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
357
+ set.map((field) => /* @__PURE__ */ jsx("span", { ref: (el) => {
358
+ if (el) anchors.current.set(field.id, el);
359
+ else anchors.current.delete(field.id);
360
+ }, className: "uix-data-workspace__chip", children: /* @__PURE__ */ jsx(
361
+ Chip,
362
+ {
363
+ "aria-haspopup": "dialog",
364
+ count: filters.counts?.[field.id],
365
+ onClick: () => edit(field, anchors.current.get(field.id) ?? null),
366
+ onRemove: () => filters.onChange(field.id, void 0),
367
+ children: /* @__PURE__ */ jsx(ChipSummary, { field, value: filters.values[field.id], options: filters.summary })
368
+ }
369
+ ) }, field.id)),
370
+ unset.length > 0 && /* @__PURE__ */ jsx("span", { ref: addRef, children: /* @__PURE__ */ jsx(Menu, { trigger: /* @__PURE__ */ jsxs("button", { type: "button", className: "uix-chip uix-chip--add", children: [
371
+ /* @__PURE__ */ jsx("span", { className: "uix-chip__icon", "aria-hidden": "true", children: /* @__PURE__ */ jsx(PlusIcon, {}) }),
372
+ /* @__PURE__ */ jsx("span", { className: "uix-chip__label", children: labels.addFilter })
373
+ ] }), children: unset.map((field) => /* @__PURE__ */ jsx(MenuItem, { onSelect: () => edit(field, addRef.current), children: field.label }, field.id)) }) }),
374
+ set.length > 0 && /* @__PURE__ */ jsx(Button, { size: "sm", variant: "link", onClick: () => {
375
+ for (const f of set) filters.onChange(f.id, void 0);
376
+ }, children: labels.clearFilters }),
377
+ /* @__PURE__ */ jsx(Popover, { id: popId, anchor: editing?.anchor ?? null, role: "dialog", "aria-label": editing?.field.label, children: editing && /* @__PURE__ */ jsx(FilterEditor, { field: editing.field, value: draft, onValueChange: setDraft, onApply: (v) => finish(v), onClear: () => finish(void 0) }) })
378
+ ] });
379
+ }
380
+ export {
381
+ DEFAULT_DATA_WORKSPACE_LABELS,
382
+ DataWorkspace
383
+ };
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { MouseEvent } from 'react';
2
+ import { KeyboardEvent, MouseEvent } from 'react';
3
3
  import { CalendarWeekday } from '../calendar-model.js';
4
4
 
5
5
  /** The viewer's local calendar date as `YYYY-MM-DD` (not UTC: "today" is a local idea). */
@@ -20,6 +20,7 @@ declare function useFieldPopover(popoverId: string, restoreFocus: () => void, on
20
20
  open: boolean;
21
21
  show: () => void;
22
22
  hide: (restore?: boolean) => void;
23
+ onFieldKeyDown: (event: KeyboardEvent<HTMLElement>) => void;
23
24
  /** Spread on the button that opens the calendar. */
24
25
  triggerProps: {
25
26
  'aria-haspopup': "dialog";
@@ -62,10 +62,17 @@ function useFieldPopover(popoverId, restoreFocus, onOpenChange) {
62
62
  skipRestore.current = false;
63
63
  }
64
64
  };
65
+ const onFieldKeyDown = (event) => {
66
+ if (event.key !== "Escape" || !isOpen(popoverEl())) return;
67
+ event.stopPropagation();
68
+ event.preventDefault();
69
+ hide();
70
+ };
65
71
  return {
66
72
  open,
67
73
  show,
68
74
  hide,
75
+ onFieldKeyDown,
69
76
  /** Spread on the button that opens the calendar. */
70
77
  triggerProps: {
71
78
  "aria-haspopup": "dialog",
@@ -2,6 +2,7 @@ import * as react from 'react';
2
2
  import { AriaAttributes, CSSProperties } from 'react';
3
3
  import { CalendarWeekday } from '../calendar-model.js';
4
4
  import { Placement } from '../overlay-position.js';
5
+ import { TimePickerLabels } from './TimePicker.js';
5
6
 
6
7
  /** Every word `DatePicker` renders or announces. */
7
8
  interface DatePickerLabels {
@@ -38,6 +39,8 @@ interface DatePickerProps {
38
39
  /**
39
40
  * How the field writes a date. Default: the locale's numeric date (22.11.2026, 11/22/2026).
40
41
  * Pass `parseDate` with it when your format is not three numbers, so typing still works.
42
+ * `formatDate`, `parseDate`, `locale` and `placeholder` default to `UixLabelsProvider`
43
+ * `dateFormat`, so one provider sets the format of every date field (HAR-2432).
41
44
  */
42
45
  formatDate?: (date: string) => string;
43
46
  /** Read typed text into `YYYY-MM-DD`, or `null` when it is not a date. Default: ISO or the locale's order. */
@@ -112,14 +115,18 @@ interface DateTimePickerProps extends Omit<DatePickerProps, 'value' | 'onValueCh
112
115
  timeZone?: string;
113
116
  /** Text shown instead of the zone's short name ("Vienna time", "UTC+2"); `null` shows none. */
114
117
  timeZoneLabel?: string | null;
115
- /** Minutes between time steps. Default 1. */
118
+ /** Minutes the time's arrow keys step by, and between the times in its list. Default 15. */
116
119
  minuteStep?: number;
120
+ /** Words of the time field (its list button, list and messages); `UixLabelsProvider` `timePicker` too. */
121
+ timeLabels?: Partial<TimePickerLabels>;
122
+ /** `true` writes the time as 2:30 PM, `false` as 14:30, whatever the locale. */
123
+ hour12?: boolean;
117
124
  /** The time a date gets when it is chosen before any time. Default `'00:00'`. */
118
125
  defaultTime?: string;
119
126
  labels?: Partial<DateTimePickerLabels>;
120
127
  }
121
128
  /**
122
- * A date and a time as one field (HAR-1383): the {@link DatePicker} and a time input, with the
129
+ * A date and a time as one field (HAR-1383): the {@link DatePicker} and a {@link TimePicker} (HAR-1835), with the
123
130
  * time zone the pair is in shown beside them. The value is `YYYY-MM-DDTHH:mm`, the shape
124
131
  * `datetime-local` uses, so it replaces that input without changing what a form submits.
125
132
  * Clearing the date clears the value; a time alone is not a value.
@@ -9,6 +9,7 @@ import { CalendarIcon } from "../icons/components.js";
9
9
  import { useUixLabels } from "../labels-context.js";
10
10
  import { fullDateLabel, localDateKey, MonthCalendar, useFieldPopover } from "./DateFieldParts.js";
11
11
  import { Popover } from "./Popover.js";
12
+ import { TimePicker } from "./TimePicker.js";
12
13
  const DEFAULT_DATE_PICKER_LABELS = {
13
14
  open: "Choose date",
14
15
  openSelected: "Change date, {date}",
@@ -25,12 +26,12 @@ const DatePicker = forwardRef(function DatePicker2({
25
26
  min,
26
27
  max,
27
28
  isUnavailable,
28
- formatDate,
29
- parseDate,
30
- locale,
29
+ formatDate: formatDateProp,
30
+ parseDate: parseDateProp,
31
+ locale: localeProp,
31
32
  weekStartsOn = 1,
32
33
  today,
33
- placeholder,
34
+ placeholder: placeholderProp,
34
35
  size = "md",
35
36
  disabled,
36
37
  readOnly,
@@ -54,7 +55,12 @@ const DatePicker = forwardRef(function DatePicker2({
54
55
  const id = idProp ?? `${uid}-input`;
55
56
  const popoverId = `${uid}-calendar`;
56
57
  const errorId = `${uid}-error`;
57
- const labels = { ...DEFAULT_DATE_PICKER_LABELS, ...useUixLabels().datePicker, ...labelOverrides };
58
+ const uixLabels = useUixLabels();
59
+ const labels = { ...DEFAULT_DATE_PICKER_LABELS, ...uixLabels.datePicker, ...labelOverrides };
60
+ const locale = localeProp ?? uixLabels.dateFormat?.locale;
61
+ const formatDate = formatDateProp ?? uixLabels.dateFormat?.formatDate;
62
+ const parseDate = parseDateProp ?? uixLabels.dateFormat?.parseDate;
63
+ const placeholder = placeholderProp ?? uixLabels.dateFormat?.placeholder;
58
64
  const anchorRef = useRef(null);
59
65
  const inputRef = useRef(null);
60
66
  useImperativeHandle(forwardedRef, () => inputRef.current);
@@ -73,7 +79,7 @@ const DatePicker = forwardRef(function DatePicker2({
73
79
  setText(value ? format(value) : "");
74
80
  setProblem(null);
75
81
  }, [value, locale]);
76
- const { open, show, hide, triggerProps } = useFieldPopover(popoverId, () => inputRef.current?.focus({ preventScroll: true }), onOpenChange);
82
+ const { open, show, hide, onFieldKeyDown, triggerProps } = useFieldPopover(popoverId, () => inputRef.current?.focus({ preventScroll: true }), onOpenChange);
77
83
  const locked = !!disabled || !!readOnly;
78
84
  const commit = () => {
79
85
  const typed = text.trim();
@@ -129,12 +135,7 @@ const DatePicker = forwardRef(function DatePicker2({
129
135
  ref: anchorRef,
130
136
  className: cx("uix-date-picker", size === "sm" && "uix-date-picker--sm", className),
131
137
  style,
132
- onKeyDown: (event) => {
133
- if (event.key !== "Escape" || !open) return;
134
- event.stopPropagation();
135
- event.preventDefault();
136
- hide();
137
- },
138
+ onKeyDown: onFieldKeyDown,
138
139
  children: [
139
140
  /* @__PURE__ */ jsxs("div", { className: "uix-date-picker__control", children: [
140
141
  /* @__PURE__ */ jsx(
@@ -212,6 +213,22 @@ const DatePicker = forwardRef(function DatePicker2({
212
213
  }
213
214
  );
214
215
  });
216
+ function labelText(label, control) {
217
+ let text = "";
218
+ const walk = (node) => {
219
+ if (node === control) return;
220
+ if (node.nodeType === 3) {
221
+ text += node.nodeValue ?? "";
222
+ return;
223
+ }
224
+ if (node.nodeType !== 1) return;
225
+ const el = node;
226
+ if (el.getAttribute("aria-hidden") === "true" || el.hidden) return;
227
+ node.childNodes.forEach(walk);
228
+ };
229
+ label.childNodes.forEach(walk);
230
+ return text.replace(/\s+/g, " ").trim();
231
+ }
215
232
  const DEFAULT_DATE_TIME_PICKER_LABELS = {
216
233
  ...DEFAULT_DATE_PICKER_LABELS,
217
234
  date: "Date",
@@ -224,7 +241,9 @@ const DateTimePicker = forwardRef(function DateTimePicker2({
224
241
  onValueChange,
225
242
  timeZone,
226
243
  timeZoneLabel,
227
- minuteStep = 1,
244
+ minuteStep = 15,
245
+ timeLabels,
246
+ hour12,
228
247
  defaultTime = "00:00",
229
248
  min,
230
249
  max,
@@ -234,7 +253,7 @@ const DateTimePicker = forwardRef(function DateTimePicker2({
234
253
  "aria-labelledby": ariaLabelledBy,
235
254
  "aria-describedby": ariaDescribedBy,
236
255
  labels: labelOverrides,
237
- locale,
256
+ locale: localeProp,
238
257
  size = "md",
239
258
  disabled,
240
259
  readOnly,
@@ -246,31 +265,48 @@ const DateTimePicker = forwardRef(function DateTimePicker2({
246
265
  const uid = useId();
247
266
  const id = idProp ?? `${uid}-date`;
248
267
  const zoneId = `${uid}-zone`;
249
- const labels = { ...DEFAULT_DATE_TIME_PICKER_LABELS, ...useUixLabels().dateTimePicker, ...labelOverrides };
268
+ const uixLabels = useUixLabels();
269
+ const labels = { ...DEFAULT_DATE_TIME_PICKER_LABELS, ...uixLabels.dateTimePicker, ...labelOverrides };
270
+ const locale = localeProp ?? uixLabels.dateFormat?.locale;
250
271
  const { date, time } = splitDateTime(value);
251
272
  const dateRef = useRef(null);
273
+ const rootRef = useRef(null);
252
274
  useImperativeHandle(forwardedRef, () => dateRef.current);
253
275
  const [pendingTime, setPendingTime] = useState("");
254
276
  const shownTime = date ? time : pendingTime;
255
277
  const [fieldLabel, setFieldLabel] = useState("");
256
278
  const [viewerZone, setViewerZone] = useState(null);
257
279
  const grouped = !!ariaLabel || !!ariaLabelledBy;
280
+ const [labelNode, setLabelNode] = useState(null);
281
+ useEffect(() => {
282
+ if (grouped) return;
283
+ const input = dateRef.current;
284
+ const label = input?.labels?.[0] ?? null;
285
+ setLabelNode(label);
286
+ setFieldLabel(label ? labelText(label, rootRef.current) : "");
287
+ });
288
+ useEffect(() => {
289
+ if (grouped || !labelNode || typeof MutationObserver === "undefined") return void 0;
290
+ const observer = new MutationObserver(() => setFieldLabel(labelText(labelNode, rootRef.current)));
291
+ observer.observe(labelNode, { childList: true, characterData: true, subtree: true, attributes: true, attributeFilter: ["aria-hidden", "hidden"] });
292
+ return () => observer.disconnect();
293
+ }, [grouped, labelNode]);
258
294
  useEffect(() => {
259
- if (!grouped) setFieldLabel(dateRef.current?.labels?.[0]?.textContent?.trim() ?? "");
260
295
  if (!timeZone) {
261
296
  try {
262
297
  setViewerZone(new Intl.DateTimeFormat().resolvedOptions().timeZone);
263
298
  } catch {
264
299
  }
265
300
  }
266
- }, [grouped, timeZone]);
301
+ }, [timeZone]);
267
302
  const zone = timeZone ?? viewerZone;
268
303
  const zoneText = timeZoneLabel === null ? null : timeZoneLabel ?? (zone ? timeZoneName(zone, date, locale) : null);
269
304
  const timeName = grouped ? labels.time : fieldLabel ? fillLabel(labels.timeOf, { label: fieldLabel }) : labels.time;
270
- const step = Math.max(1, Math.round(minuteStep)) * 60;
305
+ const step = Math.max(1, Math.round(minuteStep));
271
306
  return /* @__PURE__ */ jsxs(
272
307
  "div",
273
308
  {
309
+ ref: rootRef,
274
310
  className: cx("uix-date-time-picker", size === "sm" && "uix-date-time-picker--sm", className),
275
311
  style,
276
312
  role: "group",
@@ -305,21 +341,24 @@ const DateTimePicker = forwardRef(function DateTimePicker2({
305
341
  }
306
342
  ),
307
343
  /* @__PURE__ */ jsx(
308
- "input",
344
+ TimePicker,
309
345
  {
310
- type: "time",
311
- className: cx("uix-input", size === "sm" && "uix-input--sm", "uix-date-time-picker__time"),
312
- value: shownTime,
313
- step,
346
+ className: "uix-date-time-picker__time",
347
+ value: shownTime || null,
348
+ minuteStep: step,
349
+ locale,
350
+ hour12,
351
+ size,
314
352
  disabled,
315
353
  readOnly,
316
354
  required: required && !!date,
355
+ invalid: !!dateProps.invalid || dateProps["aria-invalid"] === true || dateProps["aria-invalid"] === "true",
317
356
  "aria-label": timeName,
318
- "aria-describedby": zoneText ? zoneId : void 0,
319
- onChange: (event) => {
320
- const next = event.target.value;
321
- if (date) onValueChange(joinDateTime(date, next, defaultTime));
322
- else setPendingTime(next);
357
+ labels: timeLabels,
358
+ "aria-describedby": [ariaDescribedBy, zoneText ? zoneId : void 0].filter(Boolean).join(" ") || void 0,
359
+ onValueChange: (next) => {
360
+ if (date) onValueChange(joinDateTime(date, next ?? "", defaultTime));
361
+ else setPendingTime(next ?? "");
323
362
  }
324
363
  }
325
364
  ),