@milktop/react-ui 0.0.0-stage → 0.1.2

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 +32 -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 +121 -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 progress indicator, as a bar or a circle.
3
+ *
4
+ * <Progress label="Course" value={64} showValue />
5
+ * <Progress variant="circle" value={80} showValue />
6
+ *
7
+ * - `value`: from `min` to `max` (0 to 100); null means indeterminate, for
8
+ * work of unknown length
9
+ * - `label`, `showValue`: a label and the formatted value (a percentage by
10
+ * default; see `formatOptions`, `locale`)
11
+ * - `translations.value`: writes the value text, ({ value, max, percent }) => '3 of 4'
12
+ * - `variant`: 'linear' (default) or 'circle'; `size` and `thickness` set the
13
+ * circle's diameter and stroke in px
14
+ *
15
+ * By hand, with Ark's parts:
16
+ *
17
+ * <Progress.Root value={40}>
18
+ * <Progress.Label>Upload</Progress.Label> <Progress.ValueText />
19
+ * <Progress.Track><Progress.Range /></Progress.Track>
20
+ * </Progress.Root>
21
+ */
22
+ import type { ReactNode } from 'react';
23
+ import { Progress as Ark } from '@ark-ui/react/progress';
24
+ import { type Classes } from '../utils.js';
25
+ import '../theme.css';
26
+ import './progress.css';
27
+ export type ProgressProps = Omit<Ark.RootProps, 'value' | 'defaultValue' | 'label'> & {
28
+ value?: number | null;
29
+ label?: ReactNode;
30
+ showValue?: boolean;
31
+ variant?: 'linear' | 'circle';
32
+ size?: number;
33
+ thickness?: number;
34
+ classes?: Classes<'root' | 'header' | 'label' | 'valueText' | 'track' | 'range' | 'circleWrap' | 'circle' | 'circleTrack' | 'circleRange'>;
35
+ };
36
+ declare function ProgressShortcut({ value, min, max, label, showValue, variant, size, thickness, locale: localeProp, className, classes, ...rest }: ProgressProps): import("react").JSX.Element;
37
+ export declare const Progress: typeof ProgressShortcut & {
38
+ Root: import("react").ForwardRefExoticComponent<Ark.RootProps & import("react").RefAttributes<HTMLDivElement>>;
39
+ Label: import("react").ForwardRefExoticComponent<Ark.LabelProps & import("react").RefAttributes<HTMLSpanElement>>;
40
+ ValueText: import("react").ForwardRefExoticComponent<Ark.ValueTextProps & import("react").RefAttributes<HTMLSpanElement>>;
41
+ Track: import("react").ForwardRefExoticComponent<Ark.TrackProps & import("react").RefAttributes<HTMLDivElement>>;
42
+ Range: import("react").ForwardRefExoticComponent<Ark.RangeProps & import("react").RefAttributes<HTMLDivElement>>;
43
+ Circle: import("react").ForwardRefExoticComponent<Ark.CircleProps & import("react").RefAttributes<SVGSVGElement>>;
44
+ CircleTrack: import("react").ForwardRefExoticComponent<Ark.CircleTrackProps & import("react").RefAttributes<SVGCircleElement>>;
45
+ CircleRange: import("react").ForwardRefExoticComponent<Ark.CircleRangeProps & import("react").RefAttributes<SVGCircleElement>>;
46
+ Context: (props: Ark.ContextProps) => ReactNode;
47
+ Header: {
48
+ (props: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
49
+ displayName: string;
50
+ };
51
+ CircleWrap: {
52
+ (props: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
53
+ displayName: string;
54
+ };
55
+ };
56
+ export {};
@@ -0,0 +1,28 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { Progress as Ark } from '@ark-ui/react/progress';
3
+ import { useLocale } from '../format/LocaleProvider.js';
4
+ import { cx, partOf, partsOf, withParts } from '../utils.js';
5
+ import '../theme.css';
6
+ import './progress.css';
7
+ // The value as Zag writes it (formatOptions, translations.value); Ark's
8
+ // ValueText would show the percentage whatever they say.
9
+ const ValueText = (props) => _jsx(Ark.Context, { children: (api) => _jsx(Ark.ValueText, { ...props, children: api.valueAsString }) });
10
+ function ProgressShortcut({ value = null, min = 0, max = 100, label = null, showValue = false, variant = 'linear', size = 48, thickness = 5, locale: localeProp, className, classes, ...rest }) {
11
+ const app = useLocale();
12
+ const locale = localeProp ?? app ?? 'en-GB';
13
+ const part = partsOf('progress', classes);
14
+ return (_jsxs(Ark.Root, { ...rest, ...part('root'), className: cx(className, classes?.root), "data-variant": variant, value: value, min: min, max: max, locale: locale, children: [(label || (showValue && variant === 'linear')) && (_jsxs("div", { ...part('header'), children: [label && _jsx(Ark.Label, { ...part('label'), children: label }), showValue && variant === 'linear' && _jsx(ValueText, { ...part('value-text') })] })), variant === 'circle' ? (_jsxs("div", { ...part('circle-wrap'), style: { '--size': `${size}px`, '--thickness': `${thickness}px` }, children: [_jsxs(Ark.Circle, { ...part('circle'), children: [_jsx(Ark.CircleTrack, { ...part('circle-track') }), _jsx(Ark.CircleRange, { ...part('circle-range') })] }), showValue && _jsx(ValueText, { ...part('value-text') })] })) : (_jsx(Ark.Track, { ...part('track'), children: _jsx(Ark.Range, { ...part('range') }) }))] }));
15
+ }
16
+ export const Progress = withParts(ProgressShortcut, {
17
+ Root: Ark.Root,
18
+ Label: Ark.Label,
19
+ ValueText: Ark.ValueText,
20
+ Track: Ark.Track,
21
+ Range: Ark.Range,
22
+ Circle: Ark.Circle,
23
+ CircleTrack: Ark.CircleTrack,
24
+ CircleRange: Ark.CircleRange,
25
+ Context: Ark.Context,
26
+ Header: partOf('progress', 'header'),
27
+ CircleWrap: partOf('progress', 'circle-wrap'),
28
+ });
@@ -0,0 +1,24 @@
1
+ @layer ui {
2
+ [data-scope=progress][data-part=root] {
3
+ display: block; width: 100%; min-width: 0; color: var(--ui-text); font-family: var(--ui-font); font-size: 14px;
4
+ &[data-variant=circle] { display: inline-block; width: auto; }
5
+ }
6
+ [data-scope=progress][data-part=header] { display: flex; justify-content: space-between; align-items: baseline; gap: 1rem; margin-bottom: 0.375rem; }
7
+ [data-scope=progress][data-part=label] { font-weight: 500; }
8
+ /* Zag calls both value texts value-text; their places tell them apart. */
9
+ [data-scope=progress][data-part=header] > [data-part=value-text] { margin-left: auto; color: var(--ui-muted); font-variant-numeric: tabular-nums; }
10
+ [data-scope=progress][data-part=track] { position: relative; height: 0.5rem; overflow: hidden; background: var(--ui-hover); border-radius: 9999px; }
11
+ [data-scope=progress][data-part=range] { height: 100%; width: var(--percent, 0); background: var(--ui-accent); border-radius: 9999px; transition: width 300ms ease;
12
+ [data-state=indeterminate] & { width: 40%; animation: ui-progress-slide 1.2s ease-in-out infinite; } }
13
+ [data-scope=progress][data-part=circle-wrap] { position: relative; display: inline-grid; place-items: center; }
14
+ /* Zag rotates the range to start at the top and sets its dash offset inline. */
15
+ [data-scope=progress][data-part=circle] { display: block;
16
+ [data-state=indeterminate] & { animation: ui-spin 1s linear infinite; } }
17
+ [data-scope=progress][data-part=circle-track] { stroke: var(--ui-hover); fill: none; }
18
+ [data-scope=progress][data-part=circle-range] { stroke: var(--ui-accent); fill: none; stroke-linecap: round;
19
+ stroke-dasharray: var(--circumference); stroke-dashoffset: var(--offset); transition: stroke-dashoffset 300ms ease;
20
+ /* Indeterminate: a 30% dash with a full gap leaves an arc to spin. */
21
+ [data-state=indeterminate] & { stroke-dasharray: calc(var(--circumference) * 0.3) var(--circumference); } }
22
+ [data-scope=progress][data-part=circle-wrap] > [data-part=value-text] { position: absolute; font-size: 12px; font-weight: 500; font-variant-numeric: tabular-nums; }
23
+ @keyframes ui-progress-slide { from { translate: -100%; } to { translate: 250%; } }
24
+ }
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Styles rich text: headings, lists, quotes, links, code, images and tables,
3
+ * e.g. the HTML an Editor saved, shown on a page.
4
+ *
5
+ * <Prose html={lesson.notes} />
6
+ * <Prose size="sm"><h2>Homework</h2><p>Worksheet 4…</p></Prose>
7
+ *
8
+ * Its look matches the Editor's, so what was written reads the same.
9
+ *
10
+ * - `html`: an HTML string to show (only from a source you trust, such as
11
+ * your own Editor's output saved by your app); or give it children
12
+ * - `size`: 'sm' (13px), 'md' (14px, default) or 'lg' (16px)
13
+ */
14
+ import type { HTMLAttributes } from 'react';
15
+ import { type Classes } from '../utils.js';
16
+ import '../theme.css';
17
+ import './prose.css';
18
+ export type ProseProps = HTMLAttributes<HTMLDivElement> & {
19
+ html?: string | null;
20
+ size?: 'sm' | 'md' | 'lg';
21
+ classes?: Classes<'root'>;
22
+ };
23
+ export declare function Prose({ html, size, className, classes, children, ...rest }: ProseProps): import("react").JSX.Element;
@@ -0,0 +1,10 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { cx, partsOf } from '../utils.js';
3
+ import '../theme.css';
4
+ import './prose.css';
5
+ export function Prose({ html = null, size = 'md', className, classes, children, ...rest }) {
6
+ const part = partsOf('prose', classes);
7
+ return html != null
8
+ ? _jsx("div", { ...rest, ...part('root'), className: cx(className, classes?.root), "data-size": size, dangerouslySetInnerHTML: { __html: html } })
9
+ : _jsx("div", { ...rest, ...part('root'), className: cx(className, classes?.root), "data-size": size, children: children });
10
+ }
@@ -0,0 +1,29 @@
1
+ /* The Editor's content look, for showing what it saved. */
2
+ @layer ui {
3
+ [data-scope=prose][data-part=root] { color: var(--ui-text); font-family: var(--ui-font); font-size: 14px; line-height: 1.6; overflow-wrap: anywhere;
4
+ &[data-size=sm] { font-size: 13px; }
5
+ &[data-size=lg] { font-size: 16px; }
6
+ & > :first-child { margin-top: 0; }
7
+ & > :last-child { margin-bottom: 0; }
8
+ & :is(p, ul, ol, blockquote, pre, table, figure) { margin: 0 0 0.75em; }
9
+ & h1 { margin: 1em 0 0.5em; font-size: 1.6em; font-weight: 700; line-height: 1.25; }
10
+ & h2 { margin: 1em 0 0.5em; font-size: 1.3em; font-weight: 600; line-height: 1.3; }
11
+ & h3 { margin: 0.9em 0 0.4em; font-size: 1.1em; font-weight: 600; line-height: 1.3; }
12
+ & h4 { margin: 0.9em 0 0.4em; font-size: 1em; font-weight: 600; }
13
+ & :is(ul, ol) { padding-left: 1.25em; }
14
+ & ul { list-style: disc; }
15
+ & ol { list-style: decimal; }
16
+ & li > p { margin: 0; }
17
+ & li + li { margin-top: 0.25em; }
18
+ & blockquote { padding-left: 0.75em; border-left: 3px solid var(--ui-border); color: var(--ui-muted); }
19
+ & code { padding: 0.125em 0.3em; border-radius: 4px; background: var(--ui-hover); font-family: ui-monospace, monospace; font-size: 0.9em; }
20
+ & pre { padding: 0.75em 1em; border-radius: var(--ui-radius); background: var(--ui-hover); overflow-x: auto; font-size: 0.9em;
21
+ & code { padding: 0; background: none; } }
22
+ & a { color: var(--ui-accent); text-decoration: underline; text-underline-offset: 2px; }
23
+ & img { display: block; max-width: 100%; height: auto; margin: 0.75em 0; border-radius: var(--ui-radius); }
24
+ & hr { margin: 1.5em 0; border: none; border-top: 1px solid var(--ui-border); }
25
+ & strong { font-weight: 600; }
26
+ & table { width: 100%; border-collapse: collapse; font-size: 0.95em; }
27
+ & :is(th, td) { padding: 0.4em 0.6em; border-bottom: 1px solid var(--ui-border); text-align: left; }
28
+ & th { font-weight: 600; } }
29
+ }
@@ -0,0 +1,59 @@
1
+ /**
2
+ * A group of radio buttons: pick one.
3
+ *
4
+ * <RadioGroup label="Lesson length" items={['30 min', '45 min', '60 min']} value={length} onValueChange={setLength} />
5
+ *
6
+ * - `items`: strings, or objects (see `labelKey`, `valueKey`, `disabledKey`; `description`)
7
+ * - `value`, `defaultValue`: the item's own value; `onValueChange`: called with it
8
+ * - `label`: a label above it (skipped inside a Field)
9
+ * - `orientation`: 'vertical' or 'horizontal'
10
+ * - `variant`: 'list' (default), or 'cards': each option a bordered card
11
+ * (with its `description`, and an `icon` from the item), chosen one outlined
12
+ * - `name`: for plain form posts
13
+ *
14
+ * By hand, with Ark's parts:
15
+ *
16
+ * <RadioGroup.Root defaultValue="45">
17
+ * <RadioGroup.Label>Length</RadioGroup.Label>
18
+ * {['30', '45'].map((value) => (
19
+ * <RadioGroup.Item key={value} value={value}>
20
+ * <RadioGroup.ItemControl /><RadioGroup.ItemText>{value} min</RadioGroup.ItemText><RadioGroup.ItemHiddenInput />
21
+ * </RadioGroup.Item>
22
+ * ))}
23
+ * </RadioGroup.Root>
24
+ */
25
+ import type { ReactNode } from 'react';
26
+ import { RadioGroup as Ark, type RadioGroupValueChangeDetails } from '@ark-ui/react/radio-group';
27
+ import 'iconify-icon';
28
+ import { type Classes } from '../utils.js';
29
+ import '../theme.css';
30
+ import './radio-group.css';
31
+ type Value<T, K extends string> = T extends string | number ? T : K extends keyof T ? T[K] : unknown;
32
+ export type RadioGroupProps<T, K extends string = 'value'> = Omit<Ark.RootProps, 'value' | 'defaultValue' | 'onValueChange' | 'label'> & {
33
+ items: readonly T[];
34
+ value?: NoInfer<Value<T, K>> | null;
35
+ defaultValue?: NoInfer<Value<T, K>> | null;
36
+ onValueChange?: (value: NoInfer<Value<T, K>> | null, details: RadioGroupValueChangeDetails) => void;
37
+ label?: ReactNode;
38
+ labelKey?: string;
39
+ valueKey?: K;
40
+ disabledKey?: string;
41
+ variant?: 'list' | 'cards';
42
+ classes?: Classes<'root' | 'label' | 'items' | 'item' | 'itemControl' | 'icon' | 'text' | 'itemText' | 'description'>;
43
+ };
44
+ declare function RadioGroupShortcut<T, K extends string = 'value'>({ items, value, defaultValue, onValueChange, label, orientation, variant, labelKey, valueKey, disabledKey, className, classes, ...rest }: RadioGroupProps<T, K>): import("react").JSX.Element;
45
+ export declare const RadioGroup: typeof RadioGroupShortcut & {
46
+ Root: import("react").ForwardRefExoticComponent<Ark.RootProps & import("react").RefAttributes<HTMLDivElement>>;
47
+ Label: import("react").ForwardRefExoticComponent<Ark.LabelProps & import("react").RefAttributes<HTMLSpanElement>>;
48
+ Item: import("react").ForwardRefExoticComponent<Ark.ItemProps & import("react").RefAttributes<HTMLLabelElement>>;
49
+ ItemControl: import("react").ForwardRefExoticComponent<Ark.ItemControlProps & import("react").RefAttributes<HTMLDivElement>>;
50
+ ItemText: import("react").ForwardRefExoticComponent<Ark.ItemTextProps & import("react").RefAttributes<HTMLSpanElement>>;
51
+ ItemHiddenInput: import("react").ForwardRefExoticComponent<Ark.ItemHiddenInputProps & import("react").RefAttributes<HTMLInputElement>>;
52
+ Indicator: import("react").ForwardRefExoticComponent<Ark.IndicatorProps & import("react").RefAttributes<HTMLDivElement>>;
53
+ Context: (props: import("@ark-ui/react/radio-group").RadioGroupContextProps) => ReactNode;
54
+ Items: {
55
+ (props: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
56
+ displayName: string;
57
+ };
58
+ };
59
+ export {};
@@ -0,0 +1,37 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { RadioGroup as Ark } from '@ark-ui/react/radio-group';
3
+ import { useFieldContext } from '@ark-ui/react/field';
4
+ import 'iconify-icon';
5
+ import { cx, partOf, partsOf, useControllable, withParts } from '../utils.js';
6
+ import '../theme.css';
7
+ import './radio-group.css';
8
+ function RadioGroupShortcut({ items, value, defaultValue, onValueChange, label = null, orientation = 'vertical', variant = 'list', labelKey = 'label', valueKey = 'value', disabledKey = 'disabled', className, classes, ...rest }) {
9
+ const field = useFieldContext();
10
+ const part = partsOf('radio-group', classes);
11
+ const [current, setCurrent] = useControllable(value, defaultValue ?? null, undefined);
12
+ const key = (item, k) => item[k];
13
+ const isObject = (item) => typeof item === 'object' && item !== null;
14
+ const labelOf = (item) => String(isObject(item) ? key(item, labelKey) : item);
15
+ const valueOf = (item) => (isObject(item) ? key(item, valueKey) : item);
16
+ const descriptionOf = (item) => (isObject(item) ? key(item, 'description') : null);
17
+ const iconOf = (item) => (isObject(item) ? key(item, 'icon') : undefined);
18
+ // Zag's values are strings; map them back to the items' own.
19
+ function change(details) {
20
+ const item = items.find((item) => String(valueOf(item)) === details.value);
21
+ const next = item === undefined ? null : valueOf(item);
22
+ setCurrent(next);
23
+ onValueChange?.(next, details);
24
+ }
25
+ return (_jsxs(Ark.Root, { ...rest, ...part('root'), className: cx(className, classes?.root), orientation: orientation, "data-variant": variant, value: current == null ? null : String(current), onValueChange: change, "aria-describedby": field?.ariaDescribedby, ...(field && { ids: { label: field.ids.label }, invalid: field.invalid, disabled: field.disabled }), children: [label && !field && _jsx(Ark.Label, { ...part('label'), children: label }), _jsx("div", { ...part('items'), children: items.map((item) => (_jsxs(Ark.Item, { value: String(valueOf(item)), disabled: isObject(item) && !!key(item, disabledKey), ...part('item'), children: [_jsx(Ark.ItemControl, { ...part('item-control') }), iconOf(item) && _jsx("iconify-icon", { ...part('icon'), icon: iconOf(item), "aria-hidden": "true" }), _jsxs("span", { ...part('text'), children: [_jsx(Ark.ItemText, { ...part('item-text'), children: labelOf(item) }), descriptionOf(item) && _jsx("span", { ...part('description'), children: descriptionOf(item) })] }), _jsx(Ark.ItemHiddenInput, {})] }, String(valueOf(item))))) })] }));
26
+ }
27
+ export const RadioGroup = withParts(RadioGroupShortcut, {
28
+ Root: Ark.Root,
29
+ Label: Ark.Label,
30
+ Item: Ark.Item,
31
+ ItemControl: Ark.ItemControl,
32
+ ItemText: Ark.ItemText,
33
+ ItemHiddenInput: Ark.ItemHiddenInput,
34
+ Indicator: Ark.Indicator,
35
+ Context: Ark.Context,
36
+ Items: partOf('radio-group', 'items'),
37
+ });
@@ -0,0 +1,30 @@
1
+ /* Ark's root (the radiogroup) holds the label and the items; built by hand,
2
+ the items can sit straight in it. */
3
+ @layer ui {
4
+ [data-scope=radio-group][data-part=root] { display: block; color: var(--ui-text); font-family: var(--ui-font);
5
+ > [data-part=item] + [data-part=item] { margin-top: 0.5rem; } }
6
+ [data-scope=radio-group][data-part=label] { display: block; font-size: 14px; font-weight: 500; margin-bottom: 0.375rem; }
7
+ [data-scope=radio-group][data-part=items] { display: flex; flex-direction: column; gap: 0.5rem;
8
+ [data-orientation=horizontal] > & { flex-direction: row; flex-wrap: wrap; gap: 0.5rem 1rem; } }
9
+ [data-scope=radio-group][data-part=item] { display: flex; align-items: flex-start; gap: 0.5rem; font-size: 14px; cursor: pointer;
10
+ &[data-disabled] { opacity: 0.5; cursor: not-allowed; } }
11
+ [data-scope=radio-group][data-part=item-control] { display: grid; place-items: center; flex-shrink: 0; width: 1rem; height: 1rem;
12
+ margin-top: 0.125rem; box-sizing: border-box; background: var(--ui-surface); border: 1px solid var(--ui-border); border-radius: 9999px;
13
+ &[data-state=checked] { border-color: var(--ui-accent); border-width: 5px; }
14
+ &[data-focus-visible] { outline: 2px solid var(--ui-ring-soft); border-color: var(--ui-ring); }
15
+ &[data-invalid] { border-color: var(--ui-danger); } }
16
+ [data-scope=radio-group][data-part=text] { display: flex; flex-direction: column; gap: 0.125rem; }
17
+ [data-scope=radio-group][data-part=description] { color: var(--ui-muted); font-size: 12px; }
18
+ /* Cards: each option a bordered card, the chosen one outlined in the accent. */
19
+ [data-scope=radio-group][data-part=icon] { flex-shrink: 0; margin-top: 0.0625rem; color: var(--ui-muted); font-size: 18px; }
20
+ [data-scope=radio-group][data-variant=cards] {
21
+ & > [data-part=items] { display: grid; grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr)); gap: 0.5rem; }
22
+ & [data-part=item] { gap: 0.625rem; padding: 0.75rem; border: 1px solid var(--ui-border); border-radius: calc(var(--ui-radius) + 2px);
23
+ background: var(--ui-surface); transition: border-color 120ms, background 120ms;
24
+ &:hover { border-color: var(--ui-muted); }
25
+ &[data-state=checked] { border-color: var(--ui-accent); background: color-mix(in srgb, var(--ui-accent-soft) 45%, var(--ui-surface));
26
+ box-shadow: 0 0 0 1px var(--ui-accent); }
27
+ &[data-focus-visible] { outline: 2px solid var(--ui-ring-soft); }
28
+ &[data-state=checked] [data-part=icon] { color: var(--ui-accent); } }
29
+ & [data-part=item-text] { font-weight: 500; } }
30
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * A number whose digits roll to their new value when it changes, e.g. a live
3
+ * count on a dashboard. Formatted like FormatNumber; still while the system
4
+ * asks for reduced motion.
5
+ *
6
+ * <RollingNumber value={appointments.length} />
7
+ * <RollingNumber value={revenue} format={{ style: 'currency', currency: 'GBP', maximumFractionDigits: 0 }} />
8
+ *
9
+ * - `value`: the number
10
+ * - `format`: Intl.NumberFormat's options (grouping by default)
11
+ * - `duration`: how long a roll takes, in ms (600)
12
+ * - `locale`: the LocaleProvider's (or the browser's) by default
13
+ *
14
+ * Assistive tech reads the whole number, not the digits.
15
+ */
16
+ import type { HTMLAttributes } from 'react';
17
+ import { type Classes } from '../utils.js';
18
+ import '../theme.css';
19
+ import './rolling-number.css';
20
+ export type RollingNumberProps = Omit<HTMLAttributes<HTMLSpanElement>, 'children'> & {
21
+ value: number;
22
+ format?: Intl.NumberFormatOptions;
23
+ duration?: number;
24
+ locale?: string;
25
+ classes?: Classes<'root' | 'digit' | 'strip' | 'char'>;
26
+ };
27
+ export declare function RollingNumber({ value, format, duration, locale, className, classes, style, ...rest }: RollingNumberProps): import("react").JSX.Element;
@@ -0,0 +1,18 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { formatNumber } from '../format/format.js';
3
+ import { useLocale } from '../format/LocaleProvider.js';
4
+ import { cx, partsOf } from '../utils.js';
5
+ import '../theme.css';
6
+ import './rolling-number.css';
7
+ const digits = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
8
+ export function RollingNumber({ value, format = {}, duration = 600, locale, className, classes, style, ...rest }) {
9
+ const app = useLocale();
10
+ const part = partsOf('rolling-number', classes);
11
+ const text = formatNumber(value, { ...format, locale: locale ?? app });
12
+ // Keyed from the right, so the ones stay the ones as the number grows.
13
+ const chars = [...text].map((char, i, all) => ({ char, key: all.length - i }));
14
+ return (_jsx("span", { ...rest, ...part('root'), className: cx(className, classes?.root), role: "img", "aria-label": text, style: { ...style, '--duration': `${duration}ms` }, children: chars.map(({ char, key }) => /\d/.test(char)
15
+ // A column of 0–9, moved so the digit shows.
16
+ ? _jsxs("span", { ...part('digit'), "aria-hidden": "true", children: [_jsx("span", { ...part('strip'), style: { '--digit': Number(char) }, children: digits.map((d) => _jsx("span", { children: d }, d)) }), _jsx("span", { ...part('sizer'), children: "0" })] }, key)
17
+ : _jsx("span", { ...part('char'), "aria-hidden": "true", children: char }, key)) }));
18
+ }
@@ -0,0 +1,10 @@
1
+ @layer ui {
2
+ [data-scope=rolling-number][data-part=root] { display: inline-flex; align-items: baseline; font-variant-numeric: tabular-nums; white-space: nowrap; }
3
+ /* One digit: a window a line tall over a column of 0–9. */
4
+ [data-scope=rolling-number][data-part=digit] { position: relative; display: inline-block; height: 1lh; overflow: hidden; }
5
+ [data-scope=rolling-number][data-part=sizer] { visibility: hidden; }
6
+ [data-scope=rolling-number][data-part=strip] { position: absolute; left: 0; top: 0; display: flex; flex-direction: column;
7
+ translate: 0 calc(var(--digit) * -1lh); transition: translate var(--duration) cubic-bezier(0.2, 0.7, 0.2, 1);
8
+ & > span { height: 1lh; }
9
+ @media (prefers-reduced-motion: reduce) { transition: none; } }
10
+ }
@@ -0,0 +1,68 @@
1
+ /**
2
+ * A segmented control: a row of options, one picked, with a sliding indicator.
3
+ *
4
+ * <Segmented items={['Day', 'Week', 'Month']} value={view} onValueChange={setView} />
5
+ * <Segmented items={[{ value: 'grid', label: 'Grid', icon: 'lucide:grid-2x2' }]} iconOnly />
6
+ *
7
+ * - `items`: strings, or objects (see `labelKey`, `valueKey`, `disabledKey`; `icon`, `tooltip`)
8
+ * - `value`, `defaultValue`: the item's own value; `onValueChange`: called with it
9
+ * - `label`: a label above it (skipped inside a Field)
10
+ * - `iconOnly`: just the icons (each keeps its label for assistive tech)
11
+ * - `tooltips`: each item's label (or its own `tooltip`) in a tooltip on
12
+ * hover and keyboard focus; on by default with `iconOnly`
13
+ * - `size`: 'sm', 'md' or 'lg'
14
+ * - `renderItem`: an option's content, (item, { selected }) => node (a count
15
+ * beside the label, say); the icon still comes first
16
+ * - `name`: for plain form posts
17
+ *
18
+ * By hand, with Ark's SegmentGroup parts (and Group, the track):
19
+ *
20
+ * <Segmented.Root defaultValue="week" orientation="horizontal">
21
+ * <Segmented.Group>
22
+ * <Segmented.Indicator />
23
+ * {['day', 'week'].map((value) => (
24
+ * <Segmented.Item key={value} value={value}><Segmented.ItemText>{value}</Segmented.ItemText><Segmented.ItemHiddenInput /></Segmented.Item>
25
+ * ))}
26
+ * </Segmented.Group>
27
+ * </Segmented.Root>
28
+ */
29
+ import { type ReactNode } from 'react';
30
+ import { SegmentGroup as Ark, type SegmentGroupValueChangeDetails } from '@ark-ui/react/segment-group';
31
+ import 'iconify-icon';
32
+ import { type Classes } from '../utils.js';
33
+ import '../theme.css';
34
+ import './segment-group.css';
35
+ type Value<T, K extends string> = T extends string | number ? T : K extends keyof T ? T[K] : unknown;
36
+ export type SegmentedProps<T, K extends string = 'value'> = Omit<Ark.RootProps, 'value' | 'defaultValue' | 'onValueChange' | 'label'> & {
37
+ items: readonly T[];
38
+ value?: NoInfer<Value<T, K>> | null;
39
+ defaultValue?: NoInfer<Value<T, K>> | null;
40
+ onValueChange?: (value: NoInfer<Value<T, K>> | null, details: SegmentGroupValueChangeDetails) => void;
41
+ label?: ReactNode;
42
+ labelKey?: string;
43
+ valueKey?: K;
44
+ disabledKey?: string;
45
+ iconOnly?: boolean;
46
+ tooltips?: boolean | null;
47
+ size?: 'sm' | 'md' | 'lg';
48
+ renderItem?: (item: T, state: {
49
+ selected: boolean;
50
+ }) => ReactNode;
51
+ classes?: Classes<'root' | 'label' | 'group' | 'indicator' | 'item' | 'itemText' | 'itemIcon' | 'tooltipTarget'>;
52
+ };
53
+ declare function SegmentedShortcut<T, K extends string = 'value'>({ items, value, defaultValue, onValueChange, label, labelKey, valueKey, disabledKey, iconOnly, tooltips, size, renderItem, className, classes, ...rest }: SegmentedProps<T, K>): import("react").JSX.Element;
54
+ export declare const Segmented: typeof SegmentedShortcut & {
55
+ Root: import("react").ForwardRefExoticComponent<Ark.RootProps & import("react").RefAttributes<HTMLDivElement>>;
56
+ Label: import("react").ForwardRefExoticComponent<Ark.LabelProps & import("react").RefAttributes<HTMLSpanElement>>;
57
+ Indicator: import("react").ForwardRefExoticComponent<Ark.IndicatorProps & import("react").RefAttributes<HTMLDivElement>>;
58
+ Item: import("react").ForwardRefExoticComponent<Ark.ItemProps & import("react").RefAttributes<HTMLLabelElement>>;
59
+ ItemText: import("react").ForwardRefExoticComponent<Ark.ItemTextProps & import("react").RefAttributes<HTMLSpanElement>>;
60
+ ItemControl: import("react").ForwardRefExoticComponent<Ark.ItemControlProps & import("react").RefAttributes<HTMLDivElement>>;
61
+ ItemHiddenInput: import("react").ForwardRefExoticComponent<Ark.ItemHiddenInputProps & import("react").RefAttributes<HTMLInputElement>>;
62
+ Context: (props: Ark.ContextProps) => ReactNode;
63
+ Group: {
64
+ (props: import("react").DetailedHTMLProps<import("react").HTMLAttributes<HTMLDivElement>, HTMLDivElement>): import("react").ReactElement<any, string | import("react").JSXElementConstructor<any>>;
65
+ displayName: string;
66
+ };
67
+ };
68
+ export {};
@@ -0,0 +1,79 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /**
3
+ * A segmented control: a row of options, one picked, with a sliding indicator.
4
+ *
5
+ * <Segmented items={['Day', 'Week', 'Month']} value={view} onValueChange={setView} />
6
+ * <Segmented items={[{ value: 'grid', label: 'Grid', icon: 'lucide:grid-2x2' }]} iconOnly />
7
+ *
8
+ * - `items`: strings, or objects (see `labelKey`, `valueKey`, `disabledKey`; `icon`, `tooltip`)
9
+ * - `value`, `defaultValue`: the item's own value; `onValueChange`: called with it
10
+ * - `label`: a label above it (skipped inside a Field)
11
+ * - `iconOnly`: just the icons (each keeps its label for assistive tech)
12
+ * - `tooltips`: each item's label (or its own `tooltip`) in a tooltip on
13
+ * hover and keyboard focus; on by default with `iconOnly`
14
+ * - `size`: 'sm', 'md' or 'lg'
15
+ * - `renderItem`: an option's content, (item, { selected }) => node (a count
16
+ * beside the label, say); the icon still comes first
17
+ * - `name`: for plain form posts
18
+ *
19
+ * By hand, with Ark's SegmentGroup parts (and Group, the track):
20
+ *
21
+ * <Segmented.Root defaultValue="week" orientation="horizontal">
22
+ * <Segmented.Group>
23
+ * <Segmented.Indicator />
24
+ * {['day', 'week'].map((value) => (
25
+ * <Segmented.Item key={value} value={value}><Segmented.ItemText>{value}</Segmented.ItemText><Segmented.ItemHiddenInput /></Segmented.Item>
26
+ * ))}
27
+ * </Segmented.Group>
28
+ * </Segmented.Root>
29
+ */
30
+ import { useState } from 'react';
31
+ import { SegmentGroup as Ark } from '@ark-ui/react/segment-group';
32
+ import { useFieldContext } from '@ark-ui/react/field';
33
+ import 'iconify-icon';
34
+ import { Tooltip } from '../tooltip/Tooltip.js';
35
+ import { cx, partOf, partsOf, useControllable, withParts } from '../utils.js';
36
+ import '../theme.css';
37
+ import './segment-group.css';
38
+ function SegmentedShortcut({ items, value, defaultValue, onValueChange, label = null, labelKey = 'label', valueKey = 'value', disabledKey = 'disabled', iconOnly = false, tooltips = null, size = 'md', renderItem, className, classes, ...rest }) {
39
+ const field = useFieldContext();
40
+ const part = partsOf('segment-group', classes);
41
+ const [current, setCurrent] = useControllable(value, defaultValue ?? null, undefined);
42
+ const key = (item, k) => item[k];
43
+ const isObject = (item) => typeof item === 'object' && item !== null;
44
+ const labelOf = (item) => String(isObject(item) ? key(item, labelKey) : item);
45
+ const valueOf = (item) => (isObject(item) ? key(item, valueKey) : item);
46
+ const iconOf = (item) => (isObject(item) ? key(item, 'icon') : undefined);
47
+ const tipFor = (item) => (isObject(item) && key(item, 'tooltip')) || labelOf(item);
48
+ // Zag's values are strings; map them back to the items' own.
49
+ function change(details) {
50
+ const item = items.find((item) => String(valueOf(item)) === details.value);
51
+ const next = item === undefined ? null : valueOf(item);
52
+ setCurrent(next);
53
+ onValueChange?.(next, details);
54
+ }
55
+ const withTooltips = tooltips ?? iconOnly;
56
+ // The focusable element is the hidden radio, so keyboard focus opens its
57
+ // tooltip by hand (pointer focus doesn't).
58
+ const [tipOpen, setTipOpen] = useState(null);
59
+ const focus = (key) => (e) => {
60
+ if (withTooltips && e.target.matches(':focus-visible'))
61
+ setTipOpen(key);
62
+ };
63
+ return (_jsxs(Ark.Root, { ...rest, ...part('root'), className: cx(className, classes?.root), "data-size": size, orientation: "horizontal", value: current == null ? null : String(current), onValueChange: change, "aria-describedby": field?.ariaDescribedby, ...(field && { ids: { label: field.ids.label }, invalid: field.invalid, disabled: field.disabled }), children: [label && !field && _jsx(Ark.Label, { ...part('label'), children: label }), _jsxs("div", { ...part('group'), children: [_jsx(Ark.Indicator, { ...part('indicator') }), items.map((item) => {
64
+ const itemKey = String(valueOf(item));
65
+ return (_jsxs(Ark.Item, { value: itemKey, disabled: isObject(item) && !!key(item, disabledKey), ...part('item'), "data-icon-only": iconOnly || undefined, children: [_jsxs(Ark.ItemText, { ...part('item-text'), children: [iconOf(item) && _jsx("iconify-icon", { ...part('item-icon'), icon: iconOf(item), "aria-hidden": "true" }), iconOnly ? _jsx("span", { ...part('sr-only'), children: labelOf(item) })
66
+ : renderItem ? renderItem(item, { selected: String(current) === itemKey }) : labelOf(item)] }), withTooltips && (_jsx(Tooltip, { content: tipFor(item), open: tipOpen === itemKey, onOpenChange: (open) => setTipOpen((tip) => (open ? itemKey : tip === itemKey ? null : tip)), children: _jsx("span", { ...part('tooltip-target') }) })), _jsx(Ark.ItemHiddenInput, { onFocus: focus(itemKey), onBlur: () => setTipOpen(null) })] }, itemKey));
67
+ })] })] }));
68
+ }
69
+ export const Segmented = withParts(SegmentedShortcut, {
70
+ Root: Ark.Root,
71
+ Label: Ark.Label,
72
+ Indicator: Ark.Indicator,
73
+ Item: Ark.Item,
74
+ ItemText: Ark.ItemText,
75
+ ItemControl: Ark.ItemControl,
76
+ ItemHiddenInput: Ark.ItemHiddenInput,
77
+ Context: Ark.Context,
78
+ Group: partOf('segment-group', 'group'),
79
+ });
@@ -0,0 +1,25 @@
1
+ @layer ui {
2
+ [data-scope=segment-group][data-part=root] { display: inline-block; max-width: 100%; color: var(--ui-text); font-family: var(--ui-font);
3
+ --seg-h: var(--ui-control-height); --seg-px: 0.75rem; --seg-px-icon: 0.5rem; --seg-icon: 15px; --seg-fs: 14px;
4
+ &[data-size=sm] { --seg-h: var(--ui-control-height-sm); --seg-px: 0.625rem; --seg-px-icon: 0.375rem; --seg-icon: 14px; --seg-fs: 12px; }
5
+ &[data-size=lg] { --seg-h: var(--ui-control-height-lg); --seg-px: 1rem; --seg-px-icon: 0.625rem; --seg-icon: 17px; --seg-fs: 16px; } }
6
+ [data-scope=segment-group][data-part=label] { display: block; font-size: 14px; font-weight: 500; margin-bottom: 0.375rem; }
7
+ [data-scope=segment-group][data-part=group] { position: relative; display: inline-flex; max-width: 100%; gap: 0.25rem; padding: 0.25rem;
8
+ box-sizing: border-box; background: var(--ui-hover); border-radius: var(--ui-radius);
9
+ &[data-disabled] { opacity: 0.5; }
10
+ &[data-invalid], &[aria-invalid=true] { outline: 1px solid var(--ui-danger); } }
11
+ [data-scope=segment-group][data-part=indicator] { position: absolute; left: var(--left); top: var(--top); width: var(--width); height: var(--height);
12
+ background: var(--ui-surface); border-radius: calc(var(--ui-radius) - 2px); box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12);
13
+ transition-property: var(--transition-property); transition-duration: 150ms; }
14
+ [data-scope=segment-group][data-part=item] { position: relative; z-index: 1; display: flex; align-items: center; justify-content: center;
15
+ flex: 1 1 auto; padding: 0 var(--seg-px); height: calc(var(--seg-h) - 8px); border-radius: calc(var(--ui-radius) - 2px);
16
+ font-size: var(--seg-fs); font-weight: 500; color: var(--ui-muted); white-space: nowrap; cursor: pointer;
17
+ &[data-state=checked] { color: var(--ui-text); }
18
+ &[data-focus-visible] { outline: 2px solid var(--ui-ring-soft); }
19
+ &[data-disabled] { opacity: 0.4; cursor: not-allowed; }
20
+ &[data-icon-only] { padding: 0 var(--seg-px-icon); } }
21
+ [data-scope=segment-group][data-part=tooltip-target] { position: absolute; inset: 0; }
22
+ [data-scope=segment-group][data-part=item-text] { display: inline-flex; align-items: center; gap: 0.375rem; }
23
+ [data-scope=segment-group][data-part=item-icon] { display: block; font-size: var(--seg-icon); }
24
+ [data-scope=segment-group][data-part=sr-only] { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
25
+ }
@@ -0,0 +1,5 @@
1
+ import 'iconify-icon';
2
+ import type { InnerProps } from './Select.js';
3
+ import '../theme.css';
4
+ import './select.css';
5
+ export declare function ListSelect<T>({ label, items, placeholder: placeholderProp, labelKey, valueKey, disabledKey, multiple, tags, variant, hideSelected, deselectable, closeOnSelect, clearable, emptyText: emptyTextProp, empty, name, size, placement, disabled, value, defaultValue, onValueChange, renderItem, renderValue, start, searchable: _searchable, load: _load, debounce: _debounce, loadingText: _loadingText, onCreate: _onCreate, renderCreate: _renderCreate, className, classes, ...rest }: InnerProps<T>): import("react").JSX.Element;