@sesamehr/react-design-system 2.0.0-beta.1 → 2.0.0-beta.11

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 (132) hide show
  1. package/README.md +34 -0
  2. package/dist/Button/ActionItem/ActionItem.d.ts +40 -0
  3. package/dist/Button/ActionItem/index.d.ts +1 -0
  4. package/dist/Button/IconButton/IconButton.d.ts +32 -0
  5. package/dist/Button/IconButton/index.d.ts +27 -0
  6. package/dist/Data/Table/Table.d.ts +1 -1
  7. package/dist/Data/Table/TableBody/TableBody.d.ts +3 -0
  8. package/dist/Data/Table/TableHead/TableHead.d.ts +25 -1
  9. package/dist/Data/Table/TableScrollbar/TableScrollbar.d.ts +21 -0
  10. package/dist/Data/Table/TableSelectCell/TableSelectCell.d.ts +8 -0
  11. package/dist/Data/Table/TableVirtualized/TableVirtualized.d.ts +45 -0
  12. package/dist/Data/Table/TableVirtualized/index.d.ts +2 -0
  13. package/dist/Data/Table/hooks/index.d.ts +3 -0
  14. package/dist/Data/Table/hooks/useDragToScroll/useDragToScroll.d.ts +12 -2
  15. package/dist/Data/Table/hooks/useTableVirtual/context.d.ts +16 -0
  16. package/dist/Data/Table/hooks/useTableVirtual/index.d.ts +3 -0
  17. package/dist/Data/Table/hooks/useTableVirtual/useTableVirtual.d.ts +36 -0
  18. package/dist/Data/Table/hooks/useTableVirtual/useTableVirtual.types.d.ts +74 -0
  19. package/dist/Data/Table/index.d.ts +2 -2
  20. package/dist/Display/Avatar/AvatarSkeleton/AvatarSkeleton.d.ts +30 -0
  21. package/dist/Display/Avatar/index.d.ts +2 -0
  22. package/dist/Display/AvatarDetails/AvatarDetails.d.ts +68 -0
  23. package/dist/Display/AvatarDetails/index.d.ts +1 -0
  24. package/dist/Display/Badge/Badge.d.ts +3 -2
  25. package/dist/Display/Badge/index.d.ts +10 -1
  26. package/dist/Display/ChatBubble/ChatBubble.d.ts +28 -0
  27. package/dist/Display/ChatBubble/ChatBubbleStatus/ChatBubbleStatus.d.ts +8 -0
  28. package/dist/Display/ChatBubble/ChatBubbleStatus/index.d.ts +10 -0
  29. package/dist/Display/ChatBubble/index.d.ts +44 -0
  30. package/dist/Display/Chip/Chip.d.ts +21 -5
  31. package/dist/Display/Chip/index.d.ts +19 -10
  32. package/dist/Display/FileCard/FileCard.d.ts +66 -0
  33. package/dist/Display/FileCard/index.d.ts +1 -0
  34. package/dist/Display/FilePreviewCard/FilePreviewCard.d.ts +49 -0
  35. package/dist/Display/FilePreviewCard/index.d.ts +1 -0
  36. package/dist/Feedback/Alert/AlertIcon.d.ts +1 -1
  37. package/dist/Feedback/Dialog/DialogBody.d.ts +18 -0
  38. package/dist/Feedback/Dialog/index.d.ts +1 -0
  39. package/dist/Feedback/Loader/Loader.d.ts +16 -0
  40. package/dist/Feedback/Loader/index.d.ts +2 -0
  41. package/dist/Feedback/Popover/PopoverContent.d.ts +0 -1
  42. package/dist/Feedback/Progress/Progress.d.ts +3 -0
  43. package/dist/Feedback/Progress/index.d.ts +17 -0
  44. package/dist/Feedback/Skeleton/Skeleton.d.ts +20 -0
  45. package/dist/Feedback/Skeleton/index.d.ts +2 -0
  46. package/dist/Feedback/Tooltip/TooltipContent.d.ts +0 -1
  47. package/dist/Forms/Field/Counter/Counter.d.ts +9 -0
  48. package/dist/Forms/Field/Counter/index.d.ts +13 -0
  49. package/dist/Forms/Field/FieldGroup/FieldGroup.d.ts +16 -1
  50. package/dist/Forms/Field/FieldLabel/FieldLabel.d.ts +16 -0
  51. package/dist/Forms/Field/FieldMessage/FieldMessage.d.ts +22 -2
  52. package/dist/Forms/Field/index.d.ts +1 -0
  53. package/dist/Forms/Field/useFieldGroup.d.ts +108 -0
  54. package/dist/Forms/Inputs/Calendar/Calendar.d.ts +55 -0
  55. package/dist/Forms/Inputs/Calendar/CalendarDay.d.ts +37 -0
  56. package/dist/Forms/Inputs/Calendar/CalendarRange.d.ts +56 -0
  57. package/dist/Forms/Inputs/Calendar/constraints.d.ts +19 -0
  58. package/dist/Forms/Inputs/Calendar/date.d.ts +28 -0
  59. package/dist/Forms/Inputs/Calendar/index.d.ts +21 -0
  60. package/dist/Forms/Inputs/Calendar/nav.d.ts +34 -0
  61. package/dist/Forms/Inputs/Calendar/testids.d.ts +28 -0
  62. package/dist/Forms/Inputs/Calendar/useCalendarLocale.d.ts +40 -0
  63. package/dist/Forms/Inputs/ChatInput/ChatInput.d.ts +68 -0
  64. package/dist/Forms/Inputs/ChatInput/index.d.ts +46 -0
  65. package/dist/Forms/Inputs/Combobox/ComboboxCancel.d.ts +14 -0
  66. package/dist/Forms/Inputs/Combobox/ComboboxChipsInput.d.ts +4 -0
  67. package/dist/Forms/Inputs/Combobox/ComboboxContent.d.ts +0 -6
  68. package/dist/Forms/Inputs/Combobox/ComboboxGroup.d.ts +6 -2
  69. package/dist/Forms/Inputs/Combobox/ComboboxInput.d.ts +6 -1
  70. package/dist/Forms/Inputs/Combobox/ComboboxItem.d.ts +4 -0
  71. package/dist/Forms/Inputs/Combobox/ComboboxItemEdit.d.ts +124 -0
  72. package/dist/Forms/Inputs/Combobox/context.d.ts +15 -1
  73. package/dist/Forms/Inputs/Combobox/index.d.ts +2 -0
  74. package/dist/Forms/Inputs/Combobox/useChipOverflow.d.ts +30 -0
  75. package/dist/Forms/Inputs/Combobox/useComboboxEditing.d.ts +40 -0
  76. package/dist/Forms/Inputs/Combobox/useComboboxLabels.d.ts +21 -0
  77. package/dist/Forms/Inputs/DatePicker/DatePicker.d.ts +51 -0
  78. package/dist/Forms/Inputs/DatePicker/DatePickerHeader.d.ts +65 -0
  79. package/dist/Forms/Inputs/DatePicker/DatePickerMonthSelect.d.ts +27 -0
  80. package/dist/Forms/Inputs/DatePicker/DatePickerTrigger.d.ts +29 -0
  81. package/dist/Forms/Inputs/DatePicker/DatePickerYearSelect.d.ts +25 -0
  82. package/dist/Forms/Inputs/DatePicker/DateRangePicker.d.ts +61 -0
  83. package/dist/Forms/Inputs/DatePicker/format.d.ts +44 -0
  84. package/dist/Forms/Inputs/DatePicker/index.d.ts +6 -0
  85. package/dist/Forms/Inputs/DatePicker/month.d.ts +28 -0
  86. package/dist/Forms/Inputs/DatePicker/useDatePickerHeader.d.ts +23 -0
  87. package/dist/Forms/Inputs/InputOtp/InputOtp.d.ts +7 -0
  88. package/dist/Forms/Inputs/InputPassword/InputPassword.d.ts +9 -1
  89. package/dist/Forms/Inputs/InputText/InputText.d.ts +9 -0
  90. package/dist/Forms/Inputs/SearchBar/SearchBar.d.ts +35 -0
  91. package/dist/Forms/Inputs/SearchBar/index.d.ts +22 -0
  92. package/dist/Forms/Inputs/SearchBar/useSearchDelay.d.ts +24 -0
  93. package/dist/Forms/Inputs/SearchPanel/SearchPanel.d.ts +71 -0
  94. package/dist/Forms/Inputs/SearchPanel/SearchPanelEmpty.d.ts +16 -0
  95. package/dist/Forms/Inputs/SearchPanel/SearchPanelGroup.d.ts +14 -0
  96. package/dist/Forms/Inputs/SearchPanel/SearchPanelInput.d.ts +31 -0
  97. package/dist/Forms/Inputs/SearchPanel/SearchPanelItem.d.ts +20 -0
  98. package/dist/Forms/Inputs/SearchPanel/SearchPanelList.d.ts +11 -0
  99. package/dist/Forms/Inputs/SearchPanel/context.d.ts +11 -0
  100. package/dist/Forms/Inputs/SearchPanel/index.d.ts +6 -0
  101. package/dist/Forms/Inputs/Select/SelectContent.d.ts +0 -4
  102. package/dist/Forms/Inputs/Select/SelectGroup.d.ts +6 -2
  103. package/dist/Forms/Inputs/Select/SelectItem.d.ts +6 -0
  104. package/dist/Forms/Inputs/Textarea/Textarea.d.ts +69 -0
  105. package/dist/Forms/Inputs/Textarea/index.d.ts +21 -0
  106. package/dist/Forms/Inputs/Toggle/RadioButton/RadioGroup.d.ts +5 -0
  107. package/dist/Forms/Inputs/Toggle/ToggleLabel/ToggleLabel.d.ts +10 -1
  108. package/dist/Forms/Inputs/index.d.ts +6 -0
  109. package/dist/Layout/Scrollbar/Scrollbar.d.ts +46 -0
  110. package/dist/Layout/Scrollbar/index.d.ts +2 -0
  111. package/dist/Layout/Scrollbar/useScrollbar.d.ts +52 -0
  112. package/dist/hooks/index.d.ts +12 -0
  113. package/dist/hooks/useAutoGrow.d.ts +22 -0
  114. package/dist/internal/Listbox/ListboxEmpty.d.ts +3 -0
  115. package/dist/internal/Listbox/ListboxItem.d.ts +23 -0
  116. package/dist/internal/Listbox/ListboxLabel.d.ts +9 -0
  117. package/dist/internal/Listbox/ListboxSeparator.d.ts +3 -0
  118. package/dist/internal/Listbox/ListboxViewport.d.ts +9 -0
  119. package/dist/internal/Surface/Surface.d.ts +35 -0
  120. package/dist/internal/index.d.ts +13 -0
  121. package/dist/lib/cssModules.d.ts +13 -0
  122. package/dist/main.d.ts +18 -7
  123. package/dist/preflight.css +391 -0
  124. package/dist/react-design-system.css +1 -1
  125. package/dist/react-design-system.js +17345 -10589
  126. package/dist/react-design-system.umd.cjs +164 -117
  127. package/package.json +4 -2
  128. package/src/assets/styles/theme-v2.css +6 -6
  129. package/src/assets/styles/theme-v3.css +7 -4
  130. package/dist/Data/Table/TableAvatar/TableAvatar.d.ts +0 -14
  131. package/dist/Display/Tag/Tag.d.ts +0 -19
  132. package/dist/Display/Tag/index.d.ts +0 -2
package/README.md CHANGED
@@ -18,6 +18,10 @@ Import the stylesheet once at your app entry:
18
18
  import '@sesamehr/react-design-system/style.css';
19
19
  ```
20
20
 
21
+ That stylesheet paints this package's components and nothing else. It carries no
22
+ reset and no utility classes, so importing it cannot restyle the application
23
+ around it — see [What the stylesheet does not do](#what-the-stylesheet-does-not-do).
24
+
21
25
  Every component is exported with the `Ox` prefix:
22
26
 
23
27
  ```tsx
@@ -64,6 +68,36 @@ from your own Tailwind setup:
64
68
  @import '@sesamehr/react-design-system/assets/styles/mainTheme.css';
65
69
  ```
66
70
 
71
+ ### What the stylesheet does not do
72
+
73
+ `style.css` contains this package's component rules and its tokens. It
74
+ deliberately does **not** contain:
75
+
76
+ - **Preflight**, or any other global reset. The components assume one — they are
77
+ written against `box-sizing: border-box`, `button { font: inherit }` and the
78
+ rest — but installing it is the application's call, not a library's. If your
79
+ app has Tailwind, you already have it. If it does not:
80
+
81
+ ```ts
82
+ import '@sesamehr/react-design-system/preflight.css';
83
+ ```
84
+
85
+ - **Utility classes.** No `.h-10`, no `.p-4`, no `.bg-brand`. Every component
86
+ carries its own `ox`-prefixed class and the declarations are compiled into it,
87
+ so nothing here can collide with the identically-named utilities your own
88
+ Tailwind build emits from your scale.
89
+
90
+ Component rules ship inside `@layer components`, which is where a Tailwind app
91
+ already sorts them: after `base`, before `utilities`. So a utility you pass in
92
+ wins — `<Button className="w-full">` is full width — without needing
93
+ `!important`.
94
+
95
+ Tokens are published under an `--ox-` prefix: override `--ox-color-brand-500`
96
+ to retheme, not `--color-brand-500`. Unprefixed, those are the names Tailwind
97
+ itself uses, and declaring them at `:root` would change what every `rounded-2xl`
98
+ in your application means.
99
+
100
+
67
101
  ## License
68
102
 
69
103
  MIT © Sesame HR
@@ -0,0 +1,40 @@
1
+ export interface ActionItemProps extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, 'type'> {
2
+ /**
3
+ * The chevron at the end. On by default: the row is drawn with one, and a
4
+ * row without it is the exception.
5
+ *
6
+ * A boolean is configuration, which the architecture rules push back on, and
7
+ * it earns the exception the same way `OxPopoverContent`'s `showArrow` does.
8
+ * The alternative is a slot prop with no default, which would make every call
9
+ * site write the chevron out — the common case paying for the rare one, and
10
+ * two call sites free to reach for a different glyph.
11
+ */
12
+ showChevron?: boolean;
13
+ dataTestid: string;
14
+ }
15
+ /**
16
+ * ActionItem — mirrors `@sesame/orxata-core` ActionItem.
17
+ *
18
+ * A full-width row that runs an action when pressed: a label that takes the
19
+ * width, and a chevron at the end saying there is something on the other side
20
+ * of the press.
21
+ *
22
+ * Not a `Button` variant, and not for the reason `IconButton` is not one —
23
+ * that one wears `.ox-button` for its colours and only redraws the box. This
24
+ * shares nothing with `Button`: the box is a block that fills its parent and
25
+ * grows with a label that wraps, where every `Button` is an inline-flex of a
26
+ * fixed height with `whitespace-nowrap`, and the fill is `brand-50` behind
27
+ * `brand-500` text, which is none of `Button`'s seven colours.
28
+ *
29
+ * **No `asChild`, and that is not an omission.** Both primitives' pass-through
30
+ * root is built for a component whose entire content is the caller's slot —
31
+ * `Button` and `Chip` are exactly that. This one owns the chevron, and that
32
+ * breaks both: Radix's `Slot` throws ("Expected a single React element child
33
+ * or `Slottable`"), and while `Slottable` answers that here, reka's `Slot` on
34
+ * the Vue side has no equivalent — it merges onto the first child of the
35
+ * component's own slot and leaves the chevron as a sibling of the caller's
36
+ * element. The two sides could not have been made to agree, and a prop that
37
+ * works on one and silently mis-renders on the other is worse than no prop.
38
+ * A row that navigates is an `onClick` and a `router.push`.
39
+ */
40
+ export declare const ActionItem: import('react').ForwardRefExoticComponent<ActionItemProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1 @@
1
+ export { ActionItem, type ActionItemProps } from './ActionItem.tsx';
@@ -0,0 +1,32 @@
1
+ import { ButtonVariants } from '../index.ts';
2
+ import { IconButtonVariants } from './index.ts';
3
+ export interface IconButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
4
+ /**
5
+ * `Button`'s colours, by its own words — the design file calls the filled
6
+ * one `primary`, but `Button` has called it `default` since it shipped and a
7
+ * caller swapping one for the other should not relearn the one word that
8
+ * differs. No `link`: the design has no such icon button, and a link with no
9
+ * text has no accessible name by construction.
10
+ */
11
+ variant?: Exclude<ButtonVariants['variant'], 'link'>;
12
+ size?: IconButtonVariants['size'];
13
+ /**
14
+ * What a screen reader announces. Required — it narrows the optional
15
+ * `aria-label` this inherits from `ButtonHTMLAttributes` — because the glyph
16
+ * is the whole control, so there is no text for the browser to fall back to
17
+ * and an unlabelled one announces as "button" and nothing else. No default
18
+ * can describe what an icon a caller chose is for, so there is not one.
19
+ */
20
+ 'aria-label': string;
21
+ /** Render as the child element instead of a `<button>` (Radix Slot). */
22
+ asChild?: boolean;
23
+ }
24
+ /**
25
+ * IconButton — mirrors `@sesame/orxata-core` IconButton.
26
+ *
27
+ * A button whose entire content is an icon, circular at every size. The icon
28
+ * comes from the caller as `children`; this sizes it and never picks it.
29
+ * `asChild` renders the child element instead of a `<button>`, via
30
+ * `@radix-ui/react-slot`.
31
+ */
32
+ export declare const IconButton: import('react').ForwardRefExoticComponent<IconButtonProps & import('react').RefAttributes<HTMLButtonElement>>;
@@ -0,0 +1,27 @@
1
+ import { VariantProps } from 'class-variance-authority';
2
+ export { IconButton, type IconButtonProps } from './IconButton.tsx';
3
+ /**
4
+ * The shape half only — the radius and the four square boxes. That is all this
5
+ * component adds.
6
+ *
7
+ * The colours are `Button`'s, and not a copy of them: `IconButton.tsx` calls
8
+ * `buttonVariants` for the variant and this for the size, so the six colour
9
+ * rules live in one file and a token changes in one place. Use both together if
10
+ * you are putting the classes on your own element:
11
+ *
12
+ * ```ts
13
+ * cn(buttonVariants({ variant, size: null }), iconButtonVariants({ size }))
14
+ * ```
15
+ *
16
+ * `size: null` is cva's opt-out, and it is load-bearing: `buttonVariants`
17
+ * defaults to `md`, which would bring `px-5`, `h-12` and `rounded-2xl` along
18
+ * and stop the box being a square circle.
19
+ *
20
+ * Class names, not utilities — see the long note in `../index.ts` for why a
21
+ * utility in a variant forces the package to publish `.size-12` into the
22
+ * consumer's cascade.
23
+ */
24
+ export declare const iconButtonVariants: (props?: ({
25
+ size?: "xs" | "sm" | "md" | "lg" | null | undefined;
26
+ } & import('class-variance-authority/types').ClassProp) | undefined) => string;
27
+ export type IconButtonVariants = VariantProps<typeof iconButtonVariants>;
@@ -37,7 +37,7 @@ export interface TableComponentProps<TData = unknown> {
37
37
  /** Center table content (default slot) — custom mode only. */
38
38
  children?: ReactNode;
39
39
  }
40
- export declare function Table<TData = unknown>({ enableDragToScroll, table, renderCell, renderHeader, detailRow: detailRowSlot, bulkHeader, bulkActions, pagination, empty, fixedLeft, fixedRight, children, }: TableComponentProps<TData>): import("react/jsx-runtime").JSX.Element;
40
+ export declare function Table<TData = unknown>({ loading, enableDragToScroll, table, renderCell, renderHeader, detailRow: detailRowSlot, bulkHeader, bulkActions, pagination, empty, fixedLeft, fixedRight, children, }: TableComponentProps<TData>): import("react/jsx-runtime").JSX.Element;
41
41
  export declare namespace Table {
42
42
  var displayName: string;
43
43
  }
@@ -16,5 +16,8 @@ export interface TableBodyProps extends React.ComponentPropsWithoutRef<'tbody'>
16
16
  /**
17
17
  * Styled `<tbody>`. When `draggable`, wraps rows in a dnd-kit sortable
18
18
  * context. Sortable item ids are derived from the index of each `items` entry.
19
+ *
20
+ * Virtualised, it also renders the two rows that stand in for the ones not
21
+ * rendered — see `Spacer` below — and refuses to be draggable at the same time.
19
22
  */
20
23
  export declare const TableBody: import('react').ForwardRefExoticComponent<TableBodyProps & import('react').RefAttributes<HTMLTableSectionElement>>;
@@ -1,3 +1,27 @@
1
1
  export type TableHeadProps = React.ComponentPropsWithoutRef<'thead'>;
2
- /** Styled `<thead>` wrapping its children in a header row. */
2
+ /**
3
+ * Styled `<thead>`. Virtualised, it renders its row twice and keeps the copy on
4
+ * screen.
5
+ *
6
+ * A virtualised table is the one case where the table is certain to be taller
7
+ * than what you can see — that is what virtualising is for — and a header that
8
+ * scrolls away takes the column names and the select-all checkbox with it. At
9
+ * ten thousand rows, getting back to them means scrolling back through all of
10
+ * them.
11
+ *
12
+ * Neither obvious way works. `position: sticky` answers to the nearest
13
+ * scrolling ancestor and nothing above it, and with pinned columns that
14
+ * ancestor is the section that owns the horizontal scroll — a box that never
15
+ * moves vertically, so the header rides away with the rows. Moving the header
16
+ * from a scroll handler works but is always one frame behind what the
17
+ * compositor has already painted, which reads as the header dropping away and
18
+ * snapping back on every frame of a scroll.
19
+ *
20
+ * So the row is rendered twice. The one in the table stays and is hidden, still
21
+ * doing the two jobs only it can do: reserving the header's height and settling
22
+ * the column widths. The copy is positioned against an ancestor that does not
23
+ * scroll, so vertical scrolling does not move it and there is nothing to
24
+ * correct. It is the same elements rendered again rather than a cloned node, so
25
+ * sorting and select-all still work in the one you can see.
26
+ */
3
27
  export declare const TableHead: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLTableSectionElement>, HTMLTableSectionElement>, "ref"> & import('react').RefAttributes<HTMLTableSectionElement>>;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Where a virtualised table's overlay scrollbar goes.
3
+ *
4
+ * Every other table in the system hides its bar: they scroll sideways, the
5
+ * shadows at the edges say there is more, and a bar would be chrome. A list of
6
+ * ten thousand rows is the opposite case — without one there is nothing to read
7
+ * your position from, and no way to cross the list in one gesture.
8
+ *
9
+ * The browser's own bar cannot be that thing here. It runs the full height of
10
+ * the scrollport, and the scrollport has to contain the header, so it always
11
+ * cuts across the column names. This one starts below them.
12
+ *
13
+ * The bar itself is `Scrollbar`, which knows nothing about any of that. What is
14
+ * left here is the arithmetic that is only true of a table, handed over as the
15
+ * custom properties it reads: the header's height, and the offset between the
16
+ * scrollport and whichever ancestor the bar is actually positioned in.
17
+ */
18
+ export declare function TableScrollbar(): import("react/jsx-runtime").JSX.Element | null;
19
+ export declare namespace TableScrollbar {
20
+ var displayName: string;
21
+ }
@@ -4,6 +4,14 @@ export interface TableSelectCellProps extends Omit<React.ComponentPropsWithoutRe
4
4
  /** Usually fixed to left */
5
5
  fixed?: boolean;
6
6
  fixedOffset?: string;
7
+ /**
8
+ * Whether this row can be selected at all.
9
+ *
10
+ * On the header cell it disables select-all, which is the right thing when
11
+ * nothing in the table can be selected — a checkbox that ticks and then
12
+ * selects nothing is worse than one that says so.
13
+ */
14
+ disabled?: boolean;
7
15
  onChange?: (checked: boolean) => void;
8
16
  }
9
17
  export declare const TableSelectCell: import('react').ForwardRefExoticComponent<TableSelectCellProps & import('react').RefAttributes<HTMLTableCellElement>>;
@@ -0,0 +1,45 @@
1
+ import { TableComponentProps } from '../Table.tsx';
2
+ import { UseTableVirtualReturn } from '../hooks/useTableVirtual/useTableVirtual.types.ts';
3
+ export type TableVirtualizedProps<TData = unknown> = TableComponentProps<TData> & {
4
+ /**
5
+ * What `useTableVirtual()` returned.
6
+ *
7
+ * Not the rows — those you map yourself, the same as in any other table.
8
+ * This is the thing that works out which rows those are, and the table
9
+ * hands it the element they scroll inside.
10
+ */
11
+ virtualizer: UseTableVirtualReturn<never>;
12
+ };
13
+ /**
14
+ * A `Table` that renders only the rows on screen.
15
+ *
16
+ * Everything but `virtualizer` is a `Table` prop and is passed straight through.
17
+ * What goes inside is what goes inside a `Table`: this is the same component,
18
+ * told where its virtualiser is.
19
+ *
20
+ * ```tsx
21
+ * const virtual = useTableVirtual(employees, { height: '480px' });
22
+ *
23
+ * <TableVirtualized virtualizer={virtual}>
24
+ * <TableBody>
25
+ * {virtual.rows.map(row => <TableRow key={row.id}>…</TableRow>)}
26
+ * </TableBody>
27
+ * </TableVirtualized>
28
+ * ```
29
+ *
30
+ * It is the one piece the Vue side does not have, and it exists because of how
31
+ * the two frameworks differ rather than because the tables do. There
32
+ * `useTableVirtual` runs in the caller's `setup`, which is already above the
33
+ * table, so it provides itself and `<Table>` is written exactly as it always
34
+ * was. A hook has nothing to provide to until something renders — so this
35
+ * renders.
36
+ *
37
+ * The alternative was a prop on `Table`, and it would not have stopped there:
38
+ * the spacers belong inside `TableBody`'s `<tbody>` and the pinned header is
39
+ * `TableHead`'s, so it would have had to be threaded to both of those by hand
40
+ * as well. A wrapper reaches all three and leaves `Table`'s own API alone.
41
+ */
42
+ export declare function TableVirtualized<TData = unknown>({ virtualizer, ...props }: TableVirtualizedProps<TData>): import("react/jsx-runtime").JSX.Element;
43
+ export declare namespace TableVirtualized {
44
+ var displayName: string;
45
+ }
@@ -0,0 +1,2 @@
1
+ export { TableVirtualized } from './TableVirtualized.tsx';
2
+ export type { TableVirtualizedProps } from './TableVirtualized.tsx';
@@ -18,3 +18,6 @@ export { useDragToScroll } from './useDragToScroll/useDragToScroll.ts';
18
18
  export type { UseDragToScrollOptions, UseDragToScrollReturn, } from './useDragToScroll/useDragToScroll.ts';
19
19
  export { useFixedColumns } from './useFixedColumns.ts';
20
20
  export type { UseFixedColumnsOptions } from './useFixedColumns.ts';
21
+ export { useTableVirtual } from './useTableVirtual/useTableVirtual.ts';
22
+ export { TableVirtualContext, useTableVirtualContext, } from './useTableVirtual/context.ts';
23
+ export type { UseTableVirtualOptions, UseTableVirtualReturn, } from './useTableVirtual/useTableVirtual.types.ts';
@@ -4,6 +4,15 @@ export interface UseDragToScrollOptions {
4
4
  enabled?: boolean | (() => boolean);
5
5
  /** Cursor to show while dragging */
6
6
  cursor?: string;
7
+ /**
8
+ * Selector for elements that own their own drag, where panning must keep out.
9
+ *
10
+ * A pan and a row reorder are the same gesture, and this hook calls
11
+ * `preventDefault()` on every `mousedown` it sees — which is exactly what
12
+ * stops dnd-kit from ever starting. Bowing out over the grip lets the two
13
+ * share the table: the handle reorders, everywhere else pans.
14
+ */
15
+ ignore?: string;
7
16
  }
8
17
  export interface UseDragToScrollReturn {
9
18
  /** Whether the user is currently dragging to scroll */
@@ -13,7 +22,8 @@ export interface UseDragToScrollReturn {
13
22
  * Hook for drag-to-scroll functionality.
14
23
  * Allows horizontal scrolling by dragging with the mouse.
15
24
  *
16
- * Note: If using row drag & drop, set enabled=false to avoid conflicts.
17
- * Use @dnd-kit for row reordering instead.
25
+ * Coexists with row drag & drop: panning keeps out of whatever `ignore`
26
+ * matches, which by default is the design system's drag grip. Both gestures can
27
+ * be live on the same table, so there is no need to turn one off.
18
28
  */
19
29
  export declare function useDragToScroll(elementRef: RefObject<HTMLElement | null>, options?: UseDragToScrollOptions): UseDragToScrollReturn;
@@ -0,0 +1,16 @@
1
+ import { UseTableVirtualReturn } from './useTableVirtual.types.ts';
2
+ /**
3
+ * How the virtualiser reaches the parts of the table that need it.
4
+ *
5
+ * The Vue side has no equivalent: `useTableVirtual` runs in the caller's
6
+ * `setup`, which is above the table, so it provides itself and nothing has to
7
+ * be passed anywhere. A hook cannot do that — nothing is above anything until
8
+ * something renders — which is what `TableVirtualized` is for.
9
+ *
10
+ * They do need reaching. The spacers standing in for the unrendered rows have
11
+ * to sit inside the `<tbody>`, which `TableBody` renders from the caller's own
12
+ * markup, and the floating header belongs to `TableHead`. Handing each of them
13
+ * a prop is the boilerplate this removes.
14
+ */
15
+ export declare const TableVirtualContext: import('react').Context<UseTableVirtualReturn<unknown> | null>;
16
+ export declare function useTableVirtualContext(): UseTableVirtualReturn<unknown> | null;
@@ -0,0 +1,3 @@
1
+ export { TableVirtualContext, useTableVirtualContext } from './context.ts';
2
+ export { useTableVirtual } from './useTableVirtual.ts';
3
+ export type { UseTableVirtualOptions, UseTableVirtualReturn, } from './useTableVirtual.types.ts';
@@ -0,0 +1,36 @@
1
+ import { UseTableVirtualOptions, UseTableVirtualReturn } from './useTableVirtual.types.ts';
2
+ /**
3
+ * Renders only the rows that are on screen, however many the table is given.
4
+ *
5
+ * Hand it the whole list and map `rows` instead: at ten thousand rows that is
6
+ * about twenty in the DOM, and the browser stops doing the work of laying out
7
+ * the other nine thousand nine hundred and eighty.
8
+ *
9
+ * ```tsx
10
+ * const virtual = useTableVirtual(employees, { maxHeight: '480px' });
11
+ *
12
+ * <TableVirtualized virtualizer={virtual}>
13
+ * <TableBody>
14
+ * {virtual.rows.map(row => <TableRow key={row.id}>…</TableRow>)}
15
+ * </TableBody>
16
+ * </TableVirtualized>
17
+ * ```
18
+ *
19
+ * `TableVirtualized` is the one piece the Vue side does not have. There the
20
+ * composable provides itself from the caller's `setup`; a hook has nothing to
21
+ * provide to until something renders, so the wrapper does it instead — and
22
+ * `Table` itself gains no prop on either side.
23
+ *
24
+ * **Not with row reordering.** `TableBody` throws if both are on. Where a row
25
+ * sits in the DOM is not where it sits in the list once only part of it is
26
+ * rendered, and dragging across ten thousand rows is not a gesture anyone can
27
+ * make. A reorderable table is a paged one.
28
+ *
29
+ * **Why spacers.** Rendering twenty rows would leave a table twenty rows tall,
30
+ * with no scrollbar and so nothing to scroll — the window could never move.
31
+ * Something has to stand in for the height of everything that is not rendered,
32
+ * and in a `<table>` that something is a pair of empty rows, one above the
33
+ * window and one below. They belong inside the `<tbody>`, so `TableBody` is
34
+ * what renders them. A caller never writes a spacer, and never should have to.
35
+ */
36
+ export declare function useTableVirtual<TData>(items: TData[], options?: UseTableVirtualOptions): UseTableVirtualReturn<TData>;
@@ -0,0 +1,74 @@
1
+ import { RefObject } from 'react';
2
+ export interface UseTableVirtualOptions {
3
+ /**
4
+ * How tall the table's scrollport is allowed to get, as a CSS length.
5
+ *
6
+ * A ceiling rather than a measurement: given fewer rows than it has room
7
+ * for, the table shrinks to them instead of leaving empty space under the
8
+ * last one.
9
+ *
10
+ * Any length the browser understands: `'480px'`, `'30vh'`,
11
+ * `'calc(100vh - 12rem)'`. It is written straight onto the element and the
12
+ * window is worked out from what that element ends up measuring, so nothing
13
+ * here cares which unit you used. `'100%'` works too, as long as whatever
14
+ * contains the table has a height of its own — a percentage of `auto` is
15
+ * `auto`, and a table that grows to fit its rows is the one case this cannot
16
+ * work with.
17
+ *
18
+ * Virtualising needs one. A table that grows to fit its rows has no scrollbar
19
+ * of its own — the page scrolls instead — and with nothing scrolling there is
20
+ * no position to work a window out from.
21
+ */
22
+ maxHeight?: string;
23
+ /**
24
+ * How tall one row is, in pixels.
25
+ *
26
+ * This is what turns a scroll position into a row index, so it is worth
27
+ * getting right: the error is paid on every row crossed, which is nothing at
28
+ * one click of the wheel and hundreds of rows after a flick. The default,
29
+ * 52px, is `--table-row-height` on `.oxTableRoot` — the minimum a row's cells
30
+ * give it with plain text in them. (Not `TableRow`'s own CSS: `height` on a
31
+ * `<tr>` is ignored by the table layout algorithm.) Rows with an avatar or two
32
+ * lines of text are taller, and those tables should say so here.
33
+ *
34
+ * It is deliberately a number you give rather than one measured from the
35
+ * page. Measuring as you scroll means the total height changes as you scroll,
36
+ * and a table whose content grows and shrinks underneath the scrollbar throws
37
+ * you somewhere else every time it does.
38
+ */
39
+ estimateSize?: number;
40
+ /** How many rows to keep either side of the window, so scrolling stays smooth. */
41
+ overscan?: number;
42
+ }
43
+ export interface UseTableVirtualReturn<TData> {
44
+ /**
45
+ * The rows that belong on screen right now, as data rather than indices — a
46
+ * caller maps these exactly the way it would map the whole list.
47
+ */
48
+ rows: TData[];
49
+ /** How many rows there are in total, window or no window. */
50
+ total: number;
51
+ /** Where a windowed row sits in the full list, for callers that need to know. */
52
+ indexOf: (windowIndex: number) => number;
53
+ /**
54
+ * Everything below is how `Table` drives this, and no caller should have to
55
+ * touch it. The scrollport is the table's, the spacers are `TableBody`'s, and
56
+ * both reach it through `TableVirtualized` rather than by hand.
57
+ */
58
+ containerRef: RefObject<HTMLElement | null>;
59
+ /**
60
+ * How `Table` registers itself as the scrollport, and how a second one is
61
+ * stopped from taking it over.
62
+ */
63
+ claim: (element: HTMLElement | null) => void;
64
+ maxHeight: string | undefined;
65
+ /** The height of everything above the window, and of everything below it. */
66
+ padStart: number;
67
+ padEnd: number;
68
+ /**
69
+ * Measures a row that turned out taller than the estimate. Without it the
70
+ * scrollbar drifts: every row that wraps makes the list a little longer than
71
+ * the virtualiser thinks it is, and by the bottom the two disagree.
72
+ */
73
+ measure: (element: Element | null) => void;
74
+ }
@@ -1,4 +1,5 @@
1
1
  export { Table, type TableComponentProps } from './Table.tsx';
2
+ export { TableVirtualized, type TableVirtualizedProps, } from './TableVirtualized/TableVirtualized.tsx';
2
3
  export { TableHead, type TableHeadProps } from './TableHead/TableHead.tsx';
3
4
  export { TableBody, type TableBodyProps } from './TableBody/TableBody.tsx';
4
5
  export { TableRow, type TableRowProps } from './TableRow/TableRow.tsx';
@@ -9,9 +10,8 @@ export { TableDragCell, type TableDragCellProps, } from './TableDragCell/TableDr
9
10
  export { TableBulkHeader, type TableBulkHeaderProps, } from './TableBulkHeader/TableBulkHeader.tsx';
10
11
  export { TablePagination, type TablePaginationProps, } from './TablePagination/TablePagination.tsx';
11
12
  export { TableEmpty, type TableEmptyProps } from './TableEmpty/TableEmpty.tsx';
12
- export { TableAvatar, type TableAvatarProps, } from './TableAvatar/TableAvatar.tsx';
13
13
  export { TableRowExpanded, type TableRowExpandedProps, } from './TableRowExpanded/TableRowExpanded.tsx';
14
14
  export { TableExpandCell, type TableExpandCellProps, } from './TableExpandCell/TableExpandCell.tsx';
15
15
  export { TableColumnVisibility, type TableColumnVisibilityProps, } from './TableColumnVisibility/TableColumnVisibility.tsx';
16
- export { useTable, type UseTableOptions, type UseTableReturn, useTableSelection, type SelectionInstance as UseTableSelectionReturn, useTableSorting, type SortingInstance as UseTableSortingReturn, useTablePagination, type UseTablePaginationOptions, type UseTablePaginationReturn, useTableDetailRow, type DetailRowInstance, type DetailRowOptions, type DetailRowPluginDef, useTablePinning, type PinningOptions as UseTablePinningOptions, type PinningInstance as UseTablePinningReturn, type CellInfo, type HeaderInfo, useTableColumns, type ColumnsOptions as UseTableColumnsOptions, type ColumnsInstance as UseTableColumnsReturn, useScrollShadow, type UseScrollShadowOptions, type UseScrollShadowReturn, useDragToScroll, type UseDragToScrollOptions, type UseDragToScrollReturn, useFixedColumns, type UseFixedColumnsOptions, } from './hooks/index.ts';
16
+ export { useTable, type UseTableOptions, type UseTableReturn, useTableSelection, type SelectionInstance as UseTableSelectionReturn, useTableSorting, type SortingInstance as UseTableSortingReturn, useTablePagination, type UseTablePaginationOptions, type UseTablePaginationReturn, useTableDetailRow, type DetailRowInstance, type DetailRowOptions, type DetailRowPluginDef, useTablePinning, type PinningOptions as UseTablePinningOptions, type PinningInstance as UseTablePinningReturn, type CellInfo, type HeaderInfo, useTableColumns, type ColumnsOptions as UseTableColumnsOptions, type ColumnsInstance as UseTableColumnsReturn, useScrollShadow, type UseScrollShadowOptions, type UseScrollShadowReturn, useDragToScroll, type UseDragToScrollOptions, type UseDragToScrollReturn, useFixedColumns, type UseFixedColumnsOptions, useTableVirtual, type UseTableVirtualOptions, type UseTableVirtualReturn, } from './hooks/index.ts';
17
17
  export type { TableProps, TableMode, ColumnDef, ColumnAlign, CellContext, SortingState, PaginationState, PaginationChangePayload, SortingChangePayload, SelectionChangePayload, FilterChangePayload, ColumnResizeMode, ColumnVisibilityState, ColumnOrderState, ExpandedState, ColumnVisibilityChangePayload, ColumnOrderChangePayload, RowExpandChangePayload, ColumnResizePayload, ColumnPinningState, } from './types';
@@ -0,0 +1,30 @@
1
+ import { AvatarSize } from '../index.ts';
2
+ export interface AvatarSkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
3
+ /** Matches the avatar's size scale — the placeholder is the same box */
4
+ size?: AvatarSize;
5
+ /** Which avatar it stands in for. Only the radius differs. */
6
+ shape?: 'rounded' | 'square';
7
+ dataTestid: string;
8
+ }
9
+ /**
10
+ * An avatar-shaped placeholder, for while the avatar is still loading.
11
+ *
12
+ * It renders `OxSkeleton` and wears the *avatar's own* size class, which is why
13
+ * this is a component and not a documented pair of utilities. `size-12` is what
14
+ * `md` happens to be today; a caller who wrote that by hand would be holding a
15
+ * copy of our scale, and it would go quietly wrong the day the scale moved.
16
+ * Here the placeholder and the real avatar read the same rule in
17
+ * `../avatarSizes.css`, so they cannot drift.
18
+ *
19
+ * **One component, not two.** `AvatarRounded` and `AvatarSquare` are separate
20
+ * because they differ in substance — a ring, an image, a status bullet, an
21
+ * action and a label, and two different corner geometries. Strip all of that
22
+ * out and the only thing left that differs is the radius, so a second component
23
+ * would be a copy of this one with one class changed. That is the
24
+ * wrapper-with-no-behaviour that `.claude/rules/component-architecture.md` §11
25
+ * rejects.
26
+ *
27
+ * The pulse and the reduced-motion behaviour are not reimplemented here: they
28
+ * come from `Skeleton`, which is the only place they are declared.
29
+ */
30
+ export declare const AvatarSkeleton: import('react').ForwardRefExoticComponent<AvatarSkeletonProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -1,6 +1,8 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  export { AvatarRounded } from './AvatarRounded/AvatarRounded.tsx';
3
3
  export type { AvatarRoundedProps } from './AvatarRounded/AvatarRounded.tsx';
4
+ export { AvatarSkeleton } from './AvatarSkeleton/AvatarSkeleton.tsx';
5
+ export type { AvatarSkeletonProps } from './AvatarSkeleton/AvatarSkeleton.tsx';
4
6
  export { AvatarSquare } from './AvatarSquare/AvatarSquare.tsx';
5
7
  export type { AvatarSquareProps } from './AvatarSquare/AvatarSquare.tsx';
6
8
  export { useAvatarBullet } from './hooks/useAvatarBullet.ts';
@@ -0,0 +1,68 @@
1
+ import { AvatarSize } from '../Avatar/index.ts';
2
+ /**
3
+ * What the avatar itself is: the picture, the fallback for when there is no
4
+ * picture, and how big the whole thing is drawn.
5
+ *
6
+ * One object rather than three props, the way `ChatInput` takes `actionLabels`
7
+ * and `ChatBubble` takes `delivery`. The prop budget is five and the text beside
8
+ * the avatar already spends three of them; folding the avatar's own settings
9
+ * into the one value they all describe buys back the room `size` needed, and
10
+ * leaves room for the next thing the avatar grows.
11
+ *
12
+ * `initials` is a field and not something derived from `name` on purpose. Real
13
+ * records carry initials separately precisely *because* the name arrives badly
14
+ * formatted — "GARCÍA LÓPEZ, M.ª José", a single word, an email address — so a
15
+ * derivation is a rule that works on every example anyone writes by hand and
16
+ * fails on the data.
17
+ */
18
+ export interface AvatarDetailsAvatar {
19
+ /** Image source URL */
20
+ src?: string;
21
+ /** Fallback initials (max 2 characters), shown when there is no image */
22
+ initials?: string;
23
+ /** 24, 32, 48, 64 or 80px. Also sets the text scale beside it. */
24
+ size?: AvatarSize;
25
+ }
26
+ /**
27
+ * An avatar with a name and an optional second line beside it.
28
+ *
29
+ * `name` and `subtitle` are props and not `children`, which reads as a
30
+ * violation of composition-over-configuration and is a deliberate exception.
31
+ * Sameness is the whole product here: this pattern appears on every list, table
32
+ * and picker we ship, and the point of having a component for it is that all of
33
+ * them render the same two lines at the same sizes and weights. Taking a node
34
+ * hands that decision back to the caller, and the first one to put a badge, a
35
+ * link or a third line in it is the moment the component stops guaranteeing
36
+ * anything. Callers who genuinely need arbitrary content next to an avatar
37
+ * should compose `AvatarSquare` themselves rather than widen this.
38
+ *
39
+ * ### The text scales with the avatar, and the caller still cannot choose it
40
+ *
41
+ * The size spans 24px to 80px, and a name at one fixed size across that range is
42
+ * wrong at both ends. So the two lines step with the box — the pairs are in the
43
+ * stylesheet, keyed off `data-size`, and they are **derived**, never passed.
44
+ * There is no text-size prop and no CSS variable a caller pokes: every
45
+ * `AvatarDetails` at a given size still renders identically to every other one,
46
+ * which is the guarantee the paragraph above is about. What the fixed-size
47
+ * version guaranteed was narrower than it looked — it guaranteed sameness
48
+ * between a 32px row and a 32px row, and there were no other sizes.
49
+ *
50
+ * `xs` and `sm` deliberately share a pair: 14/12 is already the smallest
51
+ * readable step we have, so below 32px only the picture shrinks.
52
+ *
53
+ * The prop list is four plus `dataTestid`, against a cap of five. The one spare
54
+ * is not an invitation — anything that belongs to the avatar goes into
55
+ * `AvatarDetailsAvatar`, and anything that does not has to argue for itself.
56
+ */
57
+ export interface AvatarDetailsProps extends React.ComponentPropsWithoutRef<'div'> {
58
+ /** The avatar itself: image, fallback initials and size */
59
+ avatar?: AvatarDetailsAvatar;
60
+ /** Full name to display */
61
+ name: string;
62
+ /** Subtitle (department, role, etc.) */
63
+ subtitle?: string;
64
+ /** Disabled state */
65
+ disabled?: boolean;
66
+ dataTestid: string;
67
+ }
68
+ export declare const AvatarDetails: import('react').ForwardRefExoticComponent<AvatarDetailsProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ export { AvatarDetails, type AvatarDetailsAvatar, type AvatarDetailsProps, } from './AvatarDetails.tsx';
@@ -1,7 +1,8 @@
1
1
  import { BadgeVariants } from './index.ts';
2
2
  export interface BadgeProps extends React.HTMLAttributes<HTMLSpanElement> {
3
- variant?: BadgeVariants['variant'];
3
+ /** How big the counter is. `sm` is the bare dot and takes no content. */
4
+ size?: BadgeVariants['size'];
4
5
  dataTestid: string;
5
6
  }
6
- /** Badge — mirrors `@sesame/orxata-core` Badge (cva-only). */
7
+ /** Badge — mirrors `@sesame/orxata-core` Badge: a count, or a bare dot. */
7
8
  export declare const Badge: import('react').ForwardRefExoticComponent<BadgeProps & import('react').RefAttributes<HTMLSpanElement>>;
@@ -1,6 +1,15 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  export { Badge, type BadgeProps } from './Badge.tsx';
3
+ /**
4
+ * A count, or a bare dot. Not a labelled pill.
5
+ *
6
+ * Figma's `Badges` set varies on one axis — size — and nothing else: `sm` is a
7
+ * 6px dot with no content, `md` a 16px circle and `lg` a 22px one, all of them
8
+ * `error` red with white text. The five colour variants this used to carry came
9
+ * from shadcn's Badge and were never in the design; a labelled pill is `Chip`
10
+ * or `StatusBadge`, both of which Figma does draw.
11
+ */
3
12
  export declare const badgeVariants: (props?: ({
4
- variant?: "default" | "destructive" | "outline" | "secondary" | "brand" | null | undefined;
13
+ size?: "sm" | "md" | "lg" | null | undefined;
5
14
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
6
15
  export type BadgeVariants = VariantProps<typeof badgeVariants>;