@ratio-ui/core 0.1.1 → 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 (214) hide show
  1. package/README.md +2 -0
  2. package/dist/catalogue.json +2829 -72
  3. package/dist/components/alert/Alert.d.ts +18 -0
  4. package/dist/components/alert/Alert.js +67 -0
  5. package/dist/components/alert/index.d.ts +2 -0
  6. package/dist/components/alert/index.js +1 -0
  7. package/dist/components/alert-dialog/AlertDialog.d.ts +48 -0
  8. package/dist/components/alert-dialog/AlertDialog.js +76 -0
  9. package/dist/components/alert-dialog/index.d.ts +2 -0
  10. package/dist/components/alert-dialog/index.js +1 -0
  11. package/dist/components/app-shell/AppShell.d.ts +22 -0
  12. package/dist/components/app-shell/AppShell.js +39 -0
  13. package/dist/components/app-shell/context.js +5 -0
  14. package/dist/components/app-shell/index.d.ts +2 -0
  15. package/dist/components/app-shell/index.js +1 -0
  16. package/dist/components/avatar/Avatar.d.ts +22 -0
  17. package/dist/components/avatar/Avatar.js +38 -0
  18. package/dist/components/avatar/index.d.ts +2 -0
  19. package/dist/components/avatar/index.js +1 -0
  20. package/dist/components/button/Button.d.ts +37 -0
  21. package/dist/components/button/Button.js +41 -0
  22. package/dist/components/button/index.d.ts +2 -0
  23. package/dist/components/button/index.js +1 -0
  24. package/dist/components/calendar/Calendar.d.ts +20 -0
  25. package/dist/components/calendar/Calendar.js +119 -0
  26. package/dist/components/calendar/index.d.ts +2 -0
  27. package/dist/components/calendar/index.js +1 -0
  28. package/dist/components/card/Card.d.ts +33 -0
  29. package/dist/components/card/Card.js +53 -0
  30. package/dist/components/card/index.d.ts +2 -0
  31. package/dist/components/card/index.js +1 -0
  32. package/dist/components/checkbox/Checkbox.d.ts +10 -0
  33. package/dist/components/checkbox/Checkbox.js +28 -0
  34. package/dist/components/checkbox/index.d.ts +2 -0
  35. package/dist/components/checkbox/index.js +1 -0
  36. package/dist/components/checkbox-list/CheckboxList.d.ts +36 -0
  37. package/dist/components/checkbox-list/CheckboxList.js +93 -0
  38. package/dist/components/checkbox-list/index.d.ts +2 -0
  39. package/dist/components/checkbox-list/index.js +1 -0
  40. package/dist/components/collapsible/Collapsible.d.ts +24 -0
  41. package/dist/components/collapsible/Collapsible.js +58 -0
  42. package/dist/components/collapsible/index.d.ts +2 -0
  43. package/dist/components/collapsible/index.js +1 -0
  44. package/dist/components/data-table/DataTable.d.ts +65 -0
  45. package/dist/components/data-table/DataTable.js +141 -0
  46. package/dist/components/data-table/index.d.ts +2 -0
  47. package/dist/components/data-table/index.js +1 -0
  48. package/dist/components/date-picker/DatePicker.d.ts +33 -0
  49. package/dist/components/date-picker/DatePicker.js +104 -0
  50. package/dist/components/date-picker/index.d.ts +2 -0
  51. package/dist/components/date-picker/index.js +1 -0
  52. package/dist/components/date-range-picker/DateRangePicker.d.ts +39 -0
  53. package/dist/components/date-range-picker/DateRangePicker.js +142 -0
  54. package/dist/components/date-range-picker/index.d.ts +2 -0
  55. package/dist/components/date-range-picker/index.js +1 -0
  56. package/dist/components/definition/Definition.d.ts +14 -0
  57. package/dist/components/definition/Definition.js +29 -0
  58. package/dist/components/definition/index.d.ts +2 -0
  59. package/dist/components/definition/index.js +1 -0
  60. package/dist/components/dialog/Dialog.d.ts +44 -0
  61. package/dist/components/dialog/Dialog.js +79 -0
  62. package/dist/components/dialog/index.d.ts +2 -0
  63. package/dist/components/dialog/index.js +1 -0
  64. package/dist/components/dropdown-menu/DropdownMenu.d.ts +73 -0
  65. package/dist/components/dropdown-menu/DropdownMenu.js +116 -0
  66. package/dist/components/dropdown-menu/index.d.ts +2 -0
  67. package/dist/components/dropdown-menu/index.js +1 -0
  68. package/dist/components/empty-state/EmptyState.d.ts +15 -0
  69. package/dist/components/empty-state/EmptyState.js +30 -0
  70. package/dist/components/empty-state/index.d.ts +2 -0
  71. package/dist/components/empty-state/index.js +1 -0
  72. package/dist/components/field/Field.d.ts +35 -0
  73. package/dist/components/field/Field.js +67 -0
  74. package/dist/components/field/Label.d.ts +8 -0
  75. package/dist/components/field/Label.js +13 -0
  76. package/dist/components/field/index.d.ts +3 -0
  77. package/dist/components/field/index.js +3 -0
  78. package/dist/components/filter-tabs/FilterTabs.d.ts +28 -0
  79. package/dist/components/filter-tabs/FilterTabs.js +37 -0
  80. package/dist/components/filter-tabs/index.d.ts +2 -0
  81. package/dist/components/filter-tabs/index.js +1 -0
  82. package/dist/components/global-search/GlobalSearch.d.ts +51 -0
  83. package/dist/components/global-search/GlobalSearch.js +144 -0
  84. package/dist/components/global-search/index.d.ts +2 -0
  85. package/dist/components/global-search/index.js +1 -0
  86. package/dist/components/icon/registry.d.ts +3 -2
  87. package/dist/components/icon/registry.js +57 -1
  88. package/dist/components/input/Input.d.ts +19 -0
  89. package/dist/components/input/Input.js +26 -0
  90. package/dist/components/input/index.d.ts +2 -0
  91. package/dist/components/input/index.js +1 -0
  92. package/dist/components/input-group/InputGroup.d.ts +42 -0
  93. package/dist/components/input-group/InputGroup.js +83 -0
  94. package/dist/components/input-group/index.d.ts +2 -0
  95. package/dist/components/input-group/index.js +1 -0
  96. package/dist/components/kbd/Kbd.d.ts +17 -0
  97. package/dist/components/kbd/Kbd.js +21 -0
  98. package/dist/components/kbd/index.d.ts +2 -0
  99. package/dist/components/kbd/index.js +1 -0
  100. package/dist/components/link/Link.d.ts +22 -0
  101. package/dist/components/link/Link.js +31 -0
  102. package/dist/components/link/index.d.ts +2 -0
  103. package/dist/components/link/index.js +1 -0
  104. package/dist/components/link-provider/LinkProvider.d.ts +29 -0
  105. package/dist/components/link-provider/LinkProvider.js +15 -0
  106. package/dist/components/link-provider/RatioLink.js +18 -0
  107. package/dist/components/link-provider/context.js +4 -0
  108. package/dist/components/link-provider/index.d.ts +2 -0
  109. package/dist/components/link-provider/index.js +1 -0
  110. package/dist/components/media-grid/MediaGrid.d.ts +49 -0
  111. package/dist/components/media-grid/MediaGrid.js +303 -0
  112. package/dist/components/media-grid/index.d.ts +2 -0
  113. package/dist/components/media-grid/index.js +1 -0
  114. package/dist/components/metric-strip/MetricStrip.d.ts +23 -0
  115. package/dist/components/metric-strip/MetricStrip.js +39 -0
  116. package/dist/components/metric-strip/index.d.ts +2 -0
  117. package/dist/components/metric-strip/index.js +1 -0
  118. package/dist/components/money-input/MoneyInput.d.ts +30 -0
  119. package/dist/components/money-input/MoneyInput.js +72 -0
  120. package/dist/components/money-input/index.d.ts +2 -0
  121. package/dist/components/money-input/index.js +1 -0
  122. package/dist/components/page-header/PageHeader.d.ts +37 -0
  123. package/dist/components/page-header/PageHeader.js +62 -0
  124. package/dist/components/page-header/index.d.ts +2 -0
  125. package/dist/components/page-header/index.js +1 -0
  126. package/dist/components/pagination/Pagination.d.ts +18 -0
  127. package/dist/components/pagination/Pagination.js +59 -0
  128. package/dist/components/pagination/index.d.ts +2 -0
  129. package/dist/components/pagination/index.js +1 -0
  130. package/dist/components/popover/Popover.d.ts +27 -0
  131. package/dist/components/popover/Popover.js +47 -0
  132. package/dist/components/popover/index.d.ts +2 -0
  133. package/dist/components/popover/index.js +1 -0
  134. package/dist/components/save-bar/SaveBar.d.ts +27 -0
  135. package/dist/components/save-bar/SaveBar.js +37 -0
  136. package/dist/components/save-bar/index.d.ts +2 -0
  137. package/dist/components/save-bar/index.js +1 -0
  138. package/dist/components/search-field/SearchField.d.ts +23 -0
  139. package/dist/components/search-field/SearchField.js +66 -0
  140. package/dist/components/search-field/index.d.ts +2 -0
  141. package/dist/components/search-field/index.js +1 -0
  142. package/dist/components/select/Select.d.ts +40 -0
  143. package/dist/components/select/Select.js +84 -0
  144. package/dist/components/select/index.d.ts +2 -0
  145. package/dist/components/select/index.js +1 -0
  146. package/dist/components/side-nav/SideNav.d.ts +64 -0
  147. package/dist/components/side-nav/SideNav.js +194 -0
  148. package/dist/components/side-nav/index.d.ts +2 -0
  149. package/dist/components/side-nav/index.js +1 -0
  150. package/dist/components/skeleton/Skeleton.d.ts +13 -0
  151. package/dist/components/skeleton/Skeleton.js +21 -0
  152. package/dist/components/skeleton/index.d.ts +2 -0
  153. package/dist/components/skeleton/index.js +1 -0
  154. package/dist/components/spinner/Spinner.d.ts +11 -0
  155. package/dist/components/spinner/Spinner.js +16 -0
  156. package/dist/components/spinner/index.d.ts +2 -0
  157. package/dist/components/spinner/index.js +1 -0
  158. package/dist/components/status-pill/StatusPill.d.ts +14 -0
  159. package/dist/components/status-pill/StatusPill.js +19 -0
  160. package/dist/components/status-pill/index.d.ts +2 -0
  161. package/dist/components/status-pill/index.js +1 -0
  162. package/dist/components/summary-chips/SummaryChips.d.ts +17 -0
  163. package/dist/components/summary-chips/SummaryChips.js +19 -0
  164. package/dist/components/summary-chips/index.d.ts +2 -0
  165. package/dist/components/summary-chips/index.js +1 -0
  166. package/dist/components/switch/Switch.d.ts +10 -0
  167. package/dist/components/switch/Switch.js +20 -0
  168. package/dist/components/switch/index.d.ts +2 -0
  169. package/dist/components/switch/index.js +1 -0
  170. package/dist/components/table/Table.d.ts +46 -0
  171. package/dist/components/table/Table.js +87 -0
  172. package/dist/components/table/index.d.ts +2 -0
  173. package/dist/components/table/index.js +1 -0
  174. package/dist/components/table-loader/TableLoader.d.ts +31 -0
  175. package/dist/components/table-loader/TableLoader.js +35 -0
  176. package/dist/components/table-loader/index.d.ts +2 -0
  177. package/dist/components/table-loader/index.js +1 -0
  178. package/dist/components/tabs/Tabs.d.ts +23 -0
  179. package/dist/components/tabs/Tabs.js +41 -0
  180. package/dist/components/tabs/index.d.ts +2 -0
  181. package/dist/components/tabs/index.js +1 -0
  182. package/dist/components/tag-input/TagInput.d.ts +44 -0
  183. package/dist/components/tag-input/TagInput.js +102 -0
  184. package/dist/components/tag-input/index.d.ts +2 -0
  185. package/dist/components/tag-input/index.js +1 -0
  186. package/dist/components/textarea/Textarea.d.ts +15 -0
  187. package/dist/components/textarea/Textarea.js +21 -0
  188. package/dist/components/textarea/index.d.ts +2 -0
  189. package/dist/components/textarea/index.js +1 -0
  190. package/dist/components/toaster/Toaster.d.ts +32 -0
  191. package/dist/components/toaster/Toaster.js +89 -0
  192. package/dist/components/toaster/index.d.ts +2 -0
  193. package/dist/components/toaster/index.js +1 -0
  194. package/dist/components/tooltip/Tooltip.d.ts +18 -0
  195. package/dist/components/tooltip/Tooltip.js +35 -0
  196. package/dist/components/tooltip/index.d.ts +2 -0
  197. package/dist/components/tooltip/index.js +1 -0
  198. package/dist/components/top-bar/StoreSwitcher.d.ts +26 -0
  199. package/dist/components/top-bar/StoreSwitcher.js +48 -0
  200. package/dist/components/top-bar/TopBar.d.ts +24 -0
  201. package/dist/components/top-bar/TopBar.js +53 -0
  202. package/dist/components/top-bar/index.d.ts +3 -0
  203. package/dist/components/top-bar/index.js +3 -0
  204. package/dist/components/unit-input/UnitInput.d.ts +33 -0
  205. package/dist/components/unit-input/UnitInput.js +47 -0
  206. package/dist/components/unit-input/index.d.ts +2 -0
  207. package/dist/components/unit-input/index.js +1 -0
  208. package/dist/index.d.ts +102 -1
  209. package/dist/index.js +54 -2
  210. package/dist/lib/cn.js +38 -27
  211. package/dist/lib/format.d.ts +92 -0
  212. package/dist/lib/format.js +222 -0
  213. package/dist/styles.css +1 -1
  214. package/package.json +205 -3
@@ -0,0 +1,59 @@
1
+ import { Icon } from "../icon/Icon.js";
2
+ import { formatCount } from "../../lib/format.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ // src/components/pagination/Pagination.tsx
5
+ const ARROW = "rt:inline-flex rt:size-7 rt:items-center rt:justify-center rt:rounded-md rt:bg-background rt:text-foreground-subdued rt:transition-colors rt:not-aria-disabled:cursor-pointer rt:not-aria-disabled:hover:bg-muted rt:focus-visible:focus-ring rt:aria-disabled:opacity-50";
6
+ /**
7
+ * One arrow. At the end of the list it stays focusable and is marked aria-disabled, so pressing Next onto the last page
8
+ * leaves focus on it rather than dropping it to the page; a press on it then does nothing.
9
+ */
10
+ function Arrow({ label, icon, disabled, onPress }) {
11
+ return /* @__PURE__ */ jsx("button", {
12
+ type: "button",
13
+ "aria-label": label,
14
+ "aria-disabled": disabled ? true : void 0,
15
+ className: ARROW,
16
+ onClick: disabled ? void 0 : onPress,
17
+ children: /* @__PURE__ */ jsx(Icon, {
18
+ name: icon,
19
+ size: 8
20
+ })
21
+ });
22
+ }
23
+ /**
24
+ * The footer under a table: Previous and Next arrows and the range on show, written "1 – 20 of 84 results". An arrow is
25
+ * dimmed to 50% and disabled (aria-disabled, still focusable) when there is no page that way. The parent owns the page: it passes `page` and updates it in
26
+ * `onPageChange`.
27
+ */
28
+ function Pagination({ page, pageSize, total, onPageChange, "aria-label": label = "Pagination", ...rest }) {
29
+ const size = Math.max(1, pageSize);
30
+ const lastPage = Math.max(1, Math.ceil(total / size));
31
+ const current = Math.min(Math.max(1, page), lastPage);
32
+ const from = (current - 1) * size + 1;
33
+ const to = Math.min(current * size, total);
34
+ const summary = total === 0 ? "0 results" : `${formatCount(from)} – ${formatCount(to)} of ${formatCount(total)} results`;
35
+ return /* @__PURE__ */ jsxs("nav", {
36
+ "aria-label": label,
37
+ className: "rt:flex rt:h-13 rt:items-center rt:gap-2 rt:bg-background rt:py-3",
38
+ ...rest,
39
+ children: [/* @__PURE__ */ jsxs("div", {
40
+ className: "rt:flex rt:w-14 rt:shrink-0",
41
+ children: [/* @__PURE__ */ jsx(Arrow, {
42
+ label: "Previous page",
43
+ icon: "chevron-left",
44
+ disabled: current <= 1,
45
+ onPress: () => onPageChange(current - 1)
46
+ }), /* @__PURE__ */ jsx(Arrow, {
47
+ label: "Next page",
48
+ icon: "chevron-right",
49
+ disabled: current >= lastPage,
50
+ onPress: () => onPageChange(current + 1)
51
+ })]
52
+ }), /* @__PURE__ */ jsx("p", {
53
+ role: "status",
54
+ className: "rt:min-w-26 rt:px-2 rt:text-c1 rt:whitespace-nowrap rt:text-foreground-subdued",
55
+ children: summary
56
+ })]
57
+ });
58
+ }
59
+ export { Pagination };
@@ -0,0 +1,2 @@
1
+ import { Pagination, PaginationProps } from "./Pagination.js";
2
+ export { Pagination, type PaginationProps };
@@ -0,0 +1 @@
1
+ export { Pagination } from "./Pagination.js";
@@ -0,0 +1,27 @@
1
+ import { ComponentProps } from "react";
2
+ import { Popover } from "@base-ui/react/popover";
3
+ /** The props of Popover: Base UI's root props, such as open, defaultOpen and onOpenChange. */
4
+ export type PopoverProps = Popover.Root.Props;
5
+ /** A panel that opens from a trigger and holds more than text, such as a list of notifications. Put a PopoverTrigger and a PopoverContent inside it. */
6
+ declare function Popover$1(props: PopoverProps): import("react").JSX.Element;
7
+ /** The props of PopoverTrigger: Base UI's trigger props, except className and style. Use render to put the trigger on your own element. */
8
+ export type PopoverTriggerProps = Omit<Popover.Trigger.Props, 'className' | 'style'>;
9
+ /** The element that opens the popover on click or Enter. It renders a button unless render says otherwise. */
10
+ export declare function PopoverTrigger(props: PopoverTriggerProps): import("react").JSX.Element;
11
+ /** The props of PopoverContent: the popup props plus where the popover sits. */
12
+ export type PopoverContentProps = Omit<Popover.Popup.Props, 'className' | 'style'> & Pick<Popover.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>;
13
+ /** The popover panel: a white panel with a 1px outline and no shadow, 288px wide. It opens below the trigger by default. */
14
+ export declare function PopoverContent({ align, alignOffset, side, sideOffset, ...props }: PopoverContentProps): import("react").JSX.Element;
15
+ /** The props of PopoverHeader: the attributes of a div, except className and style. */
16
+ export type PopoverHeaderProps = Omit<ComponentProps<'div'>, 'className' | 'style'>;
17
+ /** Groups a title and a description at the top of the panel. */
18
+ export declare function PopoverHeader(props: PopoverHeaderProps): import("react").JSX.Element;
19
+ /** The props of PopoverTitle: Base UI's title props. */
20
+ export type PopoverTitleProps = Omit<Popover.Title.Props, 'className' | 'style'>;
21
+ /** The title of the panel; it names the dialog for screen readers. */
22
+ export declare function PopoverTitle(props: PopoverTitleProps): import("react").JSX.Element;
23
+ /** The props of PopoverDescription: Base UI's description props. */
24
+ export type PopoverDescriptionProps = Omit<Popover.Description.Props, 'className' | 'style'>;
25
+ /** The supporting text under the title, in the muted colour. */
26
+ export declare function PopoverDescription(props: PopoverDescriptionProps): import("react").JSX.Element;
27
+ export { Popover$1 as Popover };
@@ -0,0 +1,47 @@
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Popover } from "@base-ui/react/popover";
3
+ // src/components/popover/Popover.tsx
4
+ /** A panel that opens from a trigger and holds more than text, such as a list of notifications. Put a PopoverTrigger and a PopoverContent inside it. */
5
+ function Popover$1(props) {
6
+ return /* @__PURE__ */ jsx(Popover.Root, { ...props });
7
+ }
8
+ /** The element that opens the popover on click or Enter. It renders a button unless render says otherwise. */
9
+ function PopoverTrigger(props) {
10
+ return /* @__PURE__ */ jsx(Popover.Trigger, { ...props });
11
+ }
12
+ /** The popover panel: a white panel with a 1px outline and no shadow, 288px wide. It opens below the trigger by default. */
13
+ function PopoverContent({ align = "center", alignOffset = 0, side = "bottom", sideOffset = 4, ...props }) {
14
+ return /* @__PURE__ */ jsx(Popover.Portal, { children: /* @__PURE__ */ jsx(Popover.Positioner, {
15
+ align,
16
+ alignOffset,
17
+ side,
18
+ sideOffset,
19
+ className: "rt:isolate rt:z-50",
20
+ children: /* @__PURE__ */ jsx(Popover.Popup, {
21
+ className: "rt:flex rt:w-72 rt:flex-col rt:gap-2 rt:rounded-lg rt:border rt:border-border rt:bg-popover rt:p-3 rt:text-b3 rt:text-popover-foreground rt:outline-hidden",
22
+ ...props
23
+ })
24
+ }) });
25
+ }
26
+ /** Groups a title and a description at the top of the panel. */
27
+ function PopoverHeader(props) {
28
+ return /* @__PURE__ */ jsx("div", {
29
+ className: "rt:flex rt:flex-col rt:gap-0.5",
30
+ ...props
31
+ });
32
+ }
33
+ /** The title of the panel; it names the dialog for screen readers. */
34
+ function PopoverTitle(props) {
35
+ return /* @__PURE__ */ jsx(Popover.Title, {
36
+ className: "rt:text-b4",
37
+ ...props
38
+ });
39
+ }
40
+ /** The supporting text under the title, in the muted colour. */
41
+ function PopoverDescription(props) {
42
+ return /* @__PURE__ */ jsx(Popover.Description, {
43
+ className: "rt:text-muted-foreground",
44
+ ...props
45
+ });
46
+ }
47
+ export { Popover$1 as Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger };
@@ -0,0 +1,2 @@
1
+ import { Popover, PopoverContent, PopoverContentProps, PopoverDescription, PopoverDescriptionProps, PopoverHeader, PopoverHeaderProps, PopoverProps, PopoverTitle, PopoverTitleProps, PopoverTrigger, PopoverTriggerProps } from "./Popover.js";
2
+ export { Popover, PopoverContent, type PopoverContentProps, PopoverDescription, type PopoverDescriptionProps, PopoverHeader, type PopoverHeaderProps, type PopoverProps, PopoverTitle, type PopoverTitleProps, PopoverTrigger, type PopoverTriggerProps };
@@ -0,0 +1 @@
1
+ export { Popover, PopoverContent, PopoverDescription, PopoverHeader, PopoverTitle, PopoverTrigger } from "./Popover.js";
@@ -0,0 +1,27 @@
1
+ import { HTMLAttributes, JSX, ReactNode, Ref } from "react";
2
+ /** The props of SaveBar: the HTML attributes of its div, except className, style, children and onSave. */
3
+ export type SaveBarProps = Omit<HTMLAttributes<HTMLDivElement>, 'className' | 'style' | 'children'> & {
4
+ /** Whether the form has unsaved changes. The bar renders nothing when false. */
5
+ dirty: boolean;
6
+ /** True while the save is running: Save is disabled and reads the saving label. */
7
+ saving?: boolean;
8
+ /** Called by Save. */
9
+ onSave: () => void;
10
+ /** Called by Discard. The bar asks nothing itself: confirm in the caller if you need to. */
11
+ onDiscard: () => void;
12
+ /** The message. Defaults to "Unsaved changes". */
13
+ message?: ReactNode;
14
+ /** The Save label. Defaults to "Save". */
15
+ saveLabel?: ReactNode;
16
+ /** The Save label while saving. Defaults to "Saving…". */
17
+ savingLabel?: ReactNode;
18
+ /** The Discard label. Defaults to "Discard". */
19
+ discardLabel?: ReactNode;
20
+ /** Receives the rendered div. */
21
+ ref?: Ref<HTMLDivElement>;
22
+ };
23
+ /**
24
+ * The bar that appears under the top bar when a form is dirty: a message, Discard and Save. It renders in flow, so the
25
+ * page (AppShell) decides where it sits. While saving, Save is disabled; Discard only calls onDiscard.
26
+ */
27
+ export declare function SaveBar({ dirty, saving, onSave, onDiscard, message, saveLabel, savingLabel, discardLabel, ref, ...rest }: SaveBarProps): JSX.Element | null;
@@ -0,0 +1,37 @@
1
+ import { cn } from "../../lib/cn.js";
2
+ import { Text } from "../text/Text.js";
3
+ import { Button } from "../button/Button.js";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ // src/components/save-bar/SaveBar.tsx
6
+ /**
7
+ * The bar that appears under the top bar when a form is dirty: a message, Discard and Save. It renders in flow, so the
8
+ * page (AppShell) decides where it sits. While saving, Save is disabled; Discard only calls onDiscard.
9
+ */
10
+ function SaveBar({ dirty, saving = false, onSave, onDiscard, message = "Unsaved changes", saveLabel = "Save", savingLabel = "Saving…", discardLabel = "Discard", ref, ...rest }) {
11
+ if (!dirty) return null;
12
+ return /* @__PURE__ */ jsxs("div", {
13
+ role: "status",
14
+ "data-slot": "save-bar",
15
+ ...rest,
16
+ ref,
17
+ "aria-busy": saving || void 0,
18
+ className: cn("rt:flex rt:w-full rt:min-w-0 rt:items-center rt:justify-between rt:gap-3 rt:border-b rt:border-border rt:bg-background rt:px-3 rt:py-2"),
19
+ children: [/* @__PURE__ */ jsx(Text, {
20
+ variant: "b4",
21
+ children: message
22
+ }), /* @__PURE__ */ jsxs("div", {
23
+ className: "rt:flex rt:shrink-0 rt:items-center rt:gap-2",
24
+ children: [/* @__PURE__ */ jsx(Button, {
25
+ variant: "secondary",
26
+ onClick: onDiscard,
27
+ children: discardLabel
28
+ }), /* @__PURE__ */ jsx(Button, {
29
+ variant: "main",
30
+ disabled: saving,
31
+ onClick: onSave,
32
+ children: saving ? savingLabel : saveLabel
33
+ })]
34
+ })]
35
+ });
36
+ }
37
+ export { SaveBar };
@@ -0,0 +1,2 @@
1
+ import { SaveBar, SaveBarProps } from "./SaveBar.js";
2
+ export { SaveBar, type SaveBarProps };
@@ -0,0 +1 @@
1
+ export { SaveBar } from "./SaveBar.js";
@@ -0,0 +1,23 @@
1
+ import { InputGroupSize } from "../input-group/InputGroup.js";
2
+ import "../input-group/index.js";
3
+ import { InputHTMLAttributes, JSX, Ref } from "react";
4
+ /** The props of SearchField: the HTML attributes of an input, except className, style, size, type and onChange. */
5
+ export type SearchFieldProps = Omit<InputHTMLAttributes<HTMLInputElement>, 'className' | 'style' | 'size' | 'type' | 'onChange' | 'value' | 'defaultValue'> & {
6
+ /** The accessible name of the field, such as "Search products". Required because the field has no visible label. */
7
+ label: string;
8
+ /** The text in the field. Pass it with onValueChange to control the field. */
9
+ value?: string;
10
+ /** The starting text of an uncontrolled field. */
11
+ defaultValue?: string;
12
+ /** Called with the new text on every change and when the field is cleared. It is not debounced: debounce in the app. */
13
+ onValueChange?: (value: string) => void;
14
+ /** The height in px: 36 above a listing, 32 inside a table. Defaults to 36. */
15
+ size?: InputGroupSize;
16
+ /** Receives the input element. */
17
+ ref?: Ref<HTMLInputElement>;
18
+ };
19
+ /**
20
+ * The search field above a listing: a search icon, the input and a clear button that appears once there is text.
21
+ * Escape clears it too. The field reports every change; the debounce stays in the app.
22
+ */
23
+ export declare function SearchField({ label, value, defaultValue, onValueChange, size, ref, onKeyDown, disabled, readOnly, ...rest }: SearchFieldProps): JSX.Element;
@@ -0,0 +1,66 @@
1
+ import { Icon } from "../icon/Icon.js";
2
+ import { InputGroup, InputGroupAddon, InputGroupInput } from "../input-group/InputGroup.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { useRef, useState } from "react";
5
+ // src/components/search-field/SearchField.tsx
6
+ /**
7
+ * The search field above a listing: a search icon, the input and a clear button that appears once there is text.
8
+ * Escape clears it too. The field reports every change; the debounce stays in the app.
9
+ */
10
+ function SearchField({ label, value, defaultValue = "", onValueChange, size = 36, ref, onKeyDown, disabled, readOnly, ...rest }) {
11
+ const [inner, setInner] = useState(defaultValue);
12
+ const current = value ?? inner;
13
+ const inputRef = useRef(null);
14
+ const change = (next) => {
15
+ if (value === void 0) setInner(next);
16
+ onValueChange?.(next);
17
+ };
18
+ const clear = () => {
19
+ change("");
20
+ inputRef.current?.focus();
21
+ };
22
+ const handleKeyDown = (event) => {
23
+ onKeyDown?.(event);
24
+ if (event.key === "Escape" && current !== "" && readOnly !== true && !event.defaultPrevented) {
25
+ event.preventDefault();
26
+ change("");
27
+ }
28
+ };
29
+ return /* @__PURE__ */ jsxs(InputGroup, {
30
+ size,
31
+ children: [
32
+ /* @__PURE__ */ jsx(InputGroupAddon, { children: /* @__PURE__ */ jsx(Icon, {
33
+ name: "search",
34
+ tone: "icon"
35
+ }) }),
36
+ /* @__PURE__ */ jsx(InputGroupInput, {
37
+ ...rest,
38
+ ref: (node) => {
39
+ inputRef.current = node;
40
+ if (typeof ref === "function") ref(node);
41
+ else if (ref) ref.current = node;
42
+ },
43
+ disabled,
44
+ readOnly,
45
+ role: "searchbox",
46
+ inputMode: "search",
47
+ autoComplete: "off",
48
+ "aria-label": label,
49
+ value: current,
50
+ onChange: (event) => change(event.target.value),
51
+ onKeyDown: handleKeyDown
52
+ }),
53
+ current !== "" && disabled !== true && readOnly !== true ? /* @__PURE__ */ jsx(InputGroupAddon, {
54
+ align: "end",
55
+ children: /* @__PURE__ */ jsx("button", {
56
+ type: "button",
57
+ "aria-label": "Clear search",
58
+ onClick: clear,
59
+ className: "rt:inline-flex rt:size-5 rt:items-center rt:justify-center rt:rounded-sm rt:text-icon rt:outline-none rt:transition-colors rt:hover:bg-muted rt:focus-visible:shadow-ring-focus",
60
+ children: /* @__PURE__ */ jsx(Icon, { name: "x" })
61
+ })
62
+ }) : null
63
+ ]
64
+ });
65
+ }
66
+ export { SearchField };
@@ -0,0 +1,2 @@
1
+ import { SearchField, SearchFieldProps } from "./SearchField.js";
2
+ export { SearchField, type SearchFieldProps };
@@ -0,0 +1 @@
1
+ export { SearchField } from "./SearchField.js";
@@ -0,0 +1,40 @@
1
+ import { JSX } from "react";
2
+ import { Select } from "@base-ui/react/select";
3
+ /** The props of Select: Base UI's root props, such as value, defaultValue, onValueChange, items, name and disabled. */
4
+ export type SelectProps<Value = string> = Select.Root.Props<Value>;
5
+ /** A choice from a fixed list. Pass items ({ label, value }[]) so the trigger shows the label of the chosen value. Put a SelectTrigger and a SelectContent inside it. */
6
+ declare function Select$1<Value = string>(props: SelectProps<Value>): JSX.Element;
7
+ /** The height of the trigger in px: 36 for forms, 32 for fields inside a table. */
8
+ export type SelectSize = 36 | 32;
9
+ /** The props of SelectTrigger: Base UI's trigger props except className and style, with the height. Mark an invalid field with aria-invalid. */
10
+ export type SelectTriggerProps = Omit<Select.Trigger.Props, 'className' | 'style'> & {
11
+ /** The height in px: 36 for forms, 32 inside a table. Defaults to 36. */
12
+ size?: SelectSize;
13
+ };
14
+ /** The closed field: the chosen value (or the placeholder) and a chevron at the right. Put a SelectValue inside it. */
15
+ export declare function SelectTrigger({ size, children, ...props }: SelectTriggerProps): JSX.Element;
16
+ /** The props of SelectValue: Base UI's value props except className and style. */
17
+ export type SelectValueProps = Omit<Select.Value.Props, 'className' | 'style'>;
18
+ /** Shows the label of the chosen option inside the trigger, or the placeholder while nothing is chosen. */
19
+ export declare function SelectValue(props: SelectValueProps): JSX.Element;
20
+ /** The props of SelectContent: the popup props plus where the list sits. */
21
+ export type SelectContentProps = Omit<Select.Popup.Props, 'className' | 'style'> & Pick<Select.Positioner.Props, 'align' | 'alignOffset' | 'side' | 'sideOffset'>;
22
+ /** The list: the popover look (8px radius, outline, no shadow, 6px 0 padding), as wide as the trigger. It opens below the trigger. */
23
+ export declare function SelectContent({ align, alignOffset, side, sideOffset, children, ...props }: SelectContentProps): JSX.Element;
24
+ /** The props of SelectGroup: Base UI's group props except className and style. */
25
+ export type SelectGroupProps = Omit<Select.Group.Props, 'className' | 'style'>;
26
+ /** Groups related options under a SelectLabel. */
27
+ export declare function SelectGroup(props: SelectGroupProps): JSX.Element;
28
+ /** The props of SelectLabel: Base UI's group label props except className and style. */
29
+ export type SelectLabelProps = Omit<Select.GroupLabel.Props, 'className' | 'style'>;
30
+ /** The heading of a group, in the muted colour. */
31
+ export declare function SelectLabel(props: SelectLabelProps): JSX.Element;
32
+ /** The props of SelectItem: Base UI's item props except className and style. The value is the one the select reports. */
33
+ export type SelectItemProps = Omit<Select.Item.Props, 'className' | 'style'>;
34
+ /** One option. The highlighted one has the accent background, the chosen one a check at its end, a disabled one is dimmed and cannot be chosen. */
35
+ export declare function SelectItem({ children, ...props }: SelectItemProps): JSX.Element;
36
+ /** The props of SelectSeparator: Base UI's separator props except className and style. */
37
+ export type SelectSeparatorProps = Omit<Select.Separator.Props, 'className' | 'style'>;
38
+ /** A hairline between groups. */
39
+ export declare function SelectSeparator(props: SelectSeparatorProps): JSX.Element;
40
+ export { Select$1 as Select };
@@ -0,0 +1,84 @@
1
+ import { cn } from "../../lib/cn.js";
2
+ import { Icon } from "../icon/Icon.js";
3
+ import { jsx, jsxs } from "react/jsx-runtime";
4
+ import { cva } from "class-variance-authority";
5
+ import { Select } from "@base-ui/react/select";
6
+ // src/components/select/Select.tsx
7
+ /** A choice from a fixed list. Pass items ({ label, value }[]) so the trigger shows the label of the chosen value. Put a SelectTrigger and a SelectContent inside it. */
8
+ function Select$1(props) {
9
+ return /* @__PURE__ */ jsx(Select.Root, { ...props });
10
+ }
11
+ const triggerVariants = cva("rt:flex rt:w-full rt:min-w-0 rt:items-center rt:justify-between rt:gap-2 rt:rounded-lg rt:bg-background rt:text-b3 rt:text-foreground rt:whitespace-nowrap rt:shadow-ring-subtle rt:outline-none rt:select-none rt:transition-colors rt:forced-outline rt:focus-visible:shadow-ring-focus rt:aria-invalid:shadow-ring-invalid rt:aria-invalid:focus-visible:shadow-ring-invalid rt:data-placeholder:text-muted-foreground rt:disabled:pointer-events-none rt:disabled:cursor-not-allowed rt:disabled:opacity-50", {
12
+ variants: { size: {
13
+ 36: "rt:h-9 rt:pr-8 rt:pl-3",
14
+ 32: "rt:h-8 rt:pr-8 rt:pl-2.75"
15
+ } },
16
+ defaultVariants: { size: 36 }
17
+ });
18
+ /** The closed field: the chosen value (or the placeholder) and a chevron at the right. Put a SelectValue inside it. */
19
+ function SelectTrigger({ size = 36, children, ...props }) {
20
+ return /* @__PURE__ */ jsxs(Select.Trigger, {
21
+ className: cn(triggerVariants({ size }), "rt:relative"),
22
+ ...props,
23
+ children: [children, /* @__PURE__ */ jsx(Select.Icon, {
24
+ render: /* @__PURE__ */ jsx("span", { className: "rt:pointer-events-none rt:absolute rt:right-3 rt:flex rt:text-muted-foreground" }),
25
+ children: /* @__PURE__ */ jsx(Icon, { name: "nav-caret-down" })
26
+ })]
27
+ });
28
+ }
29
+ /** Shows the label of the chosen option inside the trigger, or the placeholder while nothing is chosen. */
30
+ function SelectValue(props) {
31
+ return /* @__PURE__ */ jsx(Select.Value, {
32
+ className: "rt:min-w-0 rt:flex-1 rt:truncate rt:text-left",
33
+ ...props
34
+ });
35
+ }
36
+ /** The list: the popover look (8px radius, outline, no shadow, 6px 0 padding), as wide as the trigger. It opens below the trigger. */
37
+ function SelectContent({ align = "start", alignOffset = 0, side = "bottom", sideOffset = 4, children, ...props }) {
38
+ return /* @__PURE__ */ jsx(Select.Portal, { children: /* @__PURE__ */ jsx(Select.Positioner, {
39
+ align,
40
+ alignOffset,
41
+ side,
42
+ sideOffset,
43
+ alignItemWithTrigger: false,
44
+ className: "rt:isolate rt:z-50",
45
+ children: /* @__PURE__ */ jsx(Select.Popup, {
46
+ className: "rt:max-h-available rt:min-w-anchor rt:overflow-y-auto rt:rounded-lg rt:border rt:border-border rt:bg-popover rt:py-1.5 rt:text-b3 rt:text-popover-foreground rt:outline-hidden rt:transition-colors",
47
+ ...props,
48
+ children: /* @__PURE__ */ jsx(Select.List, { children })
49
+ })
50
+ }) });
51
+ }
52
+ /** Groups related options under a SelectLabel. */
53
+ function SelectGroup(props) {
54
+ return /* @__PURE__ */ jsx(Select.Group, { ...props });
55
+ }
56
+ /** The heading of a group, in the muted colour. */
57
+ function SelectLabel(props) {
58
+ return /* @__PURE__ */ jsx(Select.GroupLabel, {
59
+ className: "rt:px-3 rt:py-1 rt:text-label rt:uppercase rt:text-foreground-subdued",
60
+ ...props
61
+ });
62
+ }
63
+ /** One option. The highlighted one has the accent background, the chosen one a check at its end, a disabled one is dimmed and cannot be chosen. */
64
+ function SelectItem({ children, ...props }) {
65
+ return /* @__PURE__ */ jsxs(Select.Item, {
66
+ className: "rt:relative rt:flex rt:h-7 rt:cursor-default rt:items-center rt:gap-2 rt:pr-8 rt:pl-3 rt:text-b3 rt:text-foreground rt:outline-none rt:select-none rt:transition-colors rt:data-highlighted:bg-accent rt:data-highlighted:text-accent-foreground rt:data-disabled:pointer-events-none rt:data-disabled:opacity-50",
67
+ ...props,
68
+ children: [/* @__PURE__ */ jsx(Select.ItemText, {
69
+ className: "rt:flex-1 rt:truncate",
70
+ children
71
+ }), /* @__PURE__ */ jsx(Select.ItemIndicator, {
72
+ render: /* @__PURE__ */ jsx("span", { className: "rt:pointer-events-none rt:absolute rt:right-3 rt:flex" }),
73
+ children: /* @__PURE__ */ jsx(Icon, { name: "check" })
74
+ })]
75
+ });
76
+ }
77
+ /** A hairline between groups. */
78
+ function SelectSeparator(props) {
79
+ return /* @__PURE__ */ jsx(Select.Separator, {
80
+ className: "rt:my-1.5 rt:h-px rt:bg-divider",
81
+ ...props
82
+ });
83
+ }
84
+ export { Select$1 as Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue };
@@ -0,0 +1,2 @@
1
+ import { Select, SelectContent, SelectContentProps, SelectGroup, SelectGroupProps, SelectItem, SelectItemProps, SelectLabel, SelectLabelProps, SelectProps, SelectSeparator, SelectSeparatorProps, SelectSize, SelectTrigger, SelectTriggerProps, SelectValue, SelectValueProps } from "./Select.js";
2
+ export { Select, SelectContent, type SelectContentProps, SelectGroup, type SelectGroupProps, SelectItem, type SelectItemProps, SelectLabel, type SelectLabelProps, type SelectProps, SelectSeparator, type SelectSeparatorProps, type SelectSize, SelectTrigger, type SelectTriggerProps, SelectValue, type SelectValueProps };
@@ -0,0 +1 @@
1
+ export { Select, SelectContent, SelectGroup, SelectItem, SelectLabel, SelectSeparator, SelectTrigger, SelectValue } from "./Select.js";
@@ -0,0 +1,64 @@
1
+ import { IconName } from "../icon/registry.js";
2
+ import "../icon/index.js";
3
+ import { JSX, ReactNode } from "react";
4
+ /** One row of the navigation. With `children` it is a group that opens and closes. */
5
+ export type SideNavItem = {
6
+ /** The value passed to onSelect and compared with `active`. */
7
+ id: string;
8
+ /** The text of the row. */
9
+ label: string;
10
+ /** A glyph before the label. */
11
+ icon?: IconName;
12
+ /** A count shown at the end of the row, such as 12 or 10,001+. */
13
+ count?: string | number;
14
+ /** Makes the row a link to this address instead of a button. On a router, LinkProvider draws it with the app's own link. */
15
+ href?: string;
16
+ /** Nested rows. The row then opens and closes them. */
17
+ children?: SideNavItem[];
18
+ };
19
+ /** A block of rows, with an optional label that can collapse the block. */
20
+ export type SideNavSection = {
21
+ /** Identifies the section. */
22
+ id: string;
23
+ /** The small label above the rows. Without one the rows sit unlabelled. */
24
+ label?: string;
25
+ /** Whether the label collapses the section. Needs a label. */
26
+ collapsible?: boolean;
27
+ /** Whether a collapsible section starts closed. Defaults to false. */
28
+ defaultCollapsed?: boolean;
29
+ /** The rows. */
30
+ items: SideNavItem[];
31
+ };
32
+ /** The account switcher at the top. */
33
+ export type SideNavAccount = {
34
+ /** The store or person name. */
35
+ name: string;
36
+ /** The line under the name. */
37
+ role?: string;
38
+ /** Called when the switcher is pressed. */
39
+ onClick?: () => void;
40
+ };
41
+ /** The props of SideNav. */
42
+ export type SideNavProps = {
43
+ /** The accessible name of the navigation landmark. */
44
+ label: string;
45
+ /** The blocks of rows, top to bottom. */
46
+ sections: SideNavSection[];
47
+ /** The id of the current row. It is marked and its group opens. */
48
+ active?: string;
49
+ /** Called with the id of the row pressed. */
50
+ onSelect?: (id: string) => void;
51
+ /** The account switcher shown above the rows. */
52
+ account?: SideNavAccount;
53
+ /** Content pinned at the bottom, such as Settings. */
54
+ footer?: ReactNode;
55
+ /** On a phone, whether the drawer is open. */
56
+ open?: boolean;
57
+ /** On a phone, called when the drawer asks to open or close. */
58
+ onOpenChange?: (open: boolean) => void;
59
+ };
60
+ /**
61
+ * The 240px side navigation of the admin: an account switcher, blocks of rows with nested groups, counts and collapsible
62
+ * labels, and a footer pinned at the bottom. On a phone it becomes a drawer: inside AppShell the menu button in TopBar opens it and choosing a row closes it; used alone, the caller opens it with `open` and closes it in `onOpenChange`.
63
+ */
64
+ export declare function SideNav(props: SideNavProps): JSX.Element | null;