@surflane/ui 0.9.0 → 0.10.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 (291) hide show
  1. package/README.md +4 -4
  2. package/dist/accordion.d.ts +33 -17
  3. package/dist/accordion.js +10 -11
  4. package/dist/alert-dialog.d.ts +8 -4
  5. package/dist/alert-dialog.js +3 -4
  6. package/dist/app-shell.d.ts +81 -44
  7. package/dist/app-shell.js +67 -29
  8. package/dist/autocomplete.d.ts +117 -61
  9. package/dist/autocomplete.js +8 -8
  10. package/dist/avatar.d.ts +34 -17
  11. package/dist/avatar.js +8 -9
  12. package/dist/badge.d.ts +6 -10
  13. package/dist/badge.js +5 -6
  14. package/dist/bottom-navigation.d.ts +11 -41
  15. package/dist/bottom-navigation.js +9 -10
  16. package/dist/breadcrumbs.d.ts +21 -5
  17. package/dist/breadcrumbs.js +12 -14
  18. package/dist/button.d.ts +15 -8
  19. package/dist/button.js +8 -9
  20. package/dist/card.d.ts +610 -35
  21. package/dist/card.js +12 -12
  22. package/dist/chart.d.ts +9 -32
  23. package/dist/chart.js +65 -26
  24. package/dist/checkbox-group.d.ts +4 -1
  25. package/dist/checkbox-group.js +3 -4
  26. package/dist/checkbox.d.ts +13 -4
  27. package/dist/checkbox.js +6 -6
  28. package/dist/choice-label.d.ts +3 -11
  29. package/dist/choice-label.js +4 -4
  30. package/dist/class-names.d.ts +6 -0
  31. package/dist/class-names.js +18 -0
  32. package/dist/code.d.ts +13 -10
  33. package/dist/code.js +8 -5
  34. package/dist/collapsible.d.ts +25 -12
  35. package/dist/collapsible.js +7 -8
  36. package/dist/combobox.d.ts +145 -73
  37. package/dist/combobox.js +27 -27
  38. package/dist/context-menu.d.ts +106 -54
  39. package/dist/context-menu.js +4 -5
  40. package/dist/css/accordion.css +1 -1
  41. package/dist/css/alert-dialog.css +2 -2
  42. package/dist/css/all.css +7 -5
  43. package/dist/css/app-shell.css +1 -1
  44. package/dist/css/autocomplete.css +1 -1
  45. package/dist/css/avatar.css +2 -2
  46. package/dist/css/badge.css +2 -2
  47. package/dist/css/bottom-navigation.css +1 -1
  48. package/dist/css/breadcrumbs.css +3 -3
  49. package/dist/css/button.css +1 -1
  50. package/dist/css/card.css +3 -3
  51. package/dist/css/chart.css +2 -2
  52. package/dist/css/checkbox-group.css +1 -1
  53. package/dist/css/checkbox.css +1 -1
  54. package/dist/css/choice-label.css +1 -1
  55. package/dist/css/code.css +2 -2
  56. package/dist/css/collapsible.css +1 -1
  57. package/dist/css/combobox.css +1 -1
  58. package/dist/css/context-menu.css +1 -1
  59. package/dist/css/date-picker.css +1 -1
  60. package/dist/css/dialog.css +2 -2
  61. package/dist/css/drawer.css +2 -2
  62. package/dist/css/empty-state.css +2 -2
  63. package/dist/css/field.css +1 -1
  64. package/dist/css/fieldset.css +1 -1
  65. package/dist/css/file-upload.css +2 -2
  66. package/dist/css/filter-bar.css +1 -1
  67. package/dist/css/form.css +1 -1
  68. package/dist/css/icon.css +1 -1
  69. package/dist/css/inline-message.css +2 -2
  70. package/dist/css/input.css +1 -1
  71. package/dist/css/layout.css +2 -2
  72. package/dist/css/link.css +2 -2
  73. package/dist/css/list.css +2 -2
  74. package/dist/css/markdown.css +4 -4
  75. package/dist/css/menu.css +1 -1
  76. package/dist/css/menubar.css +1 -1
  77. package/dist/css/meter.css +1 -1
  78. package/dist/css/native-select.css +1 -1
  79. package/dist/css/navigation-menu.css +1 -1
  80. package/dist/css/number-field.css +1 -1
  81. package/dist/css/otp-field.css +1 -1
  82. package/dist/css/page-header.css +3 -3
  83. package/dist/css/pagination.css +2 -2
  84. package/dist/css/popover.css +1 -1
  85. package/dist/css/preview-card.css +2 -2
  86. package/dist/css/progress.css +1 -1
  87. package/dist/css/radio-group.css +1 -1
  88. package/dist/css/rules/accordion.css +5 -5
  89. package/dist/css/rules/alert-dialog.css +9 -9
  90. package/dist/css/rules/app-shell.css +274 -82
  91. package/dist/css/rules/avatar.css +7 -7
  92. package/dist/css/rules/badge.css +6 -6
  93. package/dist/css/rules/bar.css +11 -11
  94. package/dist/css/rules/base.css +30 -30
  95. package/dist/css/rules/bottom-navigation.css +57 -56
  96. package/dist/css/rules/breadcrumbs.css +2 -2
  97. package/dist/css/rules/button.css +66 -65
  98. package/dist/css/rules/card.css +3 -3
  99. package/dist/css/rules/chart.css +134 -124
  100. package/dist/css/rules/checkbox.css +5 -5
  101. package/dist/css/rules/choice-label.css +19 -18
  102. package/dist/css/rules/choice.css +65 -60
  103. package/dist/css/rules/code.css +2 -2
  104. package/dist/css/rules/collapsible.css +2 -2
  105. package/dist/css/rules/combobox.css +87 -83
  106. package/dist/css/rules/context-menu.css +1 -1
  107. package/dist/css/rules/date-picker.css +150 -144
  108. package/dist/css/rules/dialog.css +85 -79
  109. package/dist/css/rules/disclosure.css +49 -47
  110. package/dist/css/rules/drawer.css +6 -6
  111. package/dist/css/rules/empty-state.css +2 -2
  112. package/dist/css/rules/field-control.css +51 -42
  113. package/dist/css/rules/field.css +26 -24
  114. package/dist/css/rules/fieldset.css +8 -8
  115. package/dist/css/rules/file-upload.css +73 -72
  116. package/dist/css/rules/filter-bar.css +19 -18
  117. package/dist/css/rules/form.css +3 -3
  118. package/dist/css/rules/gauge.css +22 -22
  119. package/dist/css/rules/icon.css +16 -11
  120. package/dist/css/rules/inline-message.css +3 -3
  121. package/dist/css/rules/input-group.css +44 -43
  122. package/dist/css/rules/input.css +11 -11
  123. package/dist/css/rules/item.css +7 -7
  124. package/dist/css/rules/link.css +2 -2
  125. package/dist/css/rules/list.css +3 -3
  126. package/dist/css/rules/markdown.css +27 -27
  127. package/dist/css/rules/menu.css +45 -42
  128. package/dist/css/rules/menubar.css +6 -6
  129. package/dist/css/rules/navigation-menu.css +69 -66
  130. package/dist/css/rules/number-field.css +22 -21
  131. package/dist/css/rules/otp-field.css +28 -27
  132. package/dist/css/rules/panel.css +105 -100
  133. package/dist/css/rules/popover.css +23 -20
  134. package/dist/css/rules/popup.css +15 -14
  135. package/dist/css/rules/preview-card.css +20 -19
  136. package/dist/css/rules/progress.css +3 -3
  137. package/dist/css/rules/radio-group.css +8 -8
  138. package/dist/css/rules/scroll-area.css +50 -39
  139. package/dist/css/rules/select.css +39 -36
  140. package/dist/css/rules/sizing.css +119 -116
  141. package/dist/css/rules/skeleton.css +11 -11
  142. package/dist/css/rules/slider.css +43 -43
  143. package/dist/css/rules/sparkline.css +21 -21
  144. package/dist/css/rules/spinner.css +9 -9
  145. package/dist/css/rules/stat.css +32 -32
  146. package/dist/css/rules/switch.css +28 -21
  147. package/dist/css/rules/syntax-highlighter.css +37 -36
  148. package/dist/css/rules/table.css +10 -10
  149. package/dist/css/rules/tabs.css +53 -52
  150. package/dist/css/rules/textarea.css +9 -7
  151. package/dist/css/rules/toast.css +94 -90
  152. package/dist/css/rules/toggle.css +12 -12
  153. package/dist/css/rules/toolbar.css +27 -27
  154. package/dist/css/rules/tooltip.css +14 -14
  155. package/dist/css/rules/tree.css +38 -38
  156. package/dist/css/scroll-area.css +1 -1
  157. package/dist/css/select.css +1 -1
  158. package/dist/css/separator.css +2 -2
  159. package/dist/css/sheet.css +2 -2
  160. package/dist/css/sizing.css +1 -1
  161. package/dist/css/skeleton.css +1 -1
  162. package/dist/css/slider.css +1 -1
  163. package/dist/css/sparkline.css +1 -1
  164. package/dist/css/spinner.css +1 -1
  165. package/dist/css/stat.css +1 -1
  166. package/dist/css/styles.css +17 -17
  167. package/dist/css/switch.css +1 -1
  168. package/dist/css/syntax-highlighter.css +1 -1
  169. package/dist/css/table.css +2 -2
  170. package/dist/css/tabs.css +1 -1
  171. package/dist/css/textarea.css +1 -1
  172. package/dist/css/toast.css +1 -1
  173. package/dist/css/toggle-group.css +1 -1
  174. package/dist/css/toggle.css +1 -1
  175. package/dist/css/toolbar.css +1 -1
  176. package/dist/css/tooltip.css +1 -1
  177. package/dist/css/tree.css +1 -1
  178. package/dist/css/typography.css +2 -2
  179. package/dist/date-picker.js +28 -8
  180. package/dist/dialog.d.ts +20 -8
  181. package/dist/dialog.js +11 -12
  182. package/dist/drawer.d.ts +12 -4
  183. package/dist/drawer.js +5 -5
  184. package/dist/element-part.d.ts +8 -0
  185. package/dist/element-part.js +21 -0
  186. package/dist/empty-state.d.ts +602 -24
  187. package/dist/empty-state.js +9 -9
  188. package/dist/field.d.ts +60 -36
  189. package/dist/field.js +6 -6
  190. package/dist/fieldset.d.ts +19 -11
  191. package/dist/fieldset.js +2 -2
  192. package/dist/file-upload.d.ts +8 -23
  193. package/dist/file-upload.js +21 -16
  194. package/dist/filter-bar.d.ts +30 -10
  195. package/dist/filter-bar.js +16 -18
  196. package/dist/form.js +1 -1
  197. package/dist/icon.d.ts +9 -2
  198. package/dist/icon.js +6 -6
  199. package/dist/index.d.ts +4 -4
  200. package/dist/index.js +2 -3
  201. package/dist/inline-message.d.ts +51 -27
  202. package/dist/inline-message.js +10 -11
  203. package/dist/input.d.ts +4 -2
  204. package/dist/input.js +3 -4
  205. package/dist/layout.d.ts +24 -12
  206. package/dist/layout.js +27 -27
  207. package/dist/link.d.ts +3 -1
  208. package/dist/link.js +3 -4
  209. package/dist/list.d.ts +43 -27
  210. package/dist/list.js +12 -13
  211. package/dist/markdown.d.ts +14 -6
  212. package/dist/markdown.js +28 -11
  213. package/dist/menu.d.ts +113 -57
  214. package/dist/menu.js +24 -25
  215. package/dist/menubar.d.ts +5 -3
  216. package/dist/menubar.js +1 -1
  217. package/dist/meter.d.ts +46 -26
  218. package/dist/meter.js +5 -5
  219. package/dist/native-select.d.ts +4 -2
  220. package/dist/native-select.js +2 -2
  221. package/dist/navigation-menu.d.ts +76 -40
  222. package/dist/navigation-menu.js +15 -16
  223. package/dist/number-field.d.ts +44 -19
  224. package/dist/number-field.js +12 -13
  225. package/dist/otp-field.d.ts +26 -9
  226. package/dist/otp-field.js +10 -11
  227. package/dist/page-header.js +3 -4
  228. package/dist/pagination.d.ts +11 -8
  229. package/dist/pagination.js +4 -5
  230. package/dist/panel.d.ts +3 -1
  231. package/dist/panel.js +5 -6
  232. package/dist/parts.d.ts +5 -7
  233. package/dist/parts.js +8 -16
  234. package/dist/popover.d.ts +20 -12
  235. package/dist/popover.js +3 -3
  236. package/dist/preview-card.d.ts +22 -10
  237. package/dist/preview-card.js +7 -8
  238. package/dist/progress.d.ts +46 -26
  239. package/dist/progress.js +5 -5
  240. package/dist/radio-group.d.ts +16 -8
  241. package/dist/radio-group.js +5 -5
  242. package/dist/scroll-area.d.ts +4 -2
  243. package/dist/scroll-area.js +6 -6
  244. package/dist/select.d.ts +3 -1
  245. package/dist/select.js +5 -5
  246. package/dist/separator.d.ts +5 -2
  247. package/dist/separator.js +3 -4
  248. package/dist/sheet.d.ts +12 -4
  249. package/dist/sheet.js +5 -5
  250. package/dist/size.d.ts +7 -0
  251. package/dist/size.js +9 -0
  252. package/dist/sizing.d.ts +8 -3
  253. package/dist/sizing.js +8 -10
  254. package/dist/skeleton.d.ts +3 -3
  255. package/dist/skeleton.js +4 -6
  256. package/dist/slider.d.ts +55 -31
  257. package/dist/slider.js +7 -7
  258. package/dist/sparkline.d.ts +5 -20
  259. package/dist/sparkline.js +5 -7
  260. package/dist/spinner.d.ts +4 -6
  261. package/dist/spinner.js +7 -8
  262. package/dist/stat.d.ts +34 -42
  263. package/dist/stat.js +9 -10
  264. package/dist/status.js +0 -1
  265. package/dist/switch.d.ts +17 -8
  266. package/dist/switch.js +4 -5
  267. package/dist/syntax-engine.js +9 -1
  268. package/dist/syntax-highlighter.d.ts +3 -7
  269. package/dist/syntax-highlighter.js +4 -4
  270. package/dist/syntax-highlighting.js +2 -2
  271. package/dist/table.d.ts +111 -75
  272. package/dist/table.js +32 -33
  273. package/dist/tabs.d.ts +46 -26
  274. package/dist/tabs.js +5 -5
  275. package/dist/textarea.d.ts +4 -2
  276. package/dist/textarea.js +3 -4
  277. package/dist/toast.d.ts +76 -42
  278. package/dist/toast.js +28 -28
  279. package/dist/toggle-group.js +1 -1
  280. package/dist/toggle.js +1 -1
  281. package/dist/tone-transition.d.ts +1 -1
  282. package/dist/tone-transition.js +9 -8
  283. package/dist/toolbar.d.ts +55 -31
  284. package/dist/toolbar.js +6 -6
  285. package/dist/tooltip.d.ts +4 -1
  286. package/dist/tooltip.js +2 -2
  287. package/dist/tree.d.ts +12 -1
  288. package/dist/tree.js +13 -9
  289. package/dist/typography.d.ts +3 -1
  290. package/dist/typography.js +6 -8
  291. package/package.json +6 -5
package/dist/card.js CHANGED
@@ -1,25 +1,25 @@
1
- 'use client';
2
1
  import { jsx as _jsx } from "react/jsx-runtime";
3
2
  import * as React from 'react';
4
3
  import { Surface } from './layout.js';
5
- import { part, cx } from './parts.js';
6
- const CardRoot = /* @__PURE__ */ React.forwardRef(function CardRoot({ className, padding, ...props }, ref) {
7
- return (_jsx(Surface, { ...props, padding: padding, ref: ref, className: cx('pui-card', className) }));
8
- });
9
- const CardTitle = /* @__PURE__ */ React.forwardRef(function CardTitle({ level = 3, className, ...props }, ref) {
4
+ import { cx } from './class-names.js';
5
+ import { elementPart } from './element-part.js';
6
+ const CardRoot = function CardRoot({ className, padding, ref, ...props }) {
7
+ return (_jsx(Surface, { ...props, padding: padding, ref: ref, className: cx('surf-card', className) }));
8
+ };
9
+ const CardTitle = function CardTitle({ level = 3, className, ref, ...props }) {
10
10
  return React.createElement(`h${level}`, {
11
11
  ...props,
12
12
  ref,
13
- className: cx('pui-card-title', className),
13
+ className: cx('surf-card-title', className),
14
14
  });
15
- });
15
+ };
16
16
  export const Card = {
17
17
  Root: CardRoot,
18
- Header: /* @__PURE__ */ part('div', 'pui-card-header'),
18
+ Header: /* @__PURE__ */ elementPart('div', 'surf-card-header'),
19
19
  Title: CardTitle,
20
- Description: /* @__PURE__ */ part('p', 'pui-card-description'),
21
- Body: /* @__PURE__ */ part('div', 'pui-card-body'),
22
- Footer: /* @__PURE__ */ part('div', 'pui-card-footer'),
20
+ Description: /* @__PURE__ */ elementPart('p', 'surf-card-description'),
21
+ Body: /* @__PURE__ */ elementPart('div', 'surf-card-body'),
22
+ Footer: /* @__PURE__ */ elementPart('div', 'surf-card-footer'),
23
23
  };
24
24
  // Flat names for React Server Components, which cannot dot into client exports.
25
25
  export { CardRoot, CardTitle };
package/dist/chart.d.ts CHANGED
@@ -25,13 +25,11 @@ export type ChartProps = Omit<React.ComponentPropsWithoutRef<'figure'>, 'childre
25
25
  * for categories that color must separate, such as buckets or sectors. */
26
26
  palette?: 'neutral' | 'categorical';
27
27
  locale?: string;
28
+ /** Formats a value for the readout, the table and the value axis ticks. The unit
29
+ * follows it in the readout and the table, and names the axis. */
28
30
  formatValue?: (value: number) => string;
29
31
  /** Text the chart shows or announces; pass translations here. */
30
32
  labels?: Partial<ChartLabels>;
31
- /** @deprecated Use labels.missing. */
32
- missingLabel?: string;
33
- /** @deprecated Use labels.empty. */
34
- emptyLabel?: string;
35
33
  hiddenSeries?: readonly string[];
36
34
  defaultHiddenSeries?: readonly string[];
37
35
  onHiddenSeriesChange?: (keys: string[]) => void;
@@ -50,34 +48,13 @@ export type ChartLabels = {
50
48
  inspectHint: string;
51
49
  /** The data table's only row when there is no data. */
52
50
  noRows: string;
51
+ /** The legend list, given the chart's title. */
52
+ legend: (title: string) => string;
53
+ /** A legend button that shows or hides a series. */
54
+ series: (label: string) => string;
53
55
  };
54
56
  /** Cartesian trends with a persistent, keyboard-readable tooltip region and a
55
57
  * full data-table alternative. Missing values are gaps, never fabricated zeros. */
56
- export declare const Chart: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLElement>, HTMLElement>, "ref">, "children" | "title"> & {
57
- title: string;
58
- description: string;
59
- data: readonly ChartDatum[];
60
- series: readonly ChartSeries[];
61
- unit: string;
62
- xLabel: string;
63
- yLabel: string;
64
- type?: "line" | "bar" | "area";
65
- height?: number;
66
- /** Keeps 0 on the value axis. Turn it off for values far from zero, such as
67
- * prices, so the line uses the height; bars always start at zero. */
68
- includeZero?: boolean;
69
- /** neutral tells series apart by ink, dashes and markers. categorical adds six hues,
70
- * for categories that color must separate, such as buckets or sectors. */
71
- palette?: "neutral" | "categorical";
72
- locale?: string;
73
- formatValue?: (value: number) => string;
74
- /** Text the chart shows or announces; pass translations here. */
75
- labels?: Partial<ChartLabels>;
76
- /** @deprecated Use labels.missing. */
77
- missingLabel?: string;
78
- /** @deprecated Use labels.empty. */
79
- emptyLabel?: string;
80
- hiddenSeries?: readonly string[];
81
- defaultHiddenSeries?: readonly string[];
82
- onHiddenSeriesChange?: (keys: string[]) => void;
83
- } & React.RefAttributes<HTMLElement>>;
58
+ export declare const Chart: ({ title, description, data, series, unit, xLabel, yLabel, type, height, includeZero, palette, locale, formatValue, labels, hiddenSeries, defaultHiddenSeries, onHiddenSeriesChange, className, ref, ...props }: ChartProps & {
59
+ ref?: React.Ref<HTMLElement>;
60
+ }) => React.JSX.Element;
package/dist/chart.js CHANGED
@@ -18,6 +18,8 @@ const chartLabels = {
18
18
  tableCaption: (unit) => `All input measurements, including hidden series. Unit: ${unit}.`,
19
19
  inspectHint: 'Hover, touch or use chart arrow keys to inspect a measurement.',
20
20
  noRows: 'No rows.',
21
+ legend: (title) => `${title} series`,
22
+ series: (label) => `${label} series`,
21
23
  };
22
24
  /** The round step at or above a raw step: 1, 2, 2.5 or 5 times a power of ten. */
23
25
  function roundStep(raw) {
@@ -26,22 +28,56 @@ function roundStep(raw) {
26
28
  const power = 10 ** Math.floor(Math.log10(raw));
27
29
  return power * ([1, 2, 2.5, 5, 10].find((f) => f * power >= raw) ?? 10);
28
30
  }
31
+ /** The smallest round step that spans low to high in at most five intervals, so the
32
+ * top tick is the round value just above the highest one. */
33
+ function axisStep(low, high) {
34
+ let step = roundStep((high - low) / 5);
35
+ while (step && Math.ceil(high / step) - Math.floor(low / step) > 5)
36
+ step = roundStep(step * 1.01);
37
+ return step;
38
+ }
29
39
  const dashes = [undefined, '7 4', '2 4', '10 3 2 3', '12 5', '4 3'];
40
+ /** True once the font of the tick labels has loaded. Recharts measures a label to keep
41
+ * it inside the chart and caches that width; measured in the fallback font, the last
42
+ * label overflows by a few pixels once the real font arrives. */
43
+ function useFontReady(element, text) {
44
+ const [ready, setReady] = React.useState(false);
45
+ React.useEffect(() => {
46
+ if (!element)
47
+ return;
48
+ if (!document.fonts)
49
+ return setReady(true);
50
+ let live = true;
51
+ const family = getComputedStyle(element).fontFamily;
52
+ // load() starts the download of the faces that draw this text and waits for them.
53
+ void document.fonts
54
+ .load(`12px ${family}`, text || ' ')
55
+ .catch(() => [])
56
+ .then(() => {
57
+ if (live)
58
+ setReady(true);
59
+ });
60
+ return () => {
61
+ live = false;
62
+ };
63
+ }, [element, text]);
64
+ return ready;
65
+ }
30
66
  function Marker({ cx, cy, color, index, }) {
31
67
  if (typeof cx !== 'number' ||
32
68
  typeof cy !== 'number' ||
33
69
  !Number.isFinite(cx) ||
34
70
  !Number.isFinite(cy))
35
71
  return null;
36
- const props = { fill: 'var(--canvas)', stroke: color, strokeWidth: 1.8 };
72
+ const props = { fill: 'var(--surf-canvas)', stroke: color, strokeWidth: 1.8 };
37
73
  return index % 3 === 0 ? (_jsx("circle", { cx: cx, cy: cy, r: 3.5, ...props })) : index % 3 === 1 ? (_jsx("rect", { x: cx - 3.5, y: cy - 3.5, width: 7, height: 7, ...props })) : (_jsx("path", { d: `M${cx},${cy - 4.5}l4.5,8h-9Z`, ...props }));
38
74
  }
39
75
  function Pattern({ id, index, color, }) {
40
- return (_jsxs("pattern", { id: id, patternUnits: 'userSpaceOnUse', width: '8', height: '8', children: [_jsx("rect", { width: '8', height: '8', fill: color }), index % 3 === 1 ? (_jsx("path", { d: 'M-2 2L2-2M0 8L8 0M6 10L10 6', stroke: 'var(--canvas)', strokeWidth: '1.5' })) : index % 3 === 2 ? (_jsx("circle", { cx: '4', cy: '4', r: '1.4', fill: 'var(--canvas)' })) : null] }));
76
+ return (_jsxs("pattern", { id: id, patternUnits: 'userSpaceOnUse', width: '8', height: '8', children: [_jsx("rect", { width: '8', height: '8', fill: color }), index % 3 === 1 ? (_jsx("path", { d: 'M-2 2L2-2M0 8L8 0M6 10L10 6', stroke: 'var(--surf-canvas)', strokeWidth: '1.5' })) : index % 3 === 2 ? (_jsx("circle", { cx: '4', cy: '4', r: '1.4', fill: 'var(--surf-canvas)' })) : null] }));
41
77
  }
42
78
  /** A series' swatch, as the legend and the floating values draw it. */
43
79
  function SeriesMark({ type, index, color, pattern, }) {
44
- return (_jsx("svg", { className: 'pui-chart-mark', viewBox: '0 0 32 20', "aria-hidden": 'true', focusable: 'false', children: type === 'bar' ? (_jsxs(_Fragment, { children: [_jsx("defs", { children: _jsx(Pattern, { id: pattern, color: color, index: index }) }), _jsx("rect", { x: '4', y: '3', width: '24', height: '14', rx: '2', fill: `url(#${pattern})` })] })) : (_jsxs(_Fragment, { children: [_jsx("path", { d: 'M1 10h30', stroke: color, strokeWidth: '2', strokeDasharray: dashes[index % dashes.length] }), _jsx(Marker, { cx: 16, cy: 10, index: index, color: color })] })) }));
80
+ return (_jsx("svg", { className: 'surf-chart-mark', viewBox: '0 0 32 20', "aria-hidden": 'true', focusable: 'false', children: type === 'bar' ? (_jsxs(_Fragment, { children: [_jsx("defs", { children: _jsx(Pattern, { id: pattern, color: color, index: index }) }), _jsx("rect", { x: '4', y: '3', width: '24', height: '14', rx: '2', fill: `url(#${pattern})` })] })) : (_jsxs(_Fragment, { children: [_jsx("path", { d: 'M1 10h30', stroke: color, strokeWidth: '2', strokeDasharray: dashes[index % dashes.length] }), _jsx(Marker, { cx: 16, cy: 10, index: index, color: color })] })) }));
45
81
  }
46
82
  /** The active point's values beside it, for pointer and touch users. The readout
47
83
  * below the plot announces the same values, so this copy stays out of the
@@ -61,29 +97,25 @@ function FloatingValues({ host, hidden, render, }) {
61
97
  }, [shown, label, plot?.width]);
62
98
  if (!shown || !point || !plot)
63
99
  return null;
64
- // The gap between the point and the box, in px: the --space-3 step.
100
+ // The gap between the point and the box, in px: the --surf-space-3 step.
65
101
  const gap = 12;
66
102
  const start = point.x > plot.x + plot.width / 2;
67
103
  const left = Math.min(Math.max(start ? point.x - gap - width : point.x + gap, plot.x), plot.x + plot.width - width);
68
- return createPortal(_jsx("div", { ref: box, className: 'pui-chart-tooltip', "aria-hidden": 'true', style: { left, top: plot.y, visibility: width ? undefined : 'hidden' }, children: render(String(label)) }), host);
104
+ return createPortal(_jsx("div", { ref: box, className: 'surf-chart-tooltip', "aria-hidden": 'true', style: { left, top: plot.y, visibility: width ? undefined : 'hidden' }, children: render(String(label)) }), host);
69
105
  }
70
106
  /** Cartesian trends with a persistent, keyboard-readable tooltip region and a
71
107
  * full data-table alternative. Missing values are gaps, never fabricated zeros. */
72
- export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, description, data, series, unit, xLabel, yLabel, type = 'line', height = 280, includeZero = true, palette = 'neutral', locale = 'en-US', formatValue, labels, missingLabel, emptyLabel, hiddenSeries, defaultHiddenSeries = [], onHiddenSeriesChange, className, ...props }, ref) {
73
- const text = {
74
- ...chartLabels,
75
- ...(missingLabel === undefined ? {} : { missing: missingLabel }),
76
- ...(emptyLabel === undefined ? {} : { empty: emptyLabel }),
77
- ...labels,
78
- };
108
+ export const Chart = function Chart({ title, description, data, series, unit, xLabel, yLabel, type = 'line', height = 280, includeZero = true, palette = 'neutral', locale = 'en-US', formatValue, labels, hiddenSeries, defaultHiddenSeries = [], onHiddenSeriesChange, className, ref, ...props }) {
109
+ const text = { ...chartLabels, ...labels };
79
110
  const id = React.useId().replace(/[^a-zA-Z0-9_-]/g, '_');
80
111
  const colorFor = (index) => palette === 'categorical'
81
- ? `var(--chart-category-${(index % 6) + 1})`
82
- : `var(--chart-series-${(index % 3) + 1})`;
112
+ ? `var(--surf-chart-category-${(index % 6) + 1})`
113
+ : `var(--surf-chart-series-${(index % 3) + 1})`;
83
114
  const [internalHidden, setInternalHidden] = React.useState(defaultHiddenSeries);
84
115
  const hidden = new Set(hiddenSeries ?? internalHidden);
85
116
  const visible = series.filter((s) => !hidden.has(s.key));
86
117
  const [host, setHost] = React.useState(null);
118
+ const fontsReady = useFontReady(host, data.map((d) => d.label).join(''));
87
119
  const [floatHost, setFloatHost] = React.useState(null);
88
120
  const [dismissed, setDismissed] = React.useState(false);
89
121
  const firstLegend = React.useRef(null);
@@ -130,15 +162,17 @@ export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, de
130
162
  const values = rows
131
163
  .flatMap((row) => visible.map((s) => row.values[s.key]))
132
164
  .filter((value) => typeof value === 'number');
133
- // Bars grow from zero, so they always keep it on the axis. Without zero, the axis
165
+ // Bars grow from zero, so they always keep it on the axis. Either way the axis
134
166
  // spans the values, widened to round steps so its ticks read cleanly.
135
167
  const keepZero = includeZero || type === 'bar';
136
168
  const start = keepZero ? 0 : (values[0] ?? 0);
137
169
  const low = values.reduce((a, b) => Math.min(a, b), start), high = values.reduce((a, b) => Math.max(a, b), start);
138
- const step = keepZero ? 0 : roundStep((high - low) / 4);
170
+ const step = axisStep(low, high);
139
171
  const min = step ? Math.floor(low / step) * step : low, max = step ? Math.ceil(high / step) * step : high;
140
172
  const ticks = step
141
- ? Array.from({ length: Math.round((max - min) / step) + 1 }, (_, index) => min + index * step)
173
+ ? Array.from({ length: Math.round((max - min) / step) + 1 },
174
+ // Rounded, so float steps never print as 0.30000000000000004.
175
+ (_, index) => Number((min + index * step).toPrecision(12)))
142
176
  : undefined;
143
177
  const hasValues = values.length > 0;
144
178
  const changeHidden = (next) => {
@@ -150,23 +184,28 @@ export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, de
150
184
  .filter((s) => (s.key === key ? !hidden.has(key) : hidden.has(s.key)))
151
185
  .map((s) => s.key));
152
186
  const chartHeight = Number.isFinite(height) ? Math.max(200, height) : 280;
153
- return (_jsxs("figure", { ...props, ref: ref, className: cx('pui-chart', className), "aria-labelledby": `${id}-title`, children: [_jsxs("figcaption", { className: 'pui-chart-caption', children: [_jsx("strong", { id: `${id}-title`, children: title }), _jsx("p", { id: `${id}-summary`, children: description })] }), _jsxs("div", { className: 'pui-chart-frame', children: [_jsxs("div", { className: 'pui-chart-key', children: [_jsxs("p", { className: 'pui-chart-axis-label', children: [yLabel, " (", unit, ")"] }), _jsx("ul", { className: 'pui-chart-legend', "aria-label": `${title} series`, children: series.map((s, index) => (_jsx("li", { children: _jsxs("button", { ref: index === 0 ? firstLegend : undefined, type: 'button', className: 'pui-chart-legend-button', "aria-label": `${s.label} series`, "aria-pressed": !hidden.has(s.key), onClick: () => toggle(s.key), children: [_jsx(SeriesMark, { type: type, index: index, color: colorFor(index), pattern: `${id}-legend-${index}` }), _jsx("span", { children: s.label })] }) }, s.key))) })] }), hasValues ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: 'pui-chart-plot', onKeyDownCapture: (event) => {
187
+ return (_jsxs("figure", { ...props, ref: ref, className: cx('surf-chart', className), "aria-labelledby": `${id}-title`, children: [_jsxs("figcaption", { className: 'surf-chart-caption', children: [_jsx("strong", { id: `${id}-title`, children: title }), _jsx("p", { id: `${id}-summary`, children: description })] }), _jsxs("div", { className: 'surf-chart-frame', children: [_jsxs("div", { className: 'surf-chart-key', children: [_jsxs("p", { className: 'surf-chart-axis-label', children: [yLabel, " (", unit, ")"] }), _jsx("ul", { className: 'surf-chart-legend', "aria-label": text.legend(title), children: series.map((s, index) => (_jsx("li", { children: _jsxs("button", { ref: index === 0 ? firstLegend : undefined, type: 'button', className: 'surf-chart-legend-button', "aria-label": text.series(s.label), "aria-pressed": !hidden.has(s.key), onClick: () => toggle(s.key), children: [_jsx(SeriesMark, { type: type, index: index, color: colorFor(index), pattern: `${id}-legend-${index}` }), _jsx("span", { children: s.label })] }) }, s.key))) })] }), hasValues ? (_jsxs(_Fragment, { children: [_jsxs("div", { className: 'surf-chart-plot', onKeyDownCapture: (event) => {
154
188
  if (event.key === 'Escape')
155
189
  setDismissed(true);
156
190
  else if (event.key === 'ArrowLeft' ||
157
191
  event.key === 'ArrowRight')
158
192
  setDismissed(false);
159
- }, onMouseMoveCapture: () => setDismissed(false), onTouchStartCapture: () => setDismissed(false), onFocusCapture: () => setDismissed(false), children: [_jsx(ResponsiveContainer, { width: '100%', height: chartHeight, minWidth: 0, initialDimension: { width: 320, height: chartHeight }, children: _jsxs(ComposedChart, { data: rows, accessibilityLayer: true, role: 'application', "aria-label": title, "aria-describedby": `${id}-summary ${id}-keys`, margin: { top: 16, right: 20, bottom: 8, left: 0 }, children: [_jsx("defs", { children: series.map((s, index) => (_jsx(Pattern, { id: `${id}-pattern-${index}`, index: index, color: colorFor(index) }, s.key))) }), _jsx(CartesianGrid, { vertical: false, stroke: 'var(--line)' }), _jsx(XAxis, { dataKey: 'id', tickFormatter: (value) => {
193
+ }, onMouseMoveCapture: () => setDismissed(false), onTouchStartCapture: () => setDismissed(false), onFocusCapture: () => setDismissed(false), children: [_jsx(ResponsiveContainer, { width: '100%', height: chartHeight, minWidth: 0, initialDimension: { width: 320, height: chartHeight }, children: _jsxs(ComposedChart, { data: rows, accessibilityLayer: true, role: 'application', "aria-label": title, "aria-describedby": `${id}-summary ${id}-keys`, margin: { top: 16, right: 20, bottom: 8, left: 0 }, children: [_jsx("defs", { children: series.map((s, index) => (_jsx(Pattern, { id: `${id}-pattern-${index}`, index: index, color: colorFor(index) }, s.key))) }), _jsx(CartesianGrid, { vertical: false, stroke: 'var(--surf-line)' }), _jsx(XAxis, { dataKey: 'id', tickFormatter: (value) => {
160
194
  const label = byId.get(String(value))?.label ?? String(value);
161
195
  // minTickGap already drops ticks that would overlap; the cap
162
196
  // only keeps one very long label from crowding the axis.
163
197
  return label.length > 24
164
198
  ? label.slice(0, 23) + '…'
165
199
  : label;
166
- }, tick: { fill: 'var(--ink-muted)', fontSize: 12 }, tickLine: false, axisLine: { stroke: 'var(--line)' }, minTickGap: 24, interval: 'preserveStartEnd' }), _jsx(YAxis, { width: 56, tickFormatter: (value) => compact.format(Number(value)), tick: { fill: 'var(--ink-muted)', fontSize: 12 }, tickLine: false, axisLine: false, domain: [min, max === min ? max + 1 : max], ticks: ticks }), _jsx(ReferenceLine, { y: 0, stroke: 'var(--ink-muted)' }), host && (_jsx(Tooltip, { portal: host, isAnimationActive: false, active: dismissed ? false : undefined, filterNull: false, cursor: dismissed
200
+ }, tick: fontsReady && {
201
+ fill: 'var(--surf-ink-muted)',
202
+ fontSize: 12,
203
+ }, tickLine: false, axisLine: { stroke: 'var(--surf-line)' }, minTickGap: 24, interval: 'preserveStartEnd' }), _jsx(YAxis, { width: 56, tickFormatter: (value) => formatValue
204
+ ? formatValue(Number(value))
205
+ : compact.format(Number(value)), tick: { fill: 'var(--surf-ink-muted)', fontSize: 12 }, tickLine: false, axisLine: false, domain: [min, max === min ? max + 1 : max], ticks: ticks }), _jsx(ReferenceLine, { y: 0, stroke: 'var(--surf-ink-muted)' }), host && (_jsx(Tooltip, { portal: host, isAnimationActive: false, active: dismissed ? false : undefined, filterNull: false, cursor: dismissed
167
206
  ? false
168
207
  : {
169
- stroke: 'var(--control-border)',
208
+ stroke: 'var(--surf-control-border)',
170
209
  fill: 'transparent',
171
210
  }, wrapperStyle: {
172
211
  position: 'static',
@@ -176,7 +215,7 @@ export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, de
176
215
  const row = tooltip.active && !dismissed
177
216
  ? byId.get(String(tooltip.label))
178
217
  : undefined;
179
- return (_jsx("div", { className: 'pui-chart-readout', "data-chart-readout": row?.id, children: row ? (_jsxs(_Fragment, { children: [_jsx("strong", { children: row.label }), _jsx("ul", { children: visible.map((s) => (_jsxs("li", { children: [s.label, ": ", format(row.values[s.key])] }, s.key))) })] })) : (_jsx("span", { children: text.inspectHint })) }));
218
+ return (_jsx("div", { className: 'surf-chart-readout', "data-chart-readout": row?.id, children: row ? (_jsxs(_Fragment, { children: [_jsx("strong", { children: row.label }), _jsx("ul", { children: visible.map((s) => (_jsxs("li", { children: [s.label, ": ", format(row.values[s.key])] }, s.key))) })] })) : (_jsx("span", { children: text.inspectHint })) }));
180
219
  } })), series.map((s, index) => {
181
220
  const common = {
182
221
  name: s.label,
@@ -194,9 +233,9 @@ export const Chart = /* @__PURE__ */ React.forwardRef(function Chart({ title, de
194
233
  const row = byId.get(label);
195
234
  if (!row)
196
235
  return null;
197
- return (_jsxs(_Fragment, { children: [_jsx("strong", { children: row.label }), _jsx("ul", { children: series.map((s, index) => hidden.has(s.key) ? null : (_jsxs("li", { children: [_jsx(SeriesMark, { type: type, index: index, color: colorFor(index), pattern: `${id}-float-${index}` }), _jsx("span", { children: s.label }), _jsx("span", { className: 'pui-chart-tooltip-value', children: format(row.values[s.key]) })] }, s.key))) })] }));
198
- } })] }) }), _jsx("div", { className: 'pui-chart-float', ref: setFloatHost })] }), _jsx("p", { className: 'pui-chart-axis-label pui-chart-x-label', children: xLabel })] })) : (_jsx("div", { className: 'pui-chart-empty', role: 'status', children: visible.length === 0 && series.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("p", { children: text.noSeries }), _jsx(Button, { variant: 'outline', onClick: () => {
236
+ return (_jsxs(_Fragment, { children: [_jsx("strong", { children: row.label }), _jsx("ul", { children: series.map((s, index) => hidden.has(s.key) ? null : (_jsxs("li", { children: [_jsx(SeriesMark, { type: type, index: index, color: colorFor(index), pattern: `${id}-float-${index}` }), _jsx("span", { children: s.label }), _jsx("span", { className: 'surf-chart-tooltip-value', children: format(row.values[s.key]) })] }, s.key))) })] }));
237
+ } })] }) }), _jsx("div", { className: 'surf-chart-float', ref: setFloatHost })] }), _jsx("p", { className: 'surf-chart-axis-label surf-chart-x-label', children: xLabel })] })) : (_jsx("div", { className: 'surf-chart-empty', role: 'status', children: visible.length === 0 && series.length > 0 ? (_jsxs(_Fragment, { children: [_jsx("p", { children: text.noSeries }), _jsx(Button, { variant: 'outline', onClick: () => {
199
238
  setRestoreRequested(true);
200
239
  changeHidden([]);
201
- }, children: text.showAll })] })) : (_jsx("p", { children: text.empty })) }))] }), hasValues && (_jsx("p", { className: 'pui-chart-help', id: `${id}-keys`, children: text.keyboardHelp })), _jsx("div", { className: 'pui-chart-inspector', ref: setHost, role: 'status', "aria-live": 'polite', "aria-atomic": 'true', "aria-label": text.values(title), hidden: !hasValues }), _jsxs("details", { className: 'pui-chart-table', children: [_jsx("summary", { children: text.viewTable }), _jsx(Table.Container, { label: text.table(title), orientation: 'both', scrollChain: 'contain', children: _jsxs(Table.Root, { children: [_jsx(Table.Caption, { children: text.tableCaption(unit) }), _jsx(Table.Head, { children: _jsxs(Table.Row, { children: [_jsx(Table.HeaderCell, { scope: 'col', children: xLabel }), series.map((s) => (_jsxs(Table.HeaderCell, { scope: 'col', children: [s.label, " (", unit, ")"] }, s.key)))] }) }), _jsx(Table.Body, { children: rows.length ? (rows.map((row) => (_jsxs(Table.Row, { children: [_jsx(Table.HeaderCell, { scope: 'row', children: row.label }), series.map((s) => (_jsx(Table.Cell, { children: format(row.values[s.key]) }, s.key)))] }, row.id)))) : (_jsx(Table.Row, { children: _jsx(Table.Cell, { colSpan: series.length + 1, children: text.noRows }) })) })] }) })] })] }));
202
- });
240
+ }, children: text.showAll })] })) : (_jsx("p", { children: text.empty })) }))] }), hasValues && (_jsx("p", { className: 'surf-chart-help', id: `${id}-keys`, children: text.keyboardHelp })), _jsx("div", { className: 'surf-chart-inspector', ref: setHost, role: 'status', "aria-live": 'polite', "aria-atomic": 'true', "aria-label": text.values(title), hidden: !hasValues }), _jsxs("details", { className: 'surf-chart-table', children: [_jsx("summary", { children: text.viewTable }), _jsx(Table.Container, { label: text.table(title), orientation: 'both', scrollChain: 'contain', children: _jsxs(Table.Root, { children: [_jsx(Table.Caption, { children: text.tableCaption(unit) }), _jsx(Table.Head, { children: _jsxs(Table.Row, { children: [_jsx(Table.HeaderCell, { scope: 'col', children: xLabel }), series.map((s) => (_jsxs(Table.HeaderCell, { scope: 'col', children: [s.label, " (", unit, ")"] }, s.key)))] }) }), _jsx(Table.Body, { children: rows.length ? (rows.map((row) => (_jsxs(Table.Row, { children: [_jsx(Table.HeaderCell, { scope: 'row', children: row.label }), series.map((s) => (_jsx(Table.Cell, { children: format(row.values[s.key]) }, s.key)))] }, row.id)))) : (_jsx(Table.Row, { children: _jsx(Table.Cell, { colSpan: series.length + 1, children: text.noRows }) })) })] }) })] })] }));
241
+ };
@@ -1,2 +1,5 @@
1
1
  import * as React from 'react';
2
- export declare const CheckboxGroup: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/checkbox-group").CheckboxGroupProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
2
+ import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';
3
+ export declare const CheckboxGroup: ({ value, defaultValue, onValueChange, className, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCheckboxGroup> & {
4
+ ref?: React.Ref<React.ComponentRef<typeof BaseCheckboxGroup>>;
5
+ }) => React.JSX.Element;
@@ -1,16 +1,15 @@
1
1
  'use client';
2
2
  import { jsx as _jsx } from "react/jsx-runtime";
3
- import * as React from 'react';
4
3
  import { CheckboxGroup as BaseCheckboxGroup } from '@base-ui/react/checkbox-group';
5
4
  import { skin } from './parts.js';
6
5
  import { useRootRef, useResetValue } from './form-state.js';
7
6
  import { ChoiceResetPaint } from './choice.js';
8
- export const CheckboxGroup = /* @__PURE__ */ React.forwardRef(function CheckboxGroup({ value, defaultValue = [], onValueChange, className, ...props }, ref) {
7
+ export const CheckboxGroup = function CheckboxGroup({ value, defaultValue = [], onValueChange, className, ref, ...props }) {
9
8
  const [element, attach] = useRootRef(ref);
10
9
  const [selected, setSelected, revision] = useResetValue(value, defaultValue, element);
11
- return (_jsx(ChoiceResetPaint.Provider, { value: revision, children: _jsx(BaseCheckboxGroup, { ...props, ref: attach, value: selected, className: skin('pui-choice-group', className), onValueChange: (next, event) => {
10
+ return (_jsx(ChoiceResetPaint.Provider, { value: revision, children: _jsx(BaseCheckboxGroup, { ...props, ref: attach, value: selected, className: skin('surf-choice-group', className), onValueChange: (next, event) => {
12
11
  onValueChange?.(next, event);
13
12
  if (value === undefined && !event.isCanceled)
14
13
  setSelected(next);
15
14
  } }) }));
16
- });
15
+ };
@@ -1,9 +1,18 @@
1
1
  import * as React from 'react';
2
+ import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';
2
3
  import { type ChoiceSize } from './choice.js';
3
- declare const CheckboxRoot: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/checkbox").CheckboxRootProps, "ref"> & React.RefAttributes<HTMLElement>, "ref"> & ChoiceSize & React.RefAttributes<HTMLElement>>;
4
- declare const CheckboxIndicator: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/checkbox").CheckboxIndicatorProps, "ref"> & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
4
+ declare const CheckboxRoot: ({ size, checked, defaultChecked, onCheckedChange, className, form, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCheckbox.Root> & ChoiceSize & {
5
+ ref?: React.Ref<React.ComponentRef<typeof BaseCheckbox.Root>>;
6
+ }) => React.JSX.Element;
7
+ declare const CheckboxIndicator: ({ className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCheckbox.Indicator> & {
8
+ ref?: React.Ref<React.ComponentRef<typeof BaseCheckbox.Indicator>>;
9
+ }) => React.JSX.Element;
5
10
  export declare const Checkbox: {
6
- Root: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/checkbox").CheckboxRootProps, "ref"> & React.RefAttributes<HTMLElement>, "ref"> & ChoiceSize & React.RefAttributes<HTMLElement>>;
7
- Indicator: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/checkbox").CheckboxIndicatorProps, "ref"> & React.RefAttributes<HTMLSpanElement>, "ref"> & React.RefAttributes<HTMLSpanElement>>;
11
+ Root: ({ size, checked, defaultChecked, onCheckedChange, className, form, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCheckbox.Root> & ChoiceSize & {
12
+ ref?: React.Ref<React.ComponentRef<typeof BaseCheckbox.Root>>;
13
+ }) => React.JSX.Element;
14
+ Indicator: ({ className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCheckbox.Indicator> & {
15
+ ref?: React.Ref<React.ComponentRef<typeof BaseCheckbox.Indicator>>;
16
+ }) => React.JSX.Element;
8
17
  };
9
18
  export { CheckboxIndicator, CheckboxRoot };
package/dist/checkbox.js CHANGED
@@ -6,20 +6,20 @@ import { Checkbox as BaseCheckbox } from '@base-ui/react/checkbox';
6
6
  import { skin } from './parts.js';
7
7
  import { useRootRef, useResetValue } from './form-state.js';
8
8
  import { ChoiceResetPaint } from './choice.js';
9
- const CheckboxRoot = /* @__PURE__ */ React.forwardRef(function CheckboxRoot({ size, checked, defaultChecked = false, onCheckedChange, className, form, ...props }, ref) {
9
+ const CheckboxRoot = function CheckboxRoot({ size, checked, defaultChecked = false, onCheckedChange, className, form, ref, ...props }) {
10
10
  React.useContext(ChoiceResetPaint);
11
11
  const scheme = useComponentSize(size);
12
12
  const [element, attach] = useRootRef(ref);
13
13
  const [selected, setSelected] = useResetValue(checked, defaultChecked, element, form);
14
- return (_jsx(BaseCheckbox.Root, { ...props, "data-ui-size": size ? scheme : undefined, form: form, ref: attach, checked: selected, className: skin('pui-checkbox', className), onCheckedChange: (next, event) => {
14
+ return (_jsx(BaseCheckbox.Root, { ...props, "data-ui-size": size ? scheme : undefined, form: form, ref: attach, checked: selected, className: skin('surf-checkbox', className), onCheckedChange: (next, event) => {
15
15
  onCheckedChange?.(next, event);
16
16
  if (checked === undefined && !event.isCanceled)
17
17
  setSelected(next);
18
18
  } }));
19
- });
20
- const CheckboxIndicator = /* @__PURE__ */ React.forwardRef(function CheckboxIndicator({ className, children, ...props }, ref) {
21
- return (_jsx(BaseCheckbox.Indicator, { ...props, ref: ref, className: skin('pui-checkbox-indicator', className), children: children ?? (_jsxs("svg", { width: '14', height: '14', viewBox: '0 0 20 20', fill: 'none', stroke: 'currentColor', strokeWidth: '2', "aria-hidden": 'true', children: [_jsx("path", { className: 'pui-checkbox-check', d: 'm4 10 4 4 8-8' }), _jsx("path", { className: 'pui-checkbox-mixed', d: 'M4 10h12' })] })) }));
22
- });
19
+ };
20
+ const CheckboxIndicator = function CheckboxIndicator({ className, children, ref, ...props }) {
21
+ return (_jsx(BaseCheckbox.Indicator, { ...props, ref: ref, className: skin('surf-checkbox-indicator', className), children: children ?? (_jsxs("svg", { width: '14', height: '14', viewBox: '0 0 20 20', fill: 'none', stroke: 'currentColor', strokeWidth: '2', "aria-hidden": 'true', children: [_jsx("path", { className: 'surf-checkbox-check', d: 'm4 10 4 4 8-8' }), _jsx("path", { className: 'surf-checkbox-mixed', d: 'M4 10h12' })] })) }));
22
+ };
23
23
  export const Checkbox = {
24
24
  ...BaseCheckbox,
25
25
  Root: CheckboxRoot,
@@ -12,14 +12,6 @@ export type ChoiceLabelProps = Omit<React.ComponentPropsWithoutRef<'label'>, 'ch
12
12
  };
13
13
  /** A checkbox, radio or switch with its label, and an optional description below it.
14
14
  * The whole label toggles the control; the control sits on the first line. */
15
- export declare const ChoiceLabel: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.LabelHTMLAttributes<HTMLLabelElement>, HTMLLabelElement>, "ref">, "children"> & {
16
- /** The Checkbox, Radio or Switch the label names. */
17
- control: React.ReactElement<{
18
- "aria-labelledby"?: string;
19
- "aria-describedby"?: string;
20
- }>;
21
- /** The label text; it alone names the control. */
22
- children: React.ReactNode;
23
- /** A longer explanation, read as the control's description. */
24
- description?: React.ReactNode;
25
- } & React.RefAttributes<HTMLLabelElement>>;
15
+ export declare const ChoiceLabel: ({ control, children, description, className, ref, ...props }: ChoiceLabelProps & {
16
+ ref?: React.Ref<HTMLLabelElement>;
17
+ }) => React.JSX.Element;
@@ -4,11 +4,11 @@ import * as React from 'react';
4
4
  import { cx } from './parts.js';
5
5
  /** A checkbox, radio or switch with its label, and an optional description below it.
6
6
  * The whole label toggles the control; the control sits on the first line. */
7
- export const ChoiceLabel = /* @__PURE__ */ React.forwardRef(function ChoiceLabel({ control, children, description, className, ...props }, ref) {
7
+ export const ChoiceLabel = function ChoiceLabel({ control, children, description, className, ref, ...props }) {
8
8
  const id = React.useId();
9
- return (_jsxs("label", { ...props, ref: ref, className: cx('pui-choice-label', className), children: [_jsx("span", { className: 'pui-choice-control', children: React.cloneElement(control, {
9
+ return (_jsxs("label", { ...props, ref: ref, className: cx('surf-choice-label', className), children: [_jsx("span", { className: 'surf-choice-control', children: React.cloneElement(control, {
10
10
  'aria-labelledby': control.props['aria-labelledby'] ?? `${id}-label`,
11
11
  'aria-describedby': control.props['aria-describedby'] ??
12
12
  (description ? `${id}-description` : undefined),
13
- }) }), _jsxs("span", { className: 'pui-choice-text', children: [_jsx("span", { id: `${id}-label`, children: children }), description && (_jsx("span", { className: 'pui-choice-description', id: `${id}-description`, children: description }))] })] }));
14
- });
13
+ }) }), _jsxs("span", { className: 'surf-choice-text', children: [_jsx("span", { id: `${id}-label`, children: children }), description && (_jsx("span", { className: 'surf-choice-description', id: `${id}-description`, children: description }))] })] }));
14
+ };
@@ -0,0 +1,6 @@
1
+ /** Joins class names, skipping empty ones. */
2
+ export declare function cx(...classes: (string | false | null | undefined)[]): string;
3
+ /** The data-size value: a deprecated short spelling (sm, md, lg, icon-sm, icon-xs,
4
+ * icon-lg) renders as its full name, so both spellings meet the same CSS; other values
5
+ * such as xs or icon pass through. */
6
+ export declare function sizeName<Size extends string>(size?: Size): import("./size.js").ComponentSize | Size | "icon-small" | "icon-large" | undefined;
@@ -0,0 +1,18 @@
1
+ // Class and data attribute helpers, with no React: server components use them too.
2
+ import { normalizeSize } from './size.js';
3
+ /** Joins class names, skipping empty ones. */
4
+ export function cx(...classes) {
5
+ return classes.filter(Boolean).join(' ');
6
+ }
7
+ /** The data-size value: a deprecated short spelling (sm, md, lg, icon-sm, icon-xs,
8
+ * icon-lg) renders as its full name, so both spellings meet the same CSS; other values
9
+ * such as xs or icon pass through. */
10
+ export function sizeName(size) {
11
+ return size === 'sm' || size === 'md' || size === 'lg'
12
+ ? normalizeSize(size)
13
+ : size === 'icon-sm' || size === 'icon-xs'
14
+ ? 'icon-small'
15
+ : size === 'icon-lg'
16
+ ? 'icon-large'
17
+ : size;
18
+ }
package/dist/code.d.ts CHANGED
@@ -4,18 +4,21 @@ export type CodeBlockProps = Omit<React.ComponentPropsWithoutRef<'div'>, 'childr
4
4
  label?: string;
5
5
  language?: string;
6
6
  wrap?: boolean;
7
+ /** The copy button's text: the action, then the result. */
8
+ labels?: Partial<CodeBlockLabels>;
9
+ /** @deprecated Use `labels.copy`. Removed in a later minor. */
7
10
  copyLabel?: string;
11
+ /** @deprecated Use `labels.copied`. Removed in a later minor. */
8
12
  copiedLabel?: string;
13
+ /** @deprecated Use `labels.copyError`. Removed in a later minor. */
9
14
  copyErrorLabel?: string;
10
15
  onCopy?: (code: string) => void | Promise<void>;
11
16
  };
12
- export declare const CodeBlock: React.ForwardRefExoticComponent<Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, "children" | "onCopy"> & {
13
- code: string;
14
- label?: string;
15
- language?: string;
16
- wrap?: boolean;
17
- copyLabel?: string;
18
- copiedLabel?: string;
19
- copyErrorLabel?: string;
20
- onCopy?: (code: string) => void | Promise<void>;
21
- } & React.RefAttributes<HTMLDivElement>>;
17
+ export type CodeBlockLabels = {
18
+ copy: string;
19
+ copied: string;
20
+ copyError: string;
21
+ };
22
+ export declare const CodeBlock: ({ code, label, language, wrap, labels, copyLabel: legacyCopyLabel, copiedLabel: legacyCopiedLabel, copyErrorLabel: legacyCopyErrorLabel, onCopy, className, ref, ...props }: CodeBlockProps & {
23
+ ref?: React.Ref<HTMLDivElement>;
24
+ }) => React.JSX.Element;
package/dist/code.js CHANGED
@@ -9,7 +9,10 @@ import { ScrollArea } from './scroll-area.js';
9
9
  const copyIcons = { idle: 'copy', copied: 'check', failed: 'alert' };
10
10
  // Feedback stays inside the copy button and returns to the action after this long.
11
11
  const copyFeedbackDuration = 2000;
12
- export const CodeBlock = /* @__PURE__ */ React.forwardRef(function CodeBlock({ code, label = 'Code', language, wrap = false, copyLabel = 'Copy code', copiedLabel = 'Copied', copyErrorLabel = 'Copy unavailable', onCopy, className, ...props }, ref) {
12
+ export const CodeBlock = function CodeBlock({ code, label = 'Code', language, wrap = false, labels, copyLabel: legacyCopyLabel, copiedLabel: legacyCopiedLabel, copyErrorLabel: legacyCopyErrorLabel, onCopy, className, ref, ...props }) {
13
+ const copyLabel = labels?.copy ?? legacyCopyLabel ?? 'Copy code';
14
+ const copiedLabel = labels?.copied ?? legacyCopiedLabel ?? 'Copied';
15
+ const copyErrorLabel = labels?.copyError ?? legacyCopyErrorLabel ?? 'Copy unavailable';
13
16
  const [state, setState] = React.useState('idle');
14
17
  // After the first copy, each change of label fades in; the first render does not.
15
18
  const [used, setUsed] = React.useState(false);
@@ -74,11 +77,11 @@ export const CodeBlock = /* @__PURE__ */ React.forwardRef(function CodeBlock({ c
74
77
  }, copyFeedbackDuration);
75
78
  }
76
79
  const icon = state === 'copied' || state === 'failed' ? state : 'idle';
77
- return (_jsxs("div", { ...props, ref: ref, "data-wrap": wrap || undefined, className: cx('pui-code-block', className), children: [_jsxs("div", { className: 'pui-code-toolbar', children: [_jsxs("span", { className: 'pui-code-label', children: [label, language && _jsx("span", { className: 'pui-code-language', children: language })] }), _jsxs(Button, { ref: button, type: 'button', variant: 'outline', size: 'sm', className: 'pui-code-copy', onClick: copy,
80
+ return (_jsxs("div", { ...props, ref: ref, "data-wrap": wrap || undefined, className: cx('surf-code-block', className), children: [_jsxs("div", { className: 'surf-code-toolbar', children: [_jsxs("span", { className: 'surf-code-label', children: [label, language && _jsx("span", { className: 'surf-code-language', children: language })] }), _jsxs(Button, { ref: button, type: 'button', variant: 'outline', size: 'small', className: 'surf-code-copy', onClick: copy,
78
81
  // A pending copy blocks a second start but keeps focus on the button.
79
- disabled: state === 'busy', focusableWhenDisabled: true, "aria-busy": state === 'busy' || undefined, "data-copy-state": icon === 'idle' ? undefined : icon, "data-copy-used": used || undefined, children: [_jsx(Icon, { name: copyIcons[icon], className: 'pui-code-copy-icon' }, icon), _jsx("span", { "aria-live": 'polite', children: _jsx("span", { className: 'pui-code-copy-label', children: state === 'copied'
82
+ disabled: state === 'busy', focusableWhenDisabled: true, "aria-busy": state === 'busy' || undefined, "data-copy-state": icon === 'idle' ? undefined : icon, "data-copy-used": used || undefined, children: [_jsx(Icon, { name: copyIcons[icon], className: 'surf-code-copy-icon' }, icon), _jsx("span", { "aria-live": 'polite', children: _jsx("span", { className: 'surf-code-copy-label', children: state === 'copied'
80
83
  ? copiedLabel
81
84
  : state === 'failed'
82
85
  ? copyErrorLabel
83
- : copyLabel }, icon) })] })] }), _jsx(ScrollArea, { label: label, orientation: 'horizontal', children: _jsx("pre", { ref: source, className: 'pui-code-text', children: _jsx(SyntaxHighlighter, { code: code, language: language, inline: true }) }) })] }));
84
- });
86
+ : copyLabel }, icon) })] })] }), _jsx(ScrollArea, { label: label, orientation: 'horizontal', children: _jsx("pre", { ref: source, className: 'surf-code-text', children: _jsx(SyntaxHighlighter, { code: code, language: language, inline: true }) }) })] }));
87
+ };
@@ -1,18 +1,31 @@
1
1
  import * as React from 'react';
2
- declare const CollapsibleTrigger: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/collapsible").CollapsibleTriggerProps, "ref"> & React.RefAttributes<HTMLButtonElement>, "ref"> & {
2
+ import { Collapsible as BaseCollapsible } from '@base-ui/react/collapsible';
3
+ declare const CollapsibleTrigger: ({ className, children, indicator, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCollapsible.Trigger> & {
3
4
  indicator?: React.ReactNode;
4
- } & React.RefAttributes<HTMLButtonElement>>;
5
- declare const CollapsiblePanel: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/collapsible").CollapsiblePanelProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
5
+ } & {
6
+ ref?: React.Ref<React.ComponentRef<typeof BaseCollapsible.Trigger>>;
7
+ }) => React.JSX.Element;
8
+ declare const CollapsiblePanel: ({ className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCollapsible.Panel> & {
9
+ ref?: React.Ref<React.ComponentRef<typeof BaseCollapsible.Panel>>;
10
+ }) => React.JSX.Element;
6
11
  export declare const Collapsible: {
7
- Root: React.ForwardRefExoticComponent<Omit<Omit<Omit<import("@base-ui/react/collapsible").CollapsibleRootProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref">, "size"> & {
8
- size?: import("./sizing.js").ComponentSize;
9
- } & React.RefAttributes<HTMLDivElement>>;
10
- Trigger: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/collapsible").CollapsibleTriggerProps, "ref"> & React.RefAttributes<HTMLButtonElement>, "ref"> & {
12
+ Root: ({ ref, ...props }: Omit<Omit<Omit<import("@base-ui/react/collapsible").CollapsibleRootProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref">, "size"> & {
13
+ size?: import("./size.js").ComponentSize;
14
+ } & {
15
+ ref?: React.Ref<HTMLDivElement> | undefined;
16
+ }) => React.JSX.Element;
17
+ Trigger: ({ className, children, indicator, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCollapsible.Trigger> & {
11
18
  indicator?: React.ReactNode;
12
- } & React.RefAttributes<HTMLButtonElement>>;
13
- Panel: React.ForwardRefExoticComponent<Omit<Omit<import("@base-ui/react/collapsible").CollapsiblePanelProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref"> & React.RefAttributes<HTMLDivElement>>;
19
+ } & {
20
+ ref?: React.Ref<React.ComponentRef<typeof BaseCollapsible.Trigger>>;
21
+ }) => React.JSX.Element;
22
+ Panel: ({ className, children, ref, ...props }: React.ComponentPropsWithoutRef<typeof BaseCollapsible.Panel> & {
23
+ ref?: React.Ref<React.ComponentRef<typeof BaseCollapsible.Panel>>;
24
+ }) => React.JSX.Element;
14
25
  };
15
26
  export { CollapsiblePanel, CollapsibleTrigger };
16
- export declare const CollapsibleRoot: React.ForwardRefExoticComponent<Omit<Omit<Omit<import("@base-ui/react/collapsible").CollapsibleRootProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref">, "size"> & {
17
- size?: import("./sizing.js").ComponentSize;
18
- } & React.RefAttributes<HTMLDivElement>>;
27
+ export declare const CollapsibleRoot: ({ ref, ...props }: Omit<Omit<Omit<import("@base-ui/react/collapsible").CollapsibleRootProps, "ref"> & React.RefAttributes<HTMLDivElement>, "ref">, "size"> & {
28
+ size?: import("./size.js").ComponentSize;
29
+ } & {
30
+ ref?: React.Ref<HTMLDivElement> | undefined;
31
+ }) => React.JSX.Element;
@@ -1,18 +1,17 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
- import * as React from 'react';
4
3
  import { Collapsible as BaseCollapsible } from '@base-ui/react/collapsible';
5
4
  import { Icon } from './icon.js';
6
5
  import { skin, part } from './parts.js';
7
- const CollapsibleTrigger = /* @__PURE__ */ React.forwardRef(function CollapsibleTrigger({ className, children, indicator, ...props }, ref) {
8
- return (_jsxs(BaseCollapsible.Trigger, { ...props, ref: ref, className: skin('pui-disclosure-trigger', className), children: [_jsx("span", { className: 'pui-disclosure-label', children: children }), indicator === undefined ? (_jsx(Icon, { name: 'chevron-forward', className: 'pui-disclosure-chevron' })) : (indicator)] }));
9
- });
10
- const CollapsiblePanel = /* @__PURE__ */ React.forwardRef(function CollapsiblePanel({ className, children, ...props }, ref) {
11
- return (_jsx(BaseCollapsible.Panel, { ...props, ref: ref, className: skin('pui-collapsible-panel', className), children: _jsx("div", { className: 'pui-disclosure-body', children: children }) }));
12
- });
6
+ const CollapsibleTrigger = function CollapsibleTrigger({ className, children, indicator, ref, ...props }) {
7
+ return (_jsxs(BaseCollapsible.Trigger, { ...props, ref: ref, className: skin('surf-disclosure-trigger', className), children: [_jsx("span", { className: 'surf-disclosure-label', children: children }), indicator === undefined ? (_jsx(Icon, { name: 'chevron-forward', className: 'surf-disclosure-chevron' })) : (indicator)] }));
8
+ };
9
+ const CollapsiblePanel = function CollapsiblePanel({ className, children, ref, ...props }) {
10
+ return (_jsx(BaseCollapsible.Panel, { ...props, ref: ref, className: skin('surf-collapsible-panel', className), children: _jsx("div", { className: 'surf-disclosure-body', children: children }) }));
11
+ };
13
12
  export const Collapsible = {
14
13
  ...BaseCollapsible,
15
- Root: /* @__PURE__ */ part(BaseCollapsible.Root, 'pui-collapsible'),
14
+ Root: /* @__PURE__ */ part(BaseCollapsible.Root, 'surf-collapsible'),
16
15
  Trigger: CollapsibleTrigger,
17
16
  Panel: CollapsiblePanel,
18
17
  };