@tensor_1/react 2.5.0 → 2.7.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/dist/index.d.cts CHANGED
@@ -1,10 +1,221 @@
1
1
  import * as react from 'react';
2
- import { ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, TextareaHTMLAttributes, SelectHTMLAttributes, CSSProperties, HTMLAttributes, AnchorHTMLAttributes, TableHTMLAttributes, TdHTMLAttributes, ThHTMLAttributes } from 'react';
2
+ import { RefObject, ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, TextareaHTMLAttributes, SelectHTMLAttributes, CSSProperties, HTMLAttributes, AnchorHTMLAttributes, TdHTMLAttributes, TableHTMLAttributes, ThHTMLAttributes } from 'react';
3
3
 
4
4
  declare function cx(...args: (string | false | null | undefined | 0)[]): string;
5
5
 
6
6
  declare function useDialog(open: boolean): React.RefObject<HTMLDialogElement>;
7
7
 
8
+ /**
9
+ * uix table engine — framework-agnostic, dependency-free logic for data grids.
10
+ *
11
+ * Pure functions only (no DOM, no React), so the same core drives the React
12
+ * wrappers, the vanilla styleguide, and any consumer. Everything here is
13
+ * deterministic and unit-tested (see table-engine.test.mjs). The React layer
14
+ * (useTable / Table subcomponents) composes these; products may also call them
15
+ * directly. Presentation stays in table.css via the --uix-* contract.
16
+ */
17
+ type SortDir = 'ascending' | 'descending';
18
+ interface SortKey {
19
+ /** row field to sort on */
20
+ field: string;
21
+ dir: SortDir;
22
+ }
23
+ type Primitive = string | number | boolean | null | undefined;
24
+ type Row = Record<string, unknown>;
25
+ /**
26
+ * Stable multi-column sort. `keys` are applied in priority order (first is
27
+ * primary). Returns a new array; the input is not mutated.
28
+ */
29
+ declare function multiSort<T extends Row>(rows: readonly T[], keys: readonly SortKey[]): T[];
30
+ /** Cycle a header's sort state: none → ascending → descending → none. */
31
+ declare function nextSortDir(current: SortDir | 'none' | undefined): SortDir | 'none';
32
+ /**
33
+ * Toggle a field within a multi-sort key list. Without shift, it replaces the
34
+ * list with just this field (cycling its direction); with shift, it adds/updates
35
+ * the field as a secondary key (removing it when it cycles back to none).
36
+ */
37
+ declare function toggleSort(keys: readonly SortKey[], field: string, additive?: boolean): SortKey[];
38
+ type FilterKind = 'enum' | 'text' | 'number' | 'date' | 'boolean';
39
+ type FilterOp = 'isAnyOf' | 'isNoneOf' | 'contains' | 'equals' | 'startsWith' | 'eq' | 'lt' | 'gt' | 'between' | 'is';
40
+ interface ColumnFilter {
41
+ field: string;
42
+ kind: FilterKind;
43
+ op: FilterOp;
44
+ /** value(s): a scalar, an array (enum / between), or [min,max] for between */
45
+ value: Primitive | Primitive[];
46
+ }
47
+ declare function matchFilter(row: Row, f: ColumnFilter): boolean;
48
+ /** Keep rows that satisfy EVERY active filter (AND across columns). */
49
+ declare function applyFilters<T extends Row>(rows: readonly T[], filters: readonly ColumnFilter[]): T[];
50
+ /** Rows where any of `fields` (default: all string/number values) contains `query`. */
51
+ declare function searchRows<T extends Row>(rows: readonly T[], query: string, fields?: readonly string[]): T[];
52
+ interface Segment {
53
+ text: string;
54
+ match: boolean;
55
+ }
56
+ /** Split `text` into matched / unmatched segments for <mark> rendering (case-insensitive). */
57
+ declare function highlightSegments(text: string, query: string): Segment[];
58
+ interface ViewState {
59
+ sort?: SortKey[];
60
+ filters?: ColumnFilter[];
61
+ columns?: string[];
62
+ density?: 'compact' | 'standard' | 'comfortable';
63
+ q?: string;
64
+ }
65
+ /** Serialize a view to a compact, linkable query string (no leading '?'). */
66
+ declare function serializeView(v: ViewState): string;
67
+ /** Parse a query string (with or without leading '?') back into a ViewState. */
68
+ declare function parseView(qs: string): ViewState;
69
+ interface VirtualWindow {
70
+ start: number;
71
+ end: number;
72
+ padTop: number;
73
+ padBottom: number;
74
+ total: number;
75
+ }
76
+ /**
77
+ * Compute the visible row window for a fixed row height. Renders only
78
+ * [start, end) plus `overscan` rows on each side; padTop/padBottom are spacer
79
+ * heights (px) so the scrollbar stays correct. Below `threshold` rows, callers
80
+ * should skip virtualization (render all) — see shouldVirtualize.
81
+ */
82
+ declare function virtualWindow(scrollTop: number, viewportH: number, rowH: number, count: number, overscan?: number): VirtualWindow;
83
+ declare function shouldVirtualize(count: number, threshold?: number): boolean;
84
+ /** Clamp a dragged column width to a sane minimum (and optional maximum). */
85
+ declare function clampWidth(width: number, min?: number, max?: number): number;
86
+ /** Move an item from index `from` to index `to`, returning a new array. */
87
+ declare function reorder<T>(arr: readonly T[], from: number, to: number): T[];
88
+ declare function toggleId(set: ReadonlySet<string>, id: string): Set<string>;
89
+ type SelectAllState = 'none' | 'some' | 'all';
90
+ declare function selectAllState(selected: ReadonlySet<string>, pageIds: readonly string[]): SelectAllState;
91
+ /** Toggle every id on the current page on/off based on the header checkbox. */
92
+ declare function togglePage(selected: ReadonlySet<string>, pageIds: readonly string[]): Set<string>;
93
+ /** Pinned rows (kept present regardless of filter/sort) hoisted above the rest. */
94
+ declare function mergePinned<T extends Row>(all: readonly T[], visible: readonly T[], pinnedIds: ReadonlySet<string>, idField?: string): T[];
95
+
96
+ interface UseTableOptions {
97
+ /** row field used as the stable id (selection / pinning). Default: 'id'. */
98
+ idField?: string;
99
+ initialSort?: SortKey[];
100
+ initialFilters?: ColumnFilter[];
101
+ initialQuery?: string;
102
+ /** restrict full-text search to these fields (default: all values). */
103
+ searchFields?: readonly string[];
104
+ /** ids kept present + hoisted regardless of filter/sort. */
105
+ initialPinned?: Iterable<string>;
106
+ }
107
+ interface UseTableResult<T> {
108
+ /** derived view: filter → search → sort, then pinned rows hoisted to the top. */
109
+ rows: T[];
110
+ sort: SortKey[];
111
+ filters: ColumnFilter[];
112
+ query: string;
113
+ selected: ReadonlySet<string>;
114
+ pinned: ReadonlySet<string>;
115
+ /** header select-all tri-state over the current derived rows. */
116
+ selectAll: SelectAllState;
117
+ /** cycle a column's sort; pass additive (⇧-click) to keep it as a secondary key. */
118
+ toggleSort: (field: string, additive?: boolean) => void;
119
+ setSort: (keys: SortKey[]) => void;
120
+ setFilters: (filters: ColumnFilter[]) => void;
121
+ setQuery: (query: string) => void;
122
+ isSelected: (id: string) => boolean;
123
+ toggleRow: (id: string) => void;
124
+ /** toggle every currently-visible row from the header checkbox. */
125
+ toggleAllRows: () => void;
126
+ clearSelection: () => void;
127
+ togglePin: (id: string) => void;
128
+ /** current state as a ViewState + its linkable query string. */
129
+ view: ViewState;
130
+ viewQueryString: string;
131
+ /** hydrate sort/filters/query from a saved-view query string. */
132
+ applyView: (queryString: string) => void;
133
+ }
134
+ /**
135
+ * Compose the framework-agnostic table-engine into React state: sorting, typed
136
+ * filtering, full-text search, page-scoped selection, pinning, and linkable saved
137
+ * views. Presentation stays in the `<Table>` primitives + table.css; this only owns
138
+ * the state and the derived row list. The vanilla styleguide (`guide/app.js`) runs
139
+ * the same engine functions, so both layers behave identically.
140
+ */
141
+ declare function useTable<T extends Row>(data: readonly T[], options?: UseTableOptions): UseTableResult<T>;
142
+
143
+ /**
144
+ * uix overlay positioning — framework-agnostic, dependency-free anchored placement.
145
+ *
146
+ * Pure geometry (no DOM): given the anchor's rect, the floating element's size, and
147
+ * the viewport, compute where to put the floating element with two behaviours:
148
+ * • flip — if the preferred side doesn't fit, use the opposite side (or whichever
149
+ * side has more room);
150
+ * • shift — slide along the cross axis so the element stays within the viewport.
151
+ *
152
+ * The React hook (useAnchoredPosition) and the vanilla styleguide both feed this
153
+ * getBoundingClientRect() values, so anchored overlays land in the same place in every
154
+ * browser — instead of relying on CSS anchor() positioning, which is Chromium-only and
155
+ * silently detaches the overlay from its trigger everywhere else (UIX-FIX-02).
156
+ *
157
+ * Everything here is deterministic and unit-tested (see overlay-position.test.mjs).
158
+ */
159
+ type Side = 'top' | 'bottom' | 'left' | 'right';
160
+ type Align = 'start' | 'center' | 'end';
161
+ type Placement = Side | `${Side}-${Align}`;
162
+ /** A viewport-space rectangle, as returned by getBoundingClientRect(). */
163
+ interface Rect {
164
+ x: number;
165
+ y: number;
166
+ width: number;
167
+ height: number;
168
+ }
169
+ interface Size {
170
+ width: number;
171
+ height: number;
172
+ }
173
+ interface PositionOptions {
174
+ /** Preferred placement. Default `'bottom-start'`; a bare side (e.g. `'top'`) centers on the cross axis. */
175
+ placement?: Placement;
176
+ /** Gap between the anchor and the floating element, in px. Default 6. */
177
+ offset?: number;
178
+ /** Minimum gap kept from each viewport edge when shifting, in px. Default 8. */
179
+ padding?: number;
180
+ /** Flip to the opposite side when the preferred one doesn't fit. Default true. */
181
+ flip?: boolean;
182
+ /** Slide along the cross axis to stay on-screen. Default true. */
183
+ shift?: boolean;
184
+ }
185
+ interface PositionResult {
186
+ /** Viewport-space left, for `position: fixed`. */
187
+ x: number;
188
+ /** Viewport-space top, for `position: fixed`. */
189
+ y: number;
190
+ /** The placement actually used (after any flip). */
191
+ placement: Placement;
192
+ side: Side;
193
+ align: Align;
194
+ }
195
+ /**
196
+ * Compute the floating element's viewport-space position anchored to `anchor`.
197
+ * Coordinates are for `position: fixed` (same space as getBoundingClientRect).
198
+ */
199
+ declare function computePosition(anchor: Rect, floating: Size, viewport: Size, options?: PositionOptions): PositionResult;
200
+
201
+ interface UseAnchoredPositionOptions {
202
+ /** Reposition while true, and (re)attach scroll/resize listeners. */
203
+ open: boolean;
204
+ placement?: Placement;
205
+ offset?: number;
206
+ padding?: number;
207
+ }
208
+ /**
209
+ * Position a floating element (a native-popover overlay) against an anchor with
210
+ * cross-browser flip/shift — the DOM half of the overlay-position engine (UIX-FIX-02).
211
+ *
212
+ * Measures both elements with getBoundingClientRect, applies `position: fixed` + left/top
213
+ * (overriding the popover's default centered `inset:0; margin:auto`), and keeps the overlay
214
+ * glued to its anchor on scroll/resize while `open`. Returns a `reposition` fn for callers
215
+ * that want to nudge it manually (e.g. right when a native popover's `toggle` fires).
216
+ */
217
+ declare function useAnchoredPosition(anchor: RefObject<HTMLElement | null> | HTMLElement | null | undefined, floatingRef: RefObject<HTMLElement | null>, { open, placement, offset, padding }: UseAnchoredPositionOptions): () => void;
218
+
8
219
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
9
220
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'link';
10
221
  size?: 'sm' | 'md' | 'lg';
@@ -219,13 +430,27 @@ interface TabProps extends Omit<HTMLAttributes<HTMLButtonElement>, 'onChange'> {
219
430
  }
220
431
  declare function Tab({ value, children, disabled, className, onClick, ...props }: TabProps): react.JSX.Element;
221
432
 
433
+ type ShellNav = 'full' | 'rail' | 'hidden';
222
434
  interface AppShellProps extends HTMLAttributes<HTMLDivElement> {
435
+ /** Sidebar width tier: 'full' (default) → 'rail' (icon only) → 'hidden' (0). */
436
+ nav?: ShellNav;
437
+ /** Back-compat alias for nav="rail". Ignored when `nav` is set. */
223
438
  collapsed?: boolean;
439
+ /**
440
+ * Immersive focus mode: hides the sidebar AND the topbar so a wide, many-column
441
+ * table uses the whole frame. Provide `onExitFocus` to enable Esc-to-exit and
442
+ * the floating exit control.
443
+ */
444
+ focus?: boolean;
445
+ /** Called when the user presses Esc (or the exit control) while in focus mode. */
446
+ onExitFocus?: () => void;
447
+ /** Drop the content gutter so a genuinely wide table runs edge-to-edge. */
448
+ mainBleed?: boolean;
224
449
  sidebar?: ReactNode;
225
450
  topbar?: ReactNode;
226
451
  children?: ReactNode;
227
452
  }
228
- declare function AppShell({ collapsed, sidebar, topbar, children, className, ...props }: AppShellProps): react.JSX.Element;
453
+ declare function AppShell({ nav, collapsed, focus, onExitFocus, mainBleed, sidebar, topbar, children, className, ...props }: AppShellProps): react.JSX.Element;
229
454
 
230
455
  interface SidebarProps extends HTMLAttributes<HTMLElement> {
231
456
  collapsed?: boolean;
@@ -387,16 +612,20 @@ interface TableProps extends TableHTMLAttributes<HTMLTableElement> {
387
612
  density?: TableDensity;
388
613
  zebra?: boolean;
389
614
  pinnedCol?: boolean;
615
+ /** table-layout: fixed — required for reliable column widths + primary-column truncation */
616
+ fixed?: boolean;
390
617
  rowPeek?: boolean;
391
618
  v2?: boolean;
392
619
  }
393
- declare function Table({ density, zebra, pinnedCol, rowPeek, v2, className, children, ...props }: TableProps): react.JSX.Element;
620
+ declare function Table({ density, zebra, pinnedCol, fixed, rowPeek, v2, className, children, ...props }: TableProps): react.JSX.Element;
394
621
  interface ThProps extends ThHTMLAttributes<HTMLTableCellElement> {
395
622
  sortable?: boolean;
396
623
  sortDirection?: SortDirection;
624
+ /** 1-based ordinal shown when this column is a secondary key in a multi-sort */
625
+ sortOrder?: number;
397
626
  onSort?: () => void;
398
627
  }
399
- declare function Th({ sortable, sortDirection, onSort, className, children, onClick, ...props }: ThProps): react.JSX.Element;
628
+ declare function Th({ sortable, sortDirection, sortOrder, onSort, className, children, onClick, ...props }: ThProps): react.JSX.Element;
400
629
  interface TdProps extends TdHTMLAttributes<HTMLTableCellElement> {
401
630
  pinned?: boolean;
402
631
  }
@@ -406,6 +635,43 @@ interface TrProps extends HTMLAttributes<HTMLTableRowElement> {
406
635
  pinned?: boolean;
407
636
  }
408
637
  declare function Tr({ selected, pinned, className, children, ...props }: TrProps): react.JSX.Element;
638
+ interface BulkBarProps extends HTMLAttributes<HTMLDivElement> {
639
+ /** number of selected rows, rendered as "N selected" */
640
+ count?: number;
641
+ children?: ReactNode;
642
+ }
643
+ /** Contextual action bar shown above the table when ≥1 row is selected. */
644
+ declare function BulkBar({ count, children, className, ...props }: BulkBarProps): react.JSX.Element;
645
+ interface RowActionsProps extends TdHTMLAttributes<HTMLTableCellElement> {
646
+ children?: ReactNode;
647
+ }
648
+ /** Trailing cell that holds the row's hover actions (kebab, quick actions). */
649
+ declare function RowActions({ children, className, ...props }: RowActionsProps): react.JSX.Element;
650
+ interface RowActionProps extends ButtonHTMLAttributes<HTMLButtonElement> {
651
+ children?: ReactNode;
652
+ }
653
+ /** A single hover-revealed row action button (icon inside). */
654
+ declare function RowAction({ children, className, type, ...props }: RowActionProps): react.JSX.Element;
655
+ interface ExpandToggleProps extends ButtonHTMLAttributes<HTMLButtonElement> {
656
+ expanded?: boolean;
657
+ }
658
+ /** Chevron button that expands/collapses an inline detail row. */
659
+ declare function ExpandToggle({ expanded, className, type, ...props }: ExpandToggleProps): react.JSX.Element;
660
+ /** Emphasised primary cell text. */
661
+ declare function CellStrong({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
662
+ /** Secondary line under a primary cell value (muted, meta size). */
663
+ declare function CellSub({ children, className, ...props }: HTMLAttributes<HTMLSpanElement>): react.JSX.Element;
664
+ interface MarkProps extends HTMLAttributes<HTMLElement> {
665
+ children?: ReactNode;
666
+ }
667
+ /** A search-match highlight span. */
668
+ declare function Mark({ children, className, ...props }: MarkProps): react.JSX.Element;
669
+ interface HighlightedProps {
670
+ text: string;
671
+ query: string;
672
+ }
673
+ /** Render `text` with case-insensitive matches of `query` wrapped in <mark>. */
674
+ declare function Highlighted({ text, query }: HighlightedProps): react.JSX.Element;
409
675
 
410
676
  interface PaginationProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
411
677
  page: number;
@@ -464,16 +730,19 @@ interface StatProps extends HTMLAttributes<HTMLDivElement> {
464
730
  declare function Stat({ label, value, icon, meta, trend, className, ...props }: StatProps): react.JSX.Element;
465
731
 
466
732
  interface TooltipProps extends HTMLAttributes<HTMLSpanElement> {
467
- /** Tooltip text. Rendered via the CSS `[data-uix-tip]` hover/focus tooltip. */
733
+ /** Tooltip text. */
468
734
  label: string;
735
+ /** Preferred placement. Default `'top'`. */
736
+ placement?: Placement;
469
737
  children?: ReactNode;
470
738
  }
471
739
  /**
472
- * Thin wrapper over the CSS-only tooltip (`[data-uix-tip]`). Wraps its children
473
- * in a span carrying the attribute; the bubble is drawn entirely in CSS on
474
- * hover/focus. For keyboard reveal, ensure a focusable child or pass `tabIndex`.
740
+ * Tooltip whose bubble renders in the top layer via the native Popover API, so it
741
+ * escapes any `overflow: hidden/scroll` ancestor that would clip the old CSS-only
742
+ * `[data-uix-tip]` tooltip (UIX-FIX-02). Positioned by the shared overlay engine
743
+ * (flip/shift), shown on hover and keyboard focus, dismissed on blur or Escape.
475
744
  */
476
- declare function Tooltip({ label, children, ...props }: TooltipProps): react.JSX.Element;
745
+ declare function Tooltip({ label, placement, className, children, ...props }: TooltipProps): react.JSX.Element;
477
746
 
478
747
  interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
479
748
  icon?: ReactNode;
@@ -559,17 +828,65 @@ interface CommentProps extends HTMLAttributes<HTMLDivElement> {
559
828
  /** A single comment over `.uix-comment` (avatar column + body). */
560
829
  declare function Comment({ avatar, author, meta, children, className, ...props }: CommentProps): react.JSX.Element;
561
830
 
831
+ interface ComposerProps extends HTMLAttributes<HTMLDivElement> {
832
+ children?: ReactNode;
833
+ }
834
+ /**
835
+ * Composer surface over `.uix-composer` — a single box that owns the
836
+ * `:focus-within` accent ring. Drop a borderless `<textarea>` and a
837
+ * `<ComposerBar>` inside; the descendant `textarea` picks up the composer's
838
+ * padding/typography automatically, so the input never reads as a second
839
+ * nested box.
840
+ */
841
+ declare function Composer({ children, className, ...props }: ComposerProps): react.JSX.Element;
842
+ interface ComposerBarProps extends HTMLAttributes<HTMLDivElement> {
843
+ children?: ReactNode;
844
+ }
845
+ /** Action footer for a `<Composer>` over `.uix-composer__bar` (top-bordered, right-aligned). */
846
+ declare function ComposerBar({ children, className, ...props }: ComposerBarProps): react.JSX.Element;
847
+
848
+ interface SegmentedProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onChange'> {
849
+ /** The currently-selected option value. */
850
+ value?: string;
851
+ /** Fires with the option's value when a different option is chosen. */
852
+ onChange?: (value: string) => void;
853
+ children?: ReactNode;
854
+ }
855
+ /**
856
+ * Segmented single-select over `.uix-segmented` — the compact 2–3 way toggle
857
+ * (density, audience, view mode …) that reads as one pill with a lifted active
858
+ * segment. Selection state is shared with `<SegmentedOption>` via context, so
859
+ * the caller only wires `value` + `onChange` once.
860
+ */
861
+ declare function Segmented({ value, onChange, children, className, ...props }: SegmentedProps): react.JSX.Element;
862
+ interface SegmentedOptionProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'value' | 'onChange'> {
863
+ value: string;
864
+ children?: ReactNode;
865
+ }
866
+ /**
867
+ * One option in a `<Segmented>`. Active state is derived from the parent's
868
+ * `value`; the pressed segment lifts to the surface via
869
+ * `.uix-segmented__option[aria-pressed="true"]`.
870
+ */
871
+ declare function SegmentedOption({ value, children, className, onClick, ...props }: SegmentedOptionProps): react.JSX.Element;
872
+
562
873
  interface TimelineProps extends HTMLAttributes<HTMLDivElement> {
563
874
  children?: ReactNode;
564
875
  }
565
876
  /** Activity timeline container over `.uix-timeline`. */
566
877
  declare function Timeline({ children, className, ...props }: TimelineProps): react.JSX.Element;
567
878
  interface TimelineItemProps extends HTMLAttributes<HTMLDivElement> {
879
+ /**
880
+ * Custom rail node — an icon puck, an avatar, a tinted dot. Defaults to the
881
+ * accent `.uix-timeline__node` dot. Supply this to make a heterogeneous feed
882
+ * (comments + audit events) read on one rail with per-row node semantics.
883
+ */
884
+ node?: ReactNode;
568
885
  meta?: ReactNode;
569
886
  children?: ReactNode;
570
887
  }
571
888
  /** A timeline entry over `.uix-timeline__item` (node + connecting line + body). */
572
- declare function TimelineItem({ meta, children, className, ...props }: TimelineItemProps): react.JSX.Element;
889
+ declare function TimelineItem({ node, meta, children, className, ...props }: TimelineItemProps): react.JSX.Element;
573
890
 
574
891
  interface ProseProps extends HTMLAttributes<HTMLDivElement> {
575
892
  children?: ReactNode;
@@ -594,13 +911,26 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
594
911
  * wires to it via `popoverTarget={id}`. Pass `"manual"` to control open state yourself.
595
912
  */
596
913
  popover?: 'auto' | 'manual';
914
+ /**
915
+ * Element (or ref) to anchor against. When set, the popover is placed with
916
+ * cross-browser JS positioning — flip when it won't fit, shift to stay on-screen —
917
+ * instead of relying on CSS `anchor()`, which is Chromium-only and detaches the
918
+ * popover from its trigger everywhere else. The native Popover API still provides
919
+ * the top layer (so it escapes `overflow` clipping) and light-dismiss.
920
+ */
921
+ anchor?: RefObject<HTMLElement | null> | HTMLElement | null;
922
+ /** Preferred placement when `anchor` is set. Default `'bottom-start'`. */
923
+ placement?: Placement;
924
+ /** Gap between the trigger and the popover, in px. Default 6. */
925
+ offset?: number;
597
926
  children?: ReactNode;
598
927
  }
599
928
  /**
600
- * Anchored surface over `.uix-popover`, using the native Popover API.
601
- * Compose ITSM things like a filter popover by putting controls inside.
929
+ * Anchored surface over `.uix-popover`, using the native Popover API. Compose ITSM
930
+ * things like a filter popover, menu, or rich select by putting controls inside.
931
+ * Pass `anchor` to get collision-aware, cross-browser placement (UIX-FIX-02).
602
932
  */
603
- declare function Popover({ popover, children, className, ...props }: PopoverProps): react.JSX.Element;
933
+ declare function Popover({ popover, anchor, placement, offset, className, children, ...props }: PopoverProps): react.JSX.Element;
604
934
 
605
935
  interface CommandPaletteProps extends HTMLAttributes<HTMLDivElement> {
606
936
  /** Props for the search input (value/onChange/placeholder wired by the consumer). */
@@ -686,8 +1016,11 @@ interface TreeNodeProps {
686
1016
  node: TreeNodeData;
687
1017
  expanded: Set<string>;
688
1018
  selected?: string;
1019
+ selectable: boolean;
1020
+ tabbableId?: string;
689
1021
  onToggle: (id: string) => void;
690
1022
  onSelect?: (id: string) => void;
1023
+ onFocusNode: (id: string) => void;
691
1024
  level?: number;
692
1025
  }
693
1026
  interface TreeProps extends Omit<HTMLAttributes<HTMLUListElement>, 'onSelect' | 'onChange'> {
@@ -697,7 +1030,65 @@ interface TreeProps extends Omit<HTMLAttributes<HTMLUListElement>, 'onSelect' |
697
1030
  selected?: string;
698
1031
  onToggle?: (id: string) => void;
699
1032
  onSelect?: (id: string) => void;
1033
+ /**
1034
+ * Virtualize a large tree — render only the rows in view (UIX-FIX-05). Defaults to auto
1035
+ * (on past the engine's `shouldVirtualize` threshold of visible rows). When on, the tree is
1036
+ * flattened to a scrollable list of `maxHeight` with fixed-height rows; a11y is preserved via
1037
+ * `aria-level` / `aria-setsize` / `aria-posinset` instead of nested `role="group"`s.
1038
+ */
1039
+ virtualize?: boolean;
1040
+ /** Fixed row height (px) used for virtualization. Default 32. */
1041
+ rowHeight?: number;
1042
+ /** Scroll-viewport height (px) when virtualizing. Default 384. */
1043
+ maxHeight?: number;
700
1044
  }
701
- declare function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected, onToggle, onSelect, className, ...props }: TreeProps): react.JSX.Element;
1045
+ declare function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected, onToggle, onSelect, virtualize, rowHeight, maxHeight, className, ...props }: TreeProps): react.JSX.Element;
1046
+
1047
+ /**
1048
+ * uix tree model — framework-agnostic, dependency-free tree flattening + keyboard nav.
1049
+ *
1050
+ * Pure functions (no DOM, no React): flatten a nested tree into the linear list of *visible*
1051
+ * rows (respecting expansion) so it can be virtualized with the table engine's virtualWindow,
1052
+ * and resolve a keyboard key into a navigation decision. Both the plain and the virtualized
1053
+ * <Tree> render paths use these, so the two behave identically and keyboard nav works even for
1054
+ * rows that are scrolled out of the virtual window (UIX-FIX-05). Unit-tested (tree-model.test.mjs).
1055
+ */
1056
+ /** Minimal shape a node must have; the concrete node (label, icon, …) rides along as `T`. */
1057
+ interface TreeLike<T> {
1058
+ id: string;
1059
+ children?: T[];
1060
+ }
1061
+ interface FlatNode<T> {
1062
+ node: T;
1063
+ /** 1-based depth, for aria-level. */
1064
+ level: number;
1065
+ /** number of siblings at this level (this node's parent's child count), for aria-setsize. */
1066
+ setsize: number;
1067
+ /** 1-based index among those siblings, for aria-posinset. */
1068
+ posinset: number;
1069
+ hasChildren: boolean;
1070
+ isExpanded: boolean;
1071
+ }
1072
+ /**
1073
+ * Flatten a nested tree into the visible rows, in DOM/reading order. A node's children follow
1074
+ * it immediately and are included only when the node is in `expanded`.
1075
+ */
1076
+ declare function flattenTree<T extends TreeLike<T>>(nodes: readonly T[], expanded: ReadonlySet<string>, level?: number): FlatNode<T>[];
1077
+ /** A decision produced by a key press — any subset may be set. */
1078
+ interface TreeNavAction {
1079
+ /** move focus (roving tabindex) to this node id. */
1080
+ focusId?: string;
1081
+ /** toggle this node's expansion. */
1082
+ toggleId?: string;
1083
+ /** select this node id. */
1084
+ selectId?: string;
1085
+ }
1086
+ /**
1087
+ * Resolve a key press against the flattened, visible node list — the single source of truth for
1088
+ * both render paths. Mirrors the WAI-ARIA tree pattern: Up/Down move by row, Right expands then
1089
+ * descends, Left collapses then ascends to the parent, Home/End jump, Enter/Space select (and
1090
+ * toggle a parent). Returns an empty action for unhandled keys or an unknown current id.
1091
+ */
1092
+ declare function treeNav<T extends TreeLike<T>>(flat: readonly FlatNode<T>[], currentId: string | undefined, key: string): TreeNavAction;
702
1093
 
703
- export { Alert, type AlertProps, type AlertTone, AppShell, type AppShellProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, Card, type CardProps, Checkbox, type CheckboxProps, CommandGroup, type CommandGroupProps, CommandItem, type CommandItemProps, CommandPalette, type CommandPaletteProps, Comment, type CommentProps, Comments, type CommentsProps, DescriptionItem, type DescriptionItemProps, DescriptionList, type DescriptionListItem, type DescriptionListProps, DetailLayout, type DetailLayoutProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, Field, type FieldProps, Inbox, InboxDetail, type InboxDetailProps, InboxItem, type InboxItemProps, InboxList, type InboxListProps, type InboxProps, Input, InputGroup, type InputGroupProps, type InputProps, Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanProps, Label, type LabelProps, List, ListItem, type ListItemProps, type ListProps, LoadingState, type LoadingStateProps, Meter, type MeterProps, type MeterTone, Modal, type ModalProps, type NavFavouriteItem, NavFavourites, type NavFavouritesLabels, type NavFavouritesProps, NavGroup, type NavGroupProps, NavItem, type NavItemProps, Note, type NoteProps, type NoteTone, PageHeader, type PageHeaderProps, Pagination, type PaginationProps, Peek, type PeekProps, type PillTone, type PillTreatment, Popover, type PopoverProps, Progress, type ProgressProps, Prose, type ProseProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, Select, type SelectProps, Sidebar, type SidebarProps, SidebarSection, type SidebarSectionProps, Skeleton, type SkeletonProps, type SortDirection, Spinner, type SpinnerProps, StarButton, type StarButtonProps, Stat, type StatProps, type StatTrend, StatusPill, type StatusPillProps, SubNavItem, type SubNavItemProps, Switch, type SwitchProps, Tab, type TabProps, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Tabs, type TabsProps, Td, type TdProps, Textarea, type TextareaProps, Th, type ThProps, Timeline, TimelineItem, type TimelineItemProps, type TimelineProps, Toast, type ToastProps, type ToastTone, Toaster, type ToasterProps, Tooltip, type TooltipProps, Tr, type TrProps, Tree, type TreeNodeData, type TreeNodeProps, type TreeProps, UserChip, type UserChipProps, cx, useDialog };
1094
+ export { Alert, type AlertProps, type AlertTone, type Align, AppShell, type AppShellProps, Avatar, AvatarGroup, type AvatarGroupProps, type AvatarProps, BulkBar, type BulkBarProps, Button, ButtonGroup, type ButtonGroupProps, type ButtonProps, Card, type CardProps, CellStrong, CellSub, Checkbox, type CheckboxProps, type ColumnFilter, CommandGroup, type CommandGroupProps, CommandItem, type CommandItemProps, CommandPalette, type CommandPaletteProps, Comment, type CommentProps, Comments, type CommentsProps, Composer, ComposerBar, type ComposerBarProps, type ComposerProps, DescriptionItem, type DescriptionItemProps, DescriptionList, type DescriptionListItem, type DescriptionListProps, DetailLayout, type DetailLayoutProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, ExpandToggle, type ExpandToggleProps, Field, type FieldProps, type FilterKind, type FilterOp, type FlatNode, Highlighted, type HighlightedProps, Inbox, InboxDetail, type InboxDetailProps, InboxItem, type InboxItemProps, InboxList, type InboxListProps, type InboxProps, Input, InputGroup, type InputGroupProps, type InputProps, Kanban, KanbanCard, type KanbanCardProps, KanbanColumn, type KanbanColumnProps, type KanbanProps, Label, type LabelProps, List, ListItem, type ListItemProps, type ListProps, LoadingState, type LoadingStateProps, Mark, type MarkProps, Meter, type MeterProps, type MeterTone, Modal, type ModalProps, type NavFavouriteItem, NavFavourites, type NavFavouritesLabels, type NavFavouritesProps, NavGroup, type NavGroupProps, NavItem, type NavItemProps, Note, type NoteProps, type NoteTone, PageHeader, type PageHeaderProps, Pagination, type PaginationProps, Peek, type PeekProps, type PillTone, type PillTreatment, type Placement, Popover, type PopoverProps, type PositionOptions, type PositionResult, type Primitive, Progress, type ProgressProps, Prose, type ProseProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, type Rect, type Row, RowAction, type RowActionProps, RowActions, type RowActionsProps, type Segment, Segmented, SegmentedOption, type SegmentedOptionProps, type SegmentedProps, Select, type SelectAllState, type SelectProps, type ShellNav, type Side, Sidebar, type SidebarProps, SidebarSection, type SidebarSectionProps, type Size, Skeleton, type SkeletonProps, type SortDir, type SortDirection, type SortKey, Spinner, type SpinnerProps, StarButton, type StarButtonProps, Stat, type StatProps, type StatTrend, StatusPill, type StatusPillProps, SubNavItem, type SubNavItemProps, Switch, type SwitchProps, Tab, type TabProps, Table, type TableDensity, type TableProps, TableWrap, type TableWrapProps, Tabs, type TabsProps, Td, type TdProps, Textarea, type TextareaProps, Th, type ThProps, Timeline, TimelineItem, type TimelineItemProps, type TimelineProps, Toast, type ToastProps, type ToastTone, Toaster, type ToasterProps, Tooltip, type TooltipProps, Tr, type TrProps, Tree, type TreeLike, type TreeNavAction, type TreeNodeData, type TreeNodeProps, type TreeProps, type UseAnchoredPositionOptions, type UseTableOptions, type UseTableResult, UserChip, type UserChipProps, type ViewState, type VirtualWindow, applyFilters, clampWidth, computePosition, cx, flattenTree, highlightSegments, matchFilter, mergePinned, multiSort, nextSortDir, parseView, reorder, searchRows, selectAllState, serializeView, shouldVirtualize, toggleId, togglePage, toggleSort, treeNav, useAnchoredPosition, useDialog, useTable, virtualWindow };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,8 @@
1
1
  export { cx } from './cx.js';
2
2
  export { useDialog } from './hooks/useDialog.js';
3
+ export { UseTableOptions, UseTableResult, useTable } from './hooks/useTable.js';
4
+ export { UseAnchoredPositionOptions, useAnchoredPosition } from './hooks/useAnchoredPosition.js';
5
+ export { Align, Placement, PositionOptions, PositionResult, Rect, Side, Size, computePosition } from './overlay-position.js';
3
6
  export { Button, ButtonGroup, ButtonGroupProps, ButtonProps } from './components/Button.js';
4
7
  export { Input, InputGroup, InputGroupProps, InputProps } from './components/Input.js';
5
8
  export { Textarea, TextareaProps } from './components/Textarea.js';
@@ -17,14 +20,15 @@ export { DetailLayout, DetailLayoutProps } from './components/DetailLayout.js';
17
20
  export { List, ListItem, ListItemProps, ListProps } from './components/List.js';
18
21
  export { DescriptionItem, DescriptionItemProps, DescriptionList, DescriptionListItem, DescriptionListProps } from './components/DescriptionList.js';
19
22
  export { Tab, TabProps, Tabs, TabsProps } from './components/Tabs.js';
20
- export { AppShell, AppShellProps } from './components/AppShell.js';
23
+ export { AppShell, AppShellProps, ShellNav } from './components/AppShell.js';
21
24
  export { NavGroup, NavGroupProps, NavItem, NavItemProps, Sidebar, SidebarProps, SidebarSection, SidebarSectionProps, SubNavItem, SubNavItemProps } from './components/Sidebar.js';
22
25
  export { StarButton, StarButtonProps } from './components/StarButton.js';
23
26
  export { NavFavouriteItem, NavFavourites, NavFavouritesLabels, NavFavouritesProps } from './components/NavFavourites.js';
24
27
  export { Alert, AlertProps, AlertTone } from './components/Alert.js';
25
28
  export { Spinner, SpinnerProps } from './components/Spinner.js';
26
29
  export { Toast, ToastProps, ToastTone, Toaster, ToasterProps } from './components/Toast.js';
27
- export { SortDirection, Table, TableDensity, TableProps, TableWrap, TableWrapProps, Td, TdProps, Th, ThProps, Tr, TrProps } from './components/Table.js';
30
+ export { BulkBar, BulkBarProps, CellStrong, CellSub, ExpandToggle, ExpandToggleProps, Highlighted, HighlightedProps, Mark, MarkProps, RowAction, RowActionProps, RowActions, RowActionsProps, SortDirection, Table, TableDensity, TableProps, TableWrap, TableWrapProps, Td, TdProps, Th, ThProps, Tr, TrProps } from './components/Table.js';
31
+ export { ColumnFilter, FilterKind, FilterOp, Primitive, Row, Segment, SelectAllState, SortDir, SortKey, ViewState, VirtualWindow, applyFilters, clampWidth, highlightSegments, matchFilter, mergePinned, multiSort, nextSortDir, parseView, reorder, searchRows, selectAllState, serializeView, shouldVirtualize, toggleId, togglePage, toggleSort, virtualWindow } from './table-engine.js';
28
32
  export { Pagination, PaginationProps } from './components/Pagination.js';
29
33
  export { PillTone, PillTreatment, StatusPill, StatusPillProps } from './components/StatusPill.js';
30
34
  export { Progress, ProgressProps } from './components/Progress.js';
@@ -35,6 +39,8 @@ export { EmptyState, EmptyStateProps, ErrorState, ErrorStateProps, LoadingState,
35
39
  export { Label, LabelProps } from './components/Label.js';
36
40
  export { Avatar, AvatarGroup, AvatarGroupProps, AvatarProps, UserChip, UserChipProps } from './components/Avatar.js';
37
41
  export { Comment, CommentProps, Comments, CommentsProps } from './components/Comments.js';
42
+ export { Composer, ComposerBar, ComposerBarProps, ComposerProps } from './components/Composer.js';
43
+ export { Segmented, SegmentedOption, SegmentedOptionProps, SegmentedProps } from './components/Segmented.js';
38
44
  export { Timeline, TimelineItem, TimelineItemProps, TimelineProps } from './components/Timeline.js';
39
45
  export { Note, NoteProps, NoteTone, Prose, ProseProps } from './components/Prose.js';
40
46
  export { Popover, PopoverProps } from './components/Popover.js';
@@ -42,4 +48,5 @@ export { CommandGroup, CommandGroupProps, CommandItem, CommandItemProps, Command
42
48
  export { Inbox, InboxDetail, InboxDetailProps, InboxItem, InboxItemProps, InboxList, InboxListProps, InboxProps } from './components/Inbox.js';
43
49
  export { Kanban, KanbanCard, KanbanCardProps, KanbanColumn, KanbanColumnProps, KanbanProps } from './components/Kanban.js';
44
50
  export { Tree, TreeNodeData, TreeNodeProps, TreeProps } from './components/Tree.js';
51
+ export { FlatNode, TreeLike, TreeNavAction, flattenTree, treeNav } from './tree-model.js';
45
52
  import 'react';