@sesamehr/react-design-system 2.0.0-beta.5 → 2.0.0-beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/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/TableScrollbar/TableScrollbar.d.ts +5 -3
- package/dist/Data/Table/index.d.ts +0 -1
- 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 +31 -0
- package/dist/Display/AvatarDetails/index.d.ts +1 -0
- package/dist/Display/ChatBubble/ChatBubbleStatus/ChatBubbleStatus.d.ts +2 -2
- package/dist/Display/Chip/Chip.d.ts +7 -1
- package/dist/Display/Chip/index.d.ts +9 -4
- 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 +7 -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/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 +5 -0
- 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/context.d.ts +7 -0
- package/dist/Forms/Inputs/Combobox/index.d.ts +1 -0
- package/dist/Forms/Inputs/Combobox/useChipOverflow.d.ts +30 -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 +42 -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 +6 -0
- 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/main.d.ts +14 -5
- package/dist/react-design-system.css +1 -1
- package/dist/react-design-system.js +15882 -10862
- package/dist/react-design-system.umd.cjs +162 -128
- package/package.json +3 -2
- package/dist/Data/Table/TableAvatar/TableAvatar.d.ts +0 -14
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CommandGroup } from 'cmdk';
|
|
2
|
+
export interface SearchPanelGroupProps extends React.ComponentPropsWithoutRef<typeof CommandGroup> {
|
|
3
|
+
/** The heading above the rows. Anything renderable, and always the caller's. */
|
|
4
|
+
label?: React.ReactNode;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* A heading and the rows under it.
|
|
8
|
+
*
|
|
9
|
+
* Nothing here knows what the heading might say. "Documents", "Recent
|
|
10
|
+
* conversations", "People" are one application's categories on one day; a
|
|
11
|
+
* design system that shipped an enum of them would be wrong by the following
|
|
12
|
+
* release, and wrong for every other application immediately.
|
|
13
|
+
*/
|
|
14
|
+
export declare const SearchPanelGroup: import('react').ForwardRefExoticComponent<SearchPanelGroupProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { CommandInput } from 'cmdk';
|
|
2
|
+
export type SearchPanelInputProps = Omit<React.ComponentPropsWithoutRef<typeof CommandInput>, 'asChild'>;
|
|
3
|
+
/**
|
|
4
|
+
* Joins the caller's search field to the list's keyboard.
|
|
5
|
+
*
|
|
6
|
+
* Put exactly one control inside — `OxSearchBar` is the intended one, since it
|
|
7
|
+
* already owns the debounce. `asChild` hands it the arrow/Home/End/Enter
|
|
8
|
+
* handlers and `aria-activedescendant`, so the highlight moves through the
|
|
9
|
+
* rows while focus never leaves the field. Radix's `Slot`, which cmdk uses,
|
|
10
|
+
* throws on a second child rather than quietly merging onto the first.
|
|
11
|
+
*
|
|
12
|
+
* This renders no field of its own on purpose. A results panel is a way of
|
|
13
|
+
* showing what a search found, not a second opinion about what a search box
|
|
14
|
+
* looks like.
|
|
15
|
+
*
|
|
16
|
+
* It does render the row the field sits in, which is a different thing: the
|
|
17
|
+
* design draws a padded title row across the top of the panel, and `asChild`
|
|
18
|
+
* alone would have put that padding on the caller's search bar — where it would
|
|
19
|
+
* have moved the field's own border in from the panel edge instead of insetting
|
|
20
|
+
* the row.
|
|
21
|
+
*
|
|
22
|
+
* Two things cmdk decides that the field cannot override, because it writes
|
|
23
|
+
* them *after* the spread: the control becomes `type="text"` rather than
|
|
24
|
+
* `type="search"`, and it is given `role="combobox"` with `aria-controls` and
|
|
25
|
+
* `aria-activedescendant`. Neither is a problem — the only thing `type=search`
|
|
26
|
+
* adds is the browser's own clear button, which `OxSearchBar` hides and
|
|
27
|
+
* redraws anyway, and a text field that owns a list of options is what the
|
|
28
|
+
* combobox role is for, whatever the panel above it is called. It is a real
|
|
29
|
+
* difference from the Vue port, where the field keeps `type="search"`.
|
|
30
|
+
*/
|
|
31
|
+
export declare const SearchPanelInput: import('react').ForwardRefExoticComponent<SearchPanelInputProps & import('react').RefAttributes<HTMLInputElement>>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { CommandItem } from 'cmdk';
|
|
2
|
+
export interface SearchPanelItemProps extends Omit<React.ComponentPropsWithoutRef<typeof CommandItem>, 'value' | 'onSelect'> {
|
|
3
|
+
/** Handed back through the panel's `onSelect`. Unique within the panel. */
|
|
4
|
+
value: string;
|
|
5
|
+
disabled?: boolean;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* One result. Choosing it makes the panel call `onSelect` with this `value`.
|
|
9
|
+
*
|
|
10
|
+
* No check indicator, and that is the point: nothing here is selected in the
|
|
11
|
+
* sense a `Select` option is. The row is a thing you run, so it never becomes
|
|
12
|
+
* the panel's current answer and never grows a tick beside it. The shared row
|
|
13
|
+
* only leaves room on the right when an indicator is passed, so these sit
|
|
14
|
+
* flush.
|
|
15
|
+
*
|
|
16
|
+
* Whatever goes inside is the caller's — an icon and a label, an avatar and
|
|
17
|
+
* two lines, a filename and a size. `value` is the only thing this package
|
|
18
|
+
* wants, and only so it has something to hand back.
|
|
19
|
+
*/
|
|
20
|
+
export declare const SearchPanelItem: import('react').ForwardRefExoticComponent<SearchPanelItemProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { CommandList } from 'cmdk';
|
|
2
|
+
export type SearchPanelListProps = React.ComponentPropsWithoutRef<typeof CommandList>;
|
|
3
|
+
/**
|
|
4
|
+
* The scrolling list of groups and rows — `role="listbox"` and the rows in it —
|
|
5
|
+
* on a card that floats over the page.
|
|
6
|
+
*
|
|
7
|
+
* **It floats, and that is the point.** In the flow it pushed everything below
|
|
8
|
+
* the panel down the moment an answer landed, which is not what a dropdown does
|
|
9
|
+
* and is disqualifying for a search that lives in a header. The card is
|
|
10
|
+
* positioned by Radix's popper against the anchor `SearchPanel` wraps around
|
|
11
|
+
* itself, so it is exactly the field's width, it flips above the field when
|
|
12
|
+
* there is no room below, and it is `position: fixed` — no ancestor's
|
|
13
|
+
* `overflow` can clip it.
|
|
14
|
+
*
|
|
15
|
+
* **No portal, and that is also the point.** Everything the keyboard is made of
|
|
16
|
+
* is a relationship between this list and the field above it: cmdk gathers the
|
|
17
|
+
* rows by querying the `Command` element they sit inside, `aria-activedescendant`
|
|
18
|
+
* on the field points at a row's `id`, and the panel's custom properties reach
|
|
19
|
+
* the rows by inheriting down the tree. A `Popover.Portal` would move the rows
|
|
20
|
+
* out of `Command` entirely, and the arrows would stop finding them.
|
|
21
|
+
* Popper-positioned content does not need a portal to escape the flow —
|
|
22
|
+
* `position: fixed` already does — so it does not get one.
|
|
23
|
+
*
|
|
24
|
+
* The two auto-focus events are prevented for the same reason. A popover
|
|
25
|
+
* focuses its content when it opens and hands focus back when it closes; both
|
|
26
|
+
* would take focus off the search field, which is the one thing the arrow keys
|
|
27
|
+
* depend on. `role="presentation"` and the blanked `aria-labelledby` finish the
|
|
28
|
+
* job: the primitive believes it is a dialog, a screen reader must not, and the
|
|
29
|
+
* name it points at belongs to a trigger this panel does not have. Radix
|
|
30
|
+
* spreads the caller's props *after* its own `role`, so saying so here is
|
|
31
|
+
* enough — the Vue port has to write the same two attributes one level further
|
|
32
|
+
* down, where reka merges last.
|
|
33
|
+
*/
|
|
34
|
+
export declare const SearchPanelList: import('react').ForwardRefExoticComponent<Omit<{
|
|
35
|
+
children?: React.ReactNode;
|
|
36
|
+
} & Pick<Pick<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "key" | keyof import('react').HTMLAttributes<HTMLDivElement>> & {
|
|
37
|
+
ref?: React.Ref<HTMLDivElement>;
|
|
38
|
+
} & {
|
|
39
|
+
asChild?: boolean;
|
|
40
|
+
}, "asChild" | "key" | keyof import('react').HTMLAttributes<HTMLDivElement>> & {
|
|
41
|
+
label?: string;
|
|
42
|
+
} & import('react').RefAttributes<HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export interface SearchPanelContextValue {
|
|
2
|
+
/** Called with a row's `value` when that row is chosen. */
|
|
3
|
+
select: (value: string) => void;
|
|
4
|
+
}
|
|
5
|
+
export declare const SearchPanelContext: import('react').Context<SearchPanelContextValue | null>;
|
|
6
|
+
/**
|
|
7
|
+
* The Vue port reaches the root through reka's own listbox context; React has
|
|
8
|
+
* no equivalent to inject, so the root publishes one. The error message
|
|
9
|
+
* matches the Vue side's on purpose.
|
|
10
|
+
*/
|
|
11
|
+
export declare const useSearchPanelContext: () => SearchPanelContextValue;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { SearchPanel, type SearchPanelProps } from './SearchPanel.tsx';
|
|
2
|
+
export { SearchPanelEmpty, type SearchPanelEmptyProps, } from './SearchPanelEmpty.tsx';
|
|
3
|
+
export { SearchPanelGroup, type SearchPanelGroupProps, } from './SearchPanelGroup.tsx';
|
|
4
|
+
export { SearchPanelInput, type SearchPanelInputProps, } from './SearchPanelInput.tsx';
|
|
5
|
+
export { SearchPanelItem, type SearchPanelItemProps, } from './SearchPanelItem.tsx';
|
|
6
|
+
export { SearchPanelList, type SearchPanelListProps, } from './SearchPanelList.tsx';
|
|
@@ -7,5 +7,11 @@ export interface SelectContentProps extends Omit<React.ComponentPropsWithoutRef<
|
|
|
7
7
|
/**
|
|
8
8
|
* The floating list. Always positioned against the trigger rather than over it,
|
|
9
9
|
* so the popup matches the trigger's width and never covers it.
|
|
10
|
+
*
|
|
11
|
+
* `asChild` hands the primitive's positioning, `data-state` and `data-side` to
|
|
12
|
+
* the shared `Surface`, which is the one element `Popover`, `Select`,
|
|
13
|
+
* `Combobox` and `SearchPanel` may have in common. Exactly one child sits at
|
|
14
|
+
* each slot position — Radix's `Slot` throws on a second, which is the whole
|
|
15
|
+
* reason the arrangement is safe to read at a glance.
|
|
10
16
|
*/
|
|
11
17
|
export declare const SelectContent: import('react').ForwardRefExoticComponent<SelectContentProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import * as SelectPrimitive from '@radix-ui/react-select';
|
|
2
2
|
export interface SelectGroupProps extends React.ComponentPropsWithoutRef<typeof SelectPrimitive.Group> {
|
|
3
|
-
/**
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The group heading. A node rather than a string: it is the caller's word
|
|
5
|
+
* for their own category, and taking it as text would decide for them that
|
|
6
|
+
* it can only ever be text.
|
|
7
|
+
*/
|
|
8
|
+
label?: React.ReactNode;
|
|
5
9
|
}
|
|
6
10
|
/** Groups related options under a heading, announced as a group label. */
|
|
7
11
|
export declare const SelectGroup: import('react').ForwardRefExoticComponent<SelectGroupProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -6,6 +6,12 @@ export interface SelectItemProps extends React.ComponentPropsWithoutRef<typeof S
|
|
|
6
6
|
/**
|
|
7
7
|
* A single option.
|
|
8
8
|
*
|
|
9
|
+
* `asChild` hands Radix's item behaviour — `role="option"`, `data-highlighted`,
|
|
10
|
+
* `data-state`, typeahead, selection — to the shared row, which is the one
|
|
11
|
+
* thing `Select`, `Combobox` and `SearchPanel` may share. The primitive
|
|
12
|
+
* itself is not shared: this one and `Combobox`'s wrap different roots and
|
|
13
|
+
* swapping them breaks the keyboard in both.
|
|
14
|
+
*
|
|
9
15
|
* The rendered text is published to the root on mount so the trigger's render
|
|
10
16
|
* prop can name the selection. Reading it off the DOM keeps arbitrary markup
|
|
11
17
|
* working, and it runs while the list is closed too: the primitive keeps items
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { ReactNode } from 'react';
|
|
2
|
+
import { TextareaCounterState } from './index.ts';
|
|
3
|
+
export interface TextareaProps extends Omit<React.TextareaHTMLAttributes<HTMLTextAreaElement>, 'rows' | 'children'> {
|
|
4
|
+
/**
|
|
5
|
+
* How tall the surface may grow before it starts to scroll, counted in lines
|
|
6
|
+
* of text.
|
|
7
|
+
*
|
|
8
|
+
* In rows rather than pixels so the cap moves with the line height instead
|
|
9
|
+
* of cutting a row in half the first time anyone changes the type scale. The
|
|
10
|
+
* default is the design's 100px box, which is four 20px lines inside its own
|
|
11
|
+
* padding.
|
|
12
|
+
*/
|
|
13
|
+
maxRows?: number;
|
|
14
|
+
/** Controlled value. Pair with `onFieldChange`; omit for uncontrolled. */
|
|
15
|
+
field?: string;
|
|
16
|
+
/** Called on every input with the next value. */
|
|
17
|
+
onFieldChange?: (value: string) => void;
|
|
18
|
+
/**
|
|
19
|
+
* Bottom-right inside the box. A node, or a render prop called with
|
|
20
|
+
* `{ value, length }` — the limit is the caller's business and the count is
|
|
21
|
+
* the value's, so neither is a prop.
|
|
22
|
+
*/
|
|
23
|
+
counter?: ReactNode | ((state: TextareaCounterState) => ReactNode);
|
|
24
|
+
dataTestid: string;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The multi-line field: a `<textarea>` in the same box the single-line
|
|
28
|
+
* controls draw, that grows with its content and then scrolls.
|
|
29
|
+
* Mirrors `@sesame/orxata-core` Textarea.
|
|
30
|
+
*
|
|
31
|
+
* **Not `OxChatInput`.** That one is a chat composer — it owns a send
|
|
32
|
+
* contract, Enter submits, and it draws two corners of action buttons around
|
|
33
|
+
* the text. This one is a form field: it has no idea what happens to the
|
|
34
|
+
* value, Enter inserts a newline, and it sits inside an `<OxFieldGroup>` with
|
|
35
|
+
* a label above it and a message below. Reach for `OxChatInput` when the value
|
|
36
|
+
* is a message being sent somewhere; reach for this when the value is an
|
|
37
|
+
* answer on a form. They share `useAutoGrow` and nothing else, which is the
|
|
38
|
+
* only part of the two that is genuinely the same problem.
|
|
39
|
+
*
|
|
40
|
+
* **The label and the message are not here, and that is the point.**
|
|
41
|
+
* `<OxFieldLabel>` and `<OxFieldMessage>` already exist, already order
|
|
42
|
+
* themselves around a control, and — through `useFieldControl` below — already
|
|
43
|
+
* carry the `id`, `aria-invalid` and `aria-describedby` that tie the three
|
|
44
|
+
* together. A `label` prop would be a second, worse spelling of a component
|
|
45
|
+
* that is already in the package, and the design system ships no strings
|
|
46
|
+
* anyway.
|
|
47
|
+
*
|
|
48
|
+
* ```tsx
|
|
49
|
+
* <OxFieldGroup variant="error">
|
|
50
|
+
* <OxFieldLabel>Notes</OxFieldLabel>
|
|
51
|
+
* <OxTextarea field={notes} onFieldChange={setNotes} dataTestid="notes" />
|
|
52
|
+
* <OxFieldMessage>Keep it under 100 characters.</OxFieldMessage>
|
|
53
|
+
* </OxFieldGroup>
|
|
54
|
+
* ```
|
|
55
|
+
*
|
|
56
|
+
* **`field` alone does not mean "controlled" — `field` *with* `onFieldChange`
|
|
57
|
+
* does.** The Vue original is a `defineModel`, and a `defineModel` only hands
|
|
58
|
+
* control to the parent when the parent actually listens; given a value and no
|
|
59
|
+
* listener it seeds its own state and goes on working. Port `field` as
|
|
60
|
+
* unconditionally controlled and the same usage becomes a field pinned to its
|
|
61
|
+
* initial value that silently will not accept a keystroke.
|
|
62
|
+
*
|
|
63
|
+
* The `ref` is the **textarea**, not the box — which is where it differs from
|
|
64
|
+
* `OxChatInput`, whose ref is its root. This is a form control: what a caller
|
|
65
|
+
* reaches for a ref to do is focus it, select in it, or hand it to a form
|
|
66
|
+
* library. `className` still lands on the box, since the box is what reads as
|
|
67
|
+
* the control.
|
|
68
|
+
*/
|
|
69
|
+
export declare const Textarea: import('react').ForwardRefExoticComponent<TextareaProps & import('react').RefAttributes<HTMLTextAreaElement>>;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export { Textarea, type TextareaProps } from './Textarea.tsx';
|
|
2
|
+
/**
|
|
3
|
+
* What the `counter` slot is handed.
|
|
4
|
+
*
|
|
5
|
+
* Both numbers come from the field rather than from the caller, so a counter
|
|
6
|
+
* works the same whether the value is controlled or left to the textarea — an
|
|
7
|
+
* uncontrolled field posting itself in a plain `<form>` has no value in the
|
|
8
|
+
* caller's scope to count.
|
|
9
|
+
*
|
|
10
|
+
* There is no `cva` here on purpose. `Textarea` has no variants: the design
|
|
11
|
+
* draws one box, and its states come from `OxFieldGroup` through the
|
|
12
|
+
* `--controller-*` properties rather than from a class this component picks.
|
|
13
|
+
* An empty variant map would be one more thing to keep in step across two
|
|
14
|
+
* packages in exchange for nothing.
|
|
15
|
+
*/
|
|
16
|
+
export interface TextareaCounterState {
|
|
17
|
+
/** The text the field holds now. */
|
|
18
|
+
value: string;
|
|
19
|
+
/** How many characters that is — what `<OxCounter>` wants for its `value`. */
|
|
20
|
+
length: number;
|
|
21
|
+
}
|
|
@@ -5,5 +5,10 @@ export interface RadioGroupProps extends React.ComponentPropsWithoutRef<typeof R
|
|
|
5
5
|
/**
|
|
6
6
|
* RadioGroup — built on `@radix-ui/react-radio-group`.
|
|
7
7
|
* `v-model` maps to Radix `value` / `onValueChange` (+ `defaultValue`).
|
|
8
|
+
*
|
|
9
|
+
* The group is what a field names, not the radios inside it: one id cannot sit
|
|
10
|
+
* on several `<button role="radio">`s at once, so `RadioButton` stays out of
|
|
11
|
+
* the field context and this root carries `aria-labelledby` instead. Radix
|
|
12
|
+
* gives it `role="radiogroup"`, which is what makes that name land.
|
|
8
13
|
*/
|
|
9
14
|
export declare const RadioGroup: import('react').ForwardRefExoticComponent<RadioGroupProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
export interface ToggleLabelProps extends React.LabelHTMLAttributes<HTMLLabelElement> {
|
|
2
2
|
htmlFor?: string;
|
|
3
3
|
}
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* ToggleLabel — mirrors `@sesame/orxata-core` ToggleLabel.
|
|
6
|
+
*
|
|
7
|
+
* `htmlFor` falls back to whichever control claimed the surrounding
|
|
8
|
+
* `<OxFieldGroup>`'s id, because the commonest checkbox layout in the system —
|
|
9
|
+
* a field wrapping an `<OxToggleGroup>` wrapping a toggle and this — would
|
|
10
|
+
* otherwise leave the toggle's own label naming nothing. It does not take the
|
|
11
|
+
* group's `labelId`: `OxFieldLabel` already carries that, and two elements
|
|
12
|
+
* cannot share an id.
|
|
13
|
+
*/
|
|
5
14
|
export declare const ToggleLabel: import('react').ForwardRefExoticComponent<ToggleLabelProps & import('react').RefAttributes<HTMLLabelElement>>;
|
|
@@ -3,6 +3,12 @@ export { InputText, type InputTextProps } from './InputText/InputText.tsx';
|
|
|
3
3
|
export * from './InputNumber/index.ts';
|
|
4
4
|
export * from './InputPassword/index.ts';
|
|
5
5
|
export * from './InputOtp/index.ts';
|
|
6
|
+
export * from './Calendar/index.ts';
|
|
6
7
|
export * from './Combobox/index.ts';
|
|
8
|
+
export * from './ChatInput/index.ts';
|
|
9
|
+
export * from './DatePicker/index.ts';
|
|
10
|
+
export * from './SearchBar/index.ts';
|
|
11
|
+
export * from './SearchPanel/index.ts';
|
|
7
12
|
export * from './Select/index.ts';
|
|
13
|
+
export * from './Textarea/index.ts';
|
|
8
14
|
export * from './Toggle/index.ts';
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ScrollbarPort } from './useScrollbar.ts';
|
|
2
|
+
export interface ScrollbarProps extends Omit<React.HTMLAttributes<HTMLDivElement>, 'children'> {
|
|
3
|
+
/**
|
|
4
|
+
* The element that scrolls. Everything is measured from it, and its native
|
|
5
|
+
* scrollbar is hidden for as long as this one is drawn over it.
|
|
6
|
+
*/
|
|
7
|
+
port?: ScrollbarPort;
|
|
8
|
+
dataTestid: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* An overlay scrollbar for a container that scrolls vertically, drawn instead
|
|
12
|
+
* of the browser's own. Mirrors `@sesame/orxata-core` Scrollbar.
|
|
13
|
+
*
|
|
14
|
+
* Reach for it where the native bar cannot say what it needs to say. A
|
|
15
|
+
* virtualised table is the case it was built for: the bar has to start below
|
|
16
|
+
* the column names, and the native one runs the full height of the scrollport
|
|
17
|
+
* because the scrollport contains the header. A chat composer that grows to a
|
|
18
|
+
* few lines and then scrolls is the other: a native bar there is a strip of
|
|
19
|
+
* system chrome inside a rounded box, and in the browsers that reserve a gutter
|
|
20
|
+
* it shifts the text sideways the moment the field overflows.
|
|
21
|
+
*
|
|
22
|
+
* It behaves the way an overlay bar does: out of the way until you scroll or
|
|
23
|
+
* reach for the edge, and gone again shortly after. The track takes no clicks —
|
|
24
|
+
* only the thumb does — so the strip down the right of the content stays live.
|
|
25
|
+
*
|
|
26
|
+
* **Placement is the parent's.** This positions itself absolutely inside the
|
|
27
|
+
* nearest positioned ancestor and reads four custom properties for where that
|
|
28
|
+
* is, all with fallbacks that spell "fill the containing block down its right
|
|
29
|
+
* edge": `--scrollbar-top` (`0px`), `--scrollbar-right` (`0px`),
|
|
30
|
+
* `--scrollbar-left` (`auto`) and `--scrollbar-height` (`100%`).
|
|
31
|
+
*
|
|
32
|
+
* A parent whose scrollport *is* the containing block sets none of them. One
|
|
33
|
+
* that has to compensate for something — a header inside the scrollport, an
|
|
34
|
+
* `offsetParent` that is not the scrollport — works the numbers out itself and
|
|
35
|
+
* writes them here, which is why none of that arithmetic is a prop.
|
|
36
|
+
*
|
|
37
|
+
* Vertical only, deliberately. Horizontal overflow is read from the content
|
|
38
|
+
* running out of room and from the shadows at the edges; nothing in the system
|
|
39
|
+
* wants a second bar, and adding one later takes nothing away.
|
|
40
|
+
*
|
|
41
|
+
* The bar is `aria-hidden`: it is a picture of a scroll position, and the
|
|
42
|
+
* scrollport it belongs to is already reachable and scrollable from the
|
|
43
|
+
* keyboard. `mousedown`/`mousemove` are what drive the thumb, so a coarse
|
|
44
|
+
* pointer gets nothing from it and keeps the native scrolling it already had.
|
|
45
|
+
*/
|
|
46
|
+
export declare const Scrollbar: import('react').ForwardRefExoticComponent<ScrollbarProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
/**
|
|
3
|
+
* The track's own width, `w-3`.
|
|
4
|
+
*
|
|
5
|
+
* Exported because a parent that places the bar by its *left* edge has to pull
|
|
6
|
+
* it back by the full width to sit inside the scrollport rather than alongside
|
|
7
|
+
* it, and the number it pulls back by has to be the one the stylesheet uses.
|
|
8
|
+
*/
|
|
9
|
+
export declare const SCROLLBAR_THICKNESS = 12;
|
|
10
|
+
/**
|
|
11
|
+
* The element that scrolls, as a ref or as the element itself. A ref because
|
|
12
|
+
* that is what a parent normally has, and a `useRef` never re-renders anything
|
|
13
|
+
* when it fills in.
|
|
14
|
+
*/
|
|
15
|
+
export type ScrollbarPort = RefObject<HTMLElement | null> | HTMLElement | null | undefined;
|
|
16
|
+
export interface UseScrollbarReturn {
|
|
17
|
+
/** Shown while scrolling, while dragging, and near the right edge. */
|
|
18
|
+
visible: boolean;
|
|
19
|
+
/** The thumb is being dragged. */
|
|
20
|
+
dragging: boolean;
|
|
21
|
+
/** The pointer is in the strip the bar occupies, so the bar widens. */
|
|
22
|
+
near: boolean;
|
|
23
|
+
/** Where the thumb goes, in pixels. A height of zero means no thumb at all. */
|
|
24
|
+
thumb: {
|
|
25
|
+
top: number;
|
|
26
|
+
height: number;
|
|
27
|
+
};
|
|
28
|
+
/** Recompute the thumb from the port's current scroll metrics. */
|
|
29
|
+
measure: () => void;
|
|
30
|
+
/** `onMouseDown` on the thumb. */
|
|
31
|
+
startDrag: (event: React.MouseEvent) => void;
|
|
32
|
+
/** `onMouseEnter` on the thumb. See `near`. */
|
|
33
|
+
approach: () => void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* The behaviour of an overlay scrollbar, with no opinion about where it sits.
|
|
37
|
+
* Mirrors `@sesame/orxata-core` useScrollbar.
|
|
38
|
+
*
|
|
39
|
+
* Geometry only goes one way here: the track is positioned and sized by CSS,
|
|
40
|
+
* and this reads back the height it ended up with. That is what keeps the
|
|
41
|
+
* placement out — a virtualised table subtracts its `<thead>` and compensates
|
|
42
|
+
* for an `offsetParent`, a chat composer does neither, and neither of those
|
|
43
|
+
* facts has to be expressible here for both to work.
|
|
44
|
+
*
|
|
45
|
+
* Both elements are watched for resize, which is also what makes the
|
|
46
|
+
* measurement land in the right frame: a `<textarea>` that auto-grows writes
|
|
47
|
+
* its own height, the track follows it, and the resize callback runs after that
|
|
48
|
+
* write and before the paint. That matters more here than on the Vue side —
|
|
49
|
+
* a child's effects run before its parent's, so the bar cannot be ordered
|
|
50
|
+
* after the growth by declaration order alone.
|
|
51
|
+
*/
|
|
52
|
+
export declare const useScrollbar: (port: ScrollbarPort, track: RefObject<HTMLElement | null>) => UseScrollbarReturn;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hooks shared by more than one component — the React side of the Vue
|
|
3
|
+
* package's `src/composables/`, which is the rename the parity rules apply
|
|
4
|
+
* (`composables` ↔ `hooks`, see `packages/eslint-plugin/src/parity/compare.js`).
|
|
5
|
+
*
|
|
6
|
+
* A hook lives beside its component until a second one needs it; at that point
|
|
7
|
+
* it belongs here, because the alternative is a component importing out of a
|
|
8
|
+
* sibling's folder and a reader having to know that `Textarea`'s sizing is
|
|
9
|
+
* really `ChatInput`'s. See `.claude/rules/component-architecture.md` §13.
|
|
10
|
+
*/
|
|
11
|
+
export { useAutoGrow } from './useAutoGrow.ts';
|
|
12
|
+
export type { UseAutoGrowReturn } from './useAutoGrow.ts';
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { RefObject } from 'react';
|
|
2
|
+
export interface UseAutoGrowReturn {
|
|
3
|
+
/** Re-measure and re-apply the height. Cheap; call it on every keystroke. */
|
|
4
|
+
resize: () => void;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Grows a `<textarea>` with its content up to `maxRows`, then lets it scroll.
|
|
8
|
+
* Mirrors `@sesame/orxata-core` useAutoGrow.
|
|
9
|
+
*
|
|
10
|
+
* Measuring is the whole trick and it has one rule: the height has to be
|
|
11
|
+
* cleared before `scrollHeight` is read. `scrollHeight` never reports less
|
|
12
|
+
* than the element's own height, so measuring against the height left over
|
|
13
|
+
* from the previous keystroke makes the field a one-way ratchet — it grows
|
|
14
|
+
* when text is added and never shrinks when it is deleted.
|
|
15
|
+
*
|
|
16
|
+
* The cap is applied here rather than as a CSS `max-height` so that the
|
|
17
|
+
* overflow can be switched with it. A permanently scrollable textarea shows a
|
|
18
|
+
* scrollbar gutter in the browsers that reserve one, which moves the text by a
|
|
19
|
+
* few pixels for as long as the field is a single line — visible, and wrong
|
|
20
|
+
* against a design that has no scrollbar in it.
|
|
21
|
+
*/
|
|
22
|
+
export declare const useAutoGrow: (element: RefObject<HTMLTextAreaElement | null>, value: string, maxRows: number) => UseAutoGrowReturn;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type ListboxEmptyProps = React.ComponentPropsWithoutRef<'div'>;
|
|
2
|
+
/** Shown in place of the rows when a search matched nothing. Internal. */
|
|
3
|
+
export declare const ListboxEmpty: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export interface ListboxItemProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
2
|
+
/**
|
|
3
|
+
* The check mark, for lists that have one. Pass it — even as a fragment that
|
|
4
|
+
* renders nothing while the row is unchecked — and the row reserves the space
|
|
5
|
+
* on its right; leave it out and the row sits flush.
|
|
6
|
+
*/
|
|
7
|
+
indicator?: React.ReactNode;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* One row of a list: `Select`'s option, `Combobox`'s option, `SearchPanel`'
|
|
11
|
+
* result. Port of `core/src/internal/Listbox/ListboxItem`.
|
|
12
|
+
*
|
|
13
|
+
* Whether the row leaves room on the right is decided by the presence of the
|
|
14
|
+
* `indicator` prop, not by whether the row is currently checked — a list with
|
|
15
|
+
* check marks always passes it and a list without one never does, so the gap
|
|
16
|
+
* is stable instead of appearing the moment a row becomes checked.
|
|
17
|
+
*
|
|
18
|
+
* The indicator wrapper is rendered here rather than left to the caller so the
|
|
19
|
+
* positioning lives in one file. That matters less in React than in Vue, where
|
|
20
|
+
* scoped CSS would simply not reach an element authored elsewhere, but keeping
|
|
21
|
+
* the two ports the same shape is what makes them comparable.
|
|
22
|
+
*/
|
|
23
|
+
export declare const ListboxItem: import('react').ForwardRefExoticComponent<ListboxItemProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ListboxLabelProps = React.ComponentPropsWithoutRef<'div'>;
|
|
2
|
+
/**
|
|
3
|
+
* The heading above a group of rows. Internal — see `Surface.tsx`.
|
|
4
|
+
*
|
|
5
|
+
* Content is `children`, never a string prop: the heading is the caller's word
|
|
6
|
+
* for their own category, and a design system that took it as a prop would be
|
|
7
|
+
* deciding how it can be written.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ListboxLabel: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type ListboxSeparatorProps = React.ComponentPropsWithoutRef<'div'>;
|
|
2
|
+
/** The rule between two groups of rows. Internal — see `Surface.tsx`. */
|
|
3
|
+
export declare const ListboxSeparator: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ListboxViewportProps = React.ComponentPropsWithoutRef<'div'>;
|
|
2
|
+
/**
|
|
3
|
+
* The padded, scrolling box the rows sit in. Internal — see `Surface.tsx`.
|
|
4
|
+
*
|
|
5
|
+
* Reached through `asChild` from Radix's `Select.Viewport` or cmdk's
|
|
6
|
+
* `Command.List`, both of which own the scrolling behaviour and neither of
|
|
7
|
+
* which agrees on a name.
|
|
8
|
+
*/
|
|
9
|
+
export declare const ListboxViewport: import('react').ForwardRefExoticComponent<Omit<import('react').DetailedHTMLProps<import('react').HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref"> & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export interface SurfaceProps extends React.ComponentPropsWithoutRef<'div'> {
|
|
2
|
+
/**
|
|
3
|
+
* Drawn free of any trigger rather than tethered to one: no border, a deeper
|
|
4
|
+
* shadow. The command palette is the case.
|
|
5
|
+
*/
|
|
6
|
+
floating?: boolean;
|
|
7
|
+
/**
|
|
8
|
+
* Joined to the edge of whatever it drops out of, rather than separated from
|
|
9
|
+
* it by a gap: the corners on the side it meets go square, so the two boxes
|
|
10
|
+
* read as one card. `SearchPanel`'s results are the case.
|
|
11
|
+
*/
|
|
12
|
+
attached?: boolean;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* The floating surface: the card a `Popover`, a `Select`, a `Combobox` or a
|
|
16
|
+
* `SearchPanel` panel is drawn on. Port of `core/src/internal/Surface`.
|
|
17
|
+
*
|
|
18
|
+
* Internal on purpose. It carries no portal and no positioning — those belong
|
|
19
|
+
* to whichever primitive family opened it, and they are not interchangeable.
|
|
20
|
+
* What is interchangeable is the *look*: the fill, the border, the radius, the
|
|
21
|
+
* shadow and the open/close animation. Each content component keeps its own
|
|
22
|
+
* primitive as the root and reaches this element through `asChild`, so the
|
|
23
|
+
* primitive's `data-state` and `data-side` land on the div below and the
|
|
24
|
+
* animation selectors see them.
|
|
25
|
+
*
|
|
26
|
+
* It is not exported from `main.ts`. On its own it is an inert div: no
|
|
27
|
+
* keyboard, no focus management, no positioning. The public way to get one
|
|
28
|
+
* stays `OxPopover`, `OxSelect`, `OxCombobox` or `OxSearchPanel`.
|
|
29
|
+
*
|
|
30
|
+
* `forwardRef` is not optional here: `asChild` composes the primitive's ref
|
|
31
|
+
* onto this component, and a plain function component would drop it — the
|
|
32
|
+
* popover would have nothing to measure and would position itself at the
|
|
33
|
+
* origin.
|
|
34
|
+
*/
|
|
35
|
+
export declare const Surface: import('react').ForwardRefExoticComponent<SurfaceProps & import('react').RefAttributes<HTMLDivElement>>;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared presentational parts. Deliberately absent from `src/main.ts`: each is
|
|
3
|
+
* an inert element with no keyboard, no roles and no positioning, so publishing
|
|
4
|
+
* one would ship something that looks like an option and behaves like a div.
|
|
5
|
+
* The public way to build a list stays `OxSelect`, `OxCombobox` or
|
|
6
|
+
* `OxSearchPanel`, each of which pairs these with its own primitive.
|
|
7
|
+
*/
|
|
8
|
+
export { Surface, type SurfaceProps } from './Surface/Surface.tsx';
|
|
9
|
+
export { ListboxEmpty, type ListboxEmptyProps, } from './Listbox/ListboxEmpty.tsx';
|
|
10
|
+
export { ListboxItem, type ListboxItemProps } from './Listbox/ListboxItem.tsx';
|
|
11
|
+
export { ListboxLabel, type ListboxLabelProps, } from './Listbox/ListboxLabel.tsx';
|
|
12
|
+
export { ListboxSeparator, type ListboxSeparatorProps, } from './Listbox/ListboxSeparator.tsx';
|
|
13
|
+
export { ListboxViewport, type ListboxViewportProps, } from './Listbox/ListboxViewport.tsx';
|