@vitavision/ui 0.12.0 → 0.13.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 (38) hide show
  1. package/README.md +6 -3
  2. package/dist/index.d.ts +171 -7
  3. package/dist/index.js +490 -61
  4. package/dist/index.js.map +1 -1
  5. package/package.json +1 -1
  6. package/src/components/Tabs.tsx +3 -10
  7. package/src/components/ThemeToggle.tsx +1 -5
  8. package/src/components/ui/Badge.tsx +1 -4
  9. package/src/components/ui/Button.tsx +3 -15
  10. package/src/components/ui/Dialog.tsx +4 -19
  11. package/src/components/ui/Disclosure.tsx +2 -7
  12. package/src/components/ui/DropdownMenu.tsx +2 -16
  13. package/src/components/ui/Feedback.tsx +5 -9
  14. package/src/components/ui/Field.tsx +4 -15
  15. package/src/components/ui/HighlightedText.tsx +84 -0
  16. package/src/components/ui/Input.tsx +5 -43
  17. package/src/components/ui/Panel.tsx +4 -16
  18. package/src/components/ui/PoseInput.tsx +7 -5
  19. package/src/components/ui/Progress.tsx +80 -0
  20. package/src/components/ui/SegmentedControl.tsx +1 -3
  21. package/src/components/ui/Select.tsx +2 -10
  22. package/src/components/ui/Slider.tsx +2 -7
  23. package/src/components/ui/Table.tsx +155 -32
  24. package/src/components/ui/Textarea.tsx +149 -0
  25. package/src/components/ui/Toaster.tsx +3 -19
  26. package/src/components/ui/Toggle.tsx +1 -5
  27. package/src/components/ui/ToggleChip.tsx +1 -3
  28. package/src/components/ui/Tooltip.tsx +1 -5
  29. package/src/components/ui/VectorInput.tsx +1 -1
  30. package/src/components/ui/cn.ts +1 -2
  31. package/src/components/ui/highlightSpans.ts +110 -0
  32. package/src/components/ui/index.ts +10 -41
  33. package/src/components/ui/listboxModel.ts +1 -6
  34. package/src/components/ui/tableSort.ts +2 -9
  35. package/src/components/ui/tableWindow.ts +96 -0
  36. package/src/index.ts +1 -8
  37. package/src/styles.css +14 -0
  38. package/src/theme.ts +2 -7
package/README.md CHANGED
@@ -125,11 +125,14 @@ keep independent preferences.
125
125
  **Primitives** — `Badge`, `CountRun`, `StatusDot` · `Button`, `ButtonLink` (a navigation styled as a button — never nest a `Button` in a link), `buttonClasses` · `Dialog`, `ConfirmDialog`,
126
126
  `DialogClose` · `Disclosure` · `DropdownMenu`, `MenuItem`, `MenuCheckboxItem`, `MenuLabel`,
127
127
  `MenuSeparator` (a non-modal command and toggle menu) · `Callout`, `Empty`, `ErrorBox`,
128
- `ProgressBar`, `Skeleton`, `SkeletonRows` · `Field` · `Input`, `NumberInput` (with an optional
129
- `unit` written in the field; number-valued with `onValueChange`), `Textarea` · `VectorInput`,
128
+ `Skeleton`, `SkeletonRows` · `Progress` (a count out of a total, or indeterminate; `ProgressBar` is
129
+ deprecated) · `Field` · `Input`, `NumberInput` (with an optional
130
+ `unit` written in the field; number-valued with `onValueChange`), `Textarea` (optionally growing
131
+ with its content between `minRows` and `maxRows`) · `HighlightedText`, `findSpans` (a string
132
+ with its placeholders, tags and terms marked, never parsed as HTML) · `VectorInput`,
130
133
  `PoseInput` · `Kbd` · `Listbox` (single choice among options that render their own content) ·
131
134
  `PageHeader`, `Panel`, `ReadoutStrip`, `Section` · `Popover`, `PopoverClose` ·
132
- `SegmentedControl` · `Select` · `Slider` · `Table` ·
135
+ `SegmentedControl` · `Select` · `Slider` · `Table` (with `windowed` for thousands of rows) ·
133
136
  `Checkbox`, `Switch` · `ToggleChip` · `Toaster`, `toast()` (notifications from anywhere; mount one `<Toaster />` near the root) ·
134
137
  `InfoHint`, `Tooltip`, `TooltipProvider` ·
135
138
  `ThemeToggle` · plus `cn`, `focusRing`, `focusRingInset`, and `formatNumber` / `parseNumber`
package/dist/index.d.ts CHANGED
@@ -464,6 +464,9 @@ export declare function SkeletonRows({ rows, className }: {
464
464
  * A `role="progressbar"` with `aria-valuenow` in percent. Its accessible name is
465
465
  * `aria-label` if given, else `label`, else "Progress" — pass one that names the job when
466
466
  * a screen shows more than one bar.
467
+ *
468
+ * @deprecated Use `Progress`: a value out of a `max` with a "412 of 2,556" value text, an
469
+ * indeterminate state, and a track that follows the density.
467
470
  */
468
471
  export declare function ProgressBar({ fraction, label, "aria-label": ariaLabel, className }: {
469
472
  /** Done, from 0 to 1. Clamped. */
@@ -510,6 +513,75 @@ export declare function Field({ label, description, error, required, annotation,
510
513
  children: ReactNode;
511
514
  }): import("react").JSX.Element;
512
515
  //#endregion
516
+ //#region src/components/ui/highlightSpans.d.ts
517
+ /** What a highlighted span is. Each kind has its own shape on screen, not only its own colour. */
518
+ type HighlightKind = "placeholder" | "tag" | "protected-term" | "mismatch";
519
+ /** A highlighted range of the text: `[start, end)` in UTF-16 code units. */
520
+ interface HighlightSpan {
521
+ /** The offset of the span's first code unit. */
522
+ start: number;
523
+ /** The offset just past the span's last code unit. */
524
+ end: number;
525
+ /** What the span is; it decides the span's shape and its default label. */
526
+ kind: HighlightKind;
527
+ /**
528
+ * What a screen reader hears after the span, instead of the kind's default label: say
529
+ * *why* it is marked ("missing from the translation").
530
+ */
531
+ label?: string | undefined;
532
+ }
533
+ /** A pattern whose matches become spans of one kind. */
534
+ interface HighlightRule {
535
+ /** Matched against the whole text, every match (the `g` flag is added if missing). */
536
+ pattern: RegExp;
537
+ /** The kind every match gets. */
538
+ kind: HighlightKind;
539
+ /** The spans' `label`, if they need one. */
540
+ label?: string | undefined;
541
+ }
542
+ /**
543
+ * Spans for every match of every rule: `%1`, `<b>`, a glossary term. Empty matches are
544
+ * skipped. The result is sorted by start, then longest first.
545
+ *
546
+ * @param text - The string to search.
547
+ * @param rules - Each pattern and the kind its matches get.
548
+ * @returns The spans, ready for `HighlightedText`.
549
+ *
550
+ * @example
551
+ * ```ts
552
+ * findSpans("Open %1 in <b>ParamsManager</b>", [
553
+ * { pattern: /%\d+/, kind: "placeholder" },
554
+ * { pattern: /<\/?[a-z][^>]*>/i, kind: "tag" },
555
+ * { pattern: /\bParamsManager\b/, kind: "protected-term" },
556
+ * ]);
557
+ * ```
558
+ */
559
+ export declare function findSpans(text: string, rules: readonly HighlightRule[]): HighlightSpan[];
560
+ //#endregion
561
+ //#region src/components/ui/HighlightedText.d.ts
562
+ /** Props of `HighlightedText`: the text, its spans, and every `<span>` prop but `children`. */
563
+ type HighlightedTextProps = Omit<ComponentProps<"span">, "children"> & {
564
+ /** The string. Shown as text, whitespace and line breaks kept; markup in it is not interpreted. */
565
+ text: string;
566
+ /** The ranges to mark, in UTF-16 offsets, in any order; overlaps are allowed. `findSpans` builds them from patterns. */
567
+ spans?: readonly HighlightSpan[] | undefined;
568
+ /**
569
+ * What a screen reader hears after a span of each kind: "placeholder", "markup",
570
+ * "protected term" and "mismatch" by default. `null` silences a kind. A span's own `label` wins.
571
+ */
572
+ labels?: Partial<Record<HighlightKind, string | null>> | undefined;
573
+ };
574
+ /**
575
+ * A string with highlighted spans: placeholders (`%1`, `{count}`), markup tags (`<b>`),
576
+ * protected terms (`ParamsManager`) and mismatches, each drawn in its own shape. The caller
577
+ * supplies the spans, or finds them with `findSpans`.
578
+ *
579
+ * The text is rendered as text, never as HTML. Each span is a `<mark>` with `data-kind` (the
580
+ * kinds covering it, space-separated), followed by its label for screen readers ("%1,
581
+ * placeholder"), which a copy of the text leaves out.
582
+ */
583
+ export declare function HighlightedText({ text, spans, labels, className, ...rest }: HighlightedTextProps): import("react").JSX.Element;
584
+ //#endregion
513
585
  //#region src/components/ui/Input.d.ts
514
586
  /**
515
587
  * The shared look of a text-like control — border, palette, placeholder, hover, disabled and
@@ -598,11 +670,6 @@ type NumberInputProps = Omit<ComponentProps<"input">, "min" | "max" | "value"> &
598
670
  * is the native text-valued input.
599
671
  */
600
672
  export declare function NumberInput({ onValueChange, onClear, precision, ...props }: NumberInputProps): import("react").JSX.Element;
601
- /**
602
- * Multi-line text — set in mono, for JSON and lists. Takes every `<textarea>` prop, `ref`
603
- * included.
604
- */
605
- export declare function Textarea({ className, "aria-describedby": describedBy, ...rest }: ComponentProps<"textarea">): import("react").JSX.Element;
606
673
  //#endregion
607
674
  //#region src/components/ui/Kbd.d.ts
608
675
  /**
@@ -776,6 +843,39 @@ export declare function ReadoutStrip({ items, className }: {
776
843
  className?: string | undefined;
777
844
  }): import("react").JSX.Element | null;
778
845
  //#endregion
846
+ //#region src/components/ui/Progress.d.ts
847
+ /**
848
+ * The accessible value text of a progress: `"412 of 2,556"`, or `null` while indeterminate.
849
+ *
850
+ * @param value - Done so far; `null` or `undefined` for an unknown amount.
851
+ * @param max - The whole. Defaults to 100.
852
+ * @returns The text, with the value clamped to `[0, max]`.
853
+ */
854
+ export declare function progressText(value: number | null | undefined, max?: number): string | null;
855
+ /** Props of `Progress`: a value out of a `max`, or none for an unknown amount, plus the `<div>` props. */
856
+ type ProgressProps = Omit<ComponentProps<"div">, "children" | "role"> & {
857
+ /** Done so far, from 0 to `max`; clamped. `null` or left out: indeterminate, the amount unknown. */
858
+ value?: number | null | undefined;
859
+ /** The whole. Defaults to 100; a value ≤ 0 counts as 100. */
860
+ max?: number | undefined;
861
+ /**
862
+ * What a screen reader says for the value. Defaults to `"412 of 2,556"`; give your own when
863
+ * the unit matters ("412 of 2,556 strings").
864
+ */
865
+ valueText?: string | undefined;
866
+ };
867
+ /**
868
+ * A progress bar: determinate when it has a `value` (a `max`, 100 by default), indeterminate
869
+ * without one. Name it with `aria-label` or `aria-labelledby`.
870
+ *
871
+ * A `progressbar` with `aria-valuenow`, `aria-valuemax` and `aria-valuetext` ("412 of 2,556",
872
+ * or your `valueText`); indeterminate, it has none of them, as the ARIA pattern asks.
873
+ * The track follows the density in force. State is exposed as `data-state`
874
+ * (`"indeterminate"`, `"loading"` or `"complete"`). With reduced motion the indeterminate bar
875
+ * holds still.
876
+ */
877
+ export declare function Progress({ value, max, valueText, className, ...rest }: ProgressProps): import("react").JSX.Element;
878
+ //#endregion
779
879
  //#region src/components/ui/Popover.d.ts
780
880
  /** Props of `Popover`. */
781
881
  interface PopoverProps {
@@ -1064,6 +1164,25 @@ type Column<Row> = {
1064
1164
  */
1065
1165
  firstSort?: SortDirection | undefined;
1066
1166
  };
1167
+ /**
1168
+ * Windowed rendering for a long table: only the rows in view, plus `overscan` on each side,
1169
+ * are in the DOM. The rows scroll under a sticky header drawn on `surface`, the panel colour.
1170
+ */
1171
+ interface TableWindowing {
1172
+ /**
1173
+ * Every body row's height in px. Rows are drawn exactly this tall and cells keep to one line
1174
+ * (longer content is cut with an ellipsis), so it must be at least the density's own row
1175
+ * height: 36 px comfortable, 22 px compact.
1176
+ */
1177
+ rowHeight: number;
1178
+ /**
1179
+ * The scroll area's height in px, header included. Leave it out to fill the height of the
1180
+ * container, which must then have one (a flex child with `min-h-0`, a fixed-height panel).
1181
+ */
1182
+ height?: number | undefined;
1183
+ /** Rows rendered beyond each edge of the view, so a fast scroll shows no gap. Defaults to 8. */
1184
+ overscan?: number | undefined;
1185
+ }
1067
1186
  /**
1068
1187
  * A table of rows, with numeric columns set in mono and right-aligned.
1069
1188
  *
@@ -1078,8 +1197,12 @@ type Column<Row> = {
1078
1197
  * `defaultSort`) or controlled (`sort` with `onSortChange`); with `manualSort` the headers
1079
1198
  * show it and the rows render as given. Row callbacks always receive a row's index in `rows`,
1080
1199
  * whatever the order on screen.
1200
+ *
1201
+ * Activatable rows also move focus with the arrow keys, Page Up / Page Down and Home / End.
1202
+ * With `windowed` the table scrolls itself (vertically, under a sticky header), renders only the
1203
+ * rows in view, and uses a fixed layout: give columns a `width` where the content needs it.
1081
1204
  */
1082
- export declare function Table<Row>({ columns, rows, rowKey, empty, caption, className, onRowClick, isRowActive, onRowHover, sort: controlledSort, defaultSort, onSortChange, manualSort }: {
1205
+ export declare function Table<Row>({ columns, rows, rowKey, empty, caption, className, onRowClick, isRowActive, onRowHover, sort: controlledSort, defaultSort, onSortChange, manualSort, windowed }: {
1083
1206
  /** The columns, in order. */
1084
1207
  columns: Column<Row>[];
1085
1208
  /** The rows, in their own order: the order shown while the table is not sorted. */
@@ -1122,8 +1245,49 @@ export declare function Table<Row>({ columns, rows, rowKey, empty, caption, clas
1122
1245
  * and the rows render exactly as given. Mark the columns it can sort `sortable: true`.
1123
1246
  */
1124
1247
  manualSort?: boolean | undefined;
1248
+ /**
1249
+ * Render only the rows in view, for a long table: every row `rowHeight` tall, in a scroll
1250
+ * area of `height` (or the container's height) under a sticky header. Sorting, row
1251
+ * callbacks and keyboard navigation work as without it.
1252
+ */
1253
+ windowed?: TableWindowing | undefined;
1125
1254
  }): import("react").JSX.Element;
1126
1255
  //#endregion
1256
+ //#region src/components/ui/Textarea.d.ts
1257
+ /**
1258
+ * Props of `Textarea`: every `<textarea>` prop, `ref` included, plus an invalid state, the
1259
+ * mono face, and growing with the content between `minRows` and `maxRows`.
1260
+ */
1261
+ type TextareaProps = ComponentProps<"textarea"> & {
1262
+ /** Called with the new text on every edit, alongside the native `onChange`. */
1263
+ onValueChange?: ((value: string) => void) | undefined;
1264
+ /**
1265
+ * Marks the value as wrong: `aria-invalid`, `data-invalid` and a border in the defect
1266
+ * colour. Inside a `Field` with an `error` it is on without this. Say what is wrong in
1267
+ * text too (the field's `error`): the border alone is a colour.
1268
+ */
1269
+ invalid?: boolean | undefined;
1270
+ /** Sets the text in IBM Plex Mono, for code, JSON, lists, or strings whose characters all matter. */
1271
+ mono?: boolean | undefined;
1272
+ /**
1273
+ * Grows with the content from this many lines. Set it or `maxRows` to turn growing on;
1274
+ * `rows` is then ignored.
1275
+ */
1276
+ minRows?: number | undefined;
1277
+ /** Stops growing at this many lines and scrolls beyond them. Set it or `minRows` to turn growing on. */
1278
+ maxRows?: number | undefined;
1279
+ };
1280
+ /**
1281
+ * Multi-line text, on the shared control palette. Takes every `<textarea>` prop, `ref`
1282
+ * included; inside a `Field` it is described by the field's description and error, and
1283
+ * shown invalid while the field has an error.
1284
+ *
1285
+ * With `minRows` or `maxRows` it grows with its content between the two (and scrolls past
1286
+ * `maxRows`); without them it is `rows` tall and the reader can resize it. State is exposed
1287
+ * as `data-invalid`.
1288
+ */
1289
+ export declare function Textarea({ className, "aria-describedby": describedBy, invalid, mono, minRows, maxRows, rows, value, onChange, onValueChange, ref, ...rest }: TextareaProps): import("react").JSX.Element;
1290
+ //#endregion
1127
1291
  //#region src/components/ui/Toggle.d.ts
1128
1292
  /**
1129
1293
  * A setting: changes how the thing behaves from now on, and reads as one ("show the mask").
@@ -1422,5 +1586,5 @@ export declare function Tabs<Id extends string>({ items, active, onSelect, label
1422
1586
  className?: string | undefined;
1423
1587
  }): import("react").JSX.Element;
1424
1588
  //#endregion
1425
- export type { BackLink, ButtonSize, ButtonVariant, CalloutTone, Column, Density, DropdownMenuProps, ListboxOption, ListboxOptionState, ListboxProps, MeasureTone, MenuCheckboxItemProps, MenuItemProps, NumberInputProps, PopoverProps, PoseInputProps, PoseValue, Quaternion, ReadoutItem, RotationView, SelectOption, SortDirection, TabItem, TableSort, ThemeChoice, ToastOptions, ToastRecord, ToastStore, ToastTone, ToasterProps, Tone, Vec3, VectorInputProps };
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 };
1426
1590
  //# sourceMappingURL=index.d.ts.map