@sesamehr/react-design-system 1.6.1 → 2.0.0-beta.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +34 -0
- package/dist/Button/ActionItem/ActionItem.d.ts +40 -0
- package/dist/Button/ActionItem/index.d.ts +1 -0
- package/dist/Button/IconButton/IconButton.d.ts +32 -0
- package/dist/Button/IconButton/index.d.ts +27 -0
- package/dist/Data/Table/Table.d.ts +1 -1
- package/dist/Data/Table/TableBody/TableBody.d.ts +3 -0
- package/dist/Data/Table/TableHead/TableHead.d.ts +25 -1
- package/dist/Data/Table/TableScrollbar/TableScrollbar.d.ts +21 -0
- package/dist/Data/Table/TableSelectCell/TableSelectCell.d.ts +8 -0
- package/dist/Data/Table/TableVirtualized/TableVirtualized.d.ts +45 -0
- package/dist/Data/Table/TableVirtualized/index.d.ts +2 -0
- package/dist/Data/Table/hooks/index.d.ts +3 -0
- package/dist/Data/Table/hooks/useDragToScroll/useDragToScroll.d.ts +12 -2
- package/dist/Data/Table/hooks/useTableVirtual/context.d.ts +16 -0
- package/dist/Data/Table/hooks/useTableVirtual/index.d.ts +3 -0
- package/dist/Data/Table/hooks/useTableVirtual/useTableVirtual.d.ts +36 -0
- package/dist/Data/Table/hooks/useTableVirtual/useTableVirtual.types.d.ts +74 -0
- package/dist/Data/Table/index.d.ts +2 -2
- package/dist/Display/Avatar/AvatarSkeleton/AvatarSkeleton.d.ts +30 -0
- package/dist/Display/Avatar/index.d.ts +2 -0
- package/dist/Display/AvatarDetails/AvatarDetails.d.ts +68 -0
- package/dist/Display/AvatarDetails/index.d.ts +1 -0
- package/dist/Display/Badge/Badge.d.ts +3 -2
- package/dist/Display/Badge/index.d.ts +10 -1
- package/dist/Display/ChatBubble/ChatBubble.d.ts +28 -0
- package/dist/Display/ChatBubble/ChatBubbleStatus/ChatBubbleStatus.d.ts +8 -0
- package/dist/Display/ChatBubble/ChatBubbleStatus/index.d.ts +10 -0
- package/dist/Display/ChatBubble/index.d.ts +44 -0
- package/dist/Display/Chip/Chip.d.ts +21 -5
- package/dist/Display/Chip/index.d.ts +19 -10
- package/dist/Display/FileCard/FileCard.d.ts +66 -0
- package/dist/Display/FileCard/index.d.ts +1 -0
- package/dist/Display/FilePreviewCard/FilePreviewCard.d.ts +49 -0
- package/dist/Display/FilePreviewCard/index.d.ts +1 -0
- package/dist/Feedback/Alert/AlertIcon.d.ts +1 -1
- package/dist/Feedback/Dialog/DialogBody.d.ts +18 -0
- package/dist/Feedback/Dialog/index.d.ts +1 -0
- package/dist/Feedback/Loader/Loader.d.ts +16 -0
- package/dist/Feedback/Loader/index.d.ts +2 -0
- package/dist/Feedback/Popover/PopoverContent.d.ts +0 -1
- package/dist/Feedback/Progress/Progress.d.ts +3 -0
- package/dist/Feedback/Progress/index.d.ts +17 -0
- package/dist/Feedback/Skeleton/Skeleton.d.ts +20 -0
- package/dist/Feedback/Skeleton/index.d.ts +2 -0
- package/dist/Feedback/Tooltip/TooltipContent.d.ts +0 -1
- package/dist/Forms/Field/Counter/Counter.d.ts +9 -0
- package/dist/Forms/Field/Counter/index.d.ts +13 -0
- package/dist/Forms/Field/FieldGroup/FieldGroup.d.ts +16 -1
- package/dist/Forms/Field/FieldLabel/FieldLabel.d.ts +16 -0
- package/dist/Forms/Field/FieldMessage/FieldMessage.d.ts +22 -2
- package/dist/Forms/Field/index.d.ts +1 -0
- package/dist/Forms/Field/useFieldGroup.d.ts +108 -0
- package/dist/Forms/Inputs/Calendar/Calendar.d.ts +55 -0
- package/dist/Forms/Inputs/Calendar/CalendarDay.d.ts +37 -0
- package/dist/Forms/Inputs/Calendar/CalendarRange.d.ts +56 -0
- package/dist/Forms/Inputs/Calendar/constraints.d.ts +19 -0
- package/dist/Forms/Inputs/Calendar/date.d.ts +28 -0
- package/dist/Forms/Inputs/Calendar/index.d.ts +21 -0
- package/dist/Forms/Inputs/Calendar/nav.d.ts +34 -0
- package/dist/Forms/Inputs/Calendar/testids.d.ts +28 -0
- package/dist/Forms/Inputs/Calendar/useCalendarLocale.d.ts +40 -0
- package/dist/Forms/Inputs/ChatInput/ChatInput.d.ts +68 -0
- package/dist/Forms/Inputs/ChatInput/index.d.ts +46 -0
- package/dist/Forms/Inputs/Combobox/ComboboxCancel.d.ts +14 -0
- package/dist/Forms/Inputs/Combobox/ComboboxChipsInput.d.ts +4 -0
- package/dist/Forms/Inputs/Combobox/ComboboxContent.d.ts +0 -6
- package/dist/Forms/Inputs/Combobox/ComboboxGroup.d.ts +6 -2
- package/dist/Forms/Inputs/Combobox/ComboboxInput.d.ts +6 -1
- package/dist/Forms/Inputs/Combobox/ComboboxItem.d.ts +4 -0
- package/dist/Forms/Inputs/Combobox/ComboboxItemEdit.d.ts +124 -0
- package/dist/Forms/Inputs/Combobox/context.d.ts +15 -1
- package/dist/Forms/Inputs/Combobox/index.d.ts +2 -0
- package/dist/Forms/Inputs/Combobox/useChipOverflow.d.ts +30 -0
- package/dist/Forms/Inputs/Combobox/useComboboxEditing.d.ts +40 -0
- package/dist/Forms/Inputs/Combobox/useComboboxLabels.d.ts +21 -0
- package/dist/Forms/Inputs/DatePicker/DatePicker.d.ts +51 -0
- package/dist/Forms/Inputs/DatePicker/DatePickerHeader.d.ts +65 -0
- package/dist/Forms/Inputs/DatePicker/DatePickerMonthSelect.d.ts +27 -0
- package/dist/Forms/Inputs/DatePicker/DatePickerTrigger.d.ts +29 -0
- package/dist/Forms/Inputs/DatePicker/DatePickerYearSelect.d.ts +25 -0
- package/dist/Forms/Inputs/DatePicker/DateRangePicker.d.ts +61 -0
- package/dist/Forms/Inputs/DatePicker/format.d.ts +44 -0
- package/dist/Forms/Inputs/DatePicker/index.d.ts +6 -0
- package/dist/Forms/Inputs/DatePicker/month.d.ts +28 -0
- package/dist/Forms/Inputs/DatePicker/useDatePickerHeader.d.ts +23 -0
- package/dist/Forms/Inputs/InputOtp/InputOtp.d.ts +7 -0
- package/dist/Forms/Inputs/InputPassword/InputPassword.d.ts +9 -1
- package/dist/Forms/Inputs/InputText/InputText.d.ts +9 -0
- package/dist/Forms/Inputs/SearchBar/SearchBar.d.ts +35 -0
- package/dist/Forms/Inputs/SearchBar/index.d.ts +22 -0
- package/dist/Forms/Inputs/SearchBar/useSearchDelay.d.ts +24 -0
- package/dist/Forms/Inputs/SearchPanel/SearchPanel.d.ts +71 -0
- package/dist/Forms/Inputs/SearchPanel/SearchPanelEmpty.d.ts +16 -0
- package/dist/Forms/Inputs/SearchPanel/SearchPanelGroup.d.ts +14 -0
- package/dist/Forms/Inputs/SearchPanel/SearchPanelInput.d.ts +31 -0
- package/dist/Forms/Inputs/SearchPanel/SearchPanelItem.d.ts +20 -0
- package/dist/Forms/Inputs/SearchPanel/SearchPanelList.d.ts +11 -0
- package/dist/Forms/Inputs/SearchPanel/context.d.ts +11 -0
- package/dist/Forms/Inputs/SearchPanel/index.d.ts +6 -0
- package/dist/Forms/Inputs/Select/SelectContent.d.ts +0 -4
- package/dist/Forms/Inputs/Select/SelectGroup.d.ts +6 -2
- package/dist/Forms/Inputs/Select/SelectItem.d.ts +6 -0
- package/dist/Forms/Inputs/Textarea/Textarea.d.ts +69 -0
- package/dist/Forms/Inputs/Textarea/index.d.ts +21 -0
- package/dist/Forms/Inputs/Toggle/RadioButton/RadioGroup.d.ts +5 -0
- package/dist/Forms/Inputs/Toggle/ToggleLabel/ToggleLabel.d.ts +10 -1
- package/dist/Forms/Inputs/index.d.ts +6 -0
- package/dist/Layout/Scrollbar/Scrollbar.d.ts +46 -0
- package/dist/Layout/Scrollbar/index.d.ts +2 -0
- package/dist/Layout/Scrollbar/useScrollbar.d.ts +52 -0
- package/dist/hooks/index.d.ts +12 -0
- package/dist/hooks/useAutoGrow.d.ts +22 -0
- package/dist/internal/Listbox/ListboxEmpty.d.ts +3 -0
- package/dist/internal/Listbox/ListboxItem.d.ts +23 -0
- package/dist/internal/Listbox/ListboxLabel.d.ts +9 -0
- package/dist/internal/Listbox/ListboxSeparator.d.ts +3 -0
- package/dist/internal/Listbox/ListboxViewport.d.ts +9 -0
- package/dist/internal/Surface/Surface.d.ts +35 -0
- package/dist/internal/index.d.ts +13 -0
- package/dist/lib/cssModules.d.ts +13 -0
- package/dist/main.d.ts +18 -7
- package/dist/preflight.css +391 -0
- package/dist/react-design-system.css +1 -1
- package/dist/react-design-system.js +17345 -10589
- package/dist/react-design-system.umd.cjs +164 -117
- package/package.json +4 -2
- package/src/assets/styles/theme-v2.css +6 -6
- package/src/assets/styles/theme-v3.css +13 -5
- package/dist/Data/Table/TableAvatar/TableAvatar.d.ts +0 -14
- package/dist/Display/Tag/Tag.d.ts +0 -19
- 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
|
-
/**
|
|
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
|
+
}
|
|
@@ -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
|
-
*
|
|
17
|
-
*
|
|
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,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
|
-
|
|
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
|
|
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
|
-
|
|
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>;
|