@ratio-ui/core 0.2.0 → 0.3.0

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 (95) hide show
  1. package/dist/catalogue.json +1091 -10
  2. package/dist/components/alert/Alert.d.ts +18 -0
  3. package/dist/components/alert/Alert.js +67 -0
  4. package/dist/components/alert/index.d.ts +2 -0
  5. package/dist/components/alert/index.js +1 -0
  6. package/dist/components/alert-dialog/AlertDialog.d.ts +48 -0
  7. package/dist/components/alert-dialog/AlertDialog.js +76 -0
  8. package/dist/components/alert-dialog/index.d.ts +2 -0
  9. package/dist/components/alert-dialog/index.js +1 -0
  10. package/dist/components/app-shell/AppShell.js +1 -1
  11. package/dist/components/calendar/Calendar.d.ts +20 -0
  12. package/dist/components/calendar/Calendar.js +119 -0
  13. package/dist/components/calendar/index.d.ts +2 -0
  14. package/dist/components/calendar/index.js +1 -0
  15. package/dist/components/checkbox-list/CheckboxList.d.ts +36 -0
  16. package/dist/components/checkbox-list/CheckboxList.js +93 -0
  17. package/dist/components/checkbox-list/index.d.ts +2 -0
  18. package/dist/components/checkbox-list/index.js +1 -0
  19. package/dist/components/collapsible/Collapsible.d.ts +24 -0
  20. package/dist/components/collapsible/Collapsible.js +58 -0
  21. package/dist/components/collapsible/index.d.ts +2 -0
  22. package/dist/components/collapsible/index.js +1 -0
  23. package/dist/components/data-table/DataTable.js +1 -1
  24. package/dist/components/date-picker/DatePicker.d.ts +33 -0
  25. package/dist/components/date-picker/DatePicker.js +104 -0
  26. package/dist/components/date-picker/index.d.ts +2 -0
  27. package/dist/components/date-picker/index.js +1 -0
  28. package/dist/components/date-range-picker/DateRangePicker.d.ts +39 -0
  29. package/dist/components/date-range-picker/DateRangePicker.js +142 -0
  30. package/dist/components/date-range-picker/index.d.ts +2 -0
  31. package/dist/components/date-range-picker/index.js +1 -0
  32. package/dist/components/field/Field.d.ts +35 -0
  33. package/dist/components/field/Field.js +67 -0
  34. package/dist/components/field/Label.d.ts +8 -0
  35. package/dist/components/field/Label.js +13 -0
  36. package/dist/components/field/index.d.ts +3 -0
  37. package/dist/components/field/index.js +3 -0
  38. package/dist/components/filter-tabs/FilterTabs.js +1 -1
  39. package/dist/components/global-search/GlobalSearch.js +1 -1
  40. package/dist/components/icon/registry.d.ts +2 -2
  41. package/dist/components/icon/registry.js +5 -1
  42. package/dist/components/input-group/InputGroup.js +1 -1
  43. package/dist/components/link/Link.d.ts +22 -0
  44. package/dist/components/link/Link.js +31 -0
  45. package/dist/components/link/index.d.ts +2 -0
  46. package/dist/components/link/index.js +1 -0
  47. package/dist/components/media-grid/MediaGrid.d.ts +49 -0
  48. package/dist/components/media-grid/MediaGrid.js +303 -0
  49. package/dist/components/media-grid/index.d.ts +2 -0
  50. package/dist/components/media-grid/index.js +1 -0
  51. package/dist/components/money-input/MoneyInput.d.ts +30 -0
  52. package/dist/components/money-input/MoneyInput.js +72 -0
  53. package/dist/components/money-input/index.d.ts +2 -0
  54. package/dist/components/money-input/index.js +1 -0
  55. package/dist/components/page-header/PageHeader.js +1 -1
  56. package/dist/components/save-bar/SaveBar.d.ts +27 -0
  57. package/dist/components/save-bar/SaveBar.js +37 -0
  58. package/dist/components/save-bar/index.d.ts +2 -0
  59. package/dist/components/save-bar/index.js +1 -0
  60. package/dist/components/search-field/SearchField.js +1 -1
  61. package/dist/components/select/Select.d.ts +40 -0
  62. package/dist/components/select/Select.js +84 -0
  63. package/dist/components/select/index.d.ts +2 -0
  64. package/dist/components/select/index.js +1 -0
  65. package/dist/components/side-nav/SideNav.js +3 -3
  66. package/dist/components/summary-chips/SummaryChips.d.ts +17 -0
  67. package/dist/components/summary-chips/SummaryChips.js +19 -0
  68. package/dist/components/summary-chips/index.d.ts +2 -0
  69. package/dist/components/summary-chips/index.js +1 -0
  70. package/dist/components/switch/Switch.d.ts +10 -0
  71. package/dist/components/switch/Switch.js +20 -0
  72. package/dist/components/switch/index.d.ts +2 -0
  73. package/dist/components/switch/index.js +1 -0
  74. package/dist/components/table/Table.js +1 -1
  75. package/dist/components/tag-input/TagInput.d.ts +44 -0
  76. package/dist/components/tag-input/TagInput.js +102 -0
  77. package/dist/components/tag-input/index.d.ts +2 -0
  78. package/dist/components/tag-input/index.js +1 -0
  79. package/dist/components/textarea/Textarea.d.ts +15 -0
  80. package/dist/components/textarea/Textarea.js +21 -0
  81. package/dist/components/textarea/index.d.ts +2 -0
  82. package/dist/components/textarea/index.js +1 -0
  83. package/dist/components/top-bar/StoreSwitcher.js +1 -1
  84. package/dist/components/top-bar/TopBar.js +2 -2
  85. package/dist/components/unit-input/UnitInput.d.ts +33 -0
  86. package/dist/components/unit-input/UnitInput.js +47 -0
  87. package/dist/components/unit-input/index.d.ts +2 -0
  88. package/dist/components/unit-input/index.js +1 -0
  89. package/dist/index.d.ts +43 -6
  90. package/dist/index.js +26 -7
  91. package/dist/lib/cn.js +7 -1
  92. package/dist/lib/format.d.ts +65 -4
  93. package/dist/lib/format.js +163 -6
  94. package/dist/styles.css +1 -1
  95. package/package.json +78 -1
@@ -0,0 +1,18 @@
1
+ import { HTMLAttributes, JSX, ReactNode, Ref } from "react";
2
+ /** The tone of an alert. Critical uses the question 1 tokens. */
3
+ export type AlertTone = 'info' | 'success' | 'warning' | 'critical';
4
+ /** The props of Alert: the HTML attributes of its div, except className, style, children and title. */
5
+ export type AlertProps = Omit<HTMLAttributes<HTMLDivElement>, 'className' | 'style' | 'children' | 'title'> & {
6
+ /** The tone. Defaults to info. */
7
+ tone?: AlertTone;
8
+ /** An optional bold first line. */
9
+ title?: ReactNode;
10
+ /** An optional second line. */
11
+ description?: ReactNode;
12
+ /** An optional action on the right, usually one Button. */
13
+ action?: ReactNode;
14
+ /** Receives the rendered div. */
15
+ ref?: Ref<HTMLDivElement>;
16
+ };
17
+ /** A message that stays in the page: a tone glyph, an optional title and description, and an optional action. */
18
+ export declare function Alert({ tone, title, description, action, ref, ...rest }: AlertProps): JSX.Element;
@@ -0,0 +1,67 @@
1
+ import { cn } from "../../lib/cn.js";
2
+ import { Icon } from "../icon/Icon.js";
3
+ import { Text } from "../text/Text.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ // src/components/alert/Alert.tsx
6
+ const TONES = {
7
+ info: {
8
+ box: "rt:bg-primary-tint rt:border-primary-tint",
9
+ glyph: "rt:text-primary",
10
+ icon: "info-circle"
11
+ },
12
+ success: {
13
+ box: "rt:bg-success-tint rt:border-success-border",
14
+ glyph: "rt:text-success",
15
+ icon: "check"
16
+ },
17
+ warning: {
18
+ box: "rt:bg-warning-tint rt:border-warning-border",
19
+ glyph: "rt:text-warning",
20
+ icon: "alert-triangle"
21
+ },
22
+ critical: {
23
+ box: "rt:bg-alert-critical-background rt:border-alert-critical-border rt:text-alert-critical-foreground",
24
+ glyph: "rt:text-error-icon",
25
+ icon: "alert-triangle"
26
+ }
27
+ };
28
+ /** A message that stays in the page: a tone glyph, an optional title and description, and an optional action. */
29
+ function Alert({ tone = "info", title, description, action, ref, ...rest }) {
30
+ const t = TONES[tone];
31
+ return /* @__PURE__ */ jsxs("div", {
32
+ role: tone === "warning" || tone === "critical" ? "alert" : "status",
33
+ "data-slot": "alert",
34
+ ...rest,
35
+ ref,
36
+ "data-tone": tone,
37
+ className: cn("rt:flex rt:w-full rt:min-w-0 rt:items-start rt:gap-2 rt:rounded-lg rt:border rt:px-3 rt:py-2 rt:text-left rt:text-foreground", t.box),
38
+ children: [
39
+ /* @__PURE__ */ jsx("span", {
40
+ className: cn("rt:mt-0.5 rt:shrink-0", t.glyph),
41
+ children: /* @__PURE__ */ jsx(Icon, {
42
+ name: t.icon,
43
+ size: 16
44
+ })
45
+ }),
46
+ /* @__PURE__ */ jsxs("div", {
47
+ className: "rt:flex rt:min-w-0 rt:flex-1 rt:flex-col rt:gap-0.5",
48
+ children: [title ? /* @__PURE__ */ jsx(Text, {
49
+ as: "p",
50
+ variant: "b4",
51
+ tone: tone === "critical" ? "inherit" : "default",
52
+ children: title
53
+ }) : null, description ? /* @__PURE__ */ jsx(Text, {
54
+ as: "p",
55
+ tone: tone === "critical" ? "inherit" : "subdued",
56
+ children: description
57
+ }) : null]
58
+ }),
59
+ action ? /* @__PURE__ */ jsx("div", {
60
+ "data-slot": "alert-action",
61
+ className: "rt:shrink-0",
62
+ children: action
63
+ }) : null
64
+ ]
65
+ });
66
+ }
67
+ export { Alert };
@@ -0,0 +1,2 @@
1
+ import { Alert, AlertProps, AlertTone } from "./Alert.js";
2
+ export { Alert, type AlertProps, type AlertTone };
@@ -0,0 +1 @@
1
+ export { Alert } from "./Alert.js";
@@ -0,0 +1,48 @@
1
+ import { ButtonVariant } from "../button/Button.js";
2
+ import "../button/index.js";
3
+ import { ComponentProps, JSX } from "react";
4
+ import { AlertDialog } from "@base-ui/react/alert-dialog";
5
+ /**
6
+ * The root of a confirmation. It holds the open state and renders nothing itself. Pass `open` and `onOpenChange` to
7
+ * control it, or `defaultOpen` to leave it uncontrolled. Escape closes it; a click outside does not.
8
+ */
9
+ declare function AlertDialog$1(props: AlertDialog.Root.Props): JSX.Element;
10
+ /** Props of AlertDialogTrigger. */
11
+ export type AlertDialogTriggerProps = Omit<AlertDialog.Trigger.Props, 'className' | 'style'>;
12
+ /** The button that opens the confirmation. */
13
+ export declare function AlertDialogTrigger(props: AlertDialogTriggerProps): JSX.Element;
14
+ /** Props of AlertDialogContent. */
15
+ export type AlertDialogContentProps = Omit<AlertDialog.Popup.Props, 'className' | 'style'>;
16
+ /**
17
+ * The panel: 480px wide, white, drawn with the ring outline and no shadow, with no scrim behind it. Put
18
+ * AlertDialogHeader and AlertDialogFooter inside.
19
+ */
20
+ export declare function AlertDialogContent(props: AlertDialogContentProps): JSX.Element;
21
+ /** Props of AlertDialogHeader. */
22
+ export type AlertDialogHeaderProps = Omit<ComponentProps<'div'>, 'className' | 'style'>;
23
+ /** The title and description, stacked. */
24
+ export declare function AlertDialogHeader(props: AlertDialogHeaderProps): JSX.Element;
25
+ /** Props of AlertDialogFooter. */
26
+ export type AlertDialogFooterProps = Omit<ComponentProps<'div'>, 'className' | 'style'>;
27
+ /** The row of actions at the bottom, aligned to the end. */
28
+ export declare function AlertDialogFooter(props: AlertDialogFooterProps): JSX.Element;
29
+ /** Props of AlertDialogTitle. */
30
+ export type AlertDialogTitleProps = Omit<AlertDialog.Title.Props, 'className' | 'style'>;
31
+ /** The question, in the b4 style. It names the dialog for assistive technology. */
32
+ export declare function AlertDialogTitle(props: AlertDialogTitleProps): JSX.Element;
33
+ /** Props of AlertDialogDescription. */
34
+ export type AlertDialogDescriptionProps = Omit<AlertDialog.Description.Props, 'className' | 'style'>;
35
+ /** What will happen, in subdued body text. */
36
+ export declare function AlertDialogDescription(props: AlertDialogDescriptionProps): JSX.Element;
37
+ /** Props of AlertDialogAction. */
38
+ export interface AlertDialogActionProps extends Omit<AlertDialog.Close.Props, 'className' | 'style' | 'render'> {
39
+ /** The Button look. Defaults to destructive; use main for a confirmation that deletes nothing. */
40
+ variant?: Extract<ButtonVariant, 'destructive' | 'main'>;
41
+ }
42
+ /** The confirming button. It is the Button's destructive variant and closes the dialog after its onClick runs. */
43
+ export declare function AlertDialogAction({ variant, ...props }: AlertDialogActionProps): JSX.Element;
44
+ /** Props of AlertDialogCancel. */
45
+ export type AlertDialogCancelProps = Omit<AlertDialog.Close.Props, 'className' | 'style' | 'render'>;
46
+ /** The secondary button that closes the dialog without doing anything. */
47
+ export declare function AlertDialogCancel(props: AlertDialogCancelProps): JSX.Element;
48
+ export { AlertDialog$1 as AlertDialog };
@@ -0,0 +1,76 @@
1
+ import { Button } from "../button/Button.js";
2
+ import { jsx } from "react/jsx-runtime";
3
+ import { AlertDialog } from "@base-ui/react/alert-dialog";
4
+ // src/components/alert-dialog/AlertDialog.tsx
5
+ /**
6
+ * The root of a confirmation. It holds the open state and renders nothing itself. Pass `open` and `onOpenChange` to
7
+ * control it, or `defaultOpen` to leave it uncontrolled. Escape closes it; a click outside does not.
8
+ */
9
+ function AlertDialog$1(props) {
10
+ return /* @__PURE__ */ jsx(AlertDialog.Root, { ...props });
11
+ }
12
+ /** The button that opens the confirmation. */
13
+ function AlertDialogTrigger(props) {
14
+ return /* @__PURE__ */ jsx(AlertDialog.Trigger, {
15
+ "data-slot": "alert-dialog-trigger",
16
+ ...props
17
+ });
18
+ }
19
+ /**
20
+ * The panel: 480px wide, white, drawn with the ring outline and no shadow, with no scrim behind it. Put
21
+ * AlertDialogHeader and AlertDialogFooter inside.
22
+ */
23
+ function AlertDialogContent(props) {
24
+ return /* @__PURE__ */ jsx(AlertDialog.Portal, { children: /* @__PURE__ */ jsx(AlertDialog.Popup, {
25
+ "data-slot": "alert-dialog-content",
26
+ className: "rt:fixed rt:inset-0 rt:z-50 rt:m-auto rt:flex rt:h-fit rt:max-h-full rt:w-120 rt:max-w-full rt:overflow-y-auto rt:flex-col rt:gap-6 rt:rounded-lg rt:bg-popover rt:p-6 rt:text-b3 rt:text-popover-foreground rt:shadow-ring-strong rt:forced-outline rt:focus-visible:focus-ring",
27
+ ...props
28
+ }) });
29
+ }
30
+ /** The title and description, stacked. */
31
+ function AlertDialogHeader(props) {
32
+ return /* @__PURE__ */ jsx("div", {
33
+ "data-slot": "alert-dialog-header",
34
+ className: "rt:flex rt:flex-col rt:gap-1",
35
+ ...props
36
+ });
37
+ }
38
+ /** The row of actions at the bottom, aligned to the end. */
39
+ function AlertDialogFooter(props) {
40
+ return /* @__PURE__ */ jsx("div", {
41
+ "data-slot": "alert-dialog-footer",
42
+ className: "rt:flex rt:items-center rt:justify-end rt:gap-2",
43
+ ...props
44
+ });
45
+ }
46
+ /** The question, in the b4 style. It names the dialog for assistive technology. */
47
+ function AlertDialogTitle(props) {
48
+ return /* @__PURE__ */ jsx(AlertDialog.Title, {
49
+ "data-slot": "alert-dialog-title",
50
+ className: "rt:text-b4 rt:text-foreground-strong",
51
+ ...props
52
+ });
53
+ }
54
+ /** What will happen, in subdued body text. */
55
+ function AlertDialogDescription(props) {
56
+ return /* @__PURE__ */ jsx(AlertDialog.Description, {
57
+ "data-slot": "alert-dialog-description",
58
+ className: "rt:text-b3 rt:text-foreground-subdued",
59
+ ...props
60
+ });
61
+ }
62
+ /** The confirming button. It is the Button's destructive variant and closes the dialog after its onClick runs. */
63
+ function AlertDialogAction({ variant = "destructive", ...props }) {
64
+ return /* @__PURE__ */ jsx(AlertDialog.Close, {
65
+ render: /* @__PURE__ */ jsx(Button, { variant }),
66
+ ...props
67
+ });
68
+ }
69
+ /** The secondary button that closes the dialog without doing anything. */
70
+ function AlertDialogCancel(props) {
71
+ return /* @__PURE__ */ jsx(AlertDialog.Close, {
72
+ render: /* @__PURE__ */ jsx(Button, { variant: "secondary" }),
73
+ ...props
74
+ });
75
+ }
76
+ export { AlertDialog$1 as AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger };
@@ -0,0 +1,2 @@
1
+ import { AlertDialog, AlertDialogAction, AlertDialogActionProps, AlertDialogCancel, AlertDialogCancelProps, AlertDialogContent, AlertDialogContentProps, AlertDialogDescription, AlertDialogDescriptionProps, AlertDialogFooter, AlertDialogFooterProps, AlertDialogHeader, AlertDialogHeaderProps, AlertDialogTitle, AlertDialogTitleProps, AlertDialogTrigger, AlertDialogTriggerProps } from "./AlertDialog.js";
2
+ export { AlertDialog, AlertDialogAction, type AlertDialogActionProps, AlertDialogCancel, type AlertDialogCancelProps, AlertDialogContent, type AlertDialogContentProps, AlertDialogDescription, type AlertDialogDescriptionProps, AlertDialogFooter, type AlertDialogFooterProps, AlertDialogHeader, type AlertDialogHeaderProps, AlertDialogTitle, type AlertDialogTitleProps, AlertDialogTrigger, type AlertDialogTriggerProps };
@@ -0,0 +1 @@
1
+ export { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger } from "./AlertDialog.js";
@@ -1,6 +1,6 @@
1
1
  import { ShellNavContext } from "./context.js";
2
- import { useId, useState } from "react";
3
2
  import { jsx, jsxs } from "react/jsx-runtime";
3
+ import { useId, useState } from "react";
4
4
  // src/components/app-shell/AppShell.tsx
5
5
  /**
6
6
  * The frame of every page: the side nav at the left, the top bar above and the content below it. It fills the height of its
@@ -0,0 +1,20 @@
1
+ import { JSX } from "react";
2
+ import { DayPickerProps } from "react-day-picker";
3
+ /** Omit for each member of a union, so the selection modes of DayPicker stay a discriminated union. */
4
+ type DistributiveOmit<T, K extends PropertyKey> = T extends unknown ? Omit<T, K> : never;
5
+ /**
6
+ * Props of Calendar: DayPicker's props (mode, selected, onSelect, defaultMonth, month, today, disabled, startMonth,
7
+ * endMonth, numberOfMonths, showOutsideDays, locale, labels and the rest), without the ones that restyle it, replace its
8
+ * parts, change how a date is written or animate it: the calendar is drawn by the design system, dates are written by
9
+ * the format module and motion is a colour fade only.
10
+ */
11
+ export type CalendarProps = DistributiveOmit<DayPickerProps, 'className' | 'style' | 'classNames' | 'styles' | 'modifiersClassNames' | 'modifiersStyles' | 'components' | 'formatters' | 'captionLayout' | 'animate' | 'showWeekNumber'>;
12
+ /**
13
+ * A month grid to pick a day or a range of days, drawn by the design system: 28px days with a 6px radius, today in the
14
+ * accent ink, the selected day filled with the accent, a range as accent ends on a tinted band, disabled days at 50% and
15
+ * the days of the months around it in the muted ink. Every day is named in the format module's date order (28/10/2026).
16
+ * Arrow keys move between days and the previous and next buttons between months. It has no fill of its own, so it sits
17
+ * in a popover or a container as drawn.
18
+ */
19
+ export declare function Calendar({ showOutsideDays, labels, ...props }: CalendarProps): JSX.Element;
20
+ export {};
@@ -0,0 +1,119 @@
1
+ import { Icon } from "../icon/Icon.js";
2
+ import { Button } from "../button/Button.js";
3
+ import { FORMAT, formatDate } from "../../lib/format.js";
4
+ import { jsx } from "react/jsx-runtime";
5
+ import { useEffect, useRef } from "react";
6
+ import { cva } from "class-variance-authority";
7
+ import { DayPicker } from "react-day-picker";
8
+ // src/components/calendar/Calendar.tsx
9
+ const dayButtonVariants = cva("rt:flex rt:size-7 rt:items-center rt:justify-center rt:border-0 rt:p-0 rt:select-none rt:cursor-pointer rt:transition-colors rt:focus-visible:focus-ring rt:disabled:pointer-events-none rt:disabled:cursor-not-allowed rt:disabled:opacity-50", {
10
+ variants: { look: {
11
+ plain: "rt:rounded-md rt:bg-transparent rt:text-btn rt:text-foreground rt:hover:bg-muted rt:active:bg-muted",
12
+ today: "rt:rounded-md rt:bg-transparent rt:text-c3 rt:text-primary rt:hover:bg-muted rt:active:bg-muted",
13
+ outside: "rt:rounded-md rt:bg-transparent rt:text-btn rt:text-muted-foreground rt:hover:bg-muted rt:active:bg-muted",
14
+ selected: "rt:rounded-md rt:bg-primary rt:text-btn rt:text-primary-foreground rt:hover:bg-primary-hover rt:active:bg-primary-hover",
15
+ "range-middle": "rt:rounded-none rt:group-first:rounded-l-md rt:group-last:rounded-r-md rt:bg-primary-tint rt:text-btn rt:text-foreground"
16
+ } },
17
+ defaultVariants: { look: "plain" }
18
+ });
19
+ /** The look of a day from DayPicker's modifiers: a selection wins over outside, and outside over today. */
20
+ function dayLook(modifiers) {
21
+ if (modifiers.range_middle) return "range-middle";
22
+ if (modifiers.selected) return "selected";
23
+ if (modifiers.outside) return "outside";
24
+ if (modifiers.today) return "today";
25
+ return "plain";
26
+ }
27
+ /**
28
+ * The number in a day's button, written as the date pattern writes the day (two digits for DD), so the visible text is a
29
+ * word of the button's name (WCAG 2.5.3): 03 in 03/10/2026.
30
+ */
31
+ function formatDay(date) {
32
+ const day = String(date.getDate());
33
+ return FORMAT.datePattern.includes("DD") ? day.padStart(2, "0") : day;
34
+ }
35
+ /** A day as an accessible name, in the format module's date order: "Today, 28/10/2026, selected". */
36
+ function labelDay(date, modifiers) {
37
+ return `${modifiers?.today ? "Today, " : ""}${formatDate(date)}${modifiers?.selected ? ", selected" : ""}`;
38
+ }
39
+ /**
40
+ * The button of one day. DayPicker moves focus between days, so the button takes focus when its day is focused. Its look
41
+ * comes after DayPicker's props, so it replaces DayPicker's class name.
42
+ */
43
+ function CalendarDayButton({ day, modifiers, ...props }) {
44
+ const ref = useRef(null);
45
+ useEffect(() => {
46
+ if (modifiers.focused) ref.current?.focus();
47
+ }, [modifiers.focused]);
48
+ return /* @__PURE__ */ jsx("button", {
49
+ ref,
50
+ ...props,
51
+ "data-day": formatDate(day.date),
52
+ className: dayButtonVariants({ look: dayLook(modifiers) })
53
+ });
54
+ }
55
+ /** A month navigation button: the ghost Button with a chevron, disabled at the first or last allowed month. */
56
+ function navButton(icon) {
57
+ return function CalendarNavButton({ onClick, tabIndex, "aria-label": label, "aria-disabled": ariaDisabled }) {
58
+ return /* @__PURE__ */ jsx(Button, {
59
+ variant: "ghost",
60
+ iconOnly: true,
61
+ "aria-label": label ?? "",
62
+ disabled: ariaDisabled === true || ariaDisabled === "true",
63
+ tabIndex,
64
+ onClick,
65
+ children: /* @__PURE__ */ jsx(Icon, {
66
+ name: icon,
67
+ size: 12
68
+ })
69
+ });
70
+ };
71
+ }
72
+ const PreviousMonthButton = navButton("chevron-left");
73
+ const NextMonthButton = navButton("chevron-right");
74
+ const CLASS_NAMES = {
75
+ root: "rt:relative rt:w-fit rt:p-2 rt:text-foreground",
76
+ months: "rt:relative rt:flex rt:flex-col rt:gap-4 rt:md:flex-row",
77
+ month: "rt:flex rt:w-full rt:flex-col rt:gap-2",
78
+ nav: "rt:absolute rt:inset-x-0 rt:top-0 rt:z-10 rt:flex rt:w-full rt:items-center rt:justify-between rt:gap-1",
79
+ month_caption: "rt:flex rt:h-7 rt:w-full rt:items-center rt:justify-center rt:px-7",
80
+ caption_label: "rt:text-c3 rt:text-foreground rt:select-none",
81
+ month_grid: "rt:w-full rt:border-collapse",
82
+ weekdays: "rt:flex",
83
+ weekday: "rt:flex rt:w-7 rt:items-center rt:justify-center rt:text-c1 rt:text-muted-foreground rt:select-none",
84
+ week: "rt:mt-1 rt:flex rt:w-full",
85
+ day: "rt:relative rt:size-7 rt:p-0 rt:text-center rt:select-none rt:first:rounded-l-md rt:last:rounded-r-md rt:group",
86
+ range_start: "rt:rounded-l-md rt:bg-primary-tint",
87
+ range_end: "rt:rounded-r-md rt:bg-primary-tint",
88
+ hidden: "rt:invisible",
89
+ footer: "rt:pt-2 rt:text-c1 rt:text-muted-foreground"
90
+ };
91
+ /**
92
+ * A month grid to pick a day or a range of days, drawn by the design system: 28px days with a 6px radius, today in the
93
+ * accent ink, the selected day filled with the accent, a range as accent ends on a tinted band, disabled days at 50% and
94
+ * the days of the months around it in the muted ink. Every day is named in the format module's date order (28/10/2026).
95
+ * Arrow keys move between days and the previous and next buttons between months. It has no fill of its own, so it sits
96
+ * in a popover or a container as drawn.
97
+ */
98
+ function Calendar({ showOutsideDays = true, labels, ...props }) {
99
+ return /* @__PURE__ */ jsx(DayPicker, {
100
+ "data-slot": "calendar",
101
+ showOutsideDays,
102
+ classNames: CLASS_NAMES,
103
+ components: {
104
+ DayButton: CalendarDayButton,
105
+ PreviousMonthButton,
106
+ NextMonthButton
107
+ },
108
+ formatters: { formatDay },
109
+ labels: {
110
+ labelDayButton: labelDay,
111
+ labelGridcell: labelDay,
112
+ labelPrevious: () => "Previous month",
113
+ labelNext: () => "Next month",
114
+ ...labels
115
+ },
116
+ ...props
117
+ });
118
+ }
119
+ export { Calendar };
@@ -0,0 +1,2 @@
1
+ import { Calendar, CalendarProps } from "./Calendar.js";
2
+ export { Calendar, type CalendarProps };
@@ -0,0 +1 @@
1
+ export { Calendar } from "./Calendar.js";
@@ -0,0 +1,36 @@
1
+ import { HTMLAttributes, JSX } from "react";
2
+ /** One option in a CheckboxList. */
3
+ export type CheckboxListItem = {
4
+ /** The value reported in the list of chosen values. */
5
+ value: string;
6
+ /** The label beside the box. */
7
+ label: string;
8
+ /** An optional line under the label. */
9
+ description?: string;
10
+ /** Stops this item being toggled, and select-all leaves it as it is. */
11
+ disabled?: boolean;
12
+ };
13
+ /** The props of CheckboxList. */
14
+ export type CheckboxListProps = Omit<HTMLAttributes<HTMLDivElement>, 'className' | 'style' | 'title' | 'onChange' | 'defaultValue'> & {
15
+ /** The heading. The count of chosen items sits beside it. */
16
+ title: string;
17
+ /** The options. */
18
+ items: CheckboxListItem[];
19
+ /** The chosen values, when controlled. */
20
+ value?: string[];
21
+ /** The chosen values to start with, when not controlled. */
22
+ defaultValue?: string[];
23
+ /** Called with the new list of chosen values. */
24
+ onValueChange?: (value: string[]) => void;
25
+ /** Adds a "Select all" box that is mixed while only some are chosen. */
26
+ selectAll?: boolean;
27
+ /** The label of the select-all box. Defaults to "Select all". */
28
+ selectAllLabel?: string;
29
+ /** Writes the count in the heading from the chosen and total counts, already formatted. Defaults to "4 of 6". */
30
+ countLabel?: (chosen: string, total: string) => string;
31
+ };
32
+ /**
33
+ * A titled list of checkboxes with the count of chosen items in the heading ("4 of 6"), an optional description under
34
+ * each label and an optional select-all.
35
+ */
36
+ export declare function CheckboxList({ title, items, value, defaultValue, onValueChange, selectAll, selectAllLabel, countLabel, ...rest }: CheckboxListProps): JSX.Element;
@@ -0,0 +1,93 @@
1
+ import { formatCount } from "../../lib/format.js";
2
+ import { Checkbox } from "../checkbox/Checkbox.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useId, useState } from "react";
5
+ // src/components/checkbox-list/CheckboxList.tsx
6
+ /**
7
+ * A titled list of checkboxes with the count of chosen items in the heading ("4 of 6"), an optional description under
8
+ * each label and an optional select-all.
9
+ */
10
+ function CheckboxList({ title, items, value, defaultValue, onValueChange, selectAll, selectAllLabel = "Select all", countLabel = (c, t) => `${c} of ${t}`, ...rest }) {
11
+ const [inner, setInner] = useState(defaultValue ?? []);
12
+ const chosen = value ?? inner;
13
+ const baseId = useId();
14
+ const set = (next) => {
15
+ if (value === void 0) setInner(next);
16
+ onValueChange?.(next);
17
+ };
18
+ const chosenCount = items.filter((i) => chosen.includes(i.value)).length;
19
+ const toggleable = items.filter((i) => !i.disabled);
20
+ const allOn = toggleable.length > 0 && toggleable.every((i) => chosen.includes(i.value));
21
+ const someOn = chosenCount > 0;
22
+ const toggleAll = () => {
23
+ const locked = chosen.filter((v) => !toggleable.some((i) => i.value === v));
24
+ set(allOn ? locked : [...locked, ...toggleable.map((i) => i.value)]);
25
+ };
26
+ return /* @__PURE__ */ jsxs("div", {
27
+ "data-slot": "checkbox-list",
28
+ role: "group",
29
+ "aria-labelledby": `${baseId}-title`,
30
+ ...rest,
31
+ className: "rt:flex rt:flex-col rt:gap-3",
32
+ children: [
33
+ /* @__PURE__ */ jsx("div", {
34
+ className: "rt:flex rt:items-baseline rt:justify-between rt:gap-3",
35
+ children: /* @__PURE__ */ jsxs("span", {
36
+ id: `${baseId}-title`,
37
+ className: "rt:text-b4 rt:text-foreground",
38
+ children: [title, /* @__PURE__ */ jsx("span", {
39
+ "data-slot": "checkbox-list-count",
40
+ className: "rt:ml-2 rt:text-b3 rt:text-foreground-subdued",
41
+ children: countLabel(formatCount(chosenCount), formatCount(items.length))
42
+ })]
43
+ })
44
+ }),
45
+ selectAll ? /* @__PURE__ */ jsxs("div", {
46
+ className: "rt:flex rt:items-center rt:gap-2",
47
+ children: [/* @__PURE__ */ jsx(Checkbox, {
48
+ id: `${baseId}-all`,
49
+ checked: allOn,
50
+ indeterminate: someOn && !allOn,
51
+ onCheckedChange: toggleAll,
52
+ disabled: toggleable.length === 0,
53
+ "aria-label": selectAllLabel
54
+ }), /* @__PURE__ */ jsx("label", {
55
+ htmlFor: `${baseId}-all`,
56
+ className: "rt:cursor-pointer rt:text-b3 rt:text-foreground",
57
+ children: selectAllLabel
58
+ })]
59
+ }) : null,
60
+ /* @__PURE__ */ jsx("ul", {
61
+ className: "rt:flex rt:flex-col rt:gap-3",
62
+ children: items.map((item, index) => {
63
+ const id = `${baseId}-${index}`;
64
+ return /* @__PURE__ */ jsxs("li", {
65
+ className: "rt:flex rt:items-start rt:gap-2",
66
+ children: [/* @__PURE__ */ jsx("span", {
67
+ className: "rt:mt-0.5 rt:flex",
68
+ children: /* @__PURE__ */ jsx(Checkbox, {
69
+ id,
70
+ "aria-labelledby": `${id}-label`,
71
+ disabled: item.disabled,
72
+ checked: chosen.includes(item.value),
73
+ onCheckedChange: (on) => set(on ? [...chosen, item.value] : chosen.filter((v) => v !== item.value))
74
+ })
75
+ }), /* @__PURE__ */ jsxs("span", {
76
+ className: "rt:flex rt:flex-col",
77
+ children: [/* @__PURE__ */ jsx("label", {
78
+ id: `${id}-label`,
79
+ htmlFor: id,
80
+ className: "rt:cursor-pointer rt:text-b3 rt:text-foreground",
81
+ children: item.label
82
+ }), item.description ? /* @__PURE__ */ jsx("span", {
83
+ className: "rt:text-b3 rt:text-foreground-subdued",
84
+ children: item.description
85
+ }) : null]
86
+ })]
87
+ }, item.value);
88
+ })
89
+ })
90
+ ]
91
+ });
92
+ }
93
+ export { CheckboxList };
@@ -0,0 +1,2 @@
1
+ import { CheckboxList, CheckboxListItem, CheckboxListProps } from "./CheckboxList.js";
2
+ export { CheckboxList, type CheckboxListItem, type CheckboxListProps };
@@ -0,0 +1 @@
1
+ export { CheckboxList } from "./CheckboxList.js";
@@ -0,0 +1,24 @@
1
+ import { SummaryChip } from "../summary-chips/SummaryChips.js";
2
+ import "../summary-chips/index.js";
3
+ import { JSX, ReactNode, Ref } from "react";
4
+ /** The props of Collapsible. */
5
+ export interface CollapsibleProps {
6
+ /** The section heading, shown on the trigger. */
7
+ title: string;
8
+ /** The values to show as chips while the section is closed. */
9
+ summary?: readonly SummaryChip[];
10
+ /** Whether the section is open, when controlled. */
11
+ open?: boolean;
12
+ /** Whether the section starts open, when uncontrolled. Defaults to closed. */
13
+ defaultOpen?: boolean;
14
+ /** Called when the section opens or closes. */
15
+ onOpenChange?: (open: boolean) => void;
16
+ /** Stops the section from opening or closing. */
17
+ disabled?: boolean;
18
+ /** The section's content, shown when open. */
19
+ children: ReactNode;
20
+ /** Receives the rendered root. */
21
+ ref?: Ref<HTMLDivElement>;
22
+ }
23
+ /** A section that opens and closes on its heading and, while closed, still shows its values as chips. The panel appears and disappears with no height animation. */
24
+ export declare function Collapsible({ title, summary, open: openProp, defaultOpen, onOpenChange, disabled, children, ref }: CollapsibleProps): JSX.Element;
@@ -0,0 +1,58 @@
1
+ import { Icon } from "../icon/Icon.js";
2
+ import { SummaryChips } from "../summary-chips/SummaryChips.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useState } from "react";
5
+ import { Collapsible } from "@base-ui/react/collapsible";
6
+ // src/components/collapsible/Collapsible.tsx
7
+ /** A section that opens and closes on its heading and, while closed, still shows its values as chips. The panel appears and disappears with no height animation. */
8
+ function Collapsible$1({ title, summary, open: openProp, defaultOpen = false, onOpenChange, disabled, children, ref }) {
9
+ const [inner, setInner] = useState(defaultOpen);
10
+ const open = openProp ?? inner;
11
+ return /* @__PURE__ */ jsxs(Collapsible.Root, {
12
+ ref,
13
+ open,
14
+ onOpenChange: (next) => {
15
+ setInner(next);
16
+ onOpenChange?.(next);
17
+ },
18
+ disabled,
19
+ className: "rt:flex rt:flex-col rt:gap-2",
20
+ children: [
21
+ /* @__PURE__ */ jsxs(Collapsible.Trigger, {
22
+ className: "rt:group rt:flex rt:h-7 rt:w-full rt:cursor-pointer rt:items-center rt:gap-2 rt:rounded-md rt:border-0 rt:bg-transparent rt:p-0 rt:text-left rt:text-b3 rt:text-foreground rt:transition-colors rt:focus-visible:focus-ring rt:disabled:cursor-not-allowed rt:disabled:opacity-50 rt:data-disabled:opacity-50",
23
+ children: [
24
+ /* @__PURE__ */ jsx("span", {
25
+ className: "rt:group-data-panel-open:hidden",
26
+ children: /* @__PURE__ */ jsx(Icon, {
27
+ name: "chevron-right",
28
+ size: 8
29
+ })
30
+ }),
31
+ /* @__PURE__ */ jsx("span", {
32
+ className: "rt:hidden rt:group-data-panel-open:inline",
33
+ children: /* @__PURE__ */ jsx(Icon, {
34
+ name: "nav-caret-down",
35
+ size: 8
36
+ })
37
+ }),
38
+ /* @__PURE__ */ jsx("span", {
39
+ className: "rt:text-c2",
40
+ children: title
41
+ })
42
+ ]
43
+ }),
44
+ /* @__PURE__ */ jsx(Collapsible.Panel, {
45
+ className: "rt:flex rt:flex-col rt:gap-2",
46
+ children
47
+ }),
48
+ !open && summary ? /* @__PURE__ */ jsx("div", {
49
+ "data-slot": "collapsible-summary",
50
+ children: /* @__PURE__ */ jsx(SummaryChips, {
51
+ items: summary,
52
+ "aria-label": `${title} summary`
53
+ })
54
+ }) : null
55
+ ]
56
+ });
57
+ }
58
+ export { Collapsible$1 as Collapsible };
@@ -0,0 +1,2 @@
1
+ import { Collapsible, CollapsibleProps } from "./Collapsible.js";
2
+ export { Collapsible, type CollapsibleProps };
@@ -0,0 +1 @@
1
+ export { Collapsible } from "./Collapsible.js";
@@ -2,8 +2,8 @@ import { Checkbox } from "../checkbox/Checkbox.js";
2
2
  import { RatioLink } from "../link-provider/RatioLink.js";
3
3
  import { Pagination } from "../pagination/Pagination.js";
4
4
  import { Table, TableBody, TableBox, TableCell, TableHead, TableHeader, TableRow } from "../table/Table.js";
5
- import { useMemo, useSyncExternalStore } from "react";
6
5
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
6
+ import { useMemo, useSyncExternalStore } from "react";
7
7
  import { FlexRender, rowSelectionFeature, rowSortingFeature, tableFeatures, useTable } from "@tanstack/react-table";
8
8
  // src/components/data-table/DataTable.tsx
9
9
  const features = tableFeatures({