@milktop/react-ui 0.0.0-stage → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (250) hide show
  1. package/README.md +173 -2
  2. package/dist/accordion/Accordion.d.ts +65 -0
  3. package/dist/accordion/Accordion.js +61 -0
  4. package/dist/accordion/accordion.css +17 -0
  5. package/dist/action-bar/ActionBar.d.ts +33 -0
  6. package/dist/action-bar/ActionBar.js +48 -0
  7. package/dist/action-bar/action-bar.css +22 -0
  8. package/dist/alert/Alert.d.ts +28 -0
  9. package/dist/alert/Alert.js +12 -0
  10. package/dist/alert/alert.css +26 -0
  11. package/dist/app-shell/AppShell.d.ts +38 -0
  12. package/dist/app-shell/AppShell.js +92 -0
  13. package/dist/app-shell/Topbar.d.ts +20 -0
  14. package/dist/app-shell/Topbar.js +13 -0
  15. package/dist/app-shell/app-shell.css +41 -0
  16. package/dist/app-shell/shell.d.ts +9 -0
  17. package/dist/app-shell/shell.js +3 -0
  18. package/dist/attachments/Attachments.d.ts +84 -0
  19. package/dist/attachments/Attachments.js +235 -0
  20. package/dist/attachments/attachments.css +86 -0
  21. package/dist/avatar/Avatar.d.ts +31 -0
  22. package/dist/avatar/Avatar.js +41 -0
  23. package/dist/avatar/AvatarGroup.d.ts +41 -0
  24. package/dist/avatar/AvatarGroup.js +17 -0
  25. package/dist/avatar/avatar.css +73 -0
  26. package/dist/badge/Badge.d.ts +26 -0
  27. package/dist/badge/Badge.js +10 -0
  28. package/dist/badge/badge.css +24 -0
  29. package/dist/banner/Banner.d.ts +33 -0
  30. package/dist/banner/Banner.js +14 -0
  31. package/dist/banner/banner.css +25 -0
  32. package/dist/breadcrumbs/Breadcrumbs.d.ts +39 -0
  33. package/dist/breadcrumbs/Breadcrumbs.js +28 -0
  34. package/dist/breadcrumbs/breadcrumbs.css +18 -0
  35. package/dist/button/Button.d.ts +40 -0
  36. package/dist/button/Button.js +19 -0
  37. package/dist/button/button.css +63 -0
  38. package/dist/card/Card.d.ts +355 -0
  39. package/dist/card/Card.js +56 -0
  40. package/dist/card/card.css +43 -0
  41. package/dist/chart/AreaChart.d.ts +19 -0
  42. package/dist/chart/AreaChart.js +61 -0
  43. package/dist/chart/BarChart.d.ts +3 -0
  44. package/dist/chart/BarChart.js +60 -0
  45. package/dist/chart/ChartFrame.d.ts +25 -0
  46. package/dist/chart/ChartFrame.js +22 -0
  47. package/dist/chart/DonutChart.d.ts +20 -0
  48. package/dist/chart/DonutChart.js +41 -0
  49. package/dist/chart/Sparkline.d.ts +26 -0
  50. package/dist/chart/Sparkline.js +36 -0
  51. package/dist/chart/chart.css +51 -0
  52. package/dist/chart/chart.d.ts +23 -0
  53. package/dist/chart/chart.js +19 -0
  54. package/dist/checkbox/Checkbox.d.ts +50 -0
  55. package/dist/checkbox/Checkbox.js +19 -0
  56. package/dist/checkbox/CheckboxGroup.d.ts +44 -0
  57. package/dist/checkbox/CheckboxGroup.js +80 -0
  58. package/dist/checkbox/checkbox.css +49 -0
  59. package/dist/collapsible/Collapsible.d.ts +41 -0
  60. package/dist/collapsible/Collapsible.js +15 -0
  61. package/dist/collapsible/collapsible.css +20 -0
  62. package/dist/color-scheme.d.ts +18 -0
  63. package/dist/color-scheme.js +84 -0
  64. package/dist/command/Command.d.ts +64 -0
  65. package/dist/command/Command.js +162 -0
  66. package/dist/command/command.css +47 -0
  67. package/dist/confirm/confirm.css +5 -0
  68. package/dist/confirm/confirm.d.ts +42 -0
  69. package/dist/confirm/confirm.js +115 -0
  70. package/dist/copy-button/CopyButton.d.ts +30 -0
  71. package/dist/copy-button/CopyButton.js +23 -0
  72. package/dist/copy-button/copy-button.css +12 -0
  73. package/dist/css.d.ts +2 -0
  74. package/dist/data-list/DataList.d.ts +55 -0
  75. package/dist/data-list/DataList.js +43 -0
  76. package/dist/data-list/data-list.css +19 -0
  77. package/dist/date-picker/DatePicker.d.ts +95 -0
  78. package/dist/date-picker/DatePicker.js +237 -0
  79. package/dist/date-picker/date-picker.css +53 -0
  80. package/dist/dialog/Dialog.d.ts +98 -0
  81. package/dist/dialog/Dialog.js +92 -0
  82. package/dist/dialog/dialog.css +31 -0
  83. package/dist/divider/Divider.d.ts +27 -0
  84. package/dist/divider/Divider.js +8 -0
  85. package/dist/divider/divider.css +12 -0
  86. package/dist/editable/Editable.d.ts +47 -0
  87. package/dist/editable/Editable.js +51 -0
  88. package/dist/editable/editable.css +25 -0
  89. package/dist/editor/Editor.d.ts +59 -0
  90. package/dist/editor/Editor.js +220 -0
  91. package/dist/editor/editor.css +42 -0
  92. package/dist/editor/image.d.ts +1 -0
  93. package/dist/editor/image.js +23 -0
  94. package/dist/empty-state/EmptyState.d.ts +22 -0
  95. package/dist/empty-state/EmptyState.js +9 -0
  96. package/dist/empty-state/empty-state.css +14 -0
  97. package/dist/event-calendar/EventCalendar.d.ts +213 -0
  98. package/dist/event-calendar/EventCalendar.js +686 -0
  99. package/dist/event-calendar/dates.d.ts +8 -0
  100. package/dist/event-calendar/dates.js +21 -0
  101. package/dist/event-calendar/event-calendar.css +157 -0
  102. package/dist/field/Field.d.ts +66 -0
  103. package/dist/field/Field.js +23 -0
  104. package/dist/field/field.css +26 -0
  105. package/dist/file-upload/FileUpload.d.ts +60 -0
  106. package/dist/file-upload/FileUpload.js +102 -0
  107. package/dist/file-upload/file-upload.css +32 -0
  108. package/dist/format/FormatNumber.d.ts +42 -0
  109. package/dist/format/FormatNumber.js +59 -0
  110. package/dist/format/LocaleProvider.d.ts +33 -0
  111. package/dist/format/LocaleProvider.js +48 -0
  112. package/dist/format/format.d.ts +37 -0
  113. package/dist/format/format.js +74 -0
  114. package/dist/format/messages.d.ts +211 -0
  115. package/dist/format/messages.js +202 -0
  116. package/dist/highlight/Highlight.d.ts +11 -0
  117. package/dist/highlight/Highlight.js +14 -0
  118. package/dist/highlight/highlight.css +17 -0
  119. package/dist/hover-card/HoverCard.d.ts +47 -0
  120. package/dist/hover-card/HoverCard.js +18 -0
  121. package/dist/hover-card/hover-card.css +19 -0
  122. package/dist/index.d.ts +84 -0
  123. package/dist/index.js +85 -0
  124. package/dist/input/Input.d.ts +41 -0
  125. package/dist/input/Input.js +48 -0
  126. package/dist/input/input.css +25 -0
  127. package/dist/kbd/Kbd.d.ts +19 -0
  128. package/dist/kbd/Kbd.js +20 -0
  129. package/dist/kbd/kbd.css +8 -0
  130. package/dist/menu/Menu.d.ts +223 -0
  131. package/dist/menu/Menu.js +275 -0
  132. package/dist/menu/menu.css +38 -0
  133. package/dist/native-select/NativeSelect.d.ts +36 -0
  134. package/dist/native-select/NativeSelect.js +51 -0
  135. package/dist/native-select/native-select.css +16 -0
  136. package/dist/number-input/NumberInput.d.ts +56 -0
  137. package/dist/number-input/NumberInput.js +67 -0
  138. package/dist/number-input/number-input.css +21 -0
  139. package/dist/page/Page.d.ts +30 -0
  140. package/dist/page/Page.js +9 -0
  141. package/dist/page/page.css +17 -0
  142. package/dist/pagination/Pagination.d.ts +31 -0
  143. package/dist/pagination/Pagination.js +58 -0
  144. package/dist/pagination/pagination.css +15 -0
  145. package/dist/password-input/PasswordInput.d.ts +47 -0
  146. package/dist/password-input/PasswordInput.js +35 -0
  147. package/dist/password-input/password-input.css +18 -0
  148. package/dist/pin-input/PinInput.d.ts +45 -0
  149. package/dist/pin-input/PinInput.js +22 -0
  150. package/dist/pin-input/pin-input.css +13 -0
  151. package/dist/popover/Popover.d.ts +65 -0
  152. package/dist/popover/Popover.js +26 -0
  153. package/dist/popover/popover.css +16 -0
  154. package/dist/progress/Progress.d.ts +56 -0
  155. package/dist/progress/Progress.js +28 -0
  156. package/dist/progress/progress.css +24 -0
  157. package/dist/prose/Prose.d.ts +23 -0
  158. package/dist/prose/Prose.js +10 -0
  159. package/dist/prose/prose.css +29 -0
  160. package/dist/radio-group/RadioGroup.d.ts +59 -0
  161. package/dist/radio-group/RadioGroup.js +37 -0
  162. package/dist/radio-group/radio-group.css +30 -0
  163. package/dist/rolling-number/RollingNumber.d.ts +27 -0
  164. package/dist/rolling-number/RollingNumber.js +18 -0
  165. package/dist/rolling-number/rolling-number.css +10 -0
  166. package/dist/segment-group/Segmented.d.ts +68 -0
  167. package/dist/segment-group/Segmented.js +79 -0
  168. package/dist/segment-group/segment-group.css +25 -0
  169. package/dist/select/ListSelect.d.ts +5 -0
  170. package/dist/select/ListSelect.js +82 -0
  171. package/dist/select/SearchSelect.d.ts +43 -0
  172. package/dist/select/SearchSelect.js +219 -0
  173. package/dist/select/Select.d.ts +147 -0
  174. package/dist/select/Select.js +32 -0
  175. package/dist/select/items.d.ts +17 -0
  176. package/dist/select/items.js +14 -0
  177. package/dist/select/search-select.css +45 -0
  178. package/dist/select/select.css +52 -0
  179. package/dist/sheet/Sheet.d.ts +88 -0
  180. package/dist/sheet/Sheet.js +66 -0
  181. package/dist/sheet/sheet.css +44 -0
  182. package/dist/sidebar/NavGroup.d.ts +29 -0
  183. package/dist/sidebar/NavGroup.js +78 -0
  184. package/dist/sidebar/NavItem.d.ts +33 -0
  185. package/dist/sidebar/NavItem.js +50 -0
  186. package/dist/sidebar/NavSection.d.ts +20 -0
  187. package/dist/sidebar/NavSection.js +44 -0
  188. package/dist/sidebar/Sidebar.d.ts +65 -0
  189. package/dist/sidebar/Sidebar.js +59 -0
  190. package/dist/sidebar/SidebarUser.d.ts +31 -0
  191. package/dist/sidebar/SidebarUser.js +14 -0
  192. package/dist/sidebar/context.d.ts +13 -0
  193. package/dist/sidebar/context.js +6 -0
  194. package/dist/sidebar/sidebar.css +109 -0
  195. package/dist/skeleton/Skeleton.d.ts +25 -0
  196. package/dist/skeleton/Skeleton.js +8 -0
  197. package/dist/skeleton/skeleton.css +13 -0
  198. package/dist/slider/Slider.d.ts +70 -0
  199. package/dist/slider/Slider.js +65 -0
  200. package/dist/slider/slider.css +17 -0
  201. package/dist/sortable-list/SortableList.d.ts +46 -0
  202. package/dist/sortable-list/SortableList.js +85 -0
  203. package/dist/sortable-list/sortable-list.css +25 -0
  204. package/dist/spinner/Spinner.d.ts +18 -0
  205. package/dist/spinner/Spinner.js +11 -0
  206. package/dist/spinner/spinner.css +9 -0
  207. package/dist/stat/Stat.d.ts +42 -0
  208. package/dist/stat/Stat.js +21 -0
  209. package/dist/stat/Stats.d.ts +23 -0
  210. package/dist/stat/Stats.js +8 -0
  211. package/dist/stat/stat.css +34 -0
  212. package/dist/swatch-picker/SwatchPicker.d.ts +45 -0
  213. package/dist/swatch-picker/SwatchPicker.js +54 -0
  214. package/dist/swatch-picker/swatch-picker.css +38 -0
  215. package/dist/switch/Switch.d.ts +39 -0
  216. package/dist/switch/Switch.js +17 -0
  217. package/dist/switch/switch.css +13 -0
  218. package/dist/table/Table.d.ts +90 -0
  219. package/dist/table/Table.js +145 -0
  220. package/dist/table/table.css +44 -0
  221. package/dist/tabs/Tabs.d.ts +87 -0
  222. package/dist/tabs/Tabs.js +90 -0
  223. package/dist/tabs/tabs.css +53 -0
  224. package/dist/tags-input/TagsInput.d.ts +69 -0
  225. package/dist/tags-input/TagsInput.js +95 -0
  226. package/dist/tags-input/tags-input.css +37 -0
  227. package/dist/textarea/Textarea.d.ts +24 -0
  228. package/dist/textarea/Textarea.js +51 -0
  229. package/dist/textarea/textarea.css +14 -0
  230. package/dist/theme-toggle/ThemeToggle.d.ts +49 -0
  231. package/dist/theme-toggle/ThemeToggle.js +71 -0
  232. package/dist/theme-toggle/theme-toggle.css +23 -0
  233. package/dist/theme.css +119 -0
  234. package/dist/time-input/TimeInput.d.ts +25 -0
  235. package/dist/time-input/TimeInput.js +20 -0
  236. package/dist/timeline/Timeline.d.ts +50 -0
  237. package/dist/timeline/Timeline.js +15 -0
  238. package/dist/timeline/timeline.css +29 -0
  239. package/dist/toast/Toaster.d.ts +36 -0
  240. package/dist/toast/Toaster.js +25 -0
  241. package/dist/toast/toast.css +33 -0
  242. package/dist/tooltip/Tooltip.d.ts +55 -0
  243. package/dist/tooltip/Tooltip.js +48 -0
  244. package/dist/tooltip/tooltip.css +18 -0
  245. package/dist/tree-view/TreeView.d.ts +86 -0
  246. package/dist/tree-view/TreeView.js +74 -0
  247. package/dist/tree-view/tree-view.css +29 -0
  248. package/dist/utils.d.ts +19 -0
  249. package/dist/utils.js +59 -0
  250. package/package.json +99 -4
@@ -0,0 +1,56 @@
1
+ /**
2
+ * A number input with step buttons; arrow keys step too (Shift for 10).
3
+ *
4
+ * <NumberInput label="Hourly rate" value={rate} onValueChange={setRate} min={0} step={5} prefix="£" />
5
+ *
6
+ * - `value`, `defaultValue`: a number, or null when empty
7
+ * - `onValueChange`: called with the new number (or null)
8
+ * - `min`, `max`, `step`
9
+ * - `prefix`, `suffix`: text before or after it ('£', 'kg'); `icon`: an Iconify name before it
10
+ * - `formatOptions`: Intl.NumberFormat options, e.g. { style: 'currency', currency: 'GBP' }, with `locale`
11
+ * - `allowMouseWheel`: scroll over the focused input to step
12
+ * - `steppers`: false to hide the buttons
13
+ * - `name`: for plain form posts
14
+ *
15
+ * By hand, with Ark's parts:
16
+ *
17
+ * <NumberInput.Root defaultValue="3" min={0}>
18
+ * <NumberInput.Label>Guests</NumberInput.Label>
19
+ * <NumberInput.Control>
20
+ * <NumberInput.DecrementTrigger>−</NumberInput.DecrementTrigger>
21
+ * <NumberInput.Input />
22
+ * <NumberInput.IncrementTrigger>+</NumberInput.IncrementTrigger>
23
+ * </NumberInput.Control>
24
+ * </NumberInput.Root>
25
+ */
26
+ import { type ReactNode } from 'react';
27
+ import { NumberInput as Ark, type NumberInputValueChangeDetails } from '@ark-ui/react/number-input';
28
+ import 'iconify-icon';
29
+ import { type Classes } from '../utils.js';
30
+ import '../theme.css';
31
+ import './number-input.css';
32
+ export type NumberInputProps = Omit<Ark.RootProps, 'value' | 'defaultValue' | 'onValueChange' | 'label' | 'prefix'> & {
33
+ label?: ReactNode;
34
+ value?: number | null;
35
+ defaultValue?: number | null;
36
+ onValueChange?: (value: number | null, details: NumberInputValueChangeDetails) => void;
37
+ prefix?: ReactNode;
38
+ suffix?: ReactNode;
39
+ icon?: string | null;
40
+ steppers?: boolean;
41
+ placeholder?: string;
42
+ classes?: Classes<'root' | 'label' | 'control' | 'icon' | 'prefix' | 'input' | 'suffix' | 'decrementTrigger' | 'incrementTrigger'>;
43
+ };
44
+ declare function NumberInputShortcut({ label, value, defaultValue, onValueChange, prefix, suffix, icon, steppers, placeholder, className, classes, ...rest }: NumberInputProps): import("react").JSX.Element;
45
+ export declare const NumberInput: typeof NumberInputShortcut & {
46
+ Root: import("react").ForwardRefExoticComponent<Ark.RootProps & import("react").RefAttributes<HTMLDivElement>>;
47
+ Label: import("react").ForwardRefExoticComponent<Ark.LabelProps & import("react").RefAttributes<HTMLLabelElement>>;
48
+ Control: import("react").ForwardRefExoticComponent<Ark.ControlProps & import("react").RefAttributes<HTMLDivElement>>;
49
+ Input: import("react").ForwardRefExoticComponent<Ark.InputProps & import("react").RefAttributes<HTMLInputElement>>;
50
+ DecrementTrigger: import("react").ForwardRefExoticComponent<Ark.DecrementTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
51
+ IncrementTrigger: import("react").ForwardRefExoticComponent<Ark.IncrementTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
52
+ ValueText: import("react").ForwardRefExoticComponent<Ark.ValueTextProps & import("react").RefAttributes<HTMLSpanElement>>;
53
+ Scrubber: import("react").ForwardRefExoticComponent<Ark.ScrubberProps & import("react").RefAttributes<HTMLDivElement>>;
54
+ Context: (props: Ark.ContextProps) => ReactNode;
55
+ };
56
+ export {};
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * A number input with step buttons; arrow keys step too (Shift for 10).
4
+ *
5
+ * <NumberInput label="Hourly rate" value={rate} onValueChange={setRate} min={0} step={5} prefix="£" />
6
+ *
7
+ * - `value`, `defaultValue`: a number, or null when empty
8
+ * - `onValueChange`: called with the new number (or null)
9
+ * - `min`, `max`, `step`
10
+ * - `prefix`, `suffix`: text before or after it ('£', 'kg'); `icon`: an Iconify name before it
11
+ * - `formatOptions`: Intl.NumberFormat options, e.g. { style: 'currency', currency: 'GBP' }, with `locale`
12
+ * - `allowMouseWheel`: scroll over the focused input to step
13
+ * - `steppers`: false to hide the buttons
14
+ * - `name`: for plain form posts
15
+ *
16
+ * By hand, with Ark's parts:
17
+ *
18
+ * <NumberInput.Root defaultValue="3" min={0}>
19
+ * <NumberInput.Label>Guests</NumberInput.Label>
20
+ * <NumberInput.Control>
21
+ * <NumberInput.DecrementTrigger>−</NumberInput.DecrementTrigger>
22
+ * <NumberInput.Input />
23
+ * <NumberInput.IncrementTrigger>+</NumberInput.IncrementTrigger>
24
+ * </NumberInput.Control>
25
+ * </NumberInput.Root>
26
+ */
27
+ import { useState } from 'react';
28
+ import { NumberInput as Ark } from '@ark-ui/react/number-input';
29
+ import { useFieldContext } from '@ark-ui/react/field';
30
+ import 'iconify-icon';
31
+ import { cx, partsOf, withParts } from '../utils.js';
32
+ import { useMessages } from '../format/LocaleProvider.js';
33
+ import '../theme.css';
34
+ import './number-input.css';
35
+ const toText = (value) => (value == null ? '' : String(value));
36
+ function NumberInputShortcut({ label = null, value, defaultValue, onValueChange, prefix = null, suffix = null, icon = null, steppers = true, placeholder = '', className, classes, ...rest }) {
37
+ const t = useMessages();
38
+ const field = useFieldContext();
39
+ const part = partsOf('number-input', classes);
40
+ // Zag works on the text ('1.', '' while typing); `value` is its number.
41
+ // The text follows a controlled value that changes from outside.
42
+ const [text, setText] = useState(() => toText(value !== undefined ? value : defaultValue));
43
+ const [seen, setSeen] = useState(value);
44
+ if (value !== seen) {
45
+ setSeen(value);
46
+ const number = text === '' ? null : Number(text);
47
+ if (value !== number)
48
+ setText(toText(value));
49
+ }
50
+ function change(details) {
51
+ setText(details.value);
52
+ onValueChange?.(Number.isNaN(details.valueAsNumber) ? null : details.valueAsNumber, details);
53
+ }
54
+ return (_jsxs(Ark.Root, { ...(t.zag.numberInput && { translations: t.zag.numberInput }), ...rest, ...part('root'), className: cx(className, classes?.root), value: text, onValueChange: change, children: [label && !field && _jsx(Ark.Label, { ...part('label'), children: label }), _jsxs(Ark.Control, { ...part('control'), children: [icon ? _jsx("iconify-icon", { ...part('icon'), icon: icon, "aria-hidden": "true" })
55
+ : prefix != null && _jsx("span", { ...part('prefix'), children: prefix }), _jsx(Ark.Input, { ...part('input'), placeholder: placeholder }), suffix != null && _jsx("span", { ...part('suffix'), children: suffix }), steppers && _jsxs(_Fragment, { children: [_jsx(Ark.DecrementTrigger, { ...part('decrement-trigger'), children: _jsx("iconify-icon", { icon: "lucide:minus" }) }), _jsx(Ark.IncrementTrigger, { ...part('increment-trigger'), children: _jsx("iconify-icon", { icon: "lucide:plus" }) })] })] })] }));
56
+ }
57
+ export const NumberInput = withParts(NumberInputShortcut, {
58
+ Root: Ark.Root,
59
+ Label: Ark.Label,
60
+ Control: Ark.Control,
61
+ Input: Ark.Input,
62
+ DecrementTrigger: Ark.DecrementTrigger,
63
+ IncrementTrigger: Ark.IncrementTrigger,
64
+ ValueText: Ark.ValueText,
65
+ Scrubber: Ark.Scrubber,
66
+ Context: Ark.Context,
67
+ });
@@ -0,0 +1,21 @@
1
+ @layer ui {
2
+ [data-scope=number-input][data-part=root] { display: inline-block; min-width: 10rem; color: var(--ui-text); font-family: var(--ui-font); }
3
+ [data-scope=number-input][data-part=label] { display: block; font-size: 14px; font-weight: 500; margin-bottom: 0.375rem; }
4
+ [data-scope=number-input][data-part=control] { display: flex; align-items: center; gap: 0.5rem; height: var(--ui-control-height);
5
+ padding: 0 0.25rem 0 0.75rem; box-sizing: border-box; background: var(--ui-surface);
6
+ border: 1px solid var(--ui-border); border-radius: var(--ui-radius); font-size: 14px;
7
+ &:focus-within { border-color: var(--ui-ring); outline: 2px solid var(--ui-ring-soft); }
8
+ &[data-disabled] { opacity: 0.5; }
9
+ &[data-invalid], &:has([aria-invalid=true]) { border-color: var(--ui-danger); } }
10
+ [data-scope=number-input][data-part=input] { flex: 1; min-width: 0; padding: 0; border: none; background: transparent; outline: none;
11
+ color: inherit; font: inherit;
12
+ &::placeholder { color: var(--ui-muted); } }
13
+ [data-scope=number-input]:is([data-part=prefix], [data-part=suffix]) { display: flex; align-items: center; flex-shrink: 0;
14
+ color: var(--ui-muted); white-space: nowrap; }
15
+ [data-scope=number-input][data-part=icon] { display: block; width: 1em; height: 1em; font-size: 16px; color: var(--ui-muted); flex-shrink: 0; }
16
+ [data-scope=number-input]:is([data-part=decrement-trigger], [data-part=increment-trigger]) { display: grid; place-items: center;
17
+ flex-shrink: 0; width: 1.5rem; height: 1.75rem; border: none; background: transparent; border-radius: 4px;
18
+ color: var(--ui-muted); cursor: pointer;
19
+ &:hover:not([data-disabled]) { background: var(--ui-hover); color: var(--ui-text); }
20
+ &[data-disabled] { opacity: 0.4; cursor: not-allowed; } }
21
+ }
@@ -0,0 +1,30 @@
1
+ /**
2
+ * A page: its header (heading, description, actions) and content, at a
3
+ * readable width.
4
+ *
5
+ * <Page heading="Students" description="12 students" actions={<Button variant="primary">Add student</Button>}>
6
+ * …content…
7
+ * </Page>
8
+ *
9
+ * - `heading`, `description`
10
+ * - `width`: 'narrow', 'default', 'wide' or 'full'
11
+ * - `align`: 'center' or 'start'
12
+ * - `actions`, `breadcrumbs`: shown in the header
13
+ *
14
+ * What's inside a Page isn't the shell's: a Sidebar shown in the page (as an
15
+ * example, say) doesn't collapse or turn into a drawer with the app's.
16
+ */
17
+ import type { HTMLAttributes, ReactNode } from 'react';
18
+ import { type Classes } from '../utils.js';
19
+ import '../theme.css';
20
+ import './page.css';
21
+ export type PageProps = HTMLAttributes<HTMLDivElement> & {
22
+ heading?: ReactNode;
23
+ description?: ReactNode;
24
+ width?: 'narrow' | 'default' | 'wide' | 'full';
25
+ align?: 'center' | 'start';
26
+ actions?: ReactNode;
27
+ breadcrumbs?: ReactNode;
28
+ classes?: Classes<'root' | 'inner' | 'header' | 'breadcrumbs' | 'titles' | 'heading' | 'description' | 'actions' | 'content'>;
29
+ };
30
+ export declare function Page({ heading, description, width, align, actions, breadcrumbs, className, classes, children, ...rest }: PageProps): import("react").JSX.Element;
@@ -0,0 +1,9 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { cx, partsOf } from '../utils.js';
3
+ import { ShellContext } from '../app-shell/shell.js';
4
+ import '../theme.css';
5
+ import './page.css';
6
+ export function Page({ heading = null, description = null, width = 'default', align = 'center', actions = null, breadcrumbs = null, className, classes, children, ...rest }) {
7
+ const part = partsOf('page', classes);
8
+ return (_jsx("div", { ...rest, ...part('root'), className: cx(className, classes?.root), "data-width": width, "data-align": align, children: _jsxs("div", { ...part('inner'), children: [(heading || description || actions || breadcrumbs) && (_jsxs("header", { ...part('header'), children: [breadcrumbs && _jsx("div", { ...part('breadcrumbs'), children: breadcrumbs }), _jsxs("div", { ...part('titles'), children: [_jsxs("div", { children: [heading && _jsx("h1", { ...part('heading'), children: heading }), description && _jsx("p", { ...part('description'), children: description })] }), actions && _jsx("div", { ...part('actions'), children: actions })] })] })), _jsx("div", { ...part('content'), children: _jsx(ShellContext, { value: null, children: children }) })] }) }));
9
+ }
@@ -0,0 +1,17 @@
1
+ /* A page holds other components, so its rules use > to stay off them. */
2
+ @layer ui {
3
+ [data-scope=page][data-part=root] { display: block; min-width: 0; box-sizing: border-box; padding: 1rem;
4
+ color: var(--ui-text); font-family: var(--ui-font);
5
+ @media (min-width: 768px) { padding: 2rem; } }
6
+ [data-scope=page][data-part=inner] { margin: 0 auto; max-width: 56rem;
7
+ [data-align=start] > & { margin-left: 0; }
8
+ [data-width=narrow] > & { max-width: 40rem; }
9
+ [data-width=wide] > & { max-width: 80rem; }
10
+ [data-width=full] > & { max-width: none; } }
11
+ [data-scope=page][data-part=header] { display: flex; flex-direction: column; gap: 0.5rem; margin-bottom: 1.5rem; }
12
+ [data-scope=page][data-part=breadcrumbs] { font-size: 14px; color: var(--ui-muted); }
13
+ [data-scope=page][data-part=titles] { display: flex; align-items: flex-start; justify-content: space-between; gap: 1rem; flex-wrap: wrap; }
14
+ [data-scope=page][data-part=heading] { margin: 0; font-size: 24px; font-weight: 700; line-height: 1.2; }
15
+ [data-scope=page][data-part=description] { margin: 0.25rem 0 0; color: var(--ui-muted); font-size: 14px; }
16
+ [data-scope=page][data-part=actions] { display: flex; gap: 0.5rem; flex-shrink: 0; }
17
+ }
@@ -0,0 +1,31 @@
1
+ import { Pagination as Ark } from '@ark-ui/react/pagination';
2
+ import 'iconify-icon';
3
+ import { type Classes } from '../utils.js';
4
+ import '../theme.css';
5
+ import './pagination.css';
6
+ export type PaginationProps = Omit<Ark.RootProviderProps, 'value' | 'children'> & {
7
+ count?: number;
8
+ pageSize?: number;
9
+ page?: number;
10
+ defaultPage?: number;
11
+ onPageChange?: (page: number) => void;
12
+ siblingCount?: number;
13
+ summary?: boolean;
14
+ noun?: string;
15
+ firstLast?: boolean;
16
+ label?: string;
17
+ classes?: Classes<'root' | 'summary' | 'pages' | 'item' | 'ellipsis' | 'firstTrigger' | 'prevTrigger' | 'nextTrigger' | 'lastTrigger'>;
18
+ };
19
+ declare function PaginationShortcut({ count, pageSize, page: pageProp, defaultPage, onPageChange, siblingCount, summary, noun: nounProp, firstLast, label: labelProp, className, classes, ...rest }: PaginationProps): import("react").JSX.Element;
20
+ export declare const Pagination: typeof PaginationShortcut & {
21
+ Root: import("react").ForwardRefExoticComponent<Ark.RootProps & import("react").RefAttributes<HTMLElement>>;
22
+ RootProvider: import("react").ForwardRefExoticComponent<Ark.RootProviderProps & import("react").RefAttributes<HTMLElement>>;
23
+ Item: import("react").ForwardRefExoticComponent<Ark.ItemProps & import("react").RefAttributes<HTMLButtonElement>>;
24
+ Ellipsis: import("react").ForwardRefExoticComponent<Ark.EllipsisProps & import("react").RefAttributes<HTMLDivElement>>;
25
+ PrevTrigger: import("react").ForwardRefExoticComponent<Ark.PrevTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
26
+ NextTrigger: import("react").ForwardRefExoticComponent<Ark.NextTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
27
+ FirstTrigger: import("react").ForwardRefExoticComponent<Ark.FirstTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
28
+ LastTrigger: import("react").ForwardRefExoticComponent<Ark.LastTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
29
+ Context: (props: Ark.ContextProps) => import("react").ReactNode;
30
+ };
31
+ export {};
@@ -0,0 +1,58 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * Previous and next buttons and page numbers, with ellipses for long runs.
4
+ *
5
+ * <Pagination count={students.length} pageSize={10} page={page} onPageChange={setPage} />
6
+ * {students.slice((page - 1) * 10, page * 10).map(…)}
7
+ *
8
+ * - `count`: the number of items; `pageSize` per page (10)
9
+ * - `page`, `defaultPage`: the current page, from 1; `onPageChange`: called
10
+ * with the new one. Past the last page (after filtering), it goes to the
11
+ * last one
12
+ * - `siblingCount`: pages shown either side of the current one (1)
13
+ * - `summary`: shows "Showing 11–20 of 95 items" alongside
14
+ * - `noun`: what the items are called in the summary ('items')
15
+ * - `firstLast`: buttons for the first and last page, shown when some pages
16
+ * are hidden behind an ellipsis (false to never show them)
17
+ * - `label`: the nav's accessible name
18
+ *
19
+ * By hand, Ark's parts are here too: Pagination.Root, PrevTrigger, Item,
20
+ * Ellipsis, NextTrigger, FirstTrigger, LastTrigger, Context.
21
+ */
22
+ import { useEffect } from 'react';
23
+ import { Pagination as Ark, usePagination } from '@ark-ui/react/pagination';
24
+ import 'iconify-icon';
25
+ import { cx, partsOf, useControllable, withParts } from '../utils.js';
26
+ import { useLocale, useMessages } from '../format/LocaleProvider.js';
27
+ import { formatNumber } from '../format/format.js';
28
+ import '../theme.css';
29
+ import './pagination.css';
30
+ function PaginationShortcut({ count = 0, pageSize = 10, page: pageProp, defaultPage = 1, onPageChange, siblingCount = 1, summary = false, noun: nounProp, firstLast = true, label: labelProp, className, classes, ...rest }) {
31
+ const t = useMessages();
32
+ const locale = useLocale();
33
+ const noun = nounProp ?? t.pagination.noun;
34
+ const label = labelProp ?? t.pagination.label;
35
+ const fmt = (n) => formatNumber(n, { locale });
36
+ const part = partsOf('pagination', classes);
37
+ const [current, setPage] = useControllable(pageProp, defaultPage, onPageChange);
38
+ const totalPages = Math.max(1, Math.ceil(count / pageSize));
39
+ const page = Math.min(Math.max(1, current), totalPages);
40
+ // Past the last page (the list shrank): move to it.
41
+ useEffect(() => { if (current > totalPages)
42
+ setPage(totalPages); }, [current, totalPages, setPage]);
43
+ const api = usePagination({
44
+ count, pageSize, siblingCount, page, type: 'button', onPageChange: (details) => setPage(details.page),
45
+ ...(t.zag.pagination && { translations: t.zag.pagination }),
46
+ });
47
+ const from = count ? (page - 1) * pageSize + 1 : 0;
48
+ const to = Math.min(page * pageSize, count);
49
+ // First and last only help when some page numbers are hidden.
50
+ const edges = firstLast && api.pages.some((item) => item.type === 'ellipsis');
51
+ return (_jsxs(Ark.RootProvider, { value: api, ...rest, ...part('root'), className: cx(className, classes?.root), "aria-label": label, children: [summary && _jsx("span", { ...part('summary'), children: t.pagination.showing(fmt(from), fmt(to), fmt(count), noun) }), _jsxs("div", { ...part('pages'), children: [edges && _jsx(Ark.FirstTrigger, { ...part('first-trigger'), children: _jsx("iconify-icon", { icon: "lucide:chevrons-left" }) }), _jsx(Ark.PrevTrigger, { ...part('prev-trigger'), children: _jsx("iconify-icon", { icon: "lucide:chevron-left" }) }), api.pages.map((item, i) => item.type === 'page'
52
+ ? _jsx(Ark.Item, { ...item, ...part('item'), children: item.value }, i)
53
+ : _jsx(Ark.Ellipsis, { index: i, ...part('ellipsis'), children: "\u2026" }, i)), _jsx(Ark.NextTrigger, { ...part('next-trigger'), children: _jsx("iconify-icon", { icon: "lucide:chevron-right" }) }), edges && _jsx(Ark.LastTrigger, { ...part('last-trigger'), children: _jsx("iconify-icon", { icon: "lucide:chevrons-right" }) })] })] }));
54
+ }
55
+ export const Pagination = withParts(PaginationShortcut, {
56
+ Root: Ark.Root, RootProvider: Ark.RootProvider, Item: Ark.Item, Ellipsis: Ark.Ellipsis, PrevTrigger: Ark.PrevTrigger,
57
+ NextTrigger: Ark.NextTrigger, FirstTrigger: Ark.FirstTrigger, LastTrigger: Ark.LastTrigger, Context: Ark.Context,
58
+ });
@@ -0,0 +1,15 @@
1
+ @layer ui {
2
+ [data-scope=pagination][data-part=root] { display: flex; align-items: center; justify-content: space-between; gap: 1rem; flex-wrap: wrap;
3
+ color: var(--ui-text); font-family: var(--ui-font); font-size: 14px; }
4
+ [data-scope=pagination][data-part=summary] { color: var(--ui-muted); font-size: 12px; }
5
+ [data-scope=pagination][data-part=pages] { display: flex; align-items: center; gap: 0.25rem; margin-left: auto; }
6
+ [data-scope=pagination]:is([data-part=item], [data-part=first-trigger], [data-part=prev-trigger], [data-part=next-trigger], [data-part=last-trigger]) {
7
+ display: inline-flex; align-items: center; justify-content: center; min-width: 2rem; height: 2rem; padding: 0 0.5rem; box-sizing: border-box;
8
+ border: 1px solid transparent; border-radius: var(--ui-radius); background: transparent; color: inherit; font: inherit; cursor: pointer;
9
+ &:hover { background: var(--ui-hover); }
10
+ &:focus-visible { outline: 2px solid var(--ui-ring-soft); }
11
+ &:disabled { opacity: 0.4; cursor: not-allowed; background: transparent; }
12
+ }
13
+ [data-scope=pagination][data-part=item][data-selected] { border-color: var(--ui-border); background: var(--ui-surface); font-weight: 600; box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05); }
14
+ [data-scope=pagination][data-part=ellipsis] { display: inline-flex; align-items: center; justify-content: center; min-width: 2rem; height: 2rem; color: var(--ui-muted); }
15
+ }
@@ -0,0 +1,47 @@
1
+ /**
2
+ * A password input with a button to show or hide it. Other attributes go on
3
+ * the <input>.
4
+ *
5
+ * <PasswordInput label="Password" value={password} onValueChange={setPassword} autoComplete="new-password" />
6
+ *
7
+ * - `value`, `defaultValue`; `onValueChange`: called with the new text
8
+ * - `icon`: an Iconify name before it
9
+ * - `visible`, `defaultVisible`; `onVisibilityChange`: whether the password shows
10
+ *
11
+ * By hand, with Ark's parts:
12
+ *
13
+ * <PasswordInput.Root>
14
+ * <PasswordInput.Label>Password</PasswordInput.Label>
15
+ * <PasswordInput.Control>
16
+ * <PasswordInput.Input />
17
+ * <PasswordInput.VisibilityTrigger><PasswordInput.Indicator fallback="Show">Hide</PasswordInput.Indicator></PasswordInput.VisibilityTrigger>
18
+ * </PasswordInput.Control>
19
+ * </PasswordInput.Root>
20
+ */
21
+ import type { ComponentProps, ReactNode } from 'react';
22
+ import { PasswordInput as Ark, type PasswordInputVisibilityChangeDetails } from '@ark-ui/react/password-input';
23
+ import 'iconify-icon';
24
+ import { type Classes } from '../utils.js';
25
+ import '../theme.css';
26
+ import './password-input.css';
27
+ export type PasswordInputProps = Omit<ComponentProps<'input'>, 'type'> & {
28
+ label?: ReactNode;
29
+ onValueChange?: (value: string) => void;
30
+ icon?: string | null;
31
+ visible?: boolean;
32
+ defaultVisible?: boolean;
33
+ onVisibilityChange?: (visible: boolean, details: PasswordInputVisibilityChangeDetails) => void;
34
+ classes?: Classes<'root' | 'label' | 'control' | 'icon' | 'input' | 'visibilityTrigger'>;
35
+ };
36
+ declare function PasswordInputShortcut({ label, icon, visible, defaultVisible, onVisibilityChange, onValueChange, onChange, disabled, className, classes, ...rest }: PasswordInputProps): import("react").JSX.Element;
37
+ export declare const PasswordInput: typeof PasswordInputShortcut & {
38
+ Root: import("react").ForwardRefExoticComponent<Ark.RootProps & import("react").RefAttributes<HTMLDivElement>>;
39
+ RootProvider: import("react").ForwardRefExoticComponent<Ark.RootProviderProps & import("react").RefAttributes<HTMLDivElement>>;
40
+ Label: import("react").ForwardRefExoticComponent<Ark.LabelProps & import("react").RefAttributes<HTMLLabelElement>>;
41
+ Control: import("react").ForwardRefExoticComponent<Ark.ControlProps & import("react").RefAttributes<HTMLDivElement>>;
42
+ Input: import("react").ForwardRefExoticComponent<Ark.InputProps & import("react").RefAttributes<HTMLInputElement>>;
43
+ VisibilityTrigger: import("react").ForwardRefExoticComponent<Ark.VisibilityTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
44
+ Indicator: import("react").ForwardRefExoticComponent<Ark.IndicatorProps & import("react").RefAttributes<HTMLSpanElement>>;
45
+ Context: (props: Ark.ContextProps) => ReactNode;
46
+ };
47
+ export {};
@@ -0,0 +1,35 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PasswordInput as Ark, usePasswordInput } from '@ark-ui/react/password-input';
3
+ import { useFieldContext } from '@ark-ui/react/field';
4
+ import 'iconify-icon';
5
+ import { cx, partsOf, withParts } from '../utils.js';
6
+ import { useMessages } from '../format/LocaleProvider.js';
7
+ import '../theme.css';
8
+ import './password-input.css';
9
+ function PasswordInputShortcut({ label = null, icon = null, visible, defaultVisible, onVisibilityChange, onValueChange, onChange, disabled, className, classes, ...rest }) {
10
+ const t = useMessages();
11
+ const field = useFieldContext();
12
+ const part = partsOf('password-input', classes);
13
+ const password = usePasswordInput({
14
+ ...(visible !== undefined && { visible }),
15
+ ...(defaultVisible !== undefined && { defaultVisible }),
16
+ ...(disabled !== undefined && { disabled }),
17
+ ...(t.zag.passwordInput && { translations: t.zag.passwordInput }),
18
+ ...(onVisibilityChange && { onVisibilityChange: (details) => onVisibilityChange(details.visible, details) }),
19
+ });
20
+ function change(e) {
21
+ onChange?.(e);
22
+ onValueChange?.(e.target.value);
23
+ }
24
+ return (_jsxs(Ark.RootProvider, { value: password, ...part('root'), className: cx(className, classes?.root), children: [label && !field && _jsx(Ark.Label, { ...part('label'), children: label }), _jsxs(Ark.Control, { ...part('control'), children: [icon && _jsx("iconify-icon", { ...part('icon'), icon: icon, "aria-hidden": "true" }), _jsx(Ark.Input, { ...rest, ...part('input'), onChange: change }), _jsx(Ark.VisibilityTrigger, { ...part('visibility-trigger'), children: _jsx("iconify-icon", { icon: password.visible ? 'lucide:eye-off' : 'lucide:eye', "aria-hidden": "true" }) })] })] }));
25
+ }
26
+ export const PasswordInput = withParts(PasswordInputShortcut, {
27
+ Root: Ark.Root,
28
+ RootProvider: Ark.RootProvider,
29
+ Label: Ark.Label,
30
+ Control: Ark.Control,
31
+ Input: Ark.Input,
32
+ VisibilityTrigger: Ark.VisibilityTrigger,
33
+ Indicator: Ark.Indicator,
34
+ Context: Ark.Context,
35
+ });
@@ -0,0 +1,18 @@
1
+ @layer ui {
2
+ [data-scope=password-input][data-part=root] { display: block; min-width: 0; color: var(--ui-text); font-family: var(--ui-font); }
3
+ [data-scope=password-input][data-part=label] { display: block; font-size: 14px; font-weight: 500; margin-bottom: 0.375rem; }
4
+ [data-scope=password-input][data-part=control] { display: flex; align-items: center; gap: 0.5rem; height: var(--ui-control-height);
5
+ padding: 0 0.25rem 0 0.75rem; box-sizing: border-box; background: var(--ui-surface);
6
+ border: 1px solid var(--ui-border); border-radius: var(--ui-radius); font-size: 14px;
7
+ &:focus-within { border-color: var(--ui-ring); outline: 2px solid var(--ui-ring-soft); }
8
+ &[data-invalid], &:has([aria-invalid=true]) { border-color: var(--ui-danger); }
9
+ &[data-disabled] { opacity: 0.5; } }
10
+ [data-scope=password-input][data-part=input] { flex: 1; min-width: 0; padding: 0; border: none; background: transparent; outline: none;
11
+ color: inherit; font: inherit;
12
+ &::placeholder { color: var(--ui-muted); } }
13
+ [data-scope=password-input][data-part=icon] { display: block; width: 1em; height: 1em; font-size: 16px; color: var(--ui-muted); flex-shrink: 0; }
14
+ [data-scope=password-input][data-part=visibility-trigger] { display: grid; place-items: center; flex-shrink: 0; width: 1.75rem; height: 1.75rem;
15
+ border: none; background: transparent; border-radius: 4px; color: var(--ui-muted); cursor: pointer;
16
+ &:hover { background: var(--ui-hover); color: var(--ui-text); }
17
+ &:focus-visible { outline: 2px solid var(--ui-ring-soft); } }
18
+ }
@@ -0,0 +1,45 @@
1
+ /**
2
+ * A code input: one box per character, for verification codes and PINs.
3
+ *
4
+ * <PinInput label="Code" count={6} value={code} onValueChange={setCode} onComplete={verify} />
5
+ *
6
+ * - `value`, `defaultValue`: a string; `onValueChange`: called with it
7
+ * - `count`: how many boxes (4)
8
+ * - `type`: 'numeric', 'alphabetic' or 'alphanumeric'
9
+ * - `mask`: hide the characters, like a password
10
+ * - `placeholder`: shown in each empty box (none)
11
+ * - `otp`: offer one-time codes from the keyboard (autocomplete="one-time-code")
12
+ * - `onComplete`: called with the value once every box is filled
13
+ * - `name`: for plain form posts
14
+ *
15
+ * By hand, with Ark's parts:
16
+ *
17
+ * <PinInput.Root count={4}>
18
+ * <PinInput.Label>PIN</PinInput.Label>
19
+ * <PinInput.Control>{[0, 1, 2, 3].map((index) => <PinInput.Input key={index} index={index} />)}</PinInput.Control>
20
+ * <PinInput.HiddenInput />
21
+ * </PinInput.Root>
22
+ */
23
+ import type { ReactNode } from 'react';
24
+ import { PinInput as Ark, type PinInputValueChangeDetails } from '@ark-ui/react/pin-input';
25
+ import { type Classes } from '../utils.js';
26
+ import '../theme.css';
27
+ import './pin-input.css';
28
+ export type PinInputProps = Omit<Ark.RootProps, 'value' | 'defaultValue' | 'onValueChange' | 'onValueComplete' | 'label'> & {
29
+ label?: ReactNode;
30
+ value?: string;
31
+ defaultValue?: string;
32
+ onValueChange?: (value: string, details: PinInputValueChangeDetails) => void;
33
+ onComplete?: (value: string, details: PinInputValueChangeDetails) => void;
34
+ classes?: Classes<'root' | 'label' | 'control' | 'input'>;
35
+ };
36
+ declare function PinInputShortcut({ label, count, type, placeholder, value, defaultValue, onValueChange, onComplete, className, classes, ...rest }: PinInputProps): import("react").JSX.Element;
37
+ export declare const PinInput: typeof PinInputShortcut & {
38
+ Root: import("react").ForwardRefExoticComponent<Ark.RootProps & import("react").RefAttributes<HTMLDivElement>>;
39
+ Label: import("react").ForwardRefExoticComponent<Ark.LabelProps & import("react").RefAttributes<HTMLLabelElement>>;
40
+ Control: import("react").ForwardRefExoticComponent<Ark.ControlProps & import("react").RefAttributes<HTMLDivElement>>;
41
+ Input: import("react").ForwardRefExoticComponent<Ark.InputProps & import("react").RefAttributes<HTMLInputElement>>;
42
+ HiddenInput: import("react").ForwardRefExoticComponent<Ark.HiddenInputProps & import("react").RefAttributes<HTMLInputElement>>;
43
+ Context: (props: Ark.ContextProps) => ReactNode;
44
+ };
45
+ export {};
@@ -0,0 +1,22 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { PinInput as Ark } from '@ark-ui/react/pin-input';
3
+ import { useFieldContext } from '@ark-ui/react/field';
4
+ import { cx, partsOf, withParts } from '../utils.js';
5
+ import { useMessages } from '../format/LocaleProvider.js';
6
+ import '../theme.css';
7
+ import './pin-input.css';
8
+ function PinInputShortcut({ label = null, count = 4, type = 'numeric', placeholder = '', value, defaultValue, onValueChange, onComplete, className, classes, ...rest }) {
9
+ const t = useMessages();
10
+ const field = useFieldContext();
11
+ const part = partsOf('pin-input', classes);
12
+ const boxes = (text) => text.split('').slice(0, count);
13
+ return (_jsxs(Ark.Root, { ...(t.zag.pinInput && { translations: t.zag.pinInput }), ...rest, ...part('root'), className: cx(className, classes?.root), count: count, type: type, placeholder: placeholder, ...(value !== undefined && { value: boxes(value) }), ...(defaultValue !== undefined && { defaultValue: boxes(defaultValue) }), ...(onValueChange && { onValueChange: (details) => onValueChange(details.valueAsString, details) }), ...(onComplete && { onValueComplete: (details) => onComplete(details.valueAsString, details) }), children: [label && !field && _jsx(Ark.Label, { ...part('label'), children: label }), _jsx(Ark.Control, { ...part('control'), children: Array.from({ length: count }, (_, index) => _jsx(Ark.Input, { index: index, ...part('input') }, index)) }), _jsx(Ark.HiddenInput, {})] }));
14
+ }
15
+ export const PinInput = withParts(PinInputShortcut, {
16
+ Root: Ark.Root,
17
+ Label: Ark.Label,
18
+ Control: Ark.Control,
19
+ Input: Ark.Input,
20
+ HiddenInput: Ark.HiddenInput,
21
+ Context: Ark.Context,
22
+ });
@@ -0,0 +1,13 @@
1
+ @layer ui {
2
+ [data-scope=pin-input][data-part=root] { display: block; color: var(--ui-text); font-family: var(--ui-font); }
3
+ [data-scope=pin-input][data-part=label] { display: block; font-size: 14px; font-weight: 500; margin-bottom: 0.375rem; }
4
+ [data-scope=pin-input][data-part=control] { display: flex; gap: 0.5rem; }
5
+ [data-scope=pin-input][data-part=input] { width: var(--ui-control-height); height: var(--ui-control-height); padding: 0; box-sizing: border-box;
6
+ text-align: center; background: var(--ui-surface); border: 1px solid var(--ui-border); border-radius: var(--ui-radius);
7
+ color: inherit; font-family: inherit; font-size: 16px; font-weight: 500; outline: none;
8
+ &::placeholder { color: var(--ui-muted); }
9
+ &:focus { border-color: var(--ui-ring); outline: 2px solid var(--ui-ring-soft); }
10
+ &:is([data-invalid], [aria-invalid=true]) { border-color: var(--ui-danger); }
11
+ &[data-complete] { border-color: var(--ui-accent); }
12
+ &:disabled { opacity: 0.5; } }
13
+ }
@@ -0,0 +1,65 @@
1
+ /**
2
+ * A popover: a panel that opens from a trigger, for settings or details.
3
+ *
4
+ * <Popover heading="Appearance" closable placement="bottom-end"
5
+ * trigger={<Button icon="lucide:palette" aria-label="Appearance" />}>
6
+ * …content…
7
+ * </Popover>
8
+ *
9
+ * - `trigger`: the element that opens it (it gets the trigger's props, so a
10
+ * component must pass them on, as Button does)
11
+ * - `heading`, `description`: a header for the panel
12
+ * - `closable`: a close button in the corner
13
+ * - `arrow`: points the panel at its trigger
14
+ * - `modal`: traps focus and blocks the page behind it
15
+ * - `open`, `defaultOpen`; `onOpenChange`
16
+ * - `placement`: where it opens ('bottom')
17
+ *
18
+ * By hand, with Ark's parts:
19
+ *
20
+ * <Popover.Root>
21
+ * <Popover.Trigger asChild><Button>Filters</Button></Popover.Trigger>
22
+ * <Popover.Positioner>
23
+ * <Popover.Content><Popover.Title>Filters</Popover.Title>…<Popover.CloseTrigger>×</Popover.CloseTrigger></Popover.Content>
24
+ * </Popover.Positioner>
25
+ * </Popover.Root>
26
+ */
27
+ import type { ReactElement, ReactNode } from 'react';
28
+ import { Popover as Ark, type PopoverOpenChangeDetails } from '@ark-ui/react/popover';
29
+ import 'iconify-icon';
30
+ import { type Classes } from '../utils.js';
31
+ import '../theme.css';
32
+ import './popover.css';
33
+ export type PopoverProps = Omit<Ark.ContentProps, 'children'> & {
34
+ trigger?: ReactElement | null;
35
+ heading?: ReactNode;
36
+ description?: ReactNode;
37
+ closable?: boolean;
38
+ arrow?: boolean;
39
+ modal?: boolean;
40
+ open?: boolean;
41
+ defaultOpen?: boolean;
42
+ onOpenChange?: (open: boolean, details: PopoverOpenChangeDetails) => void;
43
+ placement?: NonNullable<Ark.RootProps['positioning']>['placement'];
44
+ classes?: Classes<'positioner' | 'content' | 'arrow' | 'arrowTip' | 'header' | 'title' | 'description' | 'closeTrigger'>;
45
+ children?: ReactNode;
46
+ };
47
+ declare function PopoverShortcut({ trigger, heading, description, closable, arrow, modal, open, defaultOpen, onOpenChange, placement, className, classes, children, ...rest }: PopoverProps): import("react").JSX.Element;
48
+ export declare const Popover: typeof PopoverShortcut & {
49
+ Root: (props: Ark.RootProps) => import("react").JSX.Element;
50
+ Trigger: import("react").ForwardRefExoticComponent<Ark.TriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
51
+ Anchor: import("react").ForwardRefExoticComponent<Ark.AnchorProps & import("react").RefAttributes<HTMLDivElement>>;
52
+ Positioner: import("react").ForwardRefExoticComponent<Ark.PositionerProps & import("react").RefAttributes<HTMLDivElement>>;
53
+ Content: import("react").ForwardRefExoticComponent<Ark.ContentProps & import("react").RefAttributes<HTMLDivElement>>;
54
+ Title: import("react").ForwardRefExoticComponent<Ark.TitleProps & import("react").RefAttributes<HTMLHeadingElement>>;
55
+ Description: import("react").ForwardRefExoticComponent<Ark.DescriptionProps & import("react").RefAttributes<HTMLDivElement>>;
56
+ CloseTrigger: import("react").ForwardRefExoticComponent<Ark.CloseTriggerProps & import("react").RefAttributes<HTMLButtonElement>>;
57
+ Arrow: import("react").ForwardRefExoticComponent<Ark.ArrowProps & import("react").RefAttributes<HTMLDivElement>>;
58
+ ArrowTip: import("react").ForwardRefExoticComponent<Ark.ArrowTipProps & import("react").RefAttributes<HTMLDivElement>>;
59
+ Context: (props: Ark.ContextProps) => ReactNode;
60
+ Header: {
61
+ (props: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>): ReactElement<any, string | import("react").JSXElementConstructor<any>>;
62
+ displayName: string;
63
+ };
64
+ };
65
+ export {};
@@ -0,0 +1,26 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Popover as Ark } from '@ark-ui/react/popover';
3
+ import 'iconify-icon';
4
+ import { cx, on, partOf, partsOf, withParts } from '../utils.js';
5
+ import { useMessages } from '../format/LocaleProvider.js';
6
+ import '../theme.css';
7
+ import './popover.css';
8
+ function PopoverShortcut({ trigger = null, heading = null, description = null, closable = false, arrow = false, modal = false, open, defaultOpen, onOpenChange, placement = 'bottom', className, classes, children, ...rest }) {
9
+ const t = useMessages();
10
+ const part = partsOf('popover', classes);
11
+ return (_jsxs(Ark.Root, { modal: modal, positioning: { placement, strategy: 'fixed' }, ...(open !== undefined && { open }), ...(defaultOpen !== undefined && { defaultOpen }), ...on('onOpenChange', onOpenChange, (details) => details.open), children: [trigger && _jsx(Ark.Trigger, { asChild: true, children: trigger }), _jsx(Ark.Positioner, { ...part('positioner'), children: _jsxs(Ark.Content, { ...rest, ...part('content'), className: cx(className, classes?.content), children: [arrow && _jsx(Ark.Arrow, { ...part('arrow'), children: _jsx(Ark.ArrowTip, { ...part('arrow-tip') }) }), (heading || description) && (_jsxs("div", { ...part('header'), children: [heading && _jsx(Ark.Title, { ...part('title'), children: heading }), description && _jsx(Ark.Description, { ...part('description'), children: description })] })), children, closable && _jsx(Ark.CloseTrigger, { ...part('close-trigger'), "aria-label": t.common.close, children: _jsx("iconify-icon", { icon: "lucide:x" }) })] }) })] }));
12
+ }
13
+ export const Popover = withParts(PopoverShortcut, {
14
+ Root: Ark.Root,
15
+ Trigger: Ark.Trigger,
16
+ Anchor: Ark.Anchor,
17
+ Positioner: Ark.Positioner,
18
+ Content: Ark.Content,
19
+ Title: Ark.Title,
20
+ Description: Ark.Description,
21
+ CloseTrigger: Ark.CloseTrigger,
22
+ Arrow: Ark.Arrow,
23
+ ArrowTip: Ark.ArrowTip,
24
+ Context: Ark.Context,
25
+ Header: partOf('popover', 'header'),
26
+ });
@@ -0,0 +1,16 @@
1
+ @layer ui {
2
+ /* Zag copies the content's z-index onto its positioner. */
3
+ [data-scope=popover][data-part=content] { z-index: 50; position: relative; width: 18rem; max-width: calc(100vw - 32px);
4
+ padding: 1rem; box-sizing: border-box; outline: none; font-weight: 400;
5
+ background: var(--ui-surface); color: var(--ui-text); font-family: var(--ui-font); font-size: 14px;
6
+ border: 1px solid var(--ui-border); border-radius: calc(var(--ui-radius) + 2px); box-shadow: var(--ui-shadow);
7
+ --arrow-size: 12px; --arrow-background: var(--ui-surface); }
8
+ [data-scope=popover][data-part=arrow-tip] { border-top: 1px solid var(--ui-border); border-left: 1px solid var(--ui-border); }
9
+ [data-scope=popover][data-part=header] { padding-right: 1.5rem; margin-bottom: 0.75rem;
10
+ &:last-child { margin-bottom: 0; } }
11
+ [data-scope=popover][data-part=title] { font-weight: 600; }
12
+ [data-scope=popover][data-part=description] { margin: 0.25rem 0 0; color: var(--ui-muted); }
13
+ [data-scope=popover][data-part=close-trigger] { position: absolute; top: 0.5rem; right: 0.5rem; display: grid; place-items: center;
14
+ width: 1.75rem; height: 1.75rem; border: none; background: transparent; border-radius: 4px; color: var(--ui-muted); cursor: pointer;
15
+ &:hover { background: var(--ui-hover); color: var(--ui-text); } }
16
+ }