@sesamehr/react-design-system 2.0.0-beta.6 → 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.
Files changed (84) hide show
  1. package/dist/Button/ActionItem/ActionItem.d.ts +40 -0
  2. package/dist/Button/ActionItem/index.d.ts +1 -0
  3. package/dist/Data/Table/TableScrollbar/TableScrollbar.d.ts +5 -3
  4. package/dist/Display/Avatar/AvatarSkeleton/AvatarSkeleton.d.ts +30 -0
  5. package/dist/Display/Avatar/index.d.ts +2 -0
  6. package/dist/Display/ChatBubble/ChatBubbleStatus/ChatBubbleStatus.d.ts +2 -2
  7. package/dist/Display/FileCard/FileCard.d.ts +66 -0
  8. package/dist/Display/FileCard/index.d.ts +1 -0
  9. package/dist/Display/FilePreviewCard/FilePreviewCard.d.ts +49 -0
  10. package/dist/Display/FilePreviewCard/index.d.ts +1 -0
  11. package/dist/Feedback/Alert/AlertIcon.d.ts +1 -1
  12. package/dist/Feedback/Dialog/DialogBody.d.ts +18 -0
  13. package/dist/Feedback/Dialog/index.d.ts +1 -0
  14. package/dist/Feedback/Popover/PopoverContent.d.ts +7 -1
  15. package/dist/Feedback/Progress/index.d.ts +1 -1
  16. package/dist/Feedback/Skeleton/Skeleton.d.ts +20 -0
  17. package/dist/Feedback/Skeleton/index.d.ts +2 -0
  18. package/dist/Forms/Field/FieldGroup/FieldGroup.d.ts +16 -1
  19. package/dist/Forms/Field/FieldLabel/FieldLabel.d.ts +16 -0
  20. package/dist/Forms/Field/FieldMessage/FieldMessage.d.ts +22 -2
  21. package/dist/Forms/Field/index.d.ts +1 -0
  22. package/dist/Forms/Field/useFieldGroup.d.ts +108 -0
  23. package/dist/Forms/Inputs/Calendar/Calendar.d.ts +2 -7
  24. package/dist/Forms/Inputs/Calendar/CalendarRange.d.ts +2 -7
  25. package/dist/Forms/Inputs/Calendar/date.d.ts +28 -0
  26. package/dist/Forms/Inputs/Calendar/index.d.ts +1 -0
  27. package/dist/Forms/Inputs/Calendar/nav.d.ts +34 -0
  28. package/dist/Forms/Inputs/Calendar/testids.d.ts +9 -6
  29. package/dist/Forms/Inputs/Calendar/useCalendarLocale.d.ts +18 -0
  30. package/dist/Forms/Inputs/ChatInput/ChatInput.d.ts +68 -0
  31. package/dist/Forms/Inputs/ChatInput/index.d.ts +46 -0
  32. package/dist/Forms/Inputs/Combobox/ComboboxContent.d.ts +5 -0
  33. package/dist/Forms/Inputs/Combobox/ComboboxGroup.d.ts +6 -2
  34. package/dist/Forms/Inputs/Combobox/ComboboxInput.d.ts +6 -1
  35. package/dist/Forms/Inputs/Combobox/ComboboxItem.d.ts +4 -0
  36. package/dist/Forms/Inputs/Combobox/context.d.ts +7 -0
  37. package/dist/Forms/Inputs/Combobox/useComboboxLabels.d.ts +21 -0
  38. package/dist/Forms/Inputs/DatePicker/DatePicker.d.ts +51 -0
  39. package/dist/Forms/Inputs/DatePicker/DatePickerHeader.d.ts +65 -0
  40. package/dist/Forms/Inputs/DatePicker/DatePickerMonthSelect.d.ts +27 -0
  41. package/dist/Forms/Inputs/DatePicker/DatePickerTrigger.d.ts +29 -0
  42. package/dist/Forms/Inputs/DatePicker/DatePickerYearSelect.d.ts +25 -0
  43. package/dist/Forms/Inputs/DatePicker/DateRangePicker.d.ts +61 -0
  44. package/dist/Forms/Inputs/DatePicker/format.d.ts +44 -0
  45. package/dist/Forms/Inputs/DatePicker/index.d.ts +6 -0
  46. package/dist/Forms/Inputs/DatePicker/month.d.ts +28 -0
  47. package/dist/Forms/Inputs/DatePicker/useDatePickerHeader.d.ts +23 -0
  48. package/dist/Forms/Inputs/InputOtp/InputOtp.d.ts +7 -0
  49. package/dist/Forms/Inputs/InputPassword/InputPassword.d.ts +9 -1
  50. package/dist/Forms/Inputs/InputText/InputText.d.ts +9 -0
  51. package/dist/Forms/Inputs/SearchBar/useSearchDelay.d.ts +1 -1
  52. package/dist/Forms/Inputs/SearchPanel/SearchPanel.d.ts +71 -0
  53. package/dist/Forms/Inputs/SearchPanel/SearchPanelEmpty.d.ts +16 -0
  54. package/dist/Forms/Inputs/SearchPanel/SearchPanelGroup.d.ts +14 -0
  55. package/dist/Forms/Inputs/SearchPanel/SearchPanelInput.d.ts +31 -0
  56. package/dist/Forms/Inputs/SearchPanel/SearchPanelItem.d.ts +20 -0
  57. package/dist/Forms/Inputs/SearchPanel/SearchPanelList.d.ts +42 -0
  58. package/dist/Forms/Inputs/SearchPanel/context.d.ts +11 -0
  59. package/dist/Forms/Inputs/SearchPanel/index.d.ts +6 -0
  60. package/dist/Forms/Inputs/Select/SelectContent.d.ts +6 -0
  61. package/dist/Forms/Inputs/Select/SelectGroup.d.ts +6 -2
  62. package/dist/Forms/Inputs/Select/SelectItem.d.ts +6 -0
  63. package/dist/Forms/Inputs/Textarea/Textarea.d.ts +69 -0
  64. package/dist/Forms/Inputs/Textarea/index.d.ts +21 -0
  65. package/dist/Forms/Inputs/Toggle/RadioButton/RadioGroup.d.ts +5 -0
  66. package/dist/Forms/Inputs/Toggle/ToggleLabel/ToggleLabel.d.ts +10 -1
  67. package/dist/Forms/Inputs/index.d.ts +4 -0
  68. package/dist/Layout/Scrollbar/Scrollbar.d.ts +46 -0
  69. package/dist/Layout/Scrollbar/index.d.ts +2 -0
  70. package/dist/Layout/Scrollbar/useScrollbar.d.ts +52 -0
  71. package/dist/hooks/index.d.ts +12 -0
  72. package/dist/hooks/useAutoGrow.d.ts +22 -0
  73. package/dist/internal/Listbox/ListboxEmpty.d.ts +3 -0
  74. package/dist/internal/Listbox/ListboxItem.d.ts +23 -0
  75. package/dist/internal/Listbox/ListboxLabel.d.ts +9 -0
  76. package/dist/internal/Listbox/ListboxSeparator.d.ts +3 -0
  77. package/dist/internal/Listbox/ListboxViewport.d.ts +9 -0
  78. package/dist/internal/Surface/Surface.d.ts +35 -0
  79. package/dist/internal/index.d.ts +13 -0
  80. package/dist/main.d.ts +10 -4
  81. package/dist/react-design-system.css +1 -1
  82. package/dist/react-design-system.js +10563 -9466
  83. package/dist/react-design-system.umd.cjs +156 -132
  84. package/package.json +1 -2
@@ -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';
@@ -1,5 +1,5 @@
1
1
  /**
2
- * The scrollbar a virtualised table draws for itself.
2
+ * Where a virtualised table's overlay scrollbar goes.
3
3
  *
4
4
  * Every other table in the system hides its bar: they scroll sideways, the
5
5
  * shadows at the edges say there is more, and a bar would be chrome. A list of
@@ -10,8 +10,10 @@
10
10
  * the scrollport, and the scrollport has to contain the header, so it always
11
11
  * cuts across the column names. This one starts below them.
12
12
  *
13
- * It behaves the way an overlay bar does: out of the way until you scroll or
14
- * reach for the edge, and gone again shortly after.
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.
15
17
  */
16
18
  export declare function TableScrollbar(): import("react/jsx-runtime").JSX.Element | null;
17
19
  export declare namespace TableScrollbar {
@@ -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';
@@ -1,8 +1,8 @@
1
1
  import { ChatBubbleStatusVariants } from './index.ts';
2
- export interface ChatBubbleStatusProps extends React.SVGAttributes<SVGSVGElement> {
2
+ export interface ChatBubbleStatusProps extends React.HTMLAttributes<HTMLElement> {
3
3
  /** How far along the message is */
4
4
  status?: NonNullable<ChatBubbleStatusVariants['status']>;
5
5
  dataTestid: string;
6
6
  }
7
7
  /** ChatBubbleStatus — mirrors `@sesame/orxata-core` ChatBubbleStatus. */
8
- export declare const ChatBubbleStatus: import('react').ForwardRefExoticComponent<ChatBubbleStatusProps & import('react').RefAttributes<SVGSVGElement>>;
8
+ export declare const ChatBubbleStatus: import('react').ForwardRefExoticComponent<ChatBubbleStatusProps & import('react').RefAttributes<HTMLElement>>;
@@ -0,0 +1,66 @@
1
+ /**
2
+ * One attached file as a row. Mirrors `@sesame/orxata-core` FileCard.
3
+ *
4
+ * Built on `Card` rather than redrawing the shell. The radius, the border and
5
+ * the white surface are already a component, and the only reason this file has
6
+ * a stylesheet at all is the row inside it. `flat` is the card the design
7
+ * draws: border, no lift — `Card`'s `flat` keeps the outline and drops only the
8
+ * shadow and the glass.
9
+ *
10
+ * ### Why `name` and `meta` are props and the other two are nodes
11
+ *
12
+ * Sameness is the product for the text, exactly as in `AvatarDetails`: every
13
+ * file row we ship is two lines at the same sizes and weights, and a node is
14
+ * where that guarantee goes to die — the first caller to put a link, a badge or
15
+ * a third line in it ends the point of having the component. `meta` is
16
+ * deliberately not called `size`: what the second line says is the
17
+ * application's business ("1,56 MB", "PDF · yesterday", "Uploaded by Ana"), and
18
+ * naming it after one of those would be a lie the day someone passes another.
19
+ *
20
+ * The glyph and the action are the opposite case. Mapping an extension to an
21
+ * icon is application knowledge — there are hundreds of extensions and we know
22
+ * none of them — so `icon` takes a node and falls back to a generic file glyph,
23
+ * which is the one honest thing a design system can draw. And `action` takes a
24
+ * node because *which* action is not ours either: download, delete, share,
25
+ * retry, or nothing at all. It also settles the accessible name, which we
26
+ * cannot supply since the design system ships no strings — whatever the caller
27
+ * puts there brings its own, and `IconButton` refuses to render without one.
28
+ *
29
+ * ### What it deliberately does not do
30
+ *
31
+ * **It has no width.** The design pins 300px with `min-width`, `max-width` and
32
+ * `width`, and that figure belongs to the screen it was drawn on, not to the
33
+ * component: a card that hardcodes its own width cannot sit in a grid, a
34
+ * sidebar or a flexible column, and the parent owns external layout. It fills
35
+ * what it is given. The 72px height stays, because that one is internal — a
36
+ * list of these has to have rows of equal height, and long names truncate
37
+ * rather than growing the row.
38
+ *
39
+ * **The root is not a button.** It already contains an interactive control, and
40
+ * a button inside a button is invalid HTML; making the root activate would also
41
+ * mean inventing a focus and keyboard contract the design has nothing to say
42
+ * about. A caller who wants the whole row to do something wraps it, or puts a
43
+ * link in `action`.
44
+ */
45
+ export interface FileCardProps extends Omit<React.ComponentPropsWithoutRef<'div'>, 'title'> {
46
+ /** The file's name. Truncates rather than wrapping — the row is a fixed height. */
47
+ name: string;
48
+ /**
49
+ * The second line: whatever the app knows about the file. Size in the
50
+ * design, but a type, a date or an author read just as well. Omit it and the
51
+ * row is one line.
52
+ */
53
+ meta?: string;
54
+ /**
55
+ * The glyph in the ring. Defaults to a generic file — mapping an extension to
56
+ * an icon is the application's knowledge, not ours.
57
+ */
58
+ icon?: React.ReactNode;
59
+ /**
60
+ * The one thing you can do to this file. Nothing by default; whatever you put
61
+ * here brings its own accessible name.
62
+ */
63
+ action?: React.ReactNode;
64
+ dataTestid: string;
65
+ }
66
+ export declare const FileCard: import('react').ForwardRefExoticComponent<FileCardProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ export { FileCard, type FileCardProps } from './FileCard.tsx';
@@ -0,0 +1,49 @@
1
+ /**
2
+ * A file you can see: a square thumbnail with one line under it. Mirrors
3
+ * `@sesame/orxata-core` FilePreviewCard.
4
+ *
5
+ * The sibling of `FileCard`, and deliberately not a variant of it. They differ
6
+ * in axis, in padding, in how they take their width and in what they contain —
7
+ * and, decisively, this one has neither a title nor an action. A `variant` prop
8
+ * would have to flip the layout *and* switch off the title *and* switch off the
9
+ * action, which is three configuration props spent hiding the fact that these
10
+ * are two components. What they genuinely share is the shell, and both get it
11
+ * the same way: from `Card`.
12
+ *
13
+ * ### The image
14
+ *
15
+ * `src` and `alt` rather than a node, because there is nothing to compose — it
16
+ * is one `<img>`, and taking a node would only invite a second one. `alt` is
17
+ * required and has no default for the usual reason: the design system ships no
18
+ * strings, and only the caller knows what the picture is of. Pass `""` if it is
19
+ * genuinely decorative; that is a decision, and it should have to be made.
20
+ *
21
+ * Two failure modes, both handled without a state machine. **Not loaded yet**
22
+ * is a tinted square, so the card holds its shape and reads as a pending
23
+ * thumbnail instead of a white hole. **Failed to load** swaps the `<img>` for a
24
+ * generic picture glyph carrying the same `alt` through `role="img"` — the
25
+ * browser's broken-image icon is neither styleable nor meaningful, and dropping
26
+ * the `<img>` is the only way to be rid of it. A new `src` clears the flag, so
27
+ * one bad URL does not poison the ones after it.
28
+ *
29
+ * ### Size
30
+ *
31
+ * The thumbnail is 150px square from the design, exposed as
32
+ * `--ox-file-preview-card-size` rather than a prop — a dimension is a style
33
+ * concern and CSS variables are how this system inherits those. The card itself
34
+ * has no width at all: it hugs the thumbnail, which is why the design needed no
35
+ * width on it either.
36
+ */
37
+ export interface FilePreviewCardProps extends React.ComponentPropsWithoutRef<'div'> {
38
+ /** The image to show. */
39
+ src: string;
40
+ /** What the image is of. Required — pass `""` only if it is decorative. */
41
+ alt: string;
42
+ /**
43
+ * The single line under the thumbnail: "JPG - 937 KB" in the design, but the
44
+ * app decides what is worth saying.
45
+ */
46
+ meta: string;
47
+ dataTestid: string;
48
+ }
49
+ export declare const FilePreviewCard: import('react').ForwardRefExoticComponent<FilePreviewCardProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1 @@
1
+ export { FilePreviewCard, type FilePreviewCardProps, } from './FilePreviewCard.tsx';
@@ -1,5 +1,5 @@
1
1
  export interface AlertIconProps extends React.HTMLAttributes<HTMLDivElement> {
2
2
  dataTestid: string;
3
3
  }
4
- /** AlertIcon — renders the variant's default lucide icon, or `children` if provided. */
4
+ /** AlertIcon — renders the variant's default icon, or `children` if provided. */
5
5
  export declare const AlertIcon: import('react').ForwardRefExoticComponent<AlertIconProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,18 @@
1
+ export interface DialogBodyProps extends React.HTMLAttributes<HTMLDivElement> {
2
+ dataTestid: string;
3
+ }
4
+ /**
5
+ * DialogBody — mirrors `@sesame/orxata-core` DialogBody. The scrolling region
6
+ * of a dialog.
7
+ *
8
+ * Everything else in the panel — header, footer, steppers, alerts — stays put;
9
+ * only this scrolls once the panel reaches its `max-height`. It carries no
10
+ * styling of its own: the declarations that make it the flexible, scrolling
11
+ * item live on `DialogContent` next to the `max-height` they depend on, since
12
+ * a body is only a scroll region because the panel is capped and splitting
13
+ * that pair across two files is how one of them gets changed alone.
14
+ *
15
+ * `data-slot` rather than position, so it can sit anywhere among the panel's
16
+ * children.
17
+ */
18
+ export declare const DialogBody: import('react').ForwardRefExoticComponent<DialogBodyProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -1,5 +1,6 @@
1
1
  export { Dialog, type DialogProps } from './Dialog.tsx';
2
2
  export { DialogContent, type DialogContentProps } from './DialogContent.tsx';
3
+ export { DialogBody, type DialogBodyProps } from './DialogBody.tsx';
3
4
  export { DialogTitle, type DialogTitleProps } from './DialogTitle.tsx';
4
5
  export { DialogDescription, type DialogDescriptionProps, } from './DialogDescription.tsx';
5
6
  export { DialogOverlay, type DialogOverlayProps } from './DialogOverlay.tsx';
@@ -3,5 +3,11 @@ export interface PopoverContentProps extends React.ComponentPropsWithoutRef<type
3
3
  showArrow?: boolean;
4
4
  dataTestid: string;
5
5
  }
6
- /** PopoverContent — portalled Radix popover content with optional arrow. */
6
+ /**
7
+ * PopoverContent — portalled Radix popover content with optional arrow.
8
+ *
9
+ * `asChild` draws it on the shared `Surface`, which is what keeps a popover
10
+ * and a select open on the same screen from having different corners. Only the
11
+ * padding is a popover's own.
12
+ */
7
13
  export declare const PopoverContent: import('react').ForwardRefExoticComponent<PopoverContentProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -14,6 +14,6 @@ export type { ProgressProps } from './Progress.tsx';
14
14
  * The variant is the caller's to say.
15
15
  */
16
16
  export declare const progressVariants: (props?: ({
17
- variant?: "success" | "warning" | "brand" | "error" | null | undefined;
17
+ variant?: "success" | "error" | "warning" | "brand" | null | undefined;
18
18
  } & import('class-variance-authority/types').ClassProp) | undefined) => string;
19
19
  export type ProgressVariants = VariantProps<typeof progressVariants>;
@@ -0,0 +1,20 @@
1
+ export interface SkeletonProps extends React.HTMLAttributes<HTMLDivElement> {
2
+ dataTestid: string;
3
+ }
4
+ /**
5
+ * A block that pulses while the content it stands in for is still loading.
6
+ *
7
+ * It configures nothing. One surface, and the caller gives it its shape with
8
+ * ordinary classes — `h-4 w-48` is a line of text, `size-10 rounded-full` is an
9
+ * avatar, `h-32 w-full` is a block. A `shape` or `variant` prop would be three
10
+ * names for three combinations of width, height and radius that CSS already
11
+ * says better, and it would run out the moment somebody needed a fourth.
12
+ *
13
+ * `OxLoader` and `OxProgress` are the other two, and the three are not
14
+ * interchangeable — see the MDX for which is which.
15
+ *
16
+ * `aria-hidden` sits before the spread so a caller who genuinely needs one of
17
+ * these in the accessibility tree can override it. The region carrying
18
+ * `aria-busy` is the right level, and that is the caller's.
19
+ */
20
+ export declare const Skeleton: import('react').ForwardRefExoticComponent<SkeletonProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -0,0 +1,2 @@
1
+ export { Skeleton } from './Skeleton.tsx';
2
+ export type { SkeletonProps } from './Skeleton.tsx';
@@ -1,4 +1,19 @@
1
+ import { FieldVariant } from '../useFieldGroup.ts';
1
2
  export interface FieldGroupProps extends React.HTMLAttributes<HTMLDivElement> {
2
- variant?: 'default' | 'error' | 'success' | 'warning';
3
+ variant?: FieldVariant;
3
4
  }
5
+ /**
6
+ * A label, a control and a message, ordered and wired to each other.
7
+ *
8
+ * Two mechanisms, and they are not redundant. The custom properties in the
9
+ * stylesheet paint whatever is inside — including a consumer's own control,
10
+ * which never imported anything from here — with no prop drilling. The context
11
+ * in `useFieldGroup.ts` carries what a custom property cannot: the `id` the
12
+ * label points `htmlFor` at, the `aria-describedby` that reaches the message,
13
+ * and the `aria-invalid` that says the control is wrong.
14
+ *
15
+ * Ordering is done with direct-child selectors, so the label, the control and
16
+ * the message have to be direct children of this element. Anything a consumer
17
+ * wants to wrap around the field goes outside the group, not inside it.
18
+ */
4
19
  export declare const FieldGroup: import('react').ForwardRefExoticComponent<FieldGroupProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -1,2 +1,18 @@
1
1
  export type FieldLabelProps = React.LabelHTMLAttributes<HTMLLabelElement>;
2
+ /**
3
+ * The field's label.
4
+ *
5
+ * `htmlFor` comes from the surrounding `<OxFieldGroup>` and points at whichever
6
+ * control claimed the field's id — without it this is a bare `<label>` that
7
+ * neither wraps a control nor names one, so clicking it focuses nothing and a
8
+ * screen reader reaching the control announces no name. It is left off
9
+ * entirely when no control has claimed the id, since a `htmlFor` pointing at
10
+ * nothing is not an improvement on no `htmlFor`.
11
+ *
12
+ * `id` is always there so a composite control — one with several focusable
13
+ * children, where `htmlFor` has no single target — can name itself with
14
+ * `aria-labelledby`.
15
+ *
16
+ * A `htmlFor` written by the caller comes in `...props` and wins, as it should.
17
+ */
2
18
  export declare const FieldLabel: import('react').ForwardRefExoticComponent<FieldLabelProps & import('react').RefAttributes<HTMLLabelElement>>;
@@ -1,5 +1,25 @@
1
+ import { FieldVariant } from '../useFieldGroup.ts';
1
2
  export interface FieldMessageProps extends React.HTMLAttributes<HTMLDivElement> {
2
- message?: string;
3
- variant?: 'default' | 'error' | 'success' | 'warning';
3
+ /**
4
+ * Overrides the group's variant. Leave it out inside an `<OxFieldGroup>` and
5
+ * the group's own variant comes through the context, so `error` is written
6
+ * once instead of on both.
7
+ */
8
+ variant?: FieldVariant;
4
9
  }
10
+ /**
11
+ * The field's feedback line.
12
+ *
13
+ * `id` comes from the surrounding `<OxFieldGroup>` so the control can point
14
+ * `aria-describedby` at it. Without one, the error was announced when it
15
+ * appeared and never again: tab back to a field that is already wrong and
16
+ * nothing described it.
17
+ *
18
+ * `role="alert"` and nothing else. The pair it used to carry — `role="alert"`
19
+ * with `aria-live="polite"` — contradicted itself, since `alert` already
20
+ * implies `assertive`. `alert` is the half worth keeping: it is what makes a
21
+ * message that appears after a submit interrupt, and the case it does not
22
+ * cover, a field that is *already* wrong when you reach it, is now covered by
23
+ * `aria-describedby` instead.
24
+ */
5
25
  export declare const FieldMessage: import('react').ForwardRefExoticComponent<FieldMessageProps & import('react').RefAttributes<HTMLDivElement>>;
@@ -1,3 +1,4 @@
1
1
  export { FieldGroup, type FieldGroupProps } from './FieldGroup/FieldGroup.tsx';
2
2
  export { FieldLabel, type FieldLabelProps } from './FieldLabel/FieldLabel.tsx';
3
3
  export { FieldMessage, type FieldMessageProps, } from './FieldMessage/FieldMessage.tsx';
4
+ export { useFieldControl, useFieldControlGroup, type FieldControlAttrs, type FieldControlGroupAttrs, type FieldVariant, } from './useFieldGroup.ts';
@@ -0,0 +1,108 @@
1
+ /**
2
+ * What a `<OxFieldGroup>` hands to the label, the control and the message
3
+ * inside it.
4
+ *
5
+ * `FieldGroup` already paints its children through custom properties
6
+ * (`--message-text-color`, `--controller-border-color`), and that stays: it is
7
+ * what lets a consumer's own control inherit the error colour with no prop
8
+ * drilling. A custom property cannot carry an `id` or an `aria-invalid`,
9
+ * though, so the accessible half needs a real context beside it.
10
+ *
11
+ * Every piece is optional. A control used on its own — no `FieldGroup`
12
+ * anywhere above it — gets an empty attribute bag and renders exactly as it
13
+ * did before, which is why `useFieldGroup` returns `undefined` instead of
14
+ * throwing the way `useInputPassword` does. There, a subcomponent outside its
15
+ * root is meaningless; here, a bare `<OxInputText>` is a perfectly good input.
16
+ *
17
+ * Nothing emits an IDREF that points at nothing. `aria-describedby` waits for
18
+ * a message to mount, `aria-labelledby` for a label, and `<label htmlFor>` for
19
+ * a control to claim the id — a reference to an element that is not there is
20
+ * worse than no reference, because some readers then announce nothing at all
21
+ * rather than falling back.
22
+ */
23
+ export type FieldVariant = 'default' | 'error' | 'success' | 'warning';
24
+ /** The parts of the group that announce themselves so an IDREF never dangles. */
25
+ type FieldPart = 'label' | 'message';
26
+ export interface FieldGroupContextValue {
27
+ /**
28
+ * Id on the `<label>`. A composite control — one with several focusable
29
+ * children, where `htmlFor` has no single target — names itself by pointing
30
+ * `aria-labelledby` here.
31
+ */
32
+ labelId: string;
33
+ /** Id on the message, and what a control points `aria-describedby` at. */
34
+ messageId: string;
35
+ /** What `<label htmlFor>` points at, once a control has claimed it. */
36
+ controlId: string | undefined;
37
+ variant: FieldVariant;
38
+ hasLabel: boolean;
39
+ hasMessage: boolean;
40
+ /** Announce a part as mounted. Returns the call that takes it back. */
41
+ register: (_part: FieldPart) => () => void;
42
+ /**
43
+ * Offer an id as the one the label names. The first control to ask gets it;
44
+ * a second is refused, because one label names one thing.
45
+ */
46
+ claimControl: (_id: string) => () => void;
47
+ }
48
+ export interface FieldControlAttrs {
49
+ id?: string;
50
+ 'aria-invalid'?: true;
51
+ 'aria-describedby'?: string;
52
+ }
53
+ export interface FieldControlGroupAttrs {
54
+ 'aria-labelledby'?: string;
55
+ 'aria-invalid'?: true;
56
+ 'aria-describedby'?: string;
57
+ }
58
+ export interface FieldLabelAttrs {
59
+ id?: string;
60
+ htmlFor?: string;
61
+ }
62
+ export declare const FieldGroupContext: import('react').Context<FieldGroupContextValue | null>;
63
+ /**
64
+ * The surrounding field, or `undefined` when there is none.
65
+ *
66
+ * Deliberately not a throwing `useXxx`: the context is optional, so its
67
+ * absence is not an error.
68
+ */
69
+ export declare function useFieldGroup(): FieldGroupContextValue | undefined;
70
+ /**
71
+ * Wiring for a control the `<label>` can point `htmlFor` at — anything
72
+ * labelable: `input`, `textarea`, `select`, and the `button`s Radix renders
73
+ * for a checkbox, a switch or a select trigger.
74
+ *
75
+ * Spread it *before* `{...props}` so the caller's attributes win over it, and
76
+ * hand it the caller's own `id`: that is what makes an explicit `id` survive,
77
+ * with the label following it there rather than staying on the generated one.
78
+ * Vue's half reads the id out of `useAttrs()` instead — React has no such
79
+ * channel, so the prop has to be passed in.
80
+ */
81
+ export declare function useFieldControl(id?: string): FieldControlAttrs;
82
+ /**
83
+ * Wiring for a composite — `OxRadioGroup`, `OxInputOtp` — where "put the id on
84
+ * the control" has no single answer because there are several focusable
85
+ * elements and one id cannot be on all of them.
86
+ *
87
+ * It names itself with `aria-labelledby` instead, so the element it goes on
88
+ * needs a role that takes a name from the author: Radix gives its radio group
89
+ * `role="radiogroup"`, and anything else has to say `role="group"` itself. On
90
+ * a plain `<div>` the name is dropped on the floor.
91
+ */
92
+ export declare function useFieldControlGroup(): FieldControlGroupAttrs;
93
+ /** Wiring for a `<label>` inside the group: its own id, and what it names. */
94
+ export declare function useFieldLabel(): FieldLabelAttrs;
95
+ /**
96
+ * Wiring for the message: the id a control describes itself with, and the
97
+ * group's variant so it does not have to be written on both.
98
+ */
99
+ export declare function useFieldMessage(): {
100
+ id?: string;
101
+ variant?: FieldVariant;
102
+ };
103
+ /**
104
+ * The state a `<OxFieldGroup>` owns. Split out of the component so the ids and
105
+ * the bookkeeping live next to the hooks that read them.
106
+ */
107
+ export declare function useProvideFieldGroup(variant: FieldVariant): FieldGroupContextValue;
108
+ export {};
@@ -1,5 +1,6 @@
1
1
  import { CalendarDayState } from './CalendarDay.tsx';
2
2
  import { CalendarConstraints } from './constraints.ts';
3
+ import { CalendarNav } from './nav.ts';
3
4
  /** One day. Falls back to `OxCalendarDay`. */
4
5
  type DayRenderer = (props: {
5
6
  date: Date;
@@ -34,13 +35,7 @@ export interface CalendarProps extends Pick<React.HTMLAttributes<HTMLDivElement>
34
35
  * Empty by default. Receives the visible month and the navigation state,
35
36
  * because without those nobody could build a header at all.
36
37
  */
37
- header?: (state: {
38
- month: Date;
39
- goToPrev: () => void;
40
- goToNext: () => void;
41
- canGoPrev: boolean;
42
- canGoNext: boolean;
43
- }) => React.ReactNode;
38
+ header?: (nav: CalendarNav) => React.ReactNode;
44
39
  /**
45
40
  * One month's name, above its grid. Falls back to the month and year from
46
41
  * `Intl`, and only renders when `months` is more than one — a lone month is
@@ -1,5 +1,6 @@
1
1
  import { CalendarDayState } from './CalendarDay.tsx';
2
2
  import { CalendarConstraints } from './constraints.ts';
3
+ import { CalendarNav } from './nav.ts';
3
4
  /** One day. Falls back to `OxCalendarDay`. */
4
5
  type DayRenderer = (props: {
5
6
  date: Date;
@@ -35,13 +36,7 @@ export interface CalendarRangeProps extends Pick<React.HTMLAttributes<HTMLDivEle
35
36
  * Empty by default. Receives the visible month and the navigation state,
36
37
  * because without those nobody could build a header at all.
37
38
  */
38
- header?: (state: {
39
- month: Date;
40
- goToPrev: () => void;
41
- goToNext: () => void;
42
- canGoPrev: boolean;
43
- canGoNext: boolean;
44
- }) => React.ReactNode;
39
+ header?: (nav: CalendarNav) => React.ReactNode;
45
40
  /**
46
41
  * One month's name, above its grid. Falls back to the month and year from
47
42
  * `Intl`, and only renders at all when there is more than one grid — a lone
@@ -0,0 +1,28 @@
1
+ /**
2
+ * Mirrors `@sesame/orxata-core`'s `date.ts`. Internal — none of this is
3
+ * exported from the package.
4
+ *
5
+ * The Vue half also converts between the `Date` a caller speaks and the
6
+ * `CalendarDate` reka needs; `react-day-picker` speaks `Date` throughout, so
7
+ * only the part both sides need lives here.
8
+ */
9
+ /**
10
+ * Whether `day` only appears in `month`'s grid as padding, while the month it
11
+ * actually belongs to has a grid of its own on screen.
12
+ *
13
+ * Every grid pads its first and last weeks with days of the neighbouring
14
+ * months, so with `months: 2` the 4th of April is drawn twice: once in April's
15
+ * grid, which owns it, and once in the tail of March's. Both copies read the
16
+ * same selection, so a range ending on the 4th was painted as ending in two
17
+ * places at once.
18
+ *
19
+ * The rule is contextual, not per-grid — "a day another visible grid owns" —
20
+ * which is why the visible months have to be passed in rather than inferred
21
+ * from `month` alone. March's *leading* days from February stay drawn when
22
+ * February is not on screen, and disappear when it is.
23
+ *
24
+ * With a single grid nothing else is visible to own the day, so this is always
25
+ * `false` and every outside day is drawn exactly as before. That is the whole
26
+ * reason the behaviour needs no prop: it follows from how many months are up.
27
+ */
28
+ export declare function isDrawnByAnotherMonth(day: Date, month: Date, visible: readonly Date[]): boolean;
@@ -3,6 +3,7 @@ export { Calendar, type CalendarProps } from './Calendar.tsx';
3
3
  export { CalendarRange, type CalendarRangeProps, type CalendarDateRange, } from './CalendarRange.tsx';
4
4
  export { CalendarDay, type CalendarDayProps, type CalendarDayState, } from './CalendarDay.tsx';
5
5
  export type { CalendarConstraints } from './constraints.ts';
6
+ export type { CalendarNav } from './nav.ts';
6
7
  /**
7
8
  * Only the range position varies here. The other five states — selected,
8
9
  * today, disabled, focused, outside — are `data-*` attributes rather than
@@ -0,0 +1,34 @@
1
+ /**
2
+ * What a calendar hands to whoever draws its header.
3
+ *
4
+ * `Calendar` and `CalendarRange` render no header of their own, so this is the
5
+ * whole of what a header can be built from — a type rather than an inline
6
+ * literal because `DatePickerHeader` takes it as one prop, and a header that
7
+ * cannot name its own argument is one every caller has to retype.
8
+ */
9
+ export interface CalendarNav {
10
+ /** The first month on screen. */
11
+ month: Date;
12
+ /**
13
+ * How many month grids are on screen, which is what a step moves by. A header
14
+ * that names only `month` names one of several and is wrong about the rest.
15
+ */
16
+ months: number;
17
+ /** Page one screenful back, or forward. A screenful is `months` months. */
18
+ goToPrev: () => void;
19
+ goToNext: () => void;
20
+ canGoPrev: boolean;
21
+ canGoNext: boolean;
22
+ /**
23
+ * Jump to the month a `Date` falls in, however far away it is.
24
+ *
25
+ * Stepping cannot express "the same month next year" — twelve calls to
26
+ * `goToNext` only land there when `months` divides twelve, and in React they
27
+ * do not compound at all, since each one is computed from the month of the
28
+ * render that produced them. Anything that moves by more than a page needs
29
+ * this: `OxDatePickerMonthSelect` and `OxDatePickerYearSelect`, and any month
30
+ * or year list a caller builds instead. It outlived the header's year arrows,
31
+ * which were the first thing to need it.
32
+ */
33
+ goTo: (month: Date) => void;
34
+ }