@tensor_1/react 2.6.0 → 2.8.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,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { ButtonHTMLAttributes, ReactNode, InputHTMLAttributes, TextareaHTMLAttributes, SelectHTMLAttributes, CSSProperties, HTMLAttributes, AnchorHTMLAttributes, TdHTMLAttributes, TableHTMLAttributes, 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
 
@@ -140,6 +140,82 @@ interface UseTableResult<T> {
140
140
  */
141
141
  declare function useTable<T extends Row>(data: readonly T[], options?: UseTableOptions): UseTableResult<T>;
142
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
+
143
219
  interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
144
220
  variant?: 'primary' | 'secondary' | 'outline' | 'ghost' | 'danger' | 'link';
145
221
  size?: 'sm' | 'md' | 'lg';
@@ -654,16 +730,19 @@ interface StatProps extends HTMLAttributes<HTMLDivElement> {
654
730
  declare function Stat({ label, value, icon, meta, trend, className, ...props }: StatProps): react.JSX.Element;
655
731
 
656
732
  interface TooltipProps extends HTMLAttributes<HTMLSpanElement> {
657
- /** Tooltip text. Rendered via the CSS `[data-uix-tip]` hover/focus tooltip. */
733
+ /** Tooltip text. */
658
734
  label: string;
735
+ /** Preferred placement. Default `'top'`. */
736
+ placement?: Placement;
659
737
  children?: ReactNode;
660
738
  }
661
739
  /**
662
- * Thin wrapper over the CSS-only tooltip (`[data-uix-tip]`). Wraps its children
663
- * in a span carrying the attribute; the bubble is drawn entirely in CSS on
664
- * 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.
665
744
  */
666
- declare function Tooltip({ label, children, ...props }: TooltipProps): react.JSX.Element;
745
+ declare function Tooltip({ label, placement, className, children, ...props }: TooltipProps): react.JSX.Element;
667
746
 
668
747
  interface EmptyStateProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
669
748
  icon?: ReactNode;
@@ -832,13 +911,26 @@ interface PopoverProps extends HTMLAttributes<HTMLDivElement> {
832
911
  * wires to it via `popoverTarget={id}`. Pass `"manual"` to control open state yourself.
833
912
  */
834
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;
835
926
  children?: ReactNode;
836
927
  }
837
928
  /**
838
- * Anchored surface over `.uix-popover`, using the native Popover API.
839
- * 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).
840
932
  */
841
- 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;
842
934
 
843
935
  interface CommandPaletteProps extends HTMLAttributes<HTMLDivElement> {
844
936
  /** Props for the search input (value/onChange/placeholder wired by the consumer). */
@@ -924,8 +1016,11 @@ interface TreeNodeProps {
924
1016
  node: TreeNodeData;
925
1017
  expanded: Set<string>;
926
1018
  selected?: string;
1019
+ selectable: boolean;
1020
+ tabbableId?: string;
927
1021
  onToggle: (id: string) => void;
928
1022
  onSelect?: (id: string) => void;
1023
+ onFocusNode: (id: string) => void;
929
1024
  level?: number;
930
1025
  }
931
1026
  interface TreeProps extends Omit<HTMLAttributes<HTMLUListElement>, 'onSelect' | 'onChange'> {
@@ -935,7 +1030,244 @@ interface TreeProps extends Omit<HTMLAttributes<HTMLUListElement>, 'onSelect' |
935
1030
  selected?: string;
936
1031
  onToggle?: (id: string) => void;
937
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;
1044
+ }
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;
1093
+
1094
+ interface PageIntroProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1095
+ /** Small line above the title (e.g. today's date). */
1096
+ kicker?: ReactNode;
1097
+ title: ReactNode;
1098
+ /** Supporting copy under the title. */
1099
+ lede?: ReactNode;
1100
+ /** Label shown above the search well. */
1101
+ searchLabel?: ReactNode;
1102
+ /** The search well itself (form + `.uix-searchbar` markup, or `SearchBar`-style composition). */
1103
+ search?: ReactNode;
1104
+ /** Shortcut buttons; rendered inside the `.uix-shortcut-grid` full-width row. */
1105
+ shortcuts?: ReactNode;
1106
+ /** Accessible label for the shortcuts group. */
1107
+ shortcutsLabel?: string;
1108
+ }
1109
+ /**
1110
+ * Editorial page intro — kicker / title / lede beside a search well, with an
1111
+ * optional full-width shortcut grid underneath (`.uix-page-intro`).
1112
+ */
1113
+ declare function PageIntro({ kicker, title, lede, searchLabel, search, shortcuts, shortcutsLabel, className, children, ...props }: PageIntroProps): react.JSX.Element;
1114
+ interface SectionHeadProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
1115
+ title: ReactNode;
1116
+ /** id for the `<h2>`, for `aria-labelledby` wiring on the enclosing section. */
1117
+ titleId?: string;
1118
+ /** Right-aligned slot — a `.uix-section-link` anchor, a button, a pill. */
1119
+ action?: ReactNode;
1120
+ }
1121
+ /** Section head — title row with an optional trailing action (`.uix-section-head`). */
1122
+ declare function SectionHead({ title, titleId, action, className, ...props }: SectionHeadProps): react.JSX.Element;
1123
+ interface NoticeQueueProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1124
+ /** Leading icon slot. */
1125
+ icon?: ReactNode;
1126
+ /** Bolded lead-in of the notice copy. */
1127
+ title?: ReactNode;
1128
+ /** Rest of the notice copy, after the title. */
1129
+ summary?: ReactNode;
1130
+ /** Meta line under the copy (e.g. "Needs action · Required by Friday"). */
1131
+ meta?: ReactNode;
1132
+ /** Queue position (e.g. "1 of 4 important updates"). */
1133
+ position?: ReactNode;
1134
+ /**
1135
+ * Trailing controls — previous/next arrows (put `uix-notice__arrow--previous`
1136
+ * on the previous button to flip its icon), read/view-all buttons.
1137
+ */
1138
+ actions?: ReactNode;
1139
+ }
1140
+ /**
1141
+ * Notice queue — the rotating "important updates" banner (`.uix-notice`). The
1142
+ * copy region is `aria-live="polite"` so queue rotation is announced.
1143
+ */
1144
+ declare function NoticeQueue({ icon, title, summary, meta, position, actions, className, ...props }: NoticeQueueProps): react.JSX.Element;
1145
+ interface FeaturedStageProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1146
+ /** Decorative visual (story signal + diagram). Hidden from AT unless `visualLabel` is set. */
1147
+ visual?: ReactNode;
1148
+ /** Accessible description of the visual; when set the visual gets `role="img"`. */
1149
+ visualLabel?: string;
1150
+ /**
1151
+ * Ordinal of the story on stage (e.g. "01"), rendered as the filled
1152
+ * `.uix-featured__now` chip in the eyebrow. Pair it with the matching
1153
+ * `FeaturedRundownItem`'s `number` — the selected item's number renders as
1154
+ * the same chip, and that pairing is what links rundown to stage on every
1155
+ * breakpoint (the divider caret only exists while the zones sit side by side).
1156
+ */
1157
+ ordinal?: ReactNode;
1158
+ eyebrow?: ReactNode;
1159
+ title: ReactNode;
1160
+ /** id for the `<h2>` title, for `aria-labelledby` wiring. */
1161
+ titleId?: string;
1162
+ description?: ReactNode;
1163
+ meta?: ReactNode;
1164
+ /** Call-to-action slot under the meta line. */
1165
+ action?: ReactNode;
1166
+ }
1167
+ /**
1168
+ * Featured stage — the hero story zone of the featured briefing
1169
+ * (`.uix-featured__stage`). The briefing is ONE `.uix-featured` card: put this
1170
+ * and `FeaturedRundown` directly inside it and the internal hairline, the
1171
+ * selected item's caret, and the ordinal chips connect the two zones. Content
1172
+ * is `aria-live="polite"` so swapping the featured story (from the rundown)
1173
+ * is announced.
1174
+ */
1175
+ declare function FeaturedStage({ visual, visualLabel, ordinal, eyebrow, title, titleId, description, meta, action, className, ...props }: FeaturedStageProps): react.JSX.Element;
1176
+ interface FeaturedRundownProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1177
+ /** Uppercase line above the title (e.g. "Editorial briefing"). */
1178
+ eyebrow?: ReactNode;
1179
+ title: ReactNode;
1180
+ /** id for the `<h2>` title, for `aria-labelledby` wiring. */
1181
+ titleId?: string;
1182
+ /** Trailing head slot (e.g. a count pill). */
1183
+ meta?: ReactNode;
1184
+ /** `FeaturedRundownItem`s. */
1185
+ children?: ReactNode;
1186
+ }
1187
+ /**
1188
+ * Featured rundown — the story-list zone of the featured briefing
1189
+ * (`.uix-rundown`), sitting inside the single `.uix-featured` card beside (or,
1190
+ * stacked, below) the `FeaturedStage`.
1191
+ */
1192
+ declare function FeaturedRundown({ eyebrow, title, titleId, meta, children, className, ...props }: FeaturedRundownProps): react.JSX.Element;
1193
+ interface FeaturedRundownItemProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, 'title'> {
1194
+ /** Ordinal label (e.g. "01"). */
1195
+ number?: ReactNode;
1196
+ /** Topic/duration line above the item title (e.g. "Company · 5 min"). */
1197
+ topic?: ReactNode;
1198
+ /** The story title. */
1199
+ title: ReactNode;
1200
+ /** Whether this story is on the stage — sets `aria-pressed` + `data-selected`. */
1201
+ selected?: boolean;
1202
+ }
1203
+ /**
1204
+ * One rundown story — a toggle button (`.uix-rundown__item`) whose selection
1205
+ * is conveyed with `aria-pressed` and styled through `[data-selected]`.
1206
+ */
1207
+ declare function FeaturedRundownItem({ number, topic, title, selected, className, ...props }: FeaturedRundownItemProps): react.JSX.Element;
1208
+ interface NewsLeadProps extends Omit<HTMLAttributes<HTMLElement>, 'title'> {
1209
+ /** Meta line above the title (pill + date). */
1210
+ meta?: ReactNode;
1211
+ title: ReactNode;
1212
+ summary?: ReactNode;
1213
+ }
1214
+ /** News lead — the top story of a news column (`.uix-news-lead`). */
1215
+ declare function NewsLead({ meta, title, summary, className, ...props }: NewsLeadProps): react.JSX.Element;
1216
+ interface ContentListProps extends HTMLAttributes<HTMLUListElement> {
1217
+ /** `ContentListItem`s. */
1218
+ children?: ReactNode;
1219
+ }
1220
+ /** Content list — hairline-divided rows of titled items (`.uix-content-list`). */
1221
+ declare function ContentList({ children, className, ...props }: ContentListProps): react.JSX.Element;
1222
+ interface ContentListItemProps extends Omit<HTMLAttributes<HTMLLIElement>, 'title'> {
1223
+ title: ReactNode;
1224
+ meta?: ReactNode;
1225
+ /** Trailing slot — an arrow glyph, a pill. */
1226
+ trailing?: ReactNode;
1227
+ }
1228
+ /** One content-list row — title + meta with an optional trailing slot. */
1229
+ declare function ContentListItem({ title, meta, trailing, className, ...props }: ContentListItemProps): react.JSX.Element;
1230
+ interface ResourceGridProps extends HTMLAttributes<HTMLDivElement> {
1231
+ /** Resource buttons/links (typically `.uix-btn--outline`). */
1232
+ children?: ReactNode;
1233
+ }
1234
+ /** Resource grid — a three-up grid of resource shortcuts (`.uix-resource-grid`). */
1235
+ declare function ResourceGrid({ children, className, ...props }: ResourceGridProps): react.JSX.Element;
1236
+ interface StatLineItem {
1237
+ /** Stable identity for the item; falls back to the index when omitted. */
1238
+ id?: string;
1239
+ value: ReactNode;
1240
+ label: ReactNode;
1241
+ }
1242
+ interface StatLineProps extends HTMLAttributes<HTMLDivElement> {
1243
+ items?: StatLineItem[];
1244
+ children?: ReactNode;
1245
+ }
1246
+ /**
1247
+ * Stat line — a compact value/label summary strip over a hairline
1248
+ * (`.uix-stat-line`). Use `items` for data-driven stats or hand-author
1249
+ * `.uix-stat-line__item` children.
1250
+ */
1251
+ declare function StatLine({ items, children, className, ...props }: StatLineProps): react.JSX.Element;
1252
+ interface EventRowProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
1253
+ /** Calendar-block month (e.g. "Jul"). */
1254
+ month: ReactNode;
1255
+ /** Calendar-block day (e.g. "30"). */
1256
+ day: ReactNode;
1257
+ title: ReactNode;
1258
+ meta?: ReactNode;
1259
+ }
1260
+ /** Event row — date block + title/meta (`.uix-event-row`). */
1261
+ declare function EventRow({ month, day, title, meta, className, ...props }: EventRowProps): react.JSX.Element;
1262
+ interface StatusRowProps extends HTMLAttributes<HTMLDivElement> {
1263
+ /** Leading indicator slot (e.g. a `.uix-dot`). */
1264
+ indicator?: ReactNode;
1265
+ /** Service name — takes the flexible middle (`.uix-status-row__name`). */
1266
+ name: ReactNode;
1267
+ /** Trailing meta (e.g. "Healthy"), rendered as `.uix-list-meta`. */
1268
+ meta?: ReactNode;
938
1269
  }
939
- declare function Tree({ nodes, expanded: controlledExpanded, defaultExpanded, selected, onToggle, onSelect, className, ...props }: TreeProps): react.JSX.Element;
1270
+ /** Status row — indicator + name + trailing meta (`.uix-status-row`). */
1271
+ declare function StatusRow({ indicator, name, meta, className, ...props }: StatusRowProps): react.JSX.Element;
940
1272
 
941
- export { Alert, type AlertProps, type AlertTone, 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, 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, Popover, type PopoverProps, type Primitive, Progress, type ProgressProps, Prose, type ProseProps, Radio, RadioGroup, type RadioGroupProps, type RadioProps, type Row, RowAction, type RowActionProps, RowActions, type RowActionsProps, type Segment, Segmented, SegmentedOption, type SegmentedOptionProps, type SegmentedProps, Select, type SelectAllState, type SelectProps, type ShellNav, Sidebar, type SidebarProps, SidebarSection, type SidebarSectionProps, 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 TreeNodeData, type TreeNodeProps, type TreeProps, type UseTableOptions, type UseTableResult, UserChip, type UserChipProps, type ViewState, type VirtualWindow, applyFilters, clampWidth, cx, highlightSegments, matchFilter, mergePinned, multiSort, nextSortDir, parseView, reorder, searchRows, selectAllState, serializeView, shouldVirtualize, toggleId, togglePage, toggleSort, useDialog, useTable, virtualWindow };
1273
+ 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, ContentList, ContentListItem, type ContentListItemProps, type ContentListProps, DescriptionItem, type DescriptionItemProps, DescriptionList, type DescriptionListItem, type DescriptionListProps, DetailLayout, type DetailLayoutProps, Drawer, type DrawerProps, EmptyState, type EmptyStateProps, ErrorState, type ErrorStateProps, EventRow, type EventRowProps, ExpandToggle, type ExpandToggleProps, FeaturedRundown, FeaturedRundownItem, type FeaturedRundownItemProps, type FeaturedRundownProps, FeaturedStage, type FeaturedStageProps, 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, NewsLead, type NewsLeadProps, Note, type NoteProps, type NoteTone, NoticeQueue, type NoticeQueueProps, PageHeader, type PageHeaderProps, PageIntro, type PageIntroProps, 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, ResourceGrid, type ResourceGridProps, type Row, RowAction, type RowActionProps, RowActions, type RowActionsProps, SectionHead, type SectionHeadProps, 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, StatLine, type StatLineItem, type StatLineProps, type StatProps, type StatTrend, StatusPill, type StatusPillProps, StatusRow, type StatusRowProps, 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,6 +1,8 @@
1
1
  export { cx } from './cx.js';
2
2
  export { useDialog } from './hooks/useDialog.js';
3
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';
4
6
  export { Button, ButtonGroup, ButtonGroupProps, ButtonProps } from './components/Button.js';
5
7
  export { Input, InputGroup, InputGroupProps, InputProps } from './components/Input.js';
6
8
  export { Textarea, TextareaProps } from './components/Textarea.js';
@@ -46,4 +48,6 @@ export { CommandGroup, CommandGroupProps, CommandItem, CommandItemProps, Command
46
48
  export { Inbox, InboxDetail, InboxDetailProps, InboxItem, InboxItemProps, InboxList, InboxListProps, InboxProps } from './components/Inbox.js';
47
49
  export { Kanban, KanbanCard, KanbanCardProps, KanbanColumn, KanbanColumnProps, KanbanProps } from './components/Kanban.js';
48
50
  export { Tree, TreeNodeData, TreeNodeProps, TreeProps } from './components/Tree.js';
51
+ export { FlatNode, TreeLike, TreeNavAction, flattenTree, treeNav } from './tree-model.js';
52
+ export { ContentList, ContentListItem, ContentListItemProps, ContentListProps, EventRow, EventRowProps, FeaturedRundown, FeaturedRundownItem, FeaturedRundownItemProps, FeaturedRundownProps, FeaturedStage, FeaturedStageProps, NewsLead, NewsLeadProps, NoticeQueue, NoticeQueueProps, PageIntro, PageIntroProps, ResourceGrid, ResourceGridProps, SectionHead, SectionHeadProps, StatLine, StatLineItem, StatLineProps, StatusRow, StatusRowProps } from './components/EditorialHome.js';
49
53
  import 'react';
package/dist/index.js CHANGED
@@ -1,6 +1,8 @@
1
1
  import { cx } from "./cx.js";
2
2
  import { useDialog } from "./hooks/useDialog.js";
3
3
  import { useTable } from "./hooks/useTable.js";
4
+ import { useAnchoredPosition } from "./hooks/useAnchoredPosition.js";
5
+ import { computePosition } from "./overlay-position.js";
4
6
  import { Button, ButtonGroup } from "./components/Button.js";
5
7
  import { Input, InputGroup } from "./components/Input.js";
6
8
  import { Textarea } from "./components/Textarea.js";
@@ -60,6 +62,22 @@ import { CommandPalette, CommandGroup, CommandItem } from "./components/CommandP
60
62
  import { Inbox, InboxList, InboxItem, InboxDetail } from "./components/Inbox.js";
61
63
  import { Kanban, KanbanColumn, KanbanCard } from "./components/Kanban.js";
62
64
  import { Tree } from "./components/Tree.js";
65
+ import { flattenTree, treeNav } from "./tree-model.js";
66
+ import {
67
+ PageIntro,
68
+ SectionHead,
69
+ NoticeQueue,
70
+ FeaturedStage,
71
+ FeaturedRundown,
72
+ FeaturedRundownItem,
73
+ NewsLead,
74
+ ContentList,
75
+ ContentListItem,
76
+ ResourceGrid,
77
+ StatLine,
78
+ EventRow,
79
+ StatusRow
80
+ } from "./components/EditorialHome.js";
63
81
  export {
64
82
  Alert,
65
83
  AppShell,
@@ -79,13 +97,19 @@ export {
79
97
  Comments,
80
98
  Composer,
81
99
  ComposerBar,
100
+ ContentList,
101
+ ContentListItem,
82
102
  DescriptionItem,
83
103
  DescriptionList,
84
104
  DetailLayout,
85
105
  Drawer,
86
106
  EmptyState,
87
107
  ErrorState,
108
+ EventRow,
88
109
  ExpandToggle,
110
+ FeaturedRundown,
111
+ FeaturedRundownItem,
112
+ FeaturedStage,
89
113
  Field,
90
114
  Highlighted,
91
115
  Inbox,
@@ -107,8 +131,11 @@ export {
107
131
  NavFavourites,
108
132
  NavGroup,
109
133
  NavItem,
134
+ NewsLead,
110
135
  Note,
136
+ NoticeQueue,
111
137
  PageHeader,
138
+ PageIntro,
112
139
  Pagination,
113
140
  Peek,
114
141
  Popover,
@@ -116,8 +143,10 @@ export {
116
143
  Prose,
117
144
  Radio,
118
145
  RadioGroup,
146
+ ResourceGrid,
119
147
  RowAction,
120
148
  RowActions,
149
+ SectionHead,
121
150
  Segmented,
122
151
  SegmentedOption,
123
152
  Select,
@@ -127,7 +156,9 @@ export {
127
156
  Spinner,
128
157
  StarButton,
129
158
  Stat,
159
+ StatLine,
130
160
  StatusPill,
161
+ StatusRow,
131
162
  SubNavItem,
132
163
  Switch,
133
164
  Tab,
@@ -145,7 +176,11 @@ export {
145
176
  Tr,
146
177
  Tree,
147
178
  UserChip,
179
+ computePosition,
148
180
  cx,
181
+ flattenTree,
182
+ treeNav,
183
+ useAnchoredPosition,
149
184
  useDialog,
150
185
  useTable
151
186
  };
@@ -0,0 +1,59 @@
1
+ /**
2
+ * uix overlay positioning — framework-agnostic, dependency-free anchored placement.
3
+ *
4
+ * Pure geometry (no DOM): given the anchor's rect, the floating element's size, and
5
+ * the viewport, compute where to put the floating element with two behaviours:
6
+ * • flip — if the preferred side doesn't fit, use the opposite side (or whichever
7
+ * side has more room);
8
+ * • shift — slide along the cross axis so the element stays within the viewport.
9
+ *
10
+ * The React hook (useAnchoredPosition) and the vanilla styleguide both feed this
11
+ * getBoundingClientRect() values, so anchored overlays land in the same place in every
12
+ * browser — instead of relying on CSS anchor() positioning, which is Chromium-only and
13
+ * silently detaches the overlay from its trigger everywhere else (UIX-FIX-02).
14
+ *
15
+ * Everything here is deterministic and unit-tested (see overlay-position.test.mjs).
16
+ */
17
+ type Side = 'top' | 'bottom' | 'left' | 'right';
18
+ type Align = 'start' | 'center' | 'end';
19
+ type Placement = Side | `${Side}-${Align}`;
20
+ /** A viewport-space rectangle, as returned by getBoundingClientRect(). */
21
+ interface Rect {
22
+ x: number;
23
+ y: number;
24
+ width: number;
25
+ height: number;
26
+ }
27
+ interface Size {
28
+ width: number;
29
+ height: number;
30
+ }
31
+ interface PositionOptions {
32
+ /** Preferred placement. Default `'bottom-start'`; a bare side (e.g. `'top'`) centers on the cross axis. */
33
+ placement?: Placement;
34
+ /** Gap between the anchor and the floating element, in px. Default 6. */
35
+ offset?: number;
36
+ /** Minimum gap kept from each viewport edge when shifting, in px. Default 8. */
37
+ padding?: number;
38
+ /** Flip to the opposite side when the preferred one doesn't fit. Default true. */
39
+ flip?: boolean;
40
+ /** Slide along the cross axis to stay on-screen. Default true. */
41
+ shift?: boolean;
42
+ }
43
+ interface PositionResult {
44
+ /** Viewport-space left, for `position: fixed`. */
45
+ x: number;
46
+ /** Viewport-space top, for `position: fixed`. */
47
+ y: number;
48
+ /** The placement actually used (after any flip). */
49
+ placement: Placement;
50
+ side: Side;
51
+ align: Align;
52
+ }
53
+ /**
54
+ * Compute the floating element's viewport-space position anchored to `anchor`.
55
+ * Coordinates are for `position: fixed` (same space as getBoundingClientRect).
56
+ */
57
+ declare function computePosition(anchor: Rect, floating: Size, viewport: Size, options?: PositionOptions): PositionResult;
58
+
59
+ export { type Align, type Placement, type PositionOptions, type PositionResult, type Rect, type Side, type Size, computePosition };
@@ -0,0 +1,62 @@
1
+ const OPPOSITE = { top: "bottom", bottom: "top", left: "right", right: "left" };
2
+ function parsePlacement(p) {
3
+ const [side, align] = p.split("-");
4
+ return { side, align: align ?? "center" };
5
+ }
6
+ const clamp = (v, min, max) => Math.max(min, Math.min(max, v));
7
+ function spaceOn(side, a, vp, offset) {
8
+ switch (side) {
9
+ case "top":
10
+ return a.y - offset;
11
+ case "bottom":
12
+ return vp.height - (a.y + a.height) - offset;
13
+ case "left":
14
+ return a.x - offset;
15
+ case "right":
16
+ return vp.width - (a.x + a.width) - offset;
17
+ }
18
+ }
19
+ function fitsOn(side, a, f, vp, offset, padding) {
20
+ const need = side === "top" || side === "bottom" ? f.height : f.width;
21
+ return spaceOn(side, a, vp, offset) >= need + padding;
22
+ }
23
+ function computePosition(anchor, floating, viewport, options = {}) {
24
+ const { placement = "bottom-start", offset = 6, padding = 8, flip = true, shift = true } = options;
25
+ const { side: preferred, align } = parsePlacement(placement);
26
+ let side = preferred;
27
+ if (flip && !fitsOn(side, anchor, floating, viewport, offset, padding)) {
28
+ const opp = OPPOSITE[side];
29
+ if (fitsOn(opp, anchor, floating, viewport, offset, padding) || spaceOn(opp, anchor, viewport, offset) > spaceOn(side, anchor, viewport, offset)) {
30
+ side = opp;
31
+ }
32
+ }
33
+ let x, y;
34
+ const horizontal = side === "top" || side === "bottom";
35
+ if (side === "top") y = anchor.y - floating.height - offset;
36
+ else if (side === "bottom") y = anchor.y + anchor.height + offset;
37
+ else if (side === "left") x = anchor.x - floating.width - offset;
38
+ else x = anchor.x + anchor.width + offset;
39
+ if (horizontal) {
40
+ const start = anchor.x;
41
+ const end = anchor.x + anchor.width - floating.width;
42
+ const center = anchor.x + (anchor.width - floating.width) / 2;
43
+ x = align === "start" ? start : align === "end" ? end : center;
44
+ if (shift) x = clamp(x, padding, Math.max(padding, viewport.width - floating.width - padding));
45
+ } else {
46
+ const start = anchor.y;
47
+ const end = anchor.y + anchor.height - floating.height;
48
+ const center = anchor.y + (anchor.height - floating.height) / 2;
49
+ y = align === "start" ? start : align === "end" ? end : center;
50
+ if (shift) y = clamp(y, padding, Math.max(padding, viewport.height - floating.height - padding));
51
+ }
52
+ return {
53
+ x,
54
+ y,
55
+ placement: align === "center" ? side : `${side}-${align}`,
56
+ side,
57
+ align
58
+ };
59
+ }
60
+ export {
61
+ computePosition
62
+ };