@vitavision/ui 0.13.0 → 0.14.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.
- package/README.md +2 -2
- package/dist/index.d.ts +76 -3
- package/dist/index.js +111 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/components/ui/Breakdown.tsx +139 -0
- package/src/components/ui/Table.tsx +36 -9
- package/src/components/ui/index.ts +8 -0
package/README.md
CHANGED
|
@@ -126,13 +126,13 @@ keep independent preferences.
|
|
|
126
126
|
`DialogClose` · `Disclosure` · `DropdownMenu`, `MenuItem`, `MenuCheckboxItem`, `MenuLabel`,
|
|
127
127
|
`MenuSeparator` (a non-modal command and toggle menu) · `Callout`, `Empty`, `ErrorBox`,
|
|
128
128
|
`Skeleton`, `SkeletonRows` · `Progress` (a count out of a total, or indeterminate; `ProgressBar` is
|
|
129
|
-
deprecated) · `Field` · `Input`, `NumberInput` (with an optional
|
|
129
|
+
deprecated) · `Breakdown`, `breakdownText` (counts by verdict as one thin stacked bar) · `Field` · `Input`, `NumberInput` (with an optional
|
|
130
130
|
`unit` written in the field; number-valued with `onValueChange`), `Textarea` (optionally growing
|
|
131
131
|
with its content between `minRows` and `maxRows`) · `HighlightedText`, `findSpans` (a string
|
|
132
132
|
with its placeholders, tags and terms marked, never parsed as HTML) · `VectorInput`,
|
|
133
133
|
`PoseInput` · `Kbd` · `Listbox` (single choice among options that render their own content) ·
|
|
134
134
|
`PageHeader`, `Panel`, `ReadoutStrip`, `Section` · `Popover`, `PopoverClose` ·
|
|
135
|
-
`SegmentedControl` · `Select` · `Slider` · `Table` (with `windowed` for thousands of rows) ·
|
|
135
|
+
`SegmentedControl` · `Select` · `Slider` · `Table` (with `windowed` for thousands of rows, and `selectionFollowsFocus` for keyboard selection) ·
|
|
136
136
|
`Checkbox`, `Switch` · `ToggleChip` · `Toaster`, `toast()` (notifications from anywhere; mount one `<Toaster />` near the root) ·
|
|
137
137
|
`InfoHint`, `Tooltip`, `TooltipProvider` ·
|
|
138
138
|
`ThemeToggle` · plus `cn`, `focusRing`, `focusRingInset`, and `formatNumber` / `parseNumber`
|
package/dist/index.d.ts
CHANGED
|
@@ -154,6 +154,69 @@ export declare function CountRun({ counts, className }: {
|
|
|
154
154
|
className?: string | undefined;
|
|
155
155
|
}): import("react").JSX.Element;
|
|
156
156
|
//#endregion
|
|
157
|
+
//#region src/components/ui/Breakdown.d.ts
|
|
158
|
+
/**
|
|
159
|
+
* The colour of a `Breakdown` segment: a verdict (`normal`, `warn`, `defect`) for things the app
|
|
160
|
+
* has judged, or `neutral` for a category that is no verdict (skipped, not applicable).
|
|
161
|
+
*/
|
|
162
|
+
type BreakdownTone = "normal" | "warn" | "defect" | "neutral";
|
|
163
|
+
/** One category of a `Breakdown`: how many, in which colour, and what a reader calls them. */
|
|
164
|
+
interface BreakdownSegment {
|
|
165
|
+
/** How many. Negative and non-finite values count as 0, and a segment of 0 is left out. */
|
|
166
|
+
value: number;
|
|
167
|
+
/** The colour, by meaning. */
|
|
168
|
+
tone: BreakdownTone;
|
|
169
|
+
/** What the count is, as it reads after the number: `"done"` gives "412 done". Unique among the segments. */
|
|
170
|
+
label: string;
|
|
171
|
+
}
|
|
172
|
+
/** Options of `breakdownText`, the same as the `Breakdown` props of the same names. */
|
|
173
|
+
interface BreakdownTextOptions {
|
|
174
|
+
/** The whole. Defaults to the sum of the segments; a total below the sum counts as the sum. */
|
|
175
|
+
total?: number | undefined;
|
|
176
|
+
/** What the rest of the total is, as it reads after the number: `"to do"` gives "131 to do". */
|
|
177
|
+
remainderLabel?: string | undefined;
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* The counts of a breakdown in words: `"412 done, 20 to check, 3 problems, 131 to do of 566"`.
|
|
181
|
+
*
|
|
182
|
+
* It is the default accessible name of `Breakdown`, and the text for a tooltip or a label printed
|
|
183
|
+
* beside the bar. Segments of 0 are left out; the rest of the total is named only with a
|
|
184
|
+
* `remainderLabel`. With nothing to count it reads `"0 of 566"`.
|
|
185
|
+
*
|
|
186
|
+
* @param segments - The categories, in order.
|
|
187
|
+
* @param options - The `total` and the `remainderLabel`.
|
|
188
|
+
* @returns The text.
|
|
189
|
+
*/
|
|
190
|
+
export declare function breakdownText(segments: readonly BreakdownSegment[], options?: BreakdownTextOptions): string;
|
|
191
|
+
/** Props of `Breakdown`: the segments and their total, plus the `<div>` props. */
|
|
192
|
+
type BreakdownProps = Omit<ComponentProps<"div">, "children" | "role"> & {
|
|
193
|
+
/** The categories, drawn left to right in this order, each as wide as its share of the total. */
|
|
194
|
+
segments: readonly BreakdownSegment[];
|
|
195
|
+
/**
|
|
196
|
+
* The whole. Defaults to the sum of the segments; the rest is drawn as empty track. A total
|
|
197
|
+
* below the sum counts as the sum.
|
|
198
|
+
*/
|
|
199
|
+
total?: number | undefined;
|
|
200
|
+
/** What the empty track counts, for the accessible name: `"to do"` gives "131 to do". */
|
|
201
|
+
remainderLabel?: string | undefined;
|
|
202
|
+
};
|
|
203
|
+
/**
|
|
204
|
+
* A thin bar of counts by category: 412 done, 20 to check and 3 problems out of 566, with the
|
|
205
|
+
* rest as empty track. Segments are drawn in the order given, each as wide as its share of the
|
|
206
|
+
* total (a non-zero count is never narrower than 2 px); segments of 0 are left out.
|
|
207
|
+
*
|
|
208
|
+
* Its colours are verdicts, so use it only for things the app has judged — never for a share of
|
|
209
|
+
* a continuous quantity or for series side by side (use `Progress` or a chart).
|
|
210
|
+
*
|
|
211
|
+
* A `role="img"` whose name lists every non-zero count, as `breakdownText` writes it: "412 done,
|
|
212
|
+
* 20 to check, 3 problems, 131 to do of 566". `aria-label` or `aria-labelledby` replaces it. The track
|
|
213
|
+
* matches `Progress` and follows the density in force. State is exposed as `data-state`
|
|
214
|
+
* (`"empty"` with nothing counted, `"partial"`, or `"complete"` when the segments fill the
|
|
215
|
+
* total), and each segment's tone as its `data-tone`. Width changes ease over 300 ms, and not at
|
|
216
|
+
* all with reduced motion.
|
|
217
|
+
*/
|
|
218
|
+
export declare function Breakdown({ segments, total, remainderLabel, className, "aria-label": ariaLabel, ...rest }: BreakdownProps): import("react").JSX.Element;
|
|
219
|
+
//#endregion
|
|
157
220
|
//#region src/components/ui/Button.d.ts
|
|
158
221
|
/**
|
|
159
222
|
* A button's look, by what the action is: `primary` for the one action a screen is for,
|
|
@@ -1198,11 +1261,12 @@ interface TableWindowing {
|
|
|
1198
1261
|
* show it and the rows render as given. Row callbacks always receive a row's index in `rows`,
|
|
1199
1262
|
* whatever the order on screen.
|
|
1200
1263
|
*
|
|
1201
|
-
* Activatable rows also move focus with the arrow keys, Page Up / Page Down and Home / End
|
|
1264
|
+
* Activatable rows also move focus with the arrow keys, Page Up / Page Down and Home / End;
|
|
1265
|
+
* with `selectionFollowsFocus` each of those moves also activates the row it lands on.
|
|
1202
1266
|
* With `windowed` the table scrolls itself (vertically, under a sticky header), renders only the
|
|
1203
1267
|
* rows in view, and uses a fixed layout: give columns a `width` where the content needs it.
|
|
1204
1268
|
*/
|
|
1205
|
-
export declare function Table<Row>({ columns, rows, rowKey, empty, caption, className, onRowClick, isRowActive, onRowHover, sort: controlledSort, defaultSort, onSortChange, manualSort, windowed }: {
|
|
1269
|
+
export declare function Table<Row>({ columns, rows, rowKey, empty, caption, className, onRowClick, isRowActive, onRowHover, sort: controlledSort, defaultSort, onSortChange, manualSort, windowed, selectionFollowsFocus }: {
|
|
1206
1270
|
/** The columns, in order. */
|
|
1207
1271
|
columns: Column<Row>[];
|
|
1208
1272
|
/** The rows, in their own order: the order shown while the table is not sorted. */
|
|
@@ -1251,6 +1315,15 @@ export declare function Table<Row>({ columns, rows, rowKey, empty, caption, clas
|
|
|
1251
1315
|
* callbacks and keyboard navigation work as without it.
|
|
1252
1316
|
*/
|
|
1253
1317
|
windowed?: TableWindowing | undefined;
|
|
1318
|
+
/**
|
|
1319
|
+
* Activate a row as soon as the keyboard moves to it: each arrow key, Page Up / Page Down,
|
|
1320
|
+
* Home or End that lands on another row also calls `onRowClick` for that row, with the key
|
|
1321
|
+
* press as the event — selection follows focus, as in a list where the selected item shows
|
|
1322
|
+
* its detail beside the list. Clicks, Enter and Space work as without it. Leave it off when
|
|
1323
|
+
* activating a row is costly or navigates away: then a reader can move through the rows and
|
|
1324
|
+
* choose one. Needs `onRowClick`.
|
|
1325
|
+
*/
|
|
1326
|
+
selectionFollowsFocus?: boolean | undefined;
|
|
1254
1327
|
}): import("react").JSX.Element;
|
|
1255
1328
|
//#endregion
|
|
1256
1329
|
//#region src/components/ui/Textarea.d.ts
|
|
@@ -1586,5 +1659,5 @@ export declare function Tabs<Id extends string>({ items, active, onSelect, label
|
|
|
1586
1659
|
className?: string | undefined;
|
|
1587
1660
|
}): import("react").JSX.Element;
|
|
1588
1661
|
//#endregion
|
|
1589
|
-
export type { BackLink, ButtonSize, ButtonVariant, CalloutTone, Column, Density, DropdownMenuProps, HighlightKind, HighlightRule, HighlightSpan, HighlightedTextProps, ListboxOption, ListboxOptionState, ListboxProps, MeasureTone, MenuCheckboxItemProps, MenuItemProps, NumberInputProps, PopoverProps, PoseInputProps, PoseValue, ProgressProps, Quaternion, ReadoutItem, RotationView, SelectOption, SortDirection, TabItem, TableSort, TableWindowing, TextareaProps, ThemeChoice, ToastOptions, ToastRecord, ToastStore, ToastTone, ToasterProps, Tone, Vec3, VectorInputProps };
|
|
1662
|
+
export type { BackLink, BreakdownProps, BreakdownSegment, BreakdownTextOptions, BreakdownTone, ButtonSize, ButtonVariant, CalloutTone, Column, Density, DropdownMenuProps, HighlightKind, HighlightRule, HighlightSpan, HighlightedTextProps, ListboxOption, ListboxOptionState, ListboxProps, MeasureTone, MenuCheckboxItemProps, MenuItemProps, NumberInputProps, PopoverProps, PoseInputProps, PoseValue, ProgressProps, Quaternion, ReadoutItem, RotationView, SelectOption, SortDirection, TabItem, TableSort, TableWindowing, TextareaProps, ThemeChoice, ToastOptions, ToastRecord, ToastStore, ToastTone, ToasterProps, Tone, Vec3, VectorInputProps };
|
|
1590
1663
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.js
CHANGED
|
@@ -246,7 +246,7 @@ function ThemeToggle({ storageKey = DEFAULT_THEME_STORAGE_KEY, className }) {
|
|
|
246
246
|
}
|
|
247
247
|
//#endregion
|
|
248
248
|
//#region src/components/ui/Badge.tsx
|
|
249
|
-
const TONE_CLASSES = {
|
|
249
|
+
const TONE_CLASSES$1 = {
|
|
250
250
|
neutral: "bg-raised text-fg-muted ring-line",
|
|
251
251
|
normal: "bg-normal/12 text-normal ring-normal/25",
|
|
252
252
|
defect: "bg-defect/12 text-defect ring-defect/25",
|
|
@@ -271,7 +271,7 @@ const DOT_CLASSES = {
|
|
|
271
271
|
function Badge({ tone = "neutral", className, children }) {
|
|
272
272
|
return /* @__PURE__ */ jsx("span", {
|
|
273
273
|
"data-tone": tone,
|
|
274
|
-
className: cn("inline-flex items-center gap-1 rounded-control px-1.5 py-0.5 text-xs font-medium ring-1 ring-inset", TONE_CLASSES[tone], className),
|
|
274
|
+
className: cn("inline-flex items-center gap-1 rounded-control px-1.5 py-0.5 text-xs font-medium ring-1 ring-inset", TONE_CLASSES$1[tone], className),
|
|
275
275
|
children
|
|
276
276
|
});
|
|
277
277
|
}
|
|
@@ -346,6 +346,93 @@ function DensityProvider({ value, children }) {
|
|
|
346
346
|
});
|
|
347
347
|
}
|
|
348
348
|
//#endregion
|
|
349
|
+
//#region src/components/ui/Breakdown.tsx
|
|
350
|
+
/** Counts written the same on the server and in every browser: `2,556`, `0.5`. */
|
|
351
|
+
const count$1 = new Intl.NumberFormat("en-US", { maximumFractionDigits: 2 });
|
|
352
|
+
const TONE_CLASSES = {
|
|
353
|
+
normal: "bg-normal",
|
|
354
|
+
warn: "bg-warn",
|
|
355
|
+
defect: "bg-defect",
|
|
356
|
+
neutral: "bg-fg-subtle"
|
|
357
|
+
};
|
|
358
|
+
/** A count as drawn: 0 for anything that is not a finite, positive number. */
|
|
359
|
+
const amount = (value) => Number.isFinite(value) && value > 0 ? value : 0;
|
|
360
|
+
/** The segments that are drawn, the whole, and the rest of it. */
|
|
361
|
+
function measure(segments, total) {
|
|
362
|
+
const shown = segments.filter((segment) => amount(segment.value) > 0);
|
|
363
|
+
const sum = shown.reduce((acc, segment) => acc + amount(segment.value), 0);
|
|
364
|
+
const whole = total !== void 0 && Number.isFinite(total) && total > sum ? total : sum;
|
|
365
|
+
return {
|
|
366
|
+
shown,
|
|
367
|
+
sum,
|
|
368
|
+
whole,
|
|
369
|
+
rest: whole - sum
|
|
370
|
+
};
|
|
371
|
+
}
|
|
372
|
+
/**
|
|
373
|
+
* The counts of a breakdown in words: `"412 done, 20 to check, 3 problems, 131 to do of 566"`.
|
|
374
|
+
*
|
|
375
|
+
* It is the default accessible name of `Breakdown`, and the text for a tooltip or a label printed
|
|
376
|
+
* beside the bar. Segments of 0 are left out; the rest of the total is named only with a
|
|
377
|
+
* `remainderLabel`. With nothing to count it reads `"0 of 566"`.
|
|
378
|
+
*
|
|
379
|
+
* @param segments - The categories, in order.
|
|
380
|
+
* @param options - The `total` and the `remainderLabel`.
|
|
381
|
+
* @returns The text.
|
|
382
|
+
*/
|
|
383
|
+
function breakdownText(segments, options = {}) {
|
|
384
|
+
const { shown, whole, rest } = measure(segments, options.total);
|
|
385
|
+
const parts = shown.map((segment) => `${count$1.format(amount(segment.value))} ${segment.label}`);
|
|
386
|
+
if (options.remainderLabel !== void 0 && rest > 0) parts.push(`${count$1.format(rest)} ${options.remainderLabel}`);
|
|
387
|
+
return `${parts.length > 0 ? parts.join(", ") : "0"} of ${count$1.format(whole)}`;
|
|
388
|
+
}
|
|
389
|
+
/**
|
|
390
|
+
* A thin bar of counts by category: 412 done, 20 to check and 3 problems out of 566, with the
|
|
391
|
+
* rest as empty track. Segments are drawn in the order given, each as wide as its share of the
|
|
392
|
+
* total (a non-zero count is never narrower than 2 px); segments of 0 are left out.
|
|
393
|
+
*
|
|
394
|
+
* Its colours are verdicts, so use it only for things the app has judged — never for a share of
|
|
395
|
+
* a continuous quantity or for series side by side (use `Progress` or a chart).
|
|
396
|
+
*
|
|
397
|
+
* A `role="img"` whose name lists every non-zero count, as `breakdownText` writes it: "412 done,
|
|
398
|
+
* 20 to check, 3 problems, 131 to do of 566". `aria-label` or `aria-labelledby` replaces it. The track
|
|
399
|
+
* matches `Progress` and follows the density in force. State is exposed as `data-state`
|
|
400
|
+
* (`"empty"` with nothing counted, `"partial"`, or `"complete"` when the segments fill the
|
|
401
|
+
* total), and each segment's tone as its `data-tone`. Width changes ease over 300 ms, and not at
|
|
402
|
+
* all with reduced motion.
|
|
403
|
+
*/
|
|
404
|
+
function Breakdown({ segments, total, remainderLabel, className, "aria-label": ariaLabel, ...rest }) {
|
|
405
|
+
const density = useDensity();
|
|
406
|
+
const { shown, sum, rest: remainder } = measure(segments, total);
|
|
407
|
+
const name = ariaLabel ?? (rest["aria-labelledby"] ? void 0 : breakdownText(segments, {
|
|
408
|
+
total,
|
|
409
|
+
remainderLabel
|
|
410
|
+
}));
|
|
411
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
412
|
+
role: "img",
|
|
413
|
+
"aria-label": name,
|
|
414
|
+
"data-state": sum === 0 ? "empty" : remainder > 0 ? "partial" : "complete",
|
|
415
|
+
...rest,
|
|
416
|
+
className: cn("w-full overflow-hidden rounded-full bg-line", byDensity(density, "h-1.5", "h-1"), className),
|
|
417
|
+
style: {
|
|
418
|
+
display: "flex",
|
|
419
|
+
gap: 1,
|
|
420
|
+
...rest.style
|
|
421
|
+
},
|
|
422
|
+
children: [shown.map((segment) => /* @__PURE__ */ jsx("div", {
|
|
423
|
+
"data-tone": segment.tone,
|
|
424
|
+
className: cn("h-full transition-[flex-grow] duration-300", TONE_CLASSES[segment.tone]),
|
|
425
|
+
style: {
|
|
426
|
+
flex: `${amount(segment.value)} 0 0`,
|
|
427
|
+
minWidth: 2
|
|
428
|
+
}
|
|
429
|
+
}, segment.label)), remainder > 0 && /* @__PURE__ */ jsx("div", {
|
|
430
|
+
className: "h-full transition-[flex-grow] duration-300",
|
|
431
|
+
style: { flex: `${remainder} 0 0` }
|
|
432
|
+
})]
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
//#endregion
|
|
349
436
|
//#region src/components/ui/Button.tsx
|
|
350
437
|
const VARIANT_CLASSES = {
|
|
351
438
|
primary: "bg-signal text-signal-fg hover:bg-signal-strong",
|
|
@@ -2100,11 +2187,12 @@ const SORT_ICONS = {
|
|
|
2100
2187
|
* show it and the rows render as given. Row callbacks always receive a row's index in `rows`,
|
|
2101
2188
|
* whatever the order on screen.
|
|
2102
2189
|
*
|
|
2103
|
-
* Activatable rows also move focus with the arrow keys, Page Up / Page Down and Home / End
|
|
2190
|
+
* Activatable rows also move focus with the arrow keys, Page Up / Page Down and Home / End;
|
|
2191
|
+
* with `selectionFollowsFocus` each of those moves also activates the row it lands on.
|
|
2104
2192
|
* With `windowed` the table scrolls itself (vertically, under a sticky header), renders only the
|
|
2105
2193
|
* rows in view, and uses a fixed layout: give columns a `width` where the content needs it.
|
|
2106
2194
|
*/
|
|
2107
|
-
function Table({ columns, rows, rowKey, empty = "Nothing here.", caption, className, onRowClick, isRowActive, onRowHover, sort: controlledSort, defaultSort = null, onSortChange, manualSort = false, windowed }) {
|
|
2195
|
+
function Table({ columns, rows, rowKey, empty = "Nothing here.", caption, className, onRowClick, isRowActive, onRowHover, sort: controlledSort, defaultSort = null, onSortChange, manualSort = false, windowed, selectionFollowsFocus = false }) {
|
|
2108
2196
|
const density = useDensity();
|
|
2109
2197
|
const [ownSort, setOwnSort] = useState(defaultSort);
|
|
2110
2198
|
const controlled = controlledSort !== void 0;
|
|
@@ -2143,10 +2231,12 @@ function Table({ columns, rows, rowKey, empty = "Nothing here.", caption, classN
|
|
|
2143
2231
|
after: 0
|
|
2144
2232
|
};
|
|
2145
2233
|
const isWindowed = windowed !== void 0;
|
|
2234
|
+
const hasRows = rows.length > 0;
|
|
2146
2235
|
useLayoutEffect(() => {
|
|
2147
2236
|
const scroller = scrollRef.current;
|
|
2148
|
-
if (!isWindowed || !scroller || typeof ResizeObserver === "undefined") return;
|
|
2237
|
+
if (!isWindowed || !hasRows || !scroller || typeof ResizeObserver === "undefined") return;
|
|
2149
2238
|
const measure = () => {
|
|
2239
|
+
if (!scroller.isConnected) return;
|
|
2150
2240
|
const next = {
|
|
2151
2241
|
viewport: scroller.clientHeight,
|
|
2152
2242
|
header: headRef.current?.offsetHeight ?? 0
|
|
@@ -2154,10 +2244,11 @@ function Table({ columns, rows, rowKey, empty = "Nothing here.", caption, classN
|
|
|
2154
2244
|
setMeasured((last) => last?.viewport === next.viewport && last.header === next.header ? last : next);
|
|
2155
2245
|
};
|
|
2156
2246
|
measure();
|
|
2247
|
+
setScrollTop(scroller.scrollTop);
|
|
2157
2248
|
const observer = new ResizeObserver(measure);
|
|
2158
2249
|
observer.observe(scroller);
|
|
2159
2250
|
return () => observer.disconnect();
|
|
2160
|
-
}, [isWindowed]);
|
|
2251
|
+
}, [isWindowed, hasRows]);
|
|
2161
2252
|
useLayoutEffect(() => {
|
|
2162
2253
|
const target = pendingFocus.current;
|
|
2163
2254
|
if (target === null) return;
|
|
@@ -2166,11 +2257,18 @@ function Table({ columns, rows, rowKey, empty = "Nothing here.", caption, classN
|
|
|
2166
2257
|
pendingFocus.current = null;
|
|
2167
2258
|
row.focus({ preventScroll: isWindowed });
|
|
2168
2259
|
});
|
|
2169
|
-
/**
|
|
2170
|
-
|
|
2260
|
+
/**
|
|
2261
|
+
* Moves focus from the row at `position` for a navigation key, activating the new row when
|
|
2262
|
+
* selection follows focus; `true` when the key was one.
|
|
2263
|
+
*/
|
|
2264
|
+
const moveFocus = (event, position) => {
|
|
2171
2265
|
const page = windowed ? Math.floor((viewportHeight - headerHeight) / rowHeight) : 10;
|
|
2172
|
-
const target = navigate(key, position, order.length, page);
|
|
2266
|
+
const target = navigate(event.key, position, order.length, page);
|
|
2173
2267
|
if (target === null) return false;
|
|
2268
|
+
if (selectionFollowsFocus && onRowClick && target !== position) {
|
|
2269
|
+
const index = order[target];
|
|
2270
|
+
onRowClick(rows[index], index, event);
|
|
2271
|
+
}
|
|
2174
2272
|
pendingFocus.current = target;
|
|
2175
2273
|
const scroller = scrollRef.current;
|
|
2176
2274
|
if (windowed && scroller) {
|
|
@@ -2183,9 +2281,9 @@ function Table({ columns, rows, rowKey, empty = "Nothing here.", caption, classN
|
|
|
2183
2281
|
setScrollTop(scroller.scrollTop);
|
|
2184
2282
|
}
|
|
2185
2283
|
const row = bodyRef.current?.querySelector(`tr[data-position="${target}"]`);
|
|
2186
|
-
if (row
|
|
2284
|
+
if (row) {
|
|
2187
2285
|
pendingFocus.current = null;
|
|
2188
|
-
row.focus();
|
|
2286
|
+
row.focus({ preventScroll: windowed !== void 0 });
|
|
2189
2287
|
}
|
|
2190
2288
|
return true;
|
|
2191
2289
|
};
|
|
@@ -2278,7 +2376,7 @@ function Table({ columns, rows, rowKey, empty = "Nothing here.", caption, classN
|
|
|
2278
2376
|
if (event.key === "Enter" || event.key === " ") {
|
|
2279
2377
|
event.preventDefault();
|
|
2280
2378
|
onRowClick(row, index, event);
|
|
2281
|
-
} else if (event.target === event.currentTarget && moveFocus(event
|
|
2379
|
+
} else if (event.target === event.currentTarget && moveFocus(event, position)) event.preventDefault();
|
|
2282
2380
|
} : void 0,
|
|
2283
2381
|
onPointerEnter: onRowHover ? () => onRowHover(row, index) : void 0,
|
|
2284
2382
|
onPointerLeave: onRowHover ? () => onRowHover(null, null) : void 0,
|
|
@@ -2754,6 +2852,6 @@ function Tabs({ items, active, onSelect, label, idPrefix, className }) {
|
|
|
2754
2852
|
});
|
|
2755
2853
|
}
|
|
2756
2854
|
//#endregion
|
|
2757
|
-
export { Badge, Button, ButtonLink, Callout, Checkbox, ConfirmDialog, CountRun, DEFAULT_THEME_STORAGE_KEY, DensityProvider, Dialog, DialogClose, Disclosure, DropdownMenu, Empty, ErrorBox, Field, HighlightedText, InfoHint, Input, Kbd, Listbox, MenuCheckboxItem, MenuItem, MenuLabel, MenuSeparator, NumberInput, PageHeader, Panel, Popover, PopoverClose, PoseInput, Progress, ProgressBar, ReadoutStrip, Section, SegmentedControl, Select, Skeleton, SkeletonRows, Slider, StatusDot, Switch, Table, Tabs, Textarea, ThemeToggle, Toaster, ToggleChip, Tooltip, TooltipProvider, VectorInput, buttonClasses, byDensity, cn, controlClasses, createToastStore, defaultToastStore, findSpans, focusRing, focusRingInset, formatNumber, initTheme, inputClasses, parseNumber, progressText, readThemeChoice, resolveTheme, setThemeChoice, sortRows, toast, toneColor, useControlHeight, useDensity };
|
|
2855
|
+
export { Badge, Breakdown, Button, ButtonLink, Callout, Checkbox, ConfirmDialog, CountRun, DEFAULT_THEME_STORAGE_KEY, DensityProvider, Dialog, DialogClose, Disclosure, DropdownMenu, Empty, ErrorBox, Field, HighlightedText, InfoHint, Input, Kbd, Listbox, MenuCheckboxItem, MenuItem, MenuLabel, MenuSeparator, NumberInput, PageHeader, Panel, Popover, PopoverClose, PoseInput, Progress, ProgressBar, ReadoutStrip, Section, SegmentedControl, Select, Skeleton, SkeletonRows, Slider, StatusDot, Switch, Table, Tabs, Textarea, ThemeToggle, Toaster, ToggleChip, Tooltip, TooltipProvider, VectorInput, breakdownText, buttonClasses, byDensity, cn, controlClasses, createToastStore, defaultToastStore, findSpans, focusRing, focusRingInset, formatNumber, initTheme, inputClasses, parseNumber, progressText, readThemeChoice, resolveTheme, setThemeChoice, sortRows, toast, toneColor, useControlHeight, useDensity };
|
|
2758
2856
|
|
|
2759
2857
|
//# sourceMappingURL=index.js.map
|