@godxjp/ui 31.5.0 → 31.6.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 (62) hide show
  1. package/agent/START-HERE.md +5 -5
  2. package/agent/components/BranchScopePicker.json +5 -0
  3. package/agent/components/Cascader.json +1 -1
  4. package/agent/components/DataTable.json +2 -2
  5. package/agent/components/InfiniteQueryState.json +6 -1
  6. package/agent/components/RangeTimeline.json +6 -0
  7. package/agent/components/RecordPicker.json +10 -0
  8. package/agent/components/Transfer.json +5 -0
  9. package/agent/components/Tree.json +21 -4
  10. package/agent/components/TreeSelect.json +1 -1
  11. package/agent/components.json +57 -9
  12. package/agent/index.json +5 -5
  13. package/agent/llms.txt +6 -6
  14. package/agent/tokens.json +6 -0
  15. package/dist/components/data-display/data-table.d.ts +3 -0
  16. package/dist/components/data-display/data-table.js +415 -370
  17. package/dist/components/data-display/range-timeline.d.ts +20 -0
  18. package/dist/components/data-display/range-timeline.js +217 -197
  19. package/dist/components/data-display/tree.js +179 -23
  20. package/dist/components/data-entry/branch-scope-picker.d.ts +1 -0
  21. package/dist/components/data-entry/branch-scope-picker.js +2 -1
  22. package/dist/components/data-entry/cascader.js +4 -5
  23. package/dist/components/data-entry/record-picker.d.ts +2 -0
  24. package/dist/components/data-entry/record-picker.js +22 -3
  25. package/dist/components/data-entry/transfer.d.ts +1 -1
  26. package/dist/components/data-entry/transfer.js +5 -2
  27. package/dist/components/data-entry/tree-select.js +14 -5
  28. package/dist/components/query/infinite-query-state.d.ts +1 -1
  29. package/dist/components/query/infinite-query-state.js +2 -1
  30. package/dist/contracts/measurement.json +1 -1
  31. package/dist/i18n/messages/en.json +16 -2
  32. package/dist/i18n/messages/ja.json +7 -2
  33. package/dist/i18n/messages/vi.json +7 -2
  34. package/dist/lib/hooks.d.ts +8 -4
  35. package/dist/lib/hooks.js +5 -2
  36. package/dist/lib/tree.d.ts +23 -0
  37. package/dist/lib/tree.js +29 -0
  38. package/dist/props/components/data-display.prop.d.ts +21 -2
  39. package/dist/props/components/data-entry.prop.d.ts +31 -4
  40. package/dist/props/components/query.prop.d.ts +8 -1
  41. package/dist/props/registry.d.ts +24 -6
  42. package/dist/props/registry.js +41 -4
  43. package/dist/props/vocabulary/data.prop.d.ts +32 -2
  44. package/dist/props/vocabulary/index.d.ts +1 -1
  45. package/dist/styles/data-display-layout.css +52 -0
  46. package/dist/styles/layers.json +1 -1
  47. package/dist/styles/table-layout.css +16 -1
  48. package/dist/tokens/components/tree.css +2 -0
  49. package/docs/data-display/data-table/examples/server-paged.tsx +23 -0
  50. package/docs/data-display/data-table/index.md +2 -0
  51. package/docs/data-display/timeline.tsx +33 -0
  52. package/docs/data-display/tree.tsx +154 -0
  53. package/docs/data-entry/branch-scope-picker.tsx +6 -1
  54. package/docs/data-entry/record-picker.tsx +1 -0
  55. package/docs/data-entry/transfer.tsx +1 -0
  56. package/docs/i18n/messages/en.json +19 -0
  57. package/docs/i18n/messages/ja.json +18 -0
  58. package/docs/i18n/messages/vi.json +18 -0
  59. package/docs/query/infinite-query-state.tsx +5 -1
  60. package/docs/roadmap/tree-components.md +2 -1
  61. package/package.json +2 -2
  62. package/scripts/ui-audit.mjs +15 -5
@@ -53,6 +53,16 @@ export type RangeTimelineProps = React.HTMLAttributes<HTMLElement> & {
53
53
  defaultExpandedValues?: readonly string[];
54
54
  /** Fires with the next expanded parent ids, for controlled and uncontrolled timelines alike. */
55
55
  onExpandedValuesChange?: (values: string[]) => void;
56
+ /**
57
+ * Keep the axis header (bands + ticks) on screen while the PAGE scrolls a long schedule — antd
58
+ * Table `sticky`. `offsetHeader` is the distance in px from the top of the scrolling viewport,
59
+ * e.g. the height of a fixed app topbar. The header then scrolls horizontally with the body.
60
+ * Needs no clipping ancestor (e.g. `Card`, which is `overflow: hidden`) between it and the page
61
+ * scroller. antd's `offsetScroll` / `getContainer` (a sticky horizontal scrollbar) are not ported.
62
+ */
63
+ sticky?: boolean | {
64
+ offsetHeader?: number;
65
+ };
56
66
  };
57
67
  /** A horizontal range axis. Units and labels are data; the design system owns all geometry. */
58
68
  export declare const RangeTimeline: React.ForwardRefExoticComponent<React.HTMLAttributes<HTMLElement> & {
@@ -94,4 +104,14 @@ export declare const RangeTimeline: React.ForwardRefExoticComponent<React.HTMLAt
94
104
  defaultExpandedValues?: readonly string[];
95
105
  /** Fires with the next expanded parent ids, for controlled and uncontrolled timelines alike. */
96
106
  onExpandedValuesChange?: (values: string[]) => void;
107
+ /**
108
+ * Keep the axis header (bands + ticks) on screen while the PAGE scrolls a long schedule — antd
109
+ * Table `sticky`. `offsetHeader` is the distance in px from the top of the scrolling viewport,
110
+ * e.g. the height of a fixed app topbar. The header then scrolls horizontally with the body.
111
+ * Needs no clipping ancestor (e.g. `Card`, which is `overflow: hidden`) between it and the page
112
+ * scroller. antd's `offsetScroll` / `getContainer` (a sticky horizontal scrollbar) are not ported.
113
+ */
114
+ sticky?: boolean | {
115
+ offsetHeader?: number;
116
+ };
97
117
  } & React.RefAttributes<HTMLElement>>;
@@ -1,5 +1,5 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import * as React from "react";
4
4
  import { useTranslation } from "../../i18n/use-translation.js";
5
5
  import { ChevronDown, ChevronLeft, ChevronRight, GripVertical } from "lucide-react";
@@ -19,6 +19,7 @@ const RangeTimeline = React.forwardRef(
19
19
  expandedValues,
20
20
  defaultExpandedValues,
21
21
  onExpandedValuesChange,
22
+ sticky = false,
22
23
  className,
23
24
  ...props
24
25
  }, ref) {
@@ -69,6 +70,8 @@ const RangeTimeline = React.forwardRef(
69
70
  columns.reduce((sum, column) => sum + column.units, 0)
70
71
  );
71
72
  const track = React.useRef(null);
73
+ const stickyHeader = React.useRef(null);
74
+ const bodyScroller = React.useRef(null);
72
75
  const drag = React.useRef(null);
73
76
  const [preview, setPreview] = React.useState(null);
74
77
  const deltaAt = (x) => drag.current ? Math.round((x - drag.current.x) * units * drag.current.direction / drag.current.width) : 0;
@@ -86,213 +89,230 @@ const RangeTimeline = React.forwardRef(
86
89
  const bounded = current.edge === "start" ? Math.min(delta, row.end - row.start) : Math.max(delta, row.start - row.end);
87
90
  if (bounded) onRangeChange?.(row.id, current.edge, bounded);
88
91
  };
89
- return /* @__PURE__ */ jsx(
90
- "section",
91
- {
92
- ...props,
93
- ref,
94
- className: cn("ui-range-timeline", className),
95
- "data-bordered": bordered ? "true" : void 0,
96
- "data-density": density === "default" ? void 0 : density,
97
- "aria-label": label,
98
- tabIndex: 0,
99
- children: /* @__PURE__ */ jsxs(
92
+ const canvasStyle = {
93
+ "--range-timeline-columns": Math.max(1, columns.length),
94
+ "--range-timeline-units": units
95
+ };
96
+ const header = /* @__PURE__ */ jsxs(Fragment, { children: [
97
+ bands && bands.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
98
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", "aria-hidden": "true" }),
99
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", children: bands.map((band, index) => /* @__PURE__ */ jsx(
100
+ "div",
101
+ {
102
+ className: "ui-range-timeline-column",
103
+ style: { gridColumn: `span ${band.units}` },
104
+ children: /* @__PURE__ */ jsx(Text, { size: "xs", weight: "medium", children: band.label })
105
+ },
106
+ index
107
+ )) })
108
+ ] }),
109
+ /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
110
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", children: /* @__PURE__ */ jsx(Text, { weight: "bold", children: label }) }),
111
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", ref: track, children: columns.map((column, index) => /* @__PURE__ */ jsx(
112
+ "div",
113
+ {
114
+ className: "ui-range-timeline-column",
115
+ style: { gridColumn: `span ${column.units}` },
116
+ children: /* @__PURE__ */ jsx(Text, { size: "xs", children: column.label })
117
+ },
118
+ index
119
+ )) })
120
+ ] })
121
+ ] });
122
+ const body = /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-body", role: nested ? "list" : void 0, children: [
123
+ (bordered || columns.some((column) => column.muted)) && // Decorative: the same unit tracks as the header columns, laid once behind every row so
124
+ // each vertical rule runs the full body height exactly under its header column.
125
+ /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-grid", "aria-hidden": "true", children: [
126
+ /* @__PURE__ */ jsx("div", {}),
127
+ /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", children: columns.map((column, index) => /* @__PURE__ */ jsx(
128
+ "div",
129
+ {
130
+ className: "ui-range-timeline-grid-column",
131
+ "data-muted": column.muted ? "true" : void 0,
132
+ style: { gridColumn: `span ${column.units}` }
133
+ },
134
+ index
135
+ )) })
136
+ ] }),
137
+ visibleRows.map((row, index) => {
138
+ const idBase = `${reactId}-row-${rows.indexOf(row)}`;
139
+ const delta = preview?.id === row.id ? preview.delta : 0;
140
+ const start = Math.min(row.end, row.start + (preview?.edge === "start" ? delta : 0));
141
+ const end = Math.max(row.start, row.end + (preview?.edge === "end" ? delta : 0));
142
+ const left = Math.max(0, start), right = Math.min(units, end + 1);
143
+ return /* @__PURE__ */ jsxs(
100
144
  "div",
101
145
  {
102
- className: "ui-range-timeline-canvas",
103
- style: {
104
- "--range-timeline-columns": Math.max(1, columns.length),
105
- "--range-timeline-units": units
146
+ className: "ui-range-timeline-row",
147
+ ...nested && {
148
+ role: "listitem",
149
+ "aria-level": depthOf(row) + 1,
150
+ "aria-setsize": siblingsOf(index).size,
151
+ "aria-posinset": siblingsOf(index).position
106
152
  },
107
153
  children: [
108
- bands && bands.length > 0 && /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
109
- /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", "aria-hidden": "true" }),
110
- /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", children: bands.map((band, index) => /* @__PURE__ */ jsx(
111
- "div",
112
- {
113
- className: "ui-range-timeline-column",
114
- style: { gridColumn: `span ${band.units}` },
115
- children: /* @__PURE__ */ jsx(Text, { size: "xs", weight: "medium", children: band.label })
116
- },
117
- index
118
- )) })
119
- ] }),
120
- /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-header", children: [
121
- /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", children: /* @__PURE__ */ jsx(Text, { weight: "bold", children: label }) }),
122
- /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", ref: track, children: columns.map((column, index) => /* @__PURE__ */ jsx(
123
- "div",
124
- {
125
- className: "ui-range-timeline-column",
126
- style: { gridColumn: `span ${column.units}` },
127
- children: /* @__PURE__ */ jsx(Text, { size: "xs", children: column.label })
128
- },
129
- index
130
- )) })
131
- ] }),
132
- /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-body", role: nested ? "list" : void 0, children: [
133
- (bordered || columns.some((column) => column.muted)) && // Decorative: the same unit tracks as the header columns, laid once behind every row so
134
- // each vertical rule runs the full body height exactly under its header column.
135
- /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-grid", "aria-hidden": "true", children: [
136
- /* @__PURE__ */ jsx("div", {}),
137
- /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-columns", children: columns.map((column, index) => /* @__PURE__ */ jsx(
138
- "div",
139
- {
140
- className: "ui-range-timeline-grid-column",
141
- "data-muted": column.muted ? "true" : void 0,
142
- style: { gridColumn: `span ${column.units}` }
143
- },
144
- index
145
- )) })
146
- ] }),
147
- visibleRows.map((row, index) => {
148
- const idBase = `${reactId}-row-${rows.indexOf(row)}`;
149
- const delta = preview?.id === row.id ? preview.delta : 0;
150
- const start = Math.min(row.end, row.start + (preview?.edge === "start" ? delta : 0));
151
- const end = Math.max(row.start, row.end + (preview?.edge === "end" ? delta : 0));
152
- const left = Math.max(0, start), right = Math.min(units, end + 1);
153
- return /* @__PURE__ */ jsxs(
154
- "div",
155
- {
156
- className: "ui-range-timeline-row",
157
- ...nested && {
158
- role: "listitem",
159
- "aria-level": depthOf(row) + 1,
160
- "aria-setsize": siblingsOf(index).size,
161
- "aria-posinset": siblingsOf(index).position
162
- },
163
- children: [
164
- nested ? /* @__PURE__ */ jsxs(
165
- "div",
166
- {
167
- className: "ui-range-timeline-label",
168
- "data-nested": "true",
169
- style: { "--range-timeline-depth": depthOf(row) },
170
- children: [
171
- parents.includes(row.id) ? /* @__PURE__ */ jsxs(
172
- Button,
173
- {
174
- variant: "ghost",
175
- size: "icon-xs",
176
- className: "ui-range-timeline-disclosure",
177
- "aria-expanded": isExpanded(row.id),
178
- "aria-labelledby": `${idBase}-toggle ${idBase}-label`,
179
- onClick: () => toggleRow(row.id),
180
- children: [
181
- /* @__PURE__ */ jsx("span", { id: `${idBase}-toggle`, hidden: true, children: t("rangeTimeline.childRows") }),
182
- isExpanded(row.id) ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(
183
- ChevronRight,
184
- {
185
- "aria-hidden": "true",
186
- className: "ui-range-timeline-disclosure-collapsed"
187
- }
188
- )
189
- ]
190
- }
191
- ) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ui-range-timeline-disclosure-spacer" }),
192
- /* @__PURE__ */ jsx("div", { id: `${idBase}-label`, className: "ui-range-timeline-label-content", children: row.label })
193
- ]
194
- }
195
- ) : /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", children: row.label }),
196
- /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-track", children: [
197
- today != null && today >= 0 && today < units && /* @__PURE__ */ jsx(
198
- "span",
154
+ nested ? /* @__PURE__ */ jsxs(
155
+ "div",
156
+ {
157
+ className: "ui-range-timeline-label",
158
+ "data-nested": "true",
159
+ style: { "--range-timeline-depth": depthOf(row) },
160
+ children: [
161
+ parents.includes(row.id) ? /* @__PURE__ */ jsxs(
162
+ Button,
163
+ {
164
+ variant: "ghost",
165
+ size: "icon-xs",
166
+ className: "ui-range-timeline-disclosure",
167
+ "aria-expanded": isExpanded(row.id),
168
+ "aria-labelledby": `${idBase}-toggle ${idBase}-label`,
169
+ onClick: () => toggleRow(row.id),
170
+ children: [
171
+ /* @__PURE__ */ jsx("span", { id: `${idBase}-toggle`, hidden: true, children: t("rangeTimeline.childRows") }),
172
+ isExpanded(row.id) ? /* @__PURE__ */ jsx(ChevronDown, { "aria-hidden": "true" }) : /* @__PURE__ */ jsx(
173
+ ChevronRight,
199
174
  {
200
175
  "aria-hidden": "true",
201
- className: "ui-range-timeline-today",
202
- style: { insetInlineStart: `${(today + 0.5) / units * 100}%` }
203
- }
204
- ),
205
- right <= left && (end < 0 ? /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "before", children: [
206
- /* @__PURE__ */ jsx(
207
- ChevronLeft,
208
- {
209
- "aria-hidden": "true",
210
- className: "ui-range-timeline-outside-icon"
211
- }
212
- ),
213
- /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideBefore") })
214
- ] }) : /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "after", children: [
215
- /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideAfter") }),
216
- /* @__PURE__ */ jsx(
217
- ChevronRight,
218
- {
219
- "aria-hidden": "true",
220
- className: "ui-range-timeline-outside-icon"
221
- }
222
- )
223
- ] })),
224
- right > left && /* @__PURE__ */ jsx(
225
- "div",
226
- {
227
- className: "ui-range-timeline-bar",
228
- style: {
229
- insetInlineStart: `${left / units * 100}%`,
230
- inlineSize: `${(right - left) / units * 100}%`
231
- },
232
- children: onRangeChange && (right - left) * Math.max(1, columns.length) >= units && ["start", "end"].filter(
233
- (edge) => edge === "start" ? start >= 0 && start < units : end >= 0 && end < units
234
- ).map((edge) => /* @__PURE__ */ jsx(
235
- Button,
236
- {
237
- variant: "ghost",
238
- size: "icon-xs",
239
- className: "ui-range-timeline-handle",
240
- "data-edge": edge,
241
- "aria-label": edge === "start" ? row.startLabel : row.endLabel,
242
- onPointerDown: (event) => {
243
- const width = track.current?.getBoundingClientRect().width ?? 0;
244
- if (!width || event.button !== 0) return;
245
- event.currentTarget.setPointerCapture(event.pointerId);
246
- drag.current = {
247
- id: row.id,
248
- edge,
249
- x: event.clientX,
250
- width,
251
- direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
252
- };
253
- },
254
- onPointerMove: (event) => {
255
- if (drag.current)
256
- setPreview({
257
- id: drag.current.id,
258
- edge: drag.current.edge,
259
- delta: deltaAt(event.clientX)
260
- });
261
- },
262
- onPointerUp: complete,
263
- onPointerCancel: cancel,
264
- onLostPointerCapture: cancel,
265
- onKeyDown: (event) => {
266
- if (event.key === "Escape") {
267
- cancel();
268
- return;
269
- }
270
- const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
271
- if (!step) return;
272
- event.preventDefault();
273
- const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
274
- const delta2 = step * direction;
275
- if (edge === "start" ? row.start + delta2 <= row.end : row.end + delta2 >= row.start)
276
- onRangeChange(row.id, edge, delta2);
277
- },
278
- children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
279
- },
280
- edge
281
- ))
176
+ className: "ui-range-timeline-disclosure-collapsed"
282
177
  }
283
178
  )
284
- ] })
285
- ]
179
+ ]
180
+ }
181
+ ) : /* @__PURE__ */ jsx("span", { "aria-hidden": "true", className: "ui-range-timeline-disclosure-spacer" }),
182
+ /* @__PURE__ */ jsx("div", { id: `${idBase}-label`, className: "ui-range-timeline-label-content", children: row.label })
183
+ ]
184
+ }
185
+ ) : /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-label", children: row.label }),
186
+ /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-track", children: [
187
+ today != null && today >= 0 && today < units && /* @__PURE__ */ jsx(
188
+ "span",
189
+ {
190
+ "aria-hidden": "true",
191
+ className: "ui-range-timeline-today",
192
+ style: { insetInlineStart: `${(today + 0.5) / units * 100}%` }
193
+ }
194
+ ),
195
+ right <= left && (end < 0 ? /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "before", children: [
196
+ /* @__PURE__ */ jsx(ChevronLeft, { "aria-hidden": "true", className: "ui-range-timeline-outside-icon" }),
197
+ /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideBefore") })
198
+ ] }) : /* @__PURE__ */ jsxs("span", { className: "ui-range-timeline-outside", "data-direction": "after", children: [
199
+ /* @__PURE__ */ jsx(Text, { size: "xs", tone: "muted", children: t("rangeTimeline.outsideAfter") }),
200
+ /* @__PURE__ */ jsx(ChevronRight, { "aria-hidden": "true", className: "ui-range-timeline-outside-icon" })
201
+ ] })),
202
+ right > left && /* @__PURE__ */ jsx(
203
+ "div",
204
+ {
205
+ className: "ui-range-timeline-bar",
206
+ style: {
207
+ insetInlineStart: `${left / units * 100}%`,
208
+ inlineSize: `${(right - left) / units * 100}%`
286
209
  },
287
- row.id
288
- );
289
- })
210
+ children: onRangeChange && (right - left) * Math.max(1, columns.length) >= units && ["start", "end"].filter(
211
+ (edge) => edge === "start" ? start >= 0 && start < units : end >= 0 && end < units
212
+ ).map((edge) => /* @__PURE__ */ jsx(
213
+ Button,
214
+ {
215
+ variant: "ghost",
216
+ size: "icon-xs",
217
+ className: "ui-range-timeline-handle",
218
+ "data-edge": edge,
219
+ "aria-label": edge === "start" ? row.startLabel : row.endLabel,
220
+ onPointerDown: (event) => {
221
+ const width = track.current?.getBoundingClientRect().width ?? 0;
222
+ if (!width || event.button !== 0) return;
223
+ event.currentTarget.setPointerCapture(event.pointerId);
224
+ drag.current = {
225
+ id: row.id,
226
+ edge,
227
+ x: event.clientX,
228
+ width,
229
+ direction: getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1
230
+ };
231
+ },
232
+ onPointerMove: (event) => {
233
+ if (drag.current)
234
+ setPreview({
235
+ id: drag.current.id,
236
+ edge: drag.current.edge,
237
+ delta: deltaAt(event.clientX)
238
+ });
239
+ },
240
+ onPointerUp: complete,
241
+ onPointerCancel: cancel,
242
+ onLostPointerCapture: cancel,
243
+ onKeyDown: (event) => {
244
+ if (event.key === "Escape") {
245
+ cancel();
246
+ return;
247
+ }
248
+ const step = event.key === "ArrowRight" ? 1 : event.key === "ArrowLeft" ? -1 : 0;
249
+ if (!step) return;
250
+ event.preventDefault();
251
+ const direction = getComputedStyle(event.currentTarget).direction === "rtl" ? -1 : 1;
252
+ const delta2 = step * direction;
253
+ if (edge === "start" ? row.start + delta2 <= row.end : row.end + delta2 >= row.start)
254
+ onRangeChange(row.id, edge, delta2);
255
+ },
256
+ children: /* @__PURE__ */ jsx(GripVertical, { "aria-hidden": "true" })
257
+ },
258
+ edge
259
+ ))
260
+ }
261
+ )
290
262
  ] })
291
263
  ]
292
- }
293
- )
294
- }
295
- );
264
+ },
265
+ row.id
266
+ );
267
+ })
268
+ ] });
269
+ const sectionProps = {
270
+ ...props,
271
+ ref,
272
+ className: cn("ui-range-timeline", className),
273
+ "data-bordered": bordered ? "true" : void 0,
274
+ // Only a NON-default step scopes the unit-width knob, so a theme that narrows
275
+ // --range-timeline-unit-width globally still owns the default timeline (gh#730).
276
+ "data-density": density === "default" ? void 0 : density,
277
+ "aria-label": label
278
+ };
279
+ if (!sticky) {
280
+ return /* @__PURE__ */ jsx("section", { ...sectionProps, tabIndex: 0, children: /* @__PURE__ */ jsxs("div", { className: "ui-range-timeline-canvas", style: canvasStyle, children: [
281
+ header,
282
+ body
283
+ ] }) });
284
+ }
285
+ const offsetHeader = typeof sticky === "object" ? sticky.offsetHeader ?? 0 : 0;
286
+ return /* @__PURE__ */ jsxs("section", { ...sectionProps, "data-sticky": "true", children: [
287
+ /* @__PURE__ */ jsx(
288
+ "div",
289
+ {
290
+ ref: stickyHeader,
291
+ className: "ui-range-timeline-sticky-header",
292
+ style: { "--range-timeline-sticky-offset": `${offsetHeader}px` },
293
+ onWheel: (event) => {
294
+ if (bodyScroller.current && event.deltaX)
295
+ bodyScroller.current.scrollLeft += event.deltaX;
296
+ },
297
+ children: /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-canvas", style: canvasStyle, children: header })
298
+ }
299
+ ),
300
+ /* @__PURE__ */ jsx(
301
+ "div",
302
+ {
303
+ ref: bodyScroller,
304
+ className: "ui-range-timeline-scroller",
305
+ role: "group",
306
+ "aria-label": label,
307
+ tabIndex: 0,
308
+ onScroll: (event) => {
309
+ if (stickyHeader.current)
310
+ stickyHeader.current.scrollLeft = event.currentTarget.scrollLeft;
311
+ },
312
+ children: /* @__PURE__ */ jsx("div", { className: "ui-range-timeline-canvas", style: canvasStyle, children: body })
313
+ }
314
+ )
315
+ ] });
296
316
  }
297
317
  );
298
318
  export {