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

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.
@@ -24,7 +24,7 @@ export interface AvatarSkeletonProps extends React.HTMLAttributes<HTMLDivElement
24
24
  * wrapper-with-no-behaviour that `.claude/rules/component-architecture.md` §11
25
25
  * rejects.
26
26
  *
27
- * The pulse and the reduced-motion behaviour are not reimplemented here: they
27
+ * The sweep and the reduced-motion behaviour are not reimplemented here: they
28
28
  * come from `Skeleton`, which is the only place they are declared.
29
29
  */
30
30
  export declare const AvatarSkeleton: import('react').ForwardRefExoticComponent<AvatarSkeletonProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -1,3 +1,28 @@
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
+ }
1
26
  /**
2
27
  * An avatar with a name and an optional second line beside it.
3
28
  *
@@ -11,21 +36,33 @@
11
36
  * anything. Callers who genuinely need arbitrary content next to an avatar
12
37
  * should compose `AvatarSquare` themselves rather than widen this.
13
38
  *
14
- * The prop list is full at five plus `dataTestid`, which is the cap. Anything
15
- * further has to replace one of these or be argued as a separate component —
16
- * there is no room left to slip one in.
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.
17
56
  */
18
57
  export interface AvatarDetailsProps extends React.ComponentPropsWithoutRef<'div'> {
19
- /** Image source URL */
20
- src?: string;
21
- /** Fallback initials (max 2 characters) */
22
- initials?: string;
23
- /** Disabled state */
24
- disabled?: boolean;
58
+ /** The avatar itself: image, fallback initials and size */
59
+ avatar?: AvatarDetailsAvatar;
25
60
  /** Full name to display */
26
61
  name: string;
27
62
  /** Subtitle (department, role, etc.) */
28
63
  subtitle?: string;
64
+ /** Disabled state */
65
+ disabled?: boolean;
29
66
  dataTestid: string;
30
67
  }
31
68
  export declare const AvatarDetails: import('react').ForwardRefExoticComponent<AvatarDetailsProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -1 +1 @@
1
- export { AvatarDetails, type AvatarDetailsProps } from './AvatarDetails.tsx';
1
+ export { AvatarDetails, type AvatarDetailsAvatar, type AvatarDetailsProps, } from './AvatarDetails.tsx';
@@ -1,3 +1,4 @@
1
+ import { AvatarSize } from '../Avatar/index.ts';
1
2
  export interface AvatarItem {
2
3
  src?: string;
3
4
  initials?: string;
@@ -10,6 +11,8 @@ export interface AvatarGroupProps extends Omit<React.ButtonHTMLAttributes<HTMLBu
10
11
  max?: number;
11
12
  /** Whether the group is interactive (clickable) */
12
13
  interactive?: boolean;
14
+ /** The size every avatar in the stack is drawn at. */
15
+ size?: AvatarSize;
13
16
  /** Click handler (only fired when interactive) */
14
17
  onClick?: React.MouseEventHandler<HTMLButtonElement>;
15
18
  dataTestid: string;
@@ -2,7 +2,8 @@ export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
2
2
  dataTestid: string;
3
3
  }
4
4
  /**
5
- * A block that pulses while the content it stands in for is still loading.
5
+ * A block a sheen sweeps across while the content it stands in for is still
6
+ * loading.
6
7
  *
7
8
  * It configures nothing. One surface, and the caller gives it its shape with
8
9
  * ordinary classes — `h-4 w-48` is a line of text, `size-10 rounded-full` is an
@@ -16,6 +16,25 @@ export interface ComboboxProps extends Omit<React.HTMLAttributes<HTMLDivElement>
16
16
  /** Emitted when the open state changes. */
17
17
  onOpenChange?: (open: boolean) => void;
18
18
  children?: React.ReactNode;
19
+ /**
20
+ * The term to search for, once typing has stopped. Binding it is what tells
21
+ * the combobox its options are an answer it asked for — see `ignoreFilter`.
22
+ */
23
+ onSearch?: (term: string) => void;
24
+ /**
25
+ * Quiet period, in milliseconds, between the last keystroke and `onSearch`.
26
+ * `0` emits in the same tick.
27
+ */
28
+ debounce?: number;
29
+ /**
30
+ * Whether to skip filtering the rendered options in the browser. Left unset
31
+ * it follows `onSearch`: options the caller went and fetched have already
32
+ * been filtered, by something that knows more than a literal text match does
33
+ * — search "peres", get "Ana Pérez" back from a server that folds accents,
34
+ * and a second pass here hides a correct answer with nothing logged. Pass it
35
+ * explicitly to override, `false` included.
36
+ */
37
+ ignoreFilter?: boolean;
19
38
  dataTestid: string;
20
39
  }
21
40
  /**
@@ -3,6 +3,13 @@ export interface ComboboxChipsInputProps extends Omit<React.InputHTMLAttributes<
3
3
  placeholder?: string;
4
4
  disabled?: boolean;
5
5
  size?: InputSize;
6
+ /**
7
+ * Names a chip the options cannot: a selection that arrived with the record,
8
+ * from a server, before any item existed to report a label. Return
9
+ * `undefined` for anything it does not know and the option's own label is
10
+ * used, so it never has to answer for values the list can speak for itself.
11
+ */
12
+ chipLabel?: (value: string) => string | undefined;
6
13
  /** Custom trigger content (defaults to a chevron icon). */
7
14
  trigger?: React.ReactNode;
8
15
  }
@@ -0,0 +1,134 @@
1
+ export interface ComboboxItemEditPreview {
2
+ /**
3
+ * Enter the editing state. Pass it straight to the control that starts the
4
+ * edit — `onClick={edit}` — so it receives the event and can stop it.
5
+ */
6
+ edit: (event?: {
7
+ stopPropagation: () => void;
8
+ }) => void;
9
+ }
10
+ export interface ComboboxItemEditField {
11
+ /** The text as it currently stands. */
12
+ value: string | undefined;
13
+ /** Report a keystroke from the field. */
14
+ setValue: (value: string | undefined) => void;
15
+ /** Save, and leave the editing state. */
16
+ commit: () => void;
17
+ /** Put the text back as it was, and leave the editing state. */
18
+ cancel: () => void;
19
+ }
20
+ export interface ComboboxItemEditProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children' | 'onChange'> {
21
+ /**
22
+ * The text being edited. Pass it one way — `value={label}` — and let
23
+ * `onCommit` write the new one back: it seeds the draft and re-seeds it
24
+ * whenever it changes, so the caller never holds the draft and the field
25
+ * inside `field` never has a second copy of it to disagree with. Add
26
+ * `onValueChange` for a caller who wants every keystroke.
27
+ */
28
+ value?: string;
29
+ /** The starting text when nothing is passed for `value`. */
30
+ defaultValue?: string;
31
+ /** Every keystroke, for a caller controlling the draft. */
32
+ onValueChange?: (value: string | undefined) => void;
33
+ /** The edit was saved. Carries the text as it now stands. */
34
+ onCommit?: (value: string | undefined) => void;
35
+ /** The edit was abandoned; the draft has already been put back. */
36
+ onCancel?: () => void;
37
+ /** The row while it is being edited. */
38
+ field?: (context: ComboboxItemEditField) => React.ReactNode;
39
+ /** The row the rest of the time. */
40
+ children?: (context: ComboboxItemEditPreview) => React.ReactNode;
41
+ }
42
+ /**
43
+ * An option that can be renamed without leaving the list: the row shows its
44
+ * normal content until the caller's own control asks to edit it, then hands the
45
+ * row over to the caller's own field. Port of
46
+ * `core/src/Forms/Inputs/Combobox/ComboboxItemEdit`.
47
+ *
48
+ * It holds no strings and draws no buttons — the design system ships neither.
49
+ * What it owns is the part a caller cannot get right from outside: a list whose
50
+ * every reflex is to select the row and close, aimed at a field that needs the
51
+ * click, the keystroke and the `Escape` for itself.
52
+ *
53
+ * ```tsx
54
+ * <OxComboboxItem value="other">
55
+ * <OxComboboxItemEdit
56
+ * value={label}
57
+ * onCommit={next => setLabel(next ?? '')}
58
+ * field={({ value, setValue, commit }) => (
59
+ * <>
60
+ * <OxInputText size="sm" field={value} onFieldChange={setValue} />
61
+ * <OxButton variant="ghost" onClick={commit}>…</OxButton>
62
+ * </>
63
+ * )}
64
+ * >
65
+ * {({ edit }) => (
66
+ * <>
67
+ * {label}
68
+ * <OxButton variant="ghost" onClick={edit}>…</OxButton>
69
+ * </>
70
+ * )}
71
+ * </OxComboboxItemEdit>
72
+ * </OxComboboxItem>
73
+ * ```
74
+ *
75
+ * Both states live here rather than behind the caller's own conditional for one
76
+ * reason worth the extra render prop: the control that *starts* the edit is
77
+ * itself inside the row, so its click selects the option and shuts the popover
78
+ * unless it is stopped. `edit` stops it. A caller assembling the two states
79
+ * themselves has to know that, and the version that does not know it looks
80
+ * exactly right until it is clicked.
81
+ *
82
+ * ### What is taken away from the list while editing, and by whom
83
+ *
84
+ * The Vue half is fighting reka; this one is fighting cmdk, and the two land on
85
+ * very nearly the same list:
86
+ *
87
+ * - **The click.** cmdk's `CommandItem` calls `onSelect` on `click`, and a
88
+ * single-select combobox turns a selection into `setOpen(false)`. Clicking
89
+ * into the field is a click on the row, so the popover closed under the
90
+ * cursor that opened it.
91
+ * - **`Enter`.** cmdk's `Command` dispatches a select on the highlighted row,
92
+ * which is the same close by another route. Here it is what saves the edit.
93
+ * - **`ArrowUp` / `ArrowDown` / `Home` / `End`.** All four are
94
+ * `preventDefault()`ed by `Command`, so the caret could not be moved.
95
+ * - **`pointermove`.** `CommandItem` moves the highlight onto the row under the
96
+ * cursor.
97
+ * - **`Space`** is in the list for the Vue half's sake — reka's `ListboxItem`
98
+ * selects on it *with `prevent`*, so a name with two words in it could not be
99
+ * typed. cmdk leaves the space bar alone; stopping it here costs nothing and
100
+ * keeps one list of claimed keys instead of two that drift.
101
+ *
102
+ * `Escape` is deliberately absent and is answered in `ComboboxContent`. See
103
+ * `useComboboxEditing` for why it cannot be answered here.
104
+ *
105
+ * ### Focus
106
+ *
107
+ * Nothing in this half steals focus the way reka's listbox can, so there is no
108
+ * equivalent of the `focusable` flag the Vue port suspends and restores:
109
+ * Radix's popover is non-modal and `onOpenAutoFocus` is already prevented,
110
+ * cmdk's highlight is an `aria-activedescendant` rather than a real focus move,
111
+ * and its one refocusing path fires only when the active element is cmdk's own
112
+ * input or root — never a field inside a row. What is left is the same on both
113
+ * sides: take focus on entering the edit, hand it back to the combobox's own
114
+ * field on leaving.
115
+ *
116
+ * **A dialog around the combobox is free here and was not in Vue.** A dialog
117
+ * traps focus, the popover is portalled to `body` and is therefore outside what
118
+ * the trap considers the dialog, so the `.focus()` below reads as focus
119
+ * escaping — unless a nearer focus layer has suspended the trap.
120
+ * `Popover.Content` registers one in every Radix build, untrapped when the
121
+ * popover is non-modal, which ours is. reka gives `SelectContentImpl`,
122
+ * `PopoverContentImpl` and `MenuContentImpl` a `FocusScope` and
123
+ * `ComboboxContentImpl` none, so the Vue `ComboboxContent` has to add the layer
124
+ * by hand to reach the behaviour this side gets for nothing.
125
+ *
126
+ * **One thing here has no Vue counterpart.** cmdk re-sorts the option elements
127
+ * by moving the DOM nodes themselves whenever the search term changes, and a
128
+ * focused field inside a row that gets reparented loses focus. Typing in the
129
+ * combobox's own search box while a row edit is open is therefore not the same
130
+ * experience in the two packages. Editing is reached by clicking a control in
131
+ * the row, which leaves the search box unfocused, so it takes a deliberate
132
+ * detour to hit.
133
+ */
134
+ export declare const ComboboxItemEdit: import('react').ForwardRefExoticComponent<ComboboxItemEditProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -1,3 +1,4 @@
1
+ import { ComboboxEditing } from './useComboboxEditing.ts';
1
2
  /**
2
3
  * Shared Combobox state.
3
4
  *
@@ -6,7 +7,7 @@
6
7
  * every part needs — the value, `multiple`, `disabled` and the search term — so
7
8
  * a part can be used on its own without threading props through the tree.
8
9
  */
9
- export interface ComboboxContextValue {
10
+ export interface ComboboxContextValue extends ComboboxEditing {
10
11
  /** Current selection. `string` for single-select, `string[]` for multiple. */
11
12
  value: string | string[] | undefined;
12
13
  /** Commit a selection (toggles for `multiple`). */
@@ -21,6 +22,12 @@ export interface ComboboxContextValue {
21
22
  /** Search string driving cmdk filtering. */
22
23
  search: string;
23
24
  setSearch: (search: string) => void;
25
+ /** Typing: restart the quiet period before the root's `onSearch`. */
26
+ scheduleSearch: (term: string) => void;
27
+ /** A gesture that settles the term — clearing it. Report now. */
28
+ searchImmediately: (term: string) => void;
29
+ /** Whether cmdk should leave the rendered options alone. */
30
+ skipFilter: boolean;
24
31
  /**
25
32
  * The text each option renders, keyed by the value it selects, so the field
26
33
  * can show `Barcelona` rather than `barcelona`. See `useComboboxLabels` for
@@ -28,6 +35,12 @@ export interface ComboboxContextValue {
28
35
  */
29
36
  registerLabel: (value: string, label: string) => void;
30
37
  labelFor: (value: string) => string | undefined;
38
+ /**
39
+ * The field itself, so a row that took focus for an in-place edit can hand it
40
+ * back when the edit ends. reka carries the same element on its own combobox
41
+ * context, which is where the Vue half gets it.
42
+ */
43
+ inputRef: React.RefObject<HTMLInputElement | null>;
31
44
  }
32
45
  export declare const ComboboxContext: import('react').Context<ComboboxContextValue | null>;
33
46
  export declare function useComboboxContext(): ComboboxContextValue;
@@ -4,6 +4,7 @@ export { ComboboxInput, type ComboboxInputProps } from './ComboboxInput.tsx';
4
4
  export { ComboboxChipsInput, type ComboboxChipsInputProps, } from './ComboboxChipsInput.tsx';
5
5
  export { ComboboxContent, type ComboboxContentProps, } from './ComboboxContent.tsx';
6
6
  export { ComboboxItem, type ComboboxItemProps } from './ComboboxItem.tsx';
7
+ export { ComboboxItemEdit, type ComboboxItemEditProps, } from './ComboboxItemEdit.tsx';
7
8
  export { ComboboxEmpty, type ComboboxEmptyProps } from './ComboboxEmpty.tsx';
8
9
  export { ComboboxGroup, type ComboboxGroupProps } from './ComboboxGroup.tsx';
9
10
  export { ComboboxSeparator, type ComboboxSeparatorProps, } from './ComboboxSeparator.tsx';
@@ -0,0 +1,40 @@
1
+ export interface ComboboxEditing {
2
+ /** The row entering its editing state announces how to back out of it. */
3
+ openEdit: (cancel: () => void) => void;
4
+ /** The row leaving its editing state withdraws that offer. */
5
+ closeEdit: (cancel: () => void) => void;
6
+ /**
7
+ * Back out of the open edit, if there is one. Returns whether there was —
8
+ * the caller uses that to decide whether the keystroke has been spent.
9
+ */
10
+ cancelOpenEdit: () => boolean;
11
+ }
12
+ /**
13
+ * Which row, if any, is currently being edited in place. Port of
14
+ * `core/src/Forms/Inputs/Combobox/useComboboxEditing`, where Vue's
15
+ * `provide`/`inject` does what this hook plus `ComboboxContext` do here.
16
+ *
17
+ * It exists for one keystroke. `Escape` inside the edit has to cancel the edit
18
+ * and leave the list open, and the only thing that can stop the list closing is
19
+ * the content's `onEscapeKeyDown`: Radix's dismissable layer listens on
20
+ * `document` with `capture: true`, so the editing field never sees the key
21
+ * first and cannot swallow it however hard it tries. The layer offers exactly
22
+ * one way out — `preventDefault()` on the event it hands up. So the content is
23
+ * where `Escape` has to be answered, the state is in the row, and this is the
24
+ * wire between them.
25
+ *
26
+ * The Vue half reaches the same arrangement from the opposite constraint: reka
27
+ * listens on `window` in the bubble phase, so there the field *would* see the
28
+ * key first, and handling it in both places would close the edit before the
29
+ * content was asked whether to prevent the dismissal — closing the list, which
30
+ * is the one thing this must not do. One mechanism, in the content, on both
31
+ * sides.
32
+ *
33
+ * A ref rather than state: nothing renders differently for knowing which row is
34
+ * open, and the only reader is an event handler, which wants the current value
35
+ * and not the one captured when it was last rendered.
36
+ *
37
+ * One edit at a time, and opening a second cancels the first: two rows in edit
38
+ * mode have two answers to `Escape` and no way to say which one the user meant.
39
+ */
40
+ export declare function useComboboxEditing(): ComboboxEditing;
@@ -0,0 +1,20 @@
1
+ export interface ComboboxSearch {
2
+ /** Typing: restart the quiet period, emit when it elapses. */
3
+ schedule: (term: string) => void;
4
+ /** A gesture that settles the term — clearing it. Emit now. */
5
+ immediately: (term: string) => void;
6
+ }
7
+ /**
8
+ * The wire between whichever field is typed into and the root's `onSearch`.
9
+ *
10
+ * The root is where `debounce` and `onSearch` belong — there are three fields
11
+ * (`ComboboxInput`, `ComboboxChipsInput`, and `ComboboxCancel` clearing one of
12
+ * them) and a prop on each would be the same number asked three times. The
13
+ * fields reach it through the shared context, beside `setSearch`.
14
+ *
15
+ * The fields report from their `onChange` rather than from the term itself,
16
+ * because the term is also written when a value is selected — the field is
17
+ * reset and the resolved label put in its place — and a search fired for the
18
+ * text of the option the user just picked is a request nobody asked for.
19
+ */
20
+ export declare function useComboboxSearch(debounce: number, onSearch: ((term: string) => void) | undefined): ComboboxSearch;
@@ -6,14 +6,14 @@ export interface SearchBarProps extends Omit<React.InputHTMLAttributes<HTMLInput
6
6
  * Milliseconds of no typing before `onSearch` fires. `0` fires on every
7
7
  * keystroke.
8
8
  */
9
- delay?: number;
9
+ debounce?: number;
10
10
  /** Controlled term. Pair with `onValueChange`; omit for uncontrolled. */
11
11
  value?: string;
12
12
  /** Starting term when uncontrolled. */
13
13
  defaultValue?: string;
14
14
  /** Called on every keystroke with the next term, without waiting. */
15
15
  onValueChange?: (value: string) => void;
16
- /** Called once typing has been quiet for `delay` ms — and at once on Enter or clear. */
16
+ /** Called once typing has been quiet for `debounce` ms — and at once on Enter or clear. */
17
17
  onSearch?: (term: string) => void;
18
18
  dataTestid: string;
19
19
  }
@@ -1,8 +1,6 @@
1
1
  import { VariantProps } from 'class-variance-authority';
2
2
  export { SearchBar } from './SearchBar.tsx';
3
3
  export type { SearchBarProps } from './SearchBar.tsx';
4
- export { useSearchDelay } from './useSearchDelay.ts';
5
- export type { UseSearchDelayReturn } from './useSearchDelay.ts';
6
4
  /**
7
5
  * Class names, not utilities — see `Button/index.ts` for why the package
8
6
  * cannot publish `.h-10` and `.rounded-lg` of its own. `SearchBar.module.css`
@@ -2,7 +2,10 @@ import { CardVariants } from './index.ts';
2
2
  export interface CardProps extends React.HTMLAttributes<HTMLDivElement> {
3
3
  /** Render as the child element instead of a `<div>` (Radix Slot). */
4
4
  asChild?: boolean;
5
- /** Which surface it is: `default` is white, `muted` is tinted. */
5
+ /**
6
+ * Which surface it is: `default` is white, `muted` is tinted, `highlighted`
7
+ * is filled with the brand colour and carries its own light text.
8
+ */
6
9
  tone?: CardVariants['tone'];
7
10
  /** Drops the border, the shadow and the glass — just the surface and its radius. */
8
11
  flat?: boolean;
@@ -3,9 +3,15 @@ export { Card, type CardProps } from './Card.tsx';
3
3
  /**
4
4
  * Two things vary, and they are not the same thing.
5
5
  *
6
- * `tone` is which surface it is: white, or tinted for the case the white one
7
- * cannot serve. White on white needs a border around every row to read as
8
- * separate things; a tinted surface lets the white ones separate on their own.
6
+ * `tone` is which surface it is: white, tinted for the case the white one
7
+ * cannot serve, or filled with the brand colour when the card is the one thing
8
+ * on the page meant to be looked at first. White on white needs a border around
9
+ * every row to read as separate things; a tinted surface lets the white ones
10
+ * separate on their own.
11
+ *
12
+ * `highlighted` is the only tone that also sets a text colour, because it is
13
+ * the only one whose surface is dark enough to need it. Everything inside
14
+ * inherits it, so the content composes exactly as it would on a white card.
9
15
  *
10
16
  * `flat` is what it carries on top of that surface. They are kept apart
11
17
  * because the combinations are all real: a white card over a tinted one, a
@@ -16,6 +22,6 @@ export { Card, type CardProps } from './Card.tsx';
16
22
  * styles keyed off `data-flat` rather than being bent into one.
17
23
  */
18
24
  export declare const cardVariants: (props?: ({
19
- tone?: "default" | "muted" | null | undefined;
25
+ tone?: "default" | "muted" | "highlighted" | null | undefined;
20
26
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
21
27
  export type CardVariants = VariantProps<typeof cardVariants>;
@@ -0,0 +1,27 @@
1
+ import { RefObject } from 'react';
2
+ /**
3
+ * Moves the selected pill over whichever tab is active.
4
+ *
5
+ * The selected state used to be a background on the trigger itself, which is
6
+ * why it could not travel: two elements cannot transition into one another. So
7
+ * the pill is a single element in the track, taken out of flow, and what moves
8
+ * is its geometry — published as custom properties on the track
9
+ * (`--toggle-tabs-pill-x/y/width/height`) for the stylesheet to spend.
10
+ *
11
+ * The handoff is the point. Nothing here decides how the pill is drawn: no
12
+ * `transform` string, no radius, no colour, no orientation branch. This writes
13
+ * four numbers and the component's own rule composes them, which keeps a
14
+ * measurement out of the stylesheet's job and the stylesheet's job out of here
15
+ * — and means the vertical orientation needs no code, only the `y` that is
16
+ * already being written.
17
+ *
18
+ * Both axes always, for that reason: `data-orientation="vertical"` turns the
19
+ * track into a column and the pill then travels down it, measured by exactly
20
+ * the same two rectangles.
21
+ *
22
+ * The whole of it runs off observers rather than off the render, which is what
23
+ * lets it be a single effect with no dependency on the active value: a tab
24
+ * changing, a tab arriving and a tab being resized are all DOM events by the
25
+ * time they matter here.
26
+ */
27
+ export declare function useToggleTabsPill(track: RefObject<HTMLElement | null>): void;
@@ -8,5 +8,7 @@
8
8
  * sibling's folder and a reader having to know that `Textarea`'s sizing is
9
9
  * really `ChatInput`'s. See `.claude/rules/component-architecture.md` §13.
10
10
  */
11
- export { useAutoGrow } from './useAutoGrow.ts';
12
- export type { UseAutoGrowReturn } from './useAutoGrow.ts';
11
+ export { useAutoGrow } from './useAutoGrow/useAutoGrow.ts';
12
+ export type { UseAutoGrowReturn } from './useAutoGrow/useAutoGrow.ts';
13
+ export { useSearchDebounce } from './useSearchDebounce/useSearchDebounce.ts';
14
+ export type { UseSearchDebounceReturn } from './useSearchDebounce/useSearchDebounce.ts';
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * The quiet period between typing and searching — mirrors
3
- * `@sesame/orxata-core` `useSearchDelay`.
3
+ * `@sesame/orxata-core` `useSearchDebounce`.
4
4
  *
5
5
  * A search field that emits on every keystroke turns "Marie" into five
6
6
  * requests, four of which are already stale by the time they land. Waiting for
@@ -13,7 +13,7 @@
13
13
  * drops whatever `schedule` had pending, which would otherwise fire a moment
14
14
  * later with a term the user has already moved on from.
15
15
  */
16
- export interface UseSearchDelayReturn {
16
+ export interface UseSearchDebounceReturn {
17
17
  /** Restart the quiet period; emit when it elapses. */
18
18
  schedule: (term: string) => void;
19
19
  /** Emit now, dropping anything pending. */
@@ -21,4 +21,4 @@ export interface UseSearchDelayReturn {
21
21
  /** Drop anything pending without emitting. */
22
22
  cancel: () => void;
23
23
  }
24
- export declare const useSearchDelay: (delay: number, emit: (term: string) => void) => UseSearchDelayReturn;
24
+ export declare const useSearchDebounce: (debounce: number, emit: (term: string) => void) => UseSearchDebounceReturn;
package/dist/main.d.ts CHANGED
@@ -17,7 +17,7 @@ export { Scrollbar as OxScrollbar, useScrollbar, SCROLLBAR_THICKNESS, type Scrol
17
17
  export { LocaleProvider as OxLocaleProvider } from './Locale/index.ts';
18
18
  export { normalizeLocale, useLocale } from './Locale/index.ts';
19
19
  export { AvatarRounded as OxAvatarRounded, AvatarSkeleton as OxAvatarSkeleton, AvatarSquare as OxAvatarSquare, avatarRoundedVariants, avatarSquareVariants, type AvatarRoundedVariants, type AvatarSize, type AvatarSquareVariants, type AvatarTone, } from './Display/Avatar/index.ts';
20
- export { AvatarDetails as OxAvatarDetails } from './Display/AvatarDetails/index.ts';
20
+ export { AvatarDetails as OxAvatarDetails, type AvatarDetailsAvatar, } from './Display/AvatarDetails/index.ts';
21
21
  export { AvatarGroup as OxAvatarGroup, type AvatarItem, } from './Display/AvatarGroup/index.ts';
22
22
  export { Badge as OxBadge, badgeVariants, type BadgeVariants, } from './Display/Badge/index.ts';
23
23
  export { CalendarDate as OxCalendarDate, calendarDateVariants, type CalendarDateVariants, } from './Display/CalendarDate/index.ts';
@@ -44,6 +44,6 @@ export { PageControl as OxPageControl, pageControlDots, PAGE_CONTROL_WINDOW, typ
44
44
  export { Breadcrumb as OxBreadcrumb, BreadcrumbList as OxBreadcrumbList, BreadcrumbItem as OxBreadcrumbItem, BreadcrumbLink as OxBreadcrumbLink, BreadcrumbPage as OxBreadcrumbPage, BreadcrumbSeparator as OxBreadcrumbSeparator, BreadcrumbEllipsis as OxBreadcrumbEllipsis, } from './Navigation/Breadcrumb/index.ts';
45
45
  export { Counter as OxCounter, counterVariants, type CounterVariants, } from './Forms/Field/Counter/index.ts';
46
46
  export { FieldGroup as OxFieldGroup, FieldLabel as OxFieldLabel, FieldMessage as OxFieldMessage, useFieldControl, useFieldControlGroup, type FieldControlAttrs, type FieldControlGroupAttrs, type FieldGroupProps, type FieldVariant, } from './Forms/Field/index.ts';
47
- export { InputGroup as OxInputGroup, InputText as OxInputText, InputNumber as OxInputNumber, InputNumberContent as OxInputNumberContent, InputNumberDecrement as OxInputNumberDecrement, InputNumberIncrement as OxInputNumberIncrement, InputNumberInput as OxInputNumberInput, InputPassword as OxInputPassword, InputPasswordInput as OxInputPasswordInput, InputPasswordToggle as OxInputPasswordToggle, useInputPassword, InputOtp as OxInputOtp, InputOtpGroup as OxInputOtpGroup, InputOtpSlot as OxInputOtpSlot, InputOtpSeparator as OxInputOtpSeparator, useInputOtp, Calendar as OxCalendar, CalendarRange as OxCalendarRange, CalendarDay as OxCalendarDay, calendarDayVariants, Combobox as OxCombobox, ComboboxCancel as OxComboboxCancel, ComboboxInput as OxComboboxInput, ComboboxChipsInput as OxComboboxChipsInput, ComboboxContent as OxComboboxContent, ComboboxItem as OxComboboxItem, ComboboxEmpty as OxComboboxEmpty, ComboboxGroup as OxComboboxGroup, ComboboxSeparator as OxComboboxSeparator, ChatInput as OxChatInput, DatePicker as OxDatePicker, DateRangePicker as OxDateRangePicker, DatePickerTrigger as OxDatePickerTrigger, DatePickerHeader as OxDatePickerHeader, DatePickerMonthSelect as OxDatePickerMonthSelect, DatePickerYearSelect as OxDatePickerYearSelect, SearchBar as OxSearchBar, searchBarVariants, useSearchDelay, SearchPanel as OxSearchPanel, SearchPanelInput as OxSearchPanelInput, SearchPanelList as OxSearchPanelList, SearchPanelGroup as OxSearchPanelGroup, SearchPanelItem as OxSearchPanelItem, SearchPanelEmpty as OxSearchPanelEmpty, Select as OxSelect, SelectTrigger as OxSelectTrigger, SelectContent as OxSelectContent, SelectItem as OxSelectItem, SelectGroup as OxSelectGroup, SelectSeparator as OxSelectSeparator, Textarea as OxTextarea, Switch as OxSwitch, Checkbox as OxCheckbox, RadioButton as OxRadioButton, RadioGroup as OxRadioGroup, ToggleGroup as OxToggleGroup, ToggleLabel as OxToggleLabel, ToggleDescription as OxToggleDescription, SWITCH_SIZES, type InputNumberProps, type InputPasswordProps, type InputPasswordContext, type InputOtpProps, type InputOtpSlotProps, type InputOtpContext, type CalendarProps, type CalendarRangeProps, type CalendarDateRange, type CalendarDayProps, type CalendarDayState, type CalendarDayVariants, type CalendarConstraints, type CalendarNav, type ComboboxProps, type ChatInputActionLabels, type ChatInputState, type DatePickerProps, type DateRangePickerProps, type DatePickerTriggerProps, type DatePickerHeaderProps, type DatePickerMonthSelectProps, type DatePickerYearSelectProps, type SearchBarVariants, type UseSearchDelayReturn, type SelectProps, type TextareaCounterState, type RadioGroupProps, type ToggleGroupProps, type ToggleLabelProps, type ToggleDescriptionProps, } from './Forms/Inputs/index.ts';
47
+ export { InputGroup as OxInputGroup, InputText as OxInputText, InputNumber as OxInputNumber, InputNumberContent as OxInputNumberContent, InputNumberDecrement as OxInputNumberDecrement, InputNumberIncrement as OxInputNumberIncrement, InputNumberInput as OxInputNumberInput, InputPassword as OxInputPassword, InputPasswordInput as OxInputPasswordInput, InputPasswordToggle as OxInputPasswordToggle, useInputPassword, InputOtp as OxInputOtp, InputOtpGroup as OxInputOtpGroup, InputOtpSlot as OxInputOtpSlot, InputOtpSeparator as OxInputOtpSeparator, useInputOtp, Calendar as OxCalendar, CalendarRange as OxCalendarRange, CalendarDay as OxCalendarDay, calendarDayVariants, Combobox as OxCombobox, ComboboxCancel as OxComboboxCancel, ComboboxInput as OxComboboxInput, ComboboxChipsInput as OxComboboxChipsInput, ComboboxContent as OxComboboxContent, ComboboxItem as OxComboboxItem, ComboboxItemEdit as OxComboboxItemEdit, ComboboxEmpty as OxComboboxEmpty, ComboboxGroup as OxComboboxGroup, ComboboxSeparator as OxComboboxSeparator, ChatInput as OxChatInput, DatePicker as OxDatePicker, DateRangePicker as OxDateRangePicker, DatePickerTrigger as OxDatePickerTrigger, DatePickerHeader as OxDatePickerHeader, DatePickerMonthSelect as OxDatePickerMonthSelect, DatePickerYearSelect as OxDatePickerYearSelect, SearchBar as OxSearchBar, searchBarVariants, SearchPanel as OxSearchPanel, SearchPanelInput as OxSearchPanelInput, SearchPanelList as OxSearchPanelList, SearchPanelGroup as OxSearchPanelGroup, SearchPanelItem as OxSearchPanelItem, SearchPanelEmpty as OxSearchPanelEmpty, Select as OxSelect, SelectTrigger as OxSelectTrigger, SelectContent as OxSelectContent, SelectItem as OxSelectItem, SelectGroup as OxSelectGroup, SelectSeparator as OxSelectSeparator, Textarea as OxTextarea, Switch as OxSwitch, Checkbox as OxCheckbox, RadioButton as OxRadioButton, RadioGroup as OxRadioGroup, ToggleGroup as OxToggleGroup, ToggleLabel as OxToggleLabel, ToggleDescription as OxToggleDescription, SWITCH_SIZES, type InputNumberProps, type InputPasswordProps, type InputPasswordContext, type InputOtpProps, type InputOtpSlotProps, type InputOtpContext, type CalendarProps, type CalendarRangeProps, type CalendarDateRange, type CalendarDayProps, type CalendarDayState, type CalendarDayVariants, type CalendarConstraints, type CalendarNav, type ComboboxProps, type ChatInputActionLabels, type ChatInputState, type DatePickerProps, type DateRangePickerProps, type DatePickerTriggerProps, type DatePickerHeaderProps, type DatePickerMonthSelectProps, type DatePickerYearSelectProps, type SearchBarVariants, type SelectProps, type TextareaCounterState, type RadioGroupProps, type ToggleGroupProps, type ToggleLabelProps, type ToggleDescriptionProps, } from './Forms/Inputs/index.ts';
48
48
  export { Table as OxTable, TableVirtualized as OxTableVirtualized, TableHead as OxTableHead, TableBody as OxTableBody, TableRow as OxTableRow, TableCell as OxTableCell, TableHeaderCell as OxTableHeaderCell, TableSelectCell as OxTableSelectCell, TableDragCell as OxTableDragCell, TableBulkHeader as OxTableBulkHeader, TablePagination as OxTablePagination, TableEmpty as OxTableEmpty, TableRowExpanded as OxTableRowExpanded, TableExpandCell as OxTableExpandCell, TableColumnVisibility as OxTableColumnVisibility, useTable, useTableSelection, useTableSorting, useTablePagination, useTableDetailRow, useTablePinning, useTableColumns, useScrollShadow, useDragToScroll, useFixedColumns, useTableVirtual, } from './Data/Table/index.ts';
49
49
  export type { UseTableOptions, UseTableReturn, UseTableSelectionReturn, UseTableSortingReturn, UseTablePaginationOptions, UseTablePaginationReturn, DetailRowInstance, DetailRowOptions, DetailRowPluginDef, UseTablePinningOptions, UseTablePinningReturn, CellInfo, HeaderInfo, UseTableVirtualOptions, UseTableVirtualReturn, UseTableColumnsOptions, UseTableColumnsReturn, UseScrollShadowOptions, UseScrollShadowReturn, UseDragToScrollOptions, UseDragToScrollReturn, UseFixedColumnsOptions, TableProps, TableMode, ColumnDef, ColumnAlign, CellContext, SortingState, PaginationState, PaginationChangePayload, SortingChangePayload, SelectionChangePayload, FilterChangePayload, ColumnResizeMode, ColumnVisibilityState, ColumnOrderState, ExpandedState, ColumnVisibilityChangePayload, ColumnOrderChangePayload, RowExpandChangePayload, ColumnResizePayload, ColumnPinningState, } from './Data/Table/index.ts';