@yarcl/react 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (223) hide show
  1. package/README.md +14 -2
  2. package/{src/apply.ts → dist/apply.d.ts} +4 -23
  3. package/dist/apply.js +37 -0
  4. package/dist/classes.d.ts +13 -0
  5. package/dist/classes.js +22 -0
  6. package/dist/cli.d.ts +2 -0
  7. package/dist/cli.js +58 -0
  8. package/dist/color.js +49 -32
  9. package/dist/components/Accordion.d.ts +96 -0
  10. package/dist/components/Accordion.js +148 -0
  11. package/dist/components/Alert.d.ts +60 -0
  12. package/dist/components/Alert.js +61 -0
  13. package/dist/components/Avatar.d.ts +100 -0
  14. package/dist/components/Avatar.js +89 -0
  15. package/dist/components/Badge.d.ts +44 -0
  16. package/dist/components/Badge.js +43 -0
  17. package/dist/components/Breadcrumb.d.ts +77 -0
  18. package/dist/components/Breadcrumb.js +126 -0
  19. package/dist/components/Button.d.ts +18 -0
  20. package/dist/components/Button.js +33 -0
  21. package/dist/components/ButtonGroup.d.ts +29 -0
  22. package/dist/components/ButtonGroup.js +37 -0
  23. package/dist/components/Card.d.ts +36 -0
  24. package/dist/components/Card.js +26 -0
  25. package/dist/components/Checkbox.d.ts +28 -0
  26. package/dist/components/Checkbox.js +38 -0
  27. package/dist/components/Combobox.d.ts +75 -0
  28. package/dist/components/Combobox.js +362 -0
  29. package/dist/components/CommandPalette.d.ts +92 -0
  30. package/dist/components/CommandPalette.js +293 -0
  31. package/dist/components/DatePicker.d.ts +157 -0
  32. package/dist/components/DatePicker.js +230 -0
  33. package/dist/components/Dialog.d.ts +25 -0
  34. package/dist/components/Dialog.js +29 -0
  35. package/dist/components/Divider.d.ts +23 -0
  36. package/dist/components/Divider.js +25 -0
  37. package/dist/components/Drawer.d.ts +21 -0
  38. package/dist/components/Drawer.js +25 -0
  39. package/dist/components/EmptyState.d.ts +51 -0
  40. package/dist/components/EmptyState.js +47 -0
  41. package/dist/components/Field.d.ts +27 -0
  42. package/dist/components/Field.js +59 -0
  43. package/dist/components/Heading.d.ts +26 -0
  44. package/dist/components/Heading.js +25 -0
  45. package/dist/components/HoverCard.d.ts +47 -0
  46. package/dist/components/HoverCard.js +53 -0
  47. package/dist/components/IconButton.d.ts +19 -0
  48. package/dist/components/IconButton.js +32 -0
  49. package/dist/components/Inline.d.ts +21 -0
  50. package/dist/components/Inline.js +24 -0
  51. package/dist/components/Input.d.ts +19 -0
  52. package/dist/components/Input.js +25 -0
  53. package/dist/components/Label.d.ts +46 -0
  54. package/dist/components/Label.js +33 -0
  55. package/dist/components/Link.d.ts +27 -0
  56. package/dist/components/Link.js +26 -0
  57. package/dist/components/Menu.d.ts +73 -0
  58. package/dist/components/Menu.js +143 -0
  59. package/dist/components/Modal.d.ts +45 -0
  60. package/dist/components/Modal.js +110 -0
  61. package/dist/components/NumberInput.d.ts +49 -0
  62. package/dist/components/NumberInput.js +130 -0
  63. package/dist/components/Pagination.d.ts +86 -0
  64. package/dist/components/Pagination.js +119 -0
  65. package/dist/components/Popover.d.ts +72 -0
  66. package/dist/components/Popover.js +87 -0
  67. package/dist/components/Progress.d.ts +60 -0
  68. package/dist/components/Progress.js +59 -0
  69. package/dist/components/Radio.d.ts +32 -0
  70. package/dist/components/Radio.js +47 -0
  71. package/dist/components/RadioGroup.d.ts +57 -0
  72. package/dist/components/RadioGroup.js +68 -0
  73. package/dist/components/Select.d.ts +47 -0
  74. package/dist/components/Select.js +138 -0
  75. package/dist/components/Skeleton.d.ts +46 -0
  76. package/dist/components/Skeleton.js +40 -0
  77. package/dist/components/Slider.d.ts +126 -0
  78. package/dist/components/Slider.js +166 -0
  79. package/dist/components/Spinner.d.ts +23 -0
  80. package/dist/components/Spinner.js +23 -0
  81. package/dist/components/Stack.d.ts +35 -0
  82. package/dist/components/Stack.js +24 -0
  83. package/dist/components/Switch.d.ts +27 -0
  84. package/dist/components/Switch.js +33 -0
  85. package/dist/components/Table.d.ts +71 -0
  86. package/dist/components/Table.js +61 -0
  87. package/dist/components/Tabs.d.ts +66 -0
  88. package/dist/components/Tabs.js +109 -0
  89. package/dist/components/Text.d.ts +32 -0
  90. package/dist/components/Text.js +28 -0
  91. package/dist/components/Textarea.d.ts +15 -0
  92. package/dist/components/Textarea.js +24 -0
  93. package/dist/components/Toast.d.ts +90 -0
  94. package/dist/components/Toast.js +156 -0
  95. package/dist/components/ToggleGroup.d.ts +79 -0
  96. package/dist/components/ToggleGroup.js +101 -0
  97. package/dist/components/Tooltip.d.ts +46 -0
  98. package/dist/components/Tooltip.js +62 -0
  99. package/dist/components/VisuallyHidden.d.ts +18 -0
  100. package/dist/components/VisuallyHidden.js +22 -0
  101. package/dist/contrast.d.ts +32 -0
  102. package/dist/css.d.ts +2 -2
  103. package/dist/css.js +193 -157
  104. package/dist/define.d.ts +40 -15
  105. package/dist/define.js +30 -27
  106. package/dist/demo.d.ts +2 -0
  107. package/dist/demo.js +2 -0
  108. package/dist/esbuild.cjs +5 -0
  109. package/dist/esbuild.d.ts +4 -0
  110. package/dist/esbuild.js +6 -0
  111. package/dist/field-context.d.ts +16 -0
  112. package/dist/field-context.js +17 -0
  113. package/dist/floating.d.ts +12 -0
  114. package/dist/floating.js +52 -0
  115. package/dist/hooks.d.ts +1 -0
  116. package/dist/hooks.js +12 -0
  117. package/{src/index.ts → dist/index.d.ts} +11 -33
  118. package/dist/index.js +50 -0
  119. package/dist/init.d.ts +18 -0
  120. package/dist/init.js +224 -0
  121. package/dist/plugin.d.ts +10 -26
  122. package/dist/plugin.js +152 -78
  123. package/dist/reference/DemoYarcl.d.ts +12 -0
  124. package/dist/reference/DemoYarcl.js +312 -0
  125. package/dist/reference/DesignReference.d.ts +24 -0
  126. package/dist/reference/DesignReference.js +403 -0
  127. package/dist/reference/index.js +2 -0
  128. package/dist/rollup.cjs +5 -0
  129. package/dist/rollup.d.ts +4 -0
  130. package/dist/rollup.js +6 -0
  131. package/dist/rspack.cjs +5 -0
  132. package/dist/rspack.d.ts +4 -0
  133. package/dist/rspack.js +6 -0
  134. package/dist/runtime.d.ts +13 -0
  135. package/dist/runtime.js +30 -0
  136. package/dist/setup.d.ts +6 -0
  137. package/dist/setup.js +33 -0
  138. package/{src → dist}/styles.css +224 -106
  139. package/dist/themes/bloom.d.ts +295 -0
  140. package/dist/themes/bloom.js +202 -0
  141. package/dist/themes/brutalist.d.ts +277 -0
  142. package/dist/themes/brutalist.js +199 -0
  143. package/dist/themes/compact.d.ts +274 -0
  144. package/dist/themes/compact.js +200 -0
  145. package/dist/themes/contract.d.ts +23 -0
  146. package/dist/themes/editorial.d.ts +277 -0
  147. package/dist/themes/editorial.js +183 -0
  148. package/dist/themes/index.d.ts +1425 -0
  149. package/dist/themes/index.js +45 -0
  150. package/{src/types.ts → dist/types.d.ts} +40 -37
  151. package/dist/vite.cjs +5 -0
  152. package/dist/vite.d.ts +4 -0
  153. package/dist/vite.js +6 -0
  154. package/dist/webpack.cjs +5 -0
  155. package/dist/webpack.d.ts +4 -0
  156. package/dist/webpack.js +6 -0
  157. package/dist/yarcl.config.d.ts +276 -0
  158. package/dist/yarcl.config.js +273 -0
  159. package/package.json +69 -17
  160. package/src/classes.ts +0 -23
  161. package/src/color.ts +0 -48
  162. package/src/components/Accordion.tsx +0 -274
  163. package/src/components/Alert.tsx +0 -85
  164. package/src/components/Badge.tsx +0 -79
  165. package/src/components/Breadcrumb.tsx +0 -239
  166. package/src/components/Button.tsx +0 -58
  167. package/src/components/ButtonGroup.tsx +0 -61
  168. package/src/components/Card.tsx +0 -50
  169. package/src/components/Checkbox.tsx +0 -49
  170. package/src/components/Combobox.tsx +0 -522
  171. package/src/components/CommandPalette.tsx +0 -452
  172. package/src/components/DatePicker.tsx +0 -432
  173. package/src/components/Dialog.tsx +0 -39
  174. package/src/components/Divider.tsx +0 -34
  175. package/src/components/Drawer.tsx +0 -31
  176. package/src/components/Field.tsx +0 -61
  177. package/src/components/Heading.tsx +0 -40
  178. package/src/components/HoverCard.tsx +0 -108
  179. package/src/components/IconButton.tsx +0 -59
  180. package/src/components/Inline.tsx +0 -42
  181. package/src/components/Input.tsx +0 -28
  182. package/src/components/Label.tsx +0 -58
  183. package/src/components/Link.tsx +0 -41
  184. package/src/components/Menu.tsx +0 -207
  185. package/src/components/Modal.tsx +0 -164
  186. package/src/components/NumberInput.tsx +0 -208
  187. package/src/components/Pagination.tsx +0 -227
  188. package/src/components/Popover.tsx +0 -140
  189. package/src/components/Progress.tsx +0 -122
  190. package/src/components/Radio.tsx +0 -59
  191. package/src/components/RadioGroup.tsx +0 -114
  192. package/src/components/Select.tsx +0 -197
  193. package/src/components/Skeleton.tsx +0 -95
  194. package/src/components/Slider.tsx +0 -315
  195. package/src/components/Spinner.tsx +0 -38
  196. package/src/components/Stack.tsx +0 -57
  197. package/src/components/Switch.tsx +0 -42
  198. package/src/components/Table.tsx +0 -99
  199. package/src/components/Tabs.tsx +0 -159
  200. package/src/components/Text.tsx +0 -67
  201. package/src/components/Textarea.tsx +0 -26
  202. package/src/components/Toast.tsx +0 -190
  203. package/src/components/ToggleGroup.tsx +0 -227
  204. package/src/components/Tooltip.tsx +0 -78
  205. package/src/contrast.ts +0 -82
  206. package/src/css.ts +0 -228
  207. package/src/define.check.ts +0 -259
  208. package/src/define.ts +0 -379
  209. package/src/field-context.ts +0 -31
  210. package/src/floating.tsx +0 -61
  211. package/src/hooks.ts +0 -19
  212. package/src/plugin.ts +0 -94
  213. package/src/reference/DesignReference.tsx +0 -374
  214. package/src/runtime.ts +0 -38
  215. package/src/themes/bloom.ts +0 -72
  216. package/src/themes/brutalist.ts +0 -63
  217. package/src/themes/compact.ts +0 -63
  218. package/src/themes/contract.ts +0 -24
  219. package/src/themes/editorial.ts +0 -55
  220. package/src/themes/index.ts +0 -47
  221. package/src/yarcl.config.ts +0 -104
  222. /package/{src/reference/index.ts → dist/reference/index.d.ts} +0 -0
  223. /package/{src → dist}/reference/reference.css +0 -0
@@ -0,0 +1,130 @@
1
+ import { useDefaults } from "../runtime.js";
2
+ import { colorClass, cx, radiusClass, sizeClass } from "../classes.js";
3
+ import { useControllable } from "../hooks.js";
4
+ import { useFieldProps } from "../field-context.js";
5
+ import { ChevronIcon } from "../floating.js";
6
+ import { useId, useState } from "react";
7
+ import { jsx, jsxs } from "react/jsx-runtime";
8
+ //#region src/components/NumberInput.tsx
9
+ function decimals(n) {
10
+ const text = String(n);
11
+ const exp = text.match(/e-(\d+)$/);
12
+ if (exp) return Number(exp[1]);
13
+ return text.split(".")[1]?.length ?? 0;
14
+ }
15
+ function parse(text) {
16
+ const trimmed = text.trim();
17
+ if (trimmed === "") return null;
18
+ const n = Number(trimmed);
19
+ return Number.isFinite(n) ? n : void 0;
20
+ }
21
+ /**
22
+ * A numeric input with increment and decrement buttons, exposed as a `spinbutton`.
23
+ * Arrow keys step by `step`, `PageUp` and `PageDown` by ten steps, `Home` and `End` jump to `min` and `max`.
24
+ * Shares the base size scale with {@link Input}; component size overrides can adjust either one. Works inside a {@link Field}.
25
+ *
26
+ * @example
27
+ * ```tsx
28
+ * <Field label="Guests">
29
+ * <NumberInput min={1} max={10} defaultValue={2} onValueChange={setGuests} />
30
+ * </Field>
31
+ * ```
32
+ */
33
+ function NumberInput(props) {
34
+ const own = useDefaults("NumberInput");
35
+ const fallbackId = useId();
36
+ const { value: valueProp, defaultValue = null, onValueChange, min, max, step = 1, incrementLabel = "Increase", decrementLabel = "Decrease", size, radius, color, className, style, id = fallbackId, disabled, readOnly, onBlur, onKeyDown, ...rest } = useFieldProps(props);
37
+ const [value, setValue] = useControllable(valueProp, defaultValue, onValueChange);
38
+ const [draft, setDraft] = useState(null);
39
+ const clamp = (n) => Math.min(max ?? Infinity, Math.max(min ?? -Infinity, n));
40
+ const locked = disabled || readOnly;
41
+ function update(next) {
42
+ setDraft(null);
43
+ if (next !== value) setValue(next);
44
+ }
45
+ function current() {
46
+ if (draft === null) return value;
47
+ const parsed = parse(draft);
48
+ return parsed === void 0 ? value : parsed === null ? null : clamp(parsed);
49
+ }
50
+ function stepBy(amount) {
51
+ if (locked) return;
52
+ const base = current();
53
+ if (base === null) {
54
+ update(clamp(amount > 0 ? min ?? 0 : max ?? 0));
55
+ return;
56
+ }
57
+ const precision = Math.max(decimals(base), decimals(step));
58
+ update(clamp(Number((base + amount).toFixed(precision))));
59
+ }
60
+ function handleKeyDown(event) {
61
+ onKeyDown?.(event);
62
+ if (event.defaultPrevented) return;
63
+ const action = {
64
+ ArrowUp: () => stepBy(step),
65
+ ArrowDown: () => stepBy(-step),
66
+ PageUp: () => stepBy(step * 10),
67
+ PageDown: () => stepBy(-step * 10),
68
+ Home: min === void 0 || locked ? void 0 : () => update(min),
69
+ End: max === void 0 || locked ? void 0 : () => update(max),
70
+ Enter: draft === null ? void 0 : () => update(current())
71
+ }[event.key];
72
+ if (!action) return;
73
+ if (event.key !== "Enter") event.preventDefault();
74
+ action();
75
+ }
76
+ function handleBlur(event) {
77
+ onBlur?.(event);
78
+ if (draft !== null) update(current());
79
+ }
80
+ const shown = current();
81
+ const canIncrement = !locked && (shown === null || max === void 0 || shown < max);
82
+ const canDecrement = !locked && (shown === null || min === void 0 || shown > min);
83
+ return /* @__PURE__ */ jsxs("div", {
84
+ className: cx("yarcl-number-input", sizeClass(size ?? own.size, "NumberInput"), radiusClass(radius ?? own.radius, size ?? own.size), colorClass(color ?? own.color), className),
85
+ style,
86
+ children: [/* @__PURE__ */ jsx("input", {
87
+ ...rest,
88
+ id,
89
+ type: "text",
90
+ inputMode: "decimal",
91
+ autoComplete: "off",
92
+ role: "spinbutton",
93
+ "aria-valuenow": value ?? void 0,
94
+ "aria-valuemin": min,
95
+ "aria-valuemax": max,
96
+ className: "yarcl-input yarcl-number-input-field",
97
+ value: draft ?? (value === null ? "" : String(value)),
98
+ disabled,
99
+ readOnly,
100
+ onChange: (event) => setDraft(event.target.value),
101
+ onKeyDown: handleKeyDown,
102
+ onBlur: handleBlur
103
+ }), /* @__PURE__ */ jsxs("div", {
104
+ className: "yarcl-number-input-steppers",
105
+ children: [/* @__PURE__ */ jsx("button", {
106
+ type: "button",
107
+ tabIndex: -1,
108
+ className: "yarcl-number-input-stepper yarcl-number-input-increment",
109
+ "aria-label": incrementLabel,
110
+ "aria-controls": id,
111
+ disabled: !canIncrement,
112
+ onMouseDown: (event) => event.preventDefault(),
113
+ onClick: () => stepBy(step),
114
+ children: /* @__PURE__ */ jsx(ChevronIcon, {})
115
+ }), /* @__PURE__ */ jsx("button", {
116
+ type: "button",
117
+ tabIndex: -1,
118
+ className: "yarcl-number-input-stepper yarcl-number-input-decrement",
119
+ "aria-label": decrementLabel,
120
+ "aria-controls": id,
121
+ disabled: !canDecrement,
122
+ onMouseDown: (event) => event.preventDefault(),
123
+ onClick: () => stepBy(-step),
124
+ children: /* @__PURE__ */ jsx(ChevronIcon, {})
125
+ })]
126
+ })]
127
+ });
128
+ }
129
+ //#endregion
130
+ export { NumberInput };
@@ -0,0 +1,86 @@
1
+ import type { ComponentProps } from 'react';
2
+ import type { Color, ComponentSize, Radius, Variant } from '../types';
3
+ /** Props for {@link Pagination}. */
4
+ export interface PaginationProps extends Omit<ComponentProps<'nav'>, 'color' | 'onChange'> {
5
+ /**
6
+ * Total number of pages.
7
+ * @example
8
+ * ```tsx
9
+ * <Pagination count={Math.ceil(total / perPage)} />
10
+ * ```
11
+ */
12
+ count: number;
13
+ /** Controlled current page, starting at 1. */
14
+ page?: number;
15
+ /**
16
+ * Initial page when uncontrolled.
17
+ * @default 1
18
+ */
19
+ defaultPage?: number;
20
+ /** Called with the new page when the user picks one. */
21
+ onPageChange?: (page: number) => void;
22
+ /**
23
+ * Pages shown on each side of the current page.
24
+ * @default 1
25
+ */
26
+ siblings?: number;
27
+ /**
28
+ * Pages always shown at the start and end.
29
+ * @default 1
30
+ */
31
+ boundaries?: number;
32
+ /** Size of every button, from the `sizes` config. */
33
+ size?: ComponentSize<'Pagination'>;
34
+ /** Color of every button, from the `colors` config. */
35
+ color?: Color;
36
+ /** Radius of every button, from the `radii` config, or `'size'` to match the button size. */
37
+ radius?: Radius | 'size';
38
+ /**
39
+ * Variant of the other pages and the previous and next buttons, from the `variants` config.
40
+ * @default config.defaults.softVariant
41
+ */
42
+ variant?: Variant;
43
+ /**
44
+ * Variant of the current page, from the `variants` config.
45
+ * @default config.defaults.variant
46
+ */
47
+ selectedVariant?: Variant;
48
+ /**
49
+ * Joins the buttons into one control with shared borders.
50
+ * @default false
51
+ */
52
+ attached?: boolean;
53
+ /** Disables every button. */
54
+ disabled?: boolean;
55
+ /**
56
+ * Accessible name of the navigation landmark.
57
+ * @default 'Pagination'
58
+ */
59
+ 'aria-label'?: string;
60
+ /**
61
+ * Accessible name of the previous button.
62
+ * @default 'Previous page'
63
+ */
64
+ previousLabel?: string;
65
+ /**
66
+ * Accessible name of the next button.
67
+ * @default 'Next page'
68
+ */
69
+ nextLabel?: string;
70
+ /**
71
+ * Accessible name of each page button.
72
+ * @default (page) => `Page ${page}`
73
+ */
74
+ pageLabel?: (page: number) => string;
75
+ }
76
+ /**
77
+ * Navigation between pages of results: previous and next buttons, the pages around the current one,
78
+ * and the first and last pages with an ellipsis for the gaps. Renders a `<nav>` landmark; the current
79
+ * page has `aria-current="page"`. Arrow keys, <kbd>Home</kbd> and <kbd>End</kbd> move focus between buttons.
80
+ *
81
+ * @example
82
+ * ```tsx
83
+ * <Pagination count={20} page={page} onPageChange={setPage} aria-label="Search results" />
84
+ * ```
85
+ */
86
+ export declare function Pagination({ count, page, defaultPage, onPageChange, siblings, boundaries, size, color, radius, variant, selectedVariant, attached, disabled, previousLabel, nextLabel, pageLabel, 'aria-label': ariaLabel, className, onKeyDown, ...props }: PaginationProps): import("react").JSX.Element;
@@ -0,0 +1,119 @@
1
+ import { useConfig, useDefaults } from "../runtime.js";
2
+ import { colorClass, cx, radiusClass, sizeClass, variantClass } from "../classes.js";
3
+ import { Button } from "./Button.js";
4
+ import { useControllable } from "../hooks.js";
5
+ import { IconButton } from "./IconButton.js";
6
+ import { jsx, jsxs } from "react/jsx-runtime";
7
+ //#region src/components/Pagination.tsx
8
+ var range = (start, end) => Array.from({ length: Math.max(0, end - start + 1) }, (_, i) => start + i);
9
+ function pageItems(page, count, siblings, boundaries) {
10
+ const startPages = range(1, Math.min(boundaries, count));
11
+ const endPages = range(Math.max(count - boundaries + 1, boundaries + 1), count);
12
+ const siblingsStart = Math.max(Math.min(page - siblings, count - boundaries - siblings * 2 - 1), boundaries + 2);
13
+ const siblingsEnd = Math.min(Math.max(page + siblings, boundaries + siblings * 2 + 2), count - boundaries - 1);
14
+ const items = [...startPages];
15
+ if (siblingsStart > boundaries + 2) items.push("start-ellipsis");
16
+ else if (boundaries + 1 < count - boundaries) items.push(boundaries + 1);
17
+ items.push(...range(siblingsStart, siblingsEnd));
18
+ if (siblingsEnd < count - boundaries - 1) items.push("end-ellipsis");
19
+ else if (count - boundaries > boundaries) items.push(count - boundaries);
20
+ items.push(...endPages);
21
+ return items.filter((item, i) => typeof item !== "number" || item >= 1 && item <= count && items.indexOf(item) === i);
22
+ }
23
+ var Chevron = ({ d }) => /* @__PURE__ */ jsx("svg", {
24
+ viewBox: "0 0 24 24",
25
+ fill: "none",
26
+ stroke: "currentColor",
27
+ strokeWidth: "2",
28
+ strokeLinecap: "round",
29
+ strokeLinejoin: "round",
30
+ "aria-hidden": "true",
31
+ children: /* @__PURE__ */ jsx("path", { d })
32
+ });
33
+ /**
34
+ * Navigation between pages of results: previous and next buttons, the pages around the current one,
35
+ * and the first and last pages with an ellipsis for the gaps. Renders a `<nav>` landmark; the current
36
+ * page has `aria-current="page"`. Arrow keys, <kbd>Home</kbd> and <kbd>End</kbd> move focus between buttons.
37
+ *
38
+ * @example
39
+ * ```tsx
40
+ * <Pagination count={20} page={page} onPageChange={setPage} aria-label="Search results" />
41
+ * ```
42
+ */
43
+ function Pagination({ count, page, defaultPage = 1, onPageChange, siblings = 1, boundaries = 1, size, color, radius, variant, selectedVariant, attached = false, disabled, previousLabel = "Previous page", nextLabel = "Next page", pageLabel = (n) => `Page ${n}`, "aria-label": ariaLabel = "Pagination", className, onKeyDown, ...props }) {
44
+ const config = useConfig();
45
+ const own = useDefaults("Pagination");
46
+ const resolvedSize = size ?? own.size ?? config.defaults.size;
47
+ const resolvedRadius = radius ?? own.radius ?? config.defaults.radius;
48
+ const resolvedColor = color ?? own.color ?? config.defaults.color;
49
+ const resolvedVariant = variant ?? own.variant ?? config.defaults.softVariant;
50
+ const resolvedSelected = selectedVariant ?? own.selectedVariant ?? config.defaults.variant;
51
+ const total = Math.max(0, Math.floor(count));
52
+ const [current, setCurrent] = useControllable(page, defaultPage, onPageChange);
53
+ const active = Math.min(Math.max(1, current), Math.max(1, total));
54
+ const items = pageItems(active, total, Math.max(0, siblings), Math.max(0, boundaries));
55
+ const go = (next) => {
56
+ if (disabled || next === active || next < 1 || next > total) return;
57
+ setCurrent(next);
58
+ };
59
+ function handleKeyDown(event) {
60
+ onKeyDown?.(event);
61
+ const buttons = [...event.currentTarget.querySelectorAll("button:not(:disabled)")];
62
+ const index = buttons.indexOf(document.activeElement);
63
+ if (index === -1) return;
64
+ const next = {
65
+ ArrowRight: Math.min(index + 1, buttons.length - 1),
66
+ ArrowLeft: Math.max(index - 1, 0),
67
+ Home: 0,
68
+ End: buttons.length - 1
69
+ }[event.key];
70
+ if (next === void 0) return;
71
+ event.preventDefault();
72
+ buttons[next].focus();
73
+ }
74
+ const shared = {
75
+ size: resolvedSize,
76
+ radius: resolvedRadius,
77
+ color: resolvedColor,
78
+ disabled
79
+ };
80
+ const edge = (label, target, d) => {
81
+ const unavailable = target < 1 || target > total;
82
+ return /* @__PURE__ */ jsx(IconButton, {
83
+ ...shared,
84
+ variant: resolvedVariant,
85
+ "aria-label": label,
86
+ "aria-disabled": unavailable || void 0,
87
+ onClick: () => go(target),
88
+ children: /* @__PURE__ */ jsx(Chevron, { d })
89
+ });
90
+ };
91
+ return /* @__PURE__ */ jsx("nav", {
92
+ "aria-label": ariaLabel,
93
+ className: cx("yarcl-pagination", sizeClass(resolvedSize, "Pagination"), className),
94
+ onKeyDown: handleKeyDown,
95
+ ...props,
96
+ children: /* @__PURE__ */ jsxs("div", {
97
+ className: cx("yarcl-button-group yarcl-button-group-horizontal", attached && "yarcl-button-group-attached"),
98
+ children: [
99
+ edge(previousLabel, active - 1, "m15 18-6-6 6-6"),
100
+ items.map((item) => typeof item === "number" ? /* @__PURE__ */ jsx(Button, {
101
+ ...shared,
102
+ variant: item === active ? resolvedSelected : resolvedVariant,
103
+ className: "yarcl-pagination-page",
104
+ "aria-label": pageLabel(item),
105
+ "aria-current": item === active ? "page" : void 0,
106
+ onClick: () => go(item),
107
+ children: item
108
+ }, item) : /* @__PURE__ */ jsx("span", {
109
+ "aria-hidden": "true",
110
+ className: cx("yarcl-button yarcl-pagination-ellipsis", sizeClass(resolvedSize, "Pagination"), radiusClass(resolvedRadius, resolvedSize), colorClass(resolvedColor), variantClass(resolvedVariant)),
111
+ children: "…"
112
+ }, item)),
113
+ edge(nextLabel, active + 1, "m9 18 6-6-6-6")
114
+ ]
115
+ })
116
+ });
117
+ }
118
+ //#endregion
119
+ export { Pagination };
@@ -0,0 +1,72 @@
1
+ import { type Placement } from '@floating-ui/react';
2
+ import { type ComponentProps, type ReactElement, type ReactNode, type RefObject } from 'react';
3
+ import type { Radius, Spacing } from '../types';
4
+ /** Props for {@link Popover}. */
5
+ export interface PopoverProps {
6
+ /** `Popover.Trigger` and `Popover.Content`. */
7
+ children?: ReactNode;
8
+ /** Controlled open state. */
9
+ open?: boolean;
10
+ /**
11
+ * Initial open state when uncontrolled.
12
+ * @default false
13
+ */
14
+ defaultOpen?: boolean;
15
+ /** Called when the popover opens or closes. */
16
+ onOpenChange?: (open: boolean) => void;
17
+ /**
18
+ * Preferred side. Flips when there isn't room.
19
+ * @default 'bottom'
20
+ */
21
+ placement?: Placement;
22
+ /**
23
+ * Traps focus inside the content while open.
24
+ * @default false
25
+ */
26
+ modal?: boolean;
27
+ }
28
+ declare function PopoverRoot(props: PopoverProps): import("react").JSX.Element;
29
+ /** Props for `Popover.Trigger`. */
30
+ export interface PopoverTriggerProps {
31
+ /** A single element, usually a {@link Button}. It receives the click handler and ARIA attributes. */
32
+ children: ReactElement;
33
+ }
34
+ declare function PopoverTrigger({ children }: PopoverTriggerProps): ReactElement<unknown, string | import("react").JSXElementConstructor<any>>;
35
+ /** Props for `Popover.Content`. */
36
+ export interface PopoverContentProps extends ComponentProps<'div'> {
37
+ /**
38
+ * Inner padding, from the `spacing` config.
39
+ * @default config.defaults.padding
40
+ */
41
+ padding?: Spacing;
42
+ /**
43
+ * Corner radius, from the `radii` config.
44
+ * @default config.defaults.radius
45
+ */
46
+ radius?: Radius;
47
+ /**
48
+ * Element focused when the content opens: an index into its tabbable elements, or a ref.
49
+ * @default 0
50
+ */
51
+ initialFocus?: number | RefObject<HTMLElement | null>;
52
+ }
53
+ declare function PopoverContent({ padding, radius, initialFocus, className, style, ...props }: PopoverContentProps): import("react").JSX.Element | null;
54
+ /**
55
+ * A floating panel anchored to a trigger, opened by click. Closes on Esc or outside click.
56
+ * The base for custom floating UI; use {@link Menu}, {@link Select} or {@link Combobox} for lists.
57
+ *
58
+ * @example
59
+ * ```tsx
60
+ * <Popover>
61
+ * <Popover.Trigger><Button variant="outline">Filters</Button></Popover.Trigger>
62
+ * <Popover.Content>
63
+ * <Stack><Checkbox>Archived</Checkbox></Stack>
64
+ * </Popover.Content>
65
+ * </Popover>
66
+ * ```
67
+ */
68
+ export declare const Popover: typeof PopoverRoot & {
69
+ Trigger: typeof PopoverTrigger;
70
+ Content: typeof PopoverContent;
71
+ };
72
+ export {};
@@ -0,0 +1,87 @@
1
+ import { useDefaults } from "../runtime.js";
2
+ import { cx, paddingClass, radiusClass } from "../classes.js";
3
+ import { useControllable } from "../hooks.js";
4
+ import { floatingMiddleware, useTrigger } from "../floating.js";
5
+ import { createContext, useContext } from "react";
6
+ import { jsx } from "react/jsx-runtime";
7
+ import { FloatingFocusManager, FloatingPortal, autoUpdate, useClick, useDismiss, useFloating, useInteractions, useRole } from "@floating-ui/react";
8
+ //#region src/components/Popover.tsx
9
+ var PopoverContext = createContext(null);
10
+ function usePopoverContext(component) {
11
+ const context = useContext(PopoverContext);
12
+ if (!context) throw new Error(`yarcl: <${component}> must be inside <Popover>`);
13
+ return context;
14
+ }
15
+ function usePopoverState({ open: openProp, defaultOpen = false, onOpenChange, placement = "bottom", modal = false }) {
16
+ const [open, setOpen] = useControllable(openProp, defaultOpen, onOpenChange);
17
+ const floating = useFloating({
18
+ open,
19
+ onOpenChange: setOpen,
20
+ placement,
21
+ transform: false,
22
+ whileElementsMounted: autoUpdate,
23
+ middleware: floatingMiddleware()
24
+ });
25
+ const interactions = useInteractions([
26
+ useClick(floating.context),
27
+ useDismiss(floating.context),
28
+ useRole(floating.context, { role: "dialog" })
29
+ ]);
30
+ return {
31
+ open,
32
+ setOpen,
33
+ modal,
34
+ ...floating,
35
+ ...interactions
36
+ };
37
+ }
38
+ function PopoverRoot(props) {
39
+ const state = usePopoverState(props);
40
+ return /* @__PURE__ */ jsx(PopoverContext.Provider, {
41
+ value: state,
42
+ children: props.children
43
+ });
44
+ }
45
+ function PopoverTrigger({ children }) {
46
+ const { refs, getReferenceProps } = usePopoverContext("Popover.Trigger");
47
+ return useTrigger(children, refs.setReference, getReferenceProps);
48
+ }
49
+ function PopoverContent({ padding, radius, initialFocus, className, style, ...props }) {
50
+ const own = useDefaults("Popover");
51
+ const { open, modal, refs, floatingStyles, context, getFloatingProps } = usePopoverContext("Popover.Content");
52
+ if (!open) return null;
53
+ return /* @__PURE__ */ jsx(FloatingPortal, { children: /* @__PURE__ */ jsx(FloatingFocusManager, {
54
+ context,
55
+ modal,
56
+ initialFocus,
57
+ children: /* @__PURE__ */ jsx("div", {
58
+ ref: refs.setFloating,
59
+ style: {
60
+ ...floatingStyles,
61
+ ...style
62
+ },
63
+ className: cx("yarcl-floating yarcl-panel yarcl-popover", paddingClass(padding ?? own.padding), radiusClass(radius ?? own.radius), className),
64
+ ...getFloatingProps(props)
65
+ })
66
+ }) });
67
+ }
68
+ /**
69
+ * A floating panel anchored to a trigger, opened by click. Closes on Esc or outside click.
70
+ * The base for custom floating UI; use {@link Menu}, {@link Select} or {@link Combobox} for lists.
71
+ *
72
+ * @example
73
+ * ```tsx
74
+ * <Popover>
75
+ * <Popover.Trigger><Button variant="outline">Filters</Button></Popover.Trigger>
76
+ * <Popover.Content>
77
+ * <Stack><Checkbox>Archived</Checkbox></Stack>
78
+ * </Popover.Content>
79
+ * </Popover>
80
+ * ```
81
+ */
82
+ var Popover = Object.assign(PopoverRoot, {
83
+ Trigger: PopoverTrigger,
84
+ Content: PopoverContent
85
+ });
86
+ //#endregion
87
+ export { Popover };
@@ -0,0 +1,60 @@
1
+ import { type ComponentProps, type ReactNode } from 'react';
2
+ import type { Color, ComponentSize, Radius } from '../types';
3
+ /** Props for {@link Progress}. */
4
+ export interface ProgressProps extends Omit<ComponentProps<'div'>, 'color' | 'children'> {
5
+ /**
6
+ * Current value, from 0 to `max`. Leave undefined for an indeterminate bar that animates until the work is measurable.
7
+ * @example
8
+ * ```tsx
9
+ * <Progress value={40} label="Uploading" />
10
+ * ```
11
+ */
12
+ value?: number;
13
+ /**
14
+ * The value that means complete.
15
+ * @default 100
16
+ */
17
+ max?: number;
18
+ /**
19
+ * Visible label above the bar. It also names the progress bar for screen readers;
20
+ * without it, pass `aria-label` or `aria-labelledby`.
21
+ */
22
+ label?: ReactNode;
23
+ /** Shows the value next to the label, as a percentage unless `formatValue` is set. Ignored when indeterminate. */
24
+ showValue?: boolean;
25
+ /**
26
+ * Formats the value for the visible text and `aria-valuetext`.
27
+ * @example
28
+ * ```tsx
29
+ * <Progress value={3} max={8} showValue formatValue={(v, max) => `${v} of ${max} files`} />
30
+ * ```
31
+ */
32
+ formatValue?: (value: number, max: number) => string;
33
+ /**
34
+ * Track height, scaled from the size's `iconSize` in the `sizes` config. Also sets the label's font size.
35
+ * @default config.defaults.size
36
+ */
37
+ size?: ComponentSize<'Progress'>;
38
+ /**
39
+ * Bar color, from the `colors` config.
40
+ * @default config.defaults.color
41
+ */
42
+ color?: Color;
43
+ /**
44
+ * Corner radius of the track and bar, from the `radii` config.
45
+ * @default config.defaults.radius
46
+ */
47
+ radius?: Radius | 'size';
48
+ }
49
+ /**
50
+ * A progress bar. Determinate when `value` is set, indeterminate otherwise.
51
+ * Renders `role="progressbar"` with `aria-valuenow`, `aria-valuemin` and `aria-valuemax`
52
+ * (omitted when indeterminate), named by `label` or `aria-label`.
53
+ *
54
+ * @example
55
+ * ```tsx
56
+ * <Progress value={64} label="Storage used" showValue color="warning" />
57
+ * <Progress aria-label="Loading results" />
58
+ * ```
59
+ */
60
+ export declare function Progress({ value, max, label, showValue, formatValue, size, color, radius, className, style, ...props }: ProgressProps): import("react").JSX.Element;
@@ -0,0 +1,59 @@
1
+ import { useDefaults } from "../runtime.js";
2
+ import { colorClass, cx, radiusClass, sizeClass } from "../classes.js";
3
+ import { useId } from "react";
4
+ import { jsx, jsxs } from "react/jsx-runtime";
5
+ //#region src/components/Progress.tsx
6
+ /**
7
+ * A progress bar. Determinate when `value` is set, indeterminate otherwise.
8
+ * Renders `role="progressbar"` with `aria-valuenow`, `aria-valuemin` and `aria-valuemax`
9
+ * (omitted when indeterminate), named by `label` or `aria-label`.
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * <Progress value={64} label="Storage used" showValue color="warning" />
14
+ * <Progress aria-label="Loading results" />
15
+ * ```
16
+ */
17
+ function Progress({ value, max = 100, label, showValue, formatValue, size, color, radius, className, style, ...props }) {
18
+ const own = useDefaults("Progress");
19
+ const labelId = useId();
20
+ const indeterminate = value == null;
21
+ const limit = max > 0 ? max : 100;
22
+ const current = indeterminate ? 0 : Math.min(Math.max(value, 0), limit);
23
+ const text = formatValue ? formatValue(current, limit) : `${Math.round(current / limit * 100)}%`;
24
+ const hasLabel = label != null;
25
+ const named = hasLabel || props["aria-label"] != null || props["aria-labelledby"] != null;
26
+ const valueVisible = showValue && !indeterminate;
27
+ return /* @__PURE__ */ jsxs("div", {
28
+ role: "progressbar",
29
+ "aria-labelledby": hasLabel ? labelId : void 0,
30
+ "aria-label": named ? void 0 : "Progress",
31
+ "aria-valuemin": indeterminate ? void 0 : 0,
32
+ "aria-valuemax": indeterminate ? void 0 : limit,
33
+ "aria-valuenow": indeterminate ? void 0 : current,
34
+ "aria-valuetext": indeterminate || !formatValue ? void 0 : text,
35
+ "data-indeterminate": indeterminate || void 0,
36
+ className: cx("yarcl-progress", sizeClass(size ?? own.size, "Progress"), colorClass(color ?? own.color), radiusClass(radius ?? own.radius, size ?? own.size), className),
37
+ style: {
38
+ ...indeterminate ? null : { "--yarcl-progress": current / limit },
39
+ ...style
40
+ },
41
+ ...props,
42
+ children: [(hasLabel || valueVisible) && /* @__PURE__ */ jsxs("div", {
43
+ className: "yarcl-progress-header",
44
+ children: [hasLabel && /* @__PURE__ */ jsx("span", {
45
+ id: labelId,
46
+ className: "yarcl-progress-label",
47
+ children: label
48
+ }), valueVisible && /* @__PURE__ */ jsx("span", {
49
+ className: "yarcl-progress-value",
50
+ children: text
51
+ })]
52
+ }), /* @__PURE__ */ jsx("div", {
53
+ className: "yarcl-progress-track",
54
+ children: /* @__PURE__ */ jsx("div", { className: "yarcl-progress-bar" })
55
+ })]
56
+ });
57
+ }
58
+ //#endregion
59
+ export { Progress };
@@ -0,0 +1,32 @@
1
+ import type { ComponentProps, ReactNode } from 'react';
2
+ import type { Color, ComponentSize } from '../types';
3
+ /** Props for {@link Radio}. Accepts all native `<input>` attributes except `type`, `color` and `size`. */
4
+ export interface RadioProps extends Omit<ComponentProps<'input'>, 'type' | 'color' | 'size' | 'children' | 'value'> {
5
+ /** Label shown next to the radio. */
6
+ children?: ReactNode;
7
+ /** Value reported to the {@link RadioGroup} and submitted with forms. */
8
+ value?: string;
9
+ /**
10
+ * Radio size, from the `sizes` config (uses the size's `iconSize`). Inherited from a {@link RadioGroup}.
11
+ * @default config.defaults.size
12
+ */
13
+ size?: ComponentSize<'Radio'>;
14
+ /**
15
+ * Color of the selected radio, from the `colors` config. Inherited from a {@link RadioGroup}.
16
+ * @default config.defaults.color
17
+ */
18
+ color?: Color;
19
+ }
20
+ /**
21
+ * A radio button with an optional label. Place inside a {@link RadioGroup}, or group standalone
22
+ * radios with the same `name`.
23
+ *
24
+ * @example
25
+ * ```tsx
26
+ * <RadioGroup label="Plan" defaultValue="pro">
27
+ * <Radio value="free">Free</Radio>
28
+ * <Radio value="pro">Pro</Radio>
29
+ * </RadioGroup>
30
+ * ```
31
+ */
32
+ export declare function Radio({ children, size, color, value, className, style, onChange, ...props }: RadioProps): import("react").JSX.Element;