@acronis-platform/ui-react 0.58.0 → 0.60.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 (73) hide show
  1. package/dist/components/ui/area-chart/area-chart.js +91 -63
  2. package/dist/components/ui/area-chart/area-chart.js.map +1 -1
  3. package/dist/components/ui/bar-chart/bar-chart.js +104 -73
  4. package/dist/components/ui/bar-chart/bar-chart.js.map +1 -1
  5. package/dist/components/ui/calendar/calendar.js +17 -15
  6. package/dist/components/ui/calendar/calendar.js.map +1 -1
  7. package/dist/components/ui/carousel-dialog/carousel-dialog.js +87 -0
  8. package/dist/components/ui/carousel-dialog/carousel-dialog.js.map +1 -0
  9. package/dist/components/ui/category-bar/category-bar.js +126 -0
  10. package/dist/components/ui/category-bar/category-bar.js.map +1 -0
  11. package/dist/components/ui/chart/chart-format.js +40 -0
  12. package/dist/components/ui/chart/chart-format.js.map +1 -0
  13. package/dist/components/ui/chart/chart.js.map +1 -1
  14. package/dist/components/ui/composed-chart/composed-chart.js +91 -63
  15. package/dist/components/ui/composed-chart/composed-chart.js.map +1 -1
  16. package/dist/components/ui/confidence-cone/confidence-cone.js +113 -85
  17. package/dist/components/ui/confidence-cone/confidence-cone.js.map +1 -1
  18. package/dist/components/ui/dialog/dialog.js +29 -29
  19. package/dist/components/ui/dialog/dialog.js.map +1 -1
  20. package/dist/components/ui/dialog-footer-carousel/dialog-footer-carousel.js +57 -0
  21. package/dist/components/ui/dialog-footer-carousel/dialog-footer-carousel.js.map +1 -0
  22. package/dist/components/ui/dialog-footer-default/dialog-footer-default.js +1 -1
  23. package/dist/components/ui/dialog-footer-default/dialog-footer-default.js.map +1 -1
  24. package/dist/components/ui/dialog-welcome/dialog-welcome.js +272 -0
  25. package/dist/components/ui/dialog-welcome/dialog-welcome.js.map +1 -0
  26. package/dist/components/ui/histogram/histogram.js +89 -61
  27. package/dist/components/ui/histogram/histogram.js.map +1 -1
  28. package/dist/components/ui/input/input.js.map +1 -1
  29. package/dist/components/ui/line-chart/line-chart.js +120 -92
  30. package/dist/components/ui/line-chart/line-chart.js.map +1 -1
  31. package/dist/components/ui/sankey-chart/sankey-chart.js +192 -0
  32. package/dist/components/ui/sankey-chart/sankey-chart.js.map +1 -0
  33. package/dist/components/ui/scatter-chart/scatter-chart.js +79 -51
  34. package/dist/components/ui/scatter-chart/scatter-chart.js.map +1 -1
  35. package/dist/components/ui/toolbar/toolbar.js +82 -92
  36. package/dist/components/ui/toolbar/toolbar.js.map +1 -1
  37. package/dist/index.js +461 -439
  38. package/dist/index.js.map +1 -1
  39. package/dist/lib/breakpoints.js +9 -6
  40. package/dist/lib/breakpoints.js.map +1 -1
  41. package/dist/node_modules/.pnpm/embla-carousel-react@8.6.0_react@19.2.6/node_modules/embla-carousel-react/esm/embla-carousel-react.esm.js +25 -0
  42. package/dist/node_modules/.pnpm/embla-carousel-react@8.6.0_react@19.2.6/node_modules/embla-carousel-react/esm/embla-carousel-react.esm.js.map +1 -0
  43. package/dist/node_modules/.pnpm/embla-carousel-reactive-utils@8.6.0_embla-carousel@8.6.0/node_modules/embla-carousel-reactive-utils/esm/embla-carousel-reactive-utils.esm.js +36 -0
  44. package/dist/node_modules/.pnpm/embla-carousel-reactive-utils@8.6.0_embla-carousel@8.6.0/node_modules/embla-carousel-reactive-utils/esm/embla-carousel-reactive-utils.esm.js.map +1 -0
  45. package/dist/node_modules/.pnpm/embla-carousel@8.6.0/node_modules/embla-carousel/esm/embla-carousel.esm.js +1205 -0
  46. package/dist/node_modules/.pnpm/embla-carousel@8.6.0/node_modules/embla-carousel/esm/embla-carousel.esm.js.map +1 -0
  47. package/dist/react.js +461 -439
  48. package/dist/react.js.map +1 -1
  49. package/dist/src/components/ui/area-chart/area-chart.d.ts +2 -17
  50. package/dist/src/components/ui/bar-chart/bar-chart.d.ts +2 -17
  51. package/dist/src/components/ui/carousel-dialog/carousel-dialog.d.ts +28 -0
  52. package/dist/src/components/ui/carousel-dialog/index.d.ts +1 -0
  53. package/dist/src/components/ui/category-bar/category-bar.d.ts +51 -0
  54. package/dist/src/components/ui/category-bar/index.d.ts +1 -0
  55. package/dist/src/components/ui/chart/__tests__/chart-format.test.d.ts +1 -0
  56. package/dist/src/components/ui/chart/chart-format.d.ts +111 -0
  57. package/dist/src/components/ui/chart/chart.d.ts +2 -0
  58. package/dist/src/components/ui/chart/index.d.ts +3 -1
  59. package/dist/src/components/ui/composed-chart/composed-chart.d.ts +2 -17
  60. package/dist/src/components/ui/confidence-cone/confidence-cone.d.ts +2 -19
  61. package/dist/src/components/ui/dialog-footer-carousel/dialog-footer-carousel.d.ts +9 -0
  62. package/dist/src/components/ui/dialog-footer-carousel/index.d.ts +1 -0
  63. package/dist/src/components/ui/dialog-welcome/dialog-welcome.d.ts +54 -0
  64. package/dist/src/components/ui/dialog-welcome/dialog-welcome.docs.d.ts +55 -0
  65. package/dist/src/components/ui/dialog-welcome/index.d.ts +1 -0
  66. package/dist/src/components/ui/histogram/histogram.d.ts +2 -17
  67. package/dist/src/components/ui/line-chart/line-chart.d.ts +2 -17
  68. package/dist/src/components/ui/sankey-chart/index.d.ts +2 -0
  69. package/dist/src/components/ui/sankey-chart/sankey-chart.d.ts +69 -0
  70. package/dist/src/components/ui/scatter-chart/scatter-chart.d.ts +2 -17
  71. package/dist/src/index.d.ts +5 -0
  72. package/dist/ui-react.css +1 -1
  73. package/package.json +5 -4
@@ -0,0 +1,272 @@
1
+ import { jsx as e, jsxs as w, Fragment as L } from "react/jsx-runtime";
2
+ import * as c from "react";
3
+ import U from "../../../node_modules/.pnpm/embla-carousel-react@8.6.0_react@19.2.6/node_modules/embla-carousel-react/esm/embla-carousel-react.esm.js";
4
+ import { cn as _ } from "../../../lib/utils.js";
5
+ import { useDocDir as q } from "../../../lib/use-doc-dir.js";
6
+ import { DialogRoot as G, DialogContent as H, DialogClose as J, DialogTitle as K, DialogDescription as O } from "../dialog/dialog.js";
7
+ import { DialogFooterCarousel as Q } from "../dialog-footer-carousel/dialog-footer-carousel.js";
8
+ import { Button as M } from "../button/button.js";
9
+ function F({
10
+ image: s,
11
+ title: l,
12
+ description: r,
13
+ active: a,
14
+ withBottomPadding: i = !0
15
+ }) {
16
+ return /* @__PURE__ */ w(
17
+ "div",
18
+ {
19
+ className: _(
20
+ "flex w-full flex-col items-center gap-3 pt-4",
21
+ i && "pb-4"
22
+ ),
23
+ children: [
24
+ /* @__PURE__ */ e("div", { className: "w-full overflow-hidden rounded-lg px-4", children: /* @__PURE__ */ e("div", { className: "flex h-[272px] w-full items-center justify-center rounded bg-[var(--ui-background-surface-active)]", children: s }) }),
25
+ /* @__PURE__ */ w("div", { className: "flex w-full flex-col items-center gap-1 px-4 text-center", children: [
26
+ a ? /* @__PURE__ */ e(K, { className: "w-full flex-none text-center", children: l }) : /* @__PURE__ */ e("p", { className: "w-full text-2xl font-normal leading-8 text-foreground", children: l }),
27
+ a ? /* @__PURE__ */ e(O, { className: "w-full flex-none text-center text-sm leading-6 text-foreground", children: r }) : /* @__PURE__ */ e("p", { className: "w-full text-sm leading-6 text-foreground", children: r })
28
+ ] })
29
+ ]
30
+ }
31
+ );
32
+ }
33
+ const E = [
34
+ { title: "Title", description: "Feature description." },
35
+ { title: "Title", description: "Feature description." },
36
+ { title: "Title", description: "Feature description." }
37
+ ];
38
+ function X({
39
+ slideCount: s,
40
+ selectedIndexProp: l,
41
+ onSelectedIndexChange: r
42
+ }) {
43
+ const a = q(), i = l !== void 0, d = Math.min(
44
+ Math.max(l ?? 0, 0),
45
+ Math.max(s - 1, 0)
46
+ ), [p, t] = U({
47
+ loop: !1,
48
+ direction: a,
49
+ startIndex: d
50
+ }), [v, N] = c.useState(0), o = Math.min(
51
+ Math.max(l ?? v, 0),
52
+ Math.max(s - 1, 0)
53
+ ), f = c.useRef(r);
54
+ c.useEffect(() => {
55
+ f.current = r;
56
+ }, [r]);
57
+ const m = c.useRef(i);
58
+ m.current = i;
59
+ const n = c.useRef(o);
60
+ n.current = o, c.useEffect(() => {
61
+ if (!t) return;
62
+ const u = () => {
63
+ var x;
64
+ const h = t.selectedScrollSnap();
65
+ if (m.current) {
66
+ if (!f.current) {
67
+ h !== n.current && t.scrollTo(n.current, !0);
68
+ return;
69
+ }
70
+ h !== n.current && f.current(h);
71
+ return;
72
+ }
73
+ N(h), (x = f.current) == null || x.call(f, h);
74
+ };
75
+ return u(), t.on("select", u), t.on("reInit", u), () => {
76
+ t.off("select", u), t.off("reInit", u);
77
+ };
78
+ }, [t]), c.useEffect(() => {
79
+ l === void 0 || !t || t.selectedScrollSnap() !== o && t.scrollTo(o, !0);
80
+ }, [t, l, o]);
81
+ const D = c.useRef(!0);
82
+ c.useEffect(() => {
83
+ if (t) {
84
+ if (D.current) {
85
+ D.current = !1;
86
+ return;
87
+ }
88
+ t.reInit({ direction: a });
89
+ }
90
+ }, [t, a]);
91
+ const R = c.useCallback(
92
+ (u) => {
93
+ i ? r == null || r(u) : t == null || t.scrollTo(u);
94
+ },
95
+ [i, t, r]
96
+ ), g = c.useCallback(() => {
97
+ i ? r == null || r(Math.max(o - 1, 0)) : t == null || t.scrollPrev();
98
+ }, [i, t, r, o]), k = c.useCallback(() => {
99
+ i ? r == null || r(Math.min(o + 1, s - 1)) : t == null || t.scrollNext();
100
+ }, [i, t, r, o, s]), T = o === s - 1 ? "end" : o === 0 ? "start" : "middle";
101
+ return {
102
+ emblaRef: p,
103
+ selectedIndex: o,
104
+ handleSelectIndex: R,
105
+ handleBack: g,
106
+ handleNext: k,
107
+ footerVariant: T
108
+ };
109
+ }
110
+ function Y({
111
+ slides: s,
112
+ selectedIndex: l,
113
+ emblaRef: r,
114
+ footerVariant: a,
115
+ onSelectIndex: i,
116
+ onBack: d,
117
+ onNext: p,
118
+ onPrimaryAction: t,
119
+ backLabel: v,
120
+ nextLabel: N,
121
+ primaryLabel: o,
122
+ goToSlideLabel: f
123
+ }) {
124
+ return /* @__PURE__ */ w(L, { children: [
125
+ /* @__PURE__ */ e("div", { ref: r, className: "w-full overflow-hidden", children: /* @__PURE__ */ e("div", { className: "flex", children: s.map((m, n) => /* @__PURE__ */ e(
126
+ "div",
127
+ {
128
+ className: "min-w-0 shrink-0 grow-0 basis-full",
129
+ "aria-hidden": n !== l || void 0,
130
+ inert: n !== l,
131
+ children: /* @__PURE__ */ e(
132
+ F,
133
+ {
134
+ image: m.image,
135
+ title: m.title,
136
+ description: m.description,
137
+ active: n === l
138
+ }
139
+ )
140
+ },
141
+ n
142
+ )) }) }),
143
+ /* @__PURE__ */ e(
144
+ Q,
145
+ {
146
+ variant: a,
147
+ slideCount: s.length,
148
+ selectedIndex: l,
149
+ onSelectIndex: i,
150
+ onBack: d,
151
+ onNext: p,
152
+ onPrimaryAction: t,
153
+ backLabel: v,
154
+ nextLabel: N,
155
+ primaryLabel: o,
156
+ goToSlideLabel: f
157
+ }
158
+ )
159
+ ] });
160
+ }
161
+ function Z({
162
+ image: s,
163
+ title: l,
164
+ description: r,
165
+ primaryLabel: a,
166
+ onPrimaryAction: i,
167
+ closeLabel: d,
168
+ onCloseAction: p
169
+ }) {
170
+ return /* @__PURE__ */ w("div", { className: "flex w-full flex-col items-center gap-3 pb-4", children: [
171
+ /* @__PURE__ */ e(
172
+ F,
173
+ {
174
+ image: s,
175
+ title: l,
176
+ description: r,
177
+ active: !0,
178
+ withBottomPadding: !1
179
+ }
180
+ ),
181
+ /* @__PURE__ */ w("div", { className: "flex w-full flex-col items-center gap-2 px-4", children: [
182
+ /* @__PURE__ */ e(M, { onClick: i, children: a ?? "Call to action" }),
183
+ /* @__PURE__ */ e(
184
+ J,
185
+ {
186
+ onClick: p,
187
+ render: /* @__PURE__ */ e(M, { variant: "ghost", children: d })
188
+ }
189
+ )
190
+ ] })
191
+ ] });
192
+ }
193
+ const $ = c.forwardRef(
194
+ ({
195
+ variant: s = "carousel",
196
+ slides: l = E,
197
+ selectedIndex: r,
198
+ onSelectedIndexChange: a,
199
+ backLabel: i,
200
+ nextLabel: d,
201
+ goToSlideLabel: p,
202
+ image: t,
203
+ title: v = "Title",
204
+ description: N = "Feature description.",
205
+ closeLabel: o = "Close",
206
+ onCloseAction: f,
207
+ primaryLabel: m,
208
+ onPrimaryAction: n,
209
+ portal: D,
210
+ portalContainer: R,
211
+ keepMounted: g,
212
+ className: k,
213
+ ...T
214
+ }, u) => {
215
+ const h = s === "carousel", x = l.length > 0 ? l : E, B = x.length, {
216
+ emblaRef: b,
217
+ selectedIndex: W,
218
+ handleSelectIndex: j,
219
+ handleBack: V,
220
+ handleNext: y,
221
+ footerVariant: z
222
+ } = X({
223
+ slideCount: B,
224
+ selectedIndexProp: r,
225
+ onSelectedIndexChange: a
226
+ });
227
+ return /* @__PURE__ */ e(G, { ...T, children: /* @__PURE__ */ e(
228
+ H,
229
+ {
230
+ ref: u,
231
+ size: "sm",
232
+ portal: D,
233
+ portalContainer: R,
234
+ keepMounted: g,
235
+ className: k,
236
+ children: h ? /* @__PURE__ */ e(
237
+ Y,
238
+ {
239
+ slides: x,
240
+ selectedIndex: W,
241
+ emblaRef: b,
242
+ footerVariant: z,
243
+ onSelectIndex: j,
244
+ onBack: V,
245
+ onNext: y,
246
+ onPrimaryAction: n,
247
+ backLabel: i,
248
+ nextLabel: d,
249
+ primaryLabel: m,
250
+ goToSlideLabel: p
251
+ }
252
+ ) : /* @__PURE__ */ e(
253
+ Z,
254
+ {
255
+ image: t,
256
+ title: v,
257
+ description: N,
258
+ primaryLabel: m,
259
+ onPrimaryAction: n,
260
+ closeLabel: o,
261
+ onCloseAction: f
262
+ }
263
+ )
264
+ }
265
+ ) });
266
+ }
267
+ );
268
+ $.displayName = "DialogWelcome";
269
+ export {
270
+ $ as DialogWelcome
271
+ };
272
+ //# sourceMappingURL=dialog-welcome.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialog-welcome.js","sources":["../../../../src/components/ui/dialog-welcome/dialog-welcome.tsx"],"sourcesContent":["import * as React from 'react';\nimport useEmblaCarousel from 'embla-carousel-react';\n\nimport { cn } from '@/lib/utils';\nimport { useDocDir } from '@/lib/use-doc-dir';\n\nimport { Button } from '../button';\nimport {\n DialogClose,\n DialogContent,\n type DialogContentProps,\n DialogDescription,\n DialogRoot,\n DialogTitle,\n} from '../dialog';\nimport {\n DialogFooterCarousel,\n type DialogFooterCarouselVariant,\n} from '../dialog-footer-carousel';\n\n// Ports Figma's \"DialogWelcome\" component (node 7162:26459, variants\n// carousel/single): a `Container` (reuses the generic `DialogContent` popup\n// chrome — bg/radius/shadow already match the `--ui-dialog-container-*` tier)\n// around a `DialogBody` (Image + Title + Description) and, for\n// `variant=\"carousel\"`, a `DialogFooterCarousel` driven by a real Embla\n// instance built from scratch here — no import from any existing carousel\n// implementation.\n\nexport interface DialogWelcomeSlide {\n /** Illustration/media for the slide. Falls back to a placeholder surface when omitted. */\n image?: React.ReactNode;\n title: string;\n description: string;\n}\n\nexport type DialogWelcomeVariant = 'carousel' | 'single';\n\ninterface DialogWelcomeSlideBodyProps {\n image?: React.ReactNode;\n title: string;\n description: string;\n /** Whether this slide currently owns the dialog's accessible name/description. */\n active: boolean;\n /**\n * Whether this renders the DialogBody's own bottom padding (Figma's\n * `py-16` applied around the whole body). `false` when more DialogBody\n * content (e.g. the `single` variant's buttons) follows, so the caller can\n * apply the correct `gap-12` between them instead of stacking padding on\n * top of a gap.\n */\n withBottomPadding?: boolean;\n}\n\nfunction DialogWelcomeSlideBody({\n image,\n title,\n description,\n active,\n withBottomPadding = true,\n}: DialogWelcomeSlideBodyProps) {\n return (\n <div\n className={cn(\n 'flex w-full flex-col items-center gap-3 pt-4',\n withBottomPadding && 'pb-4'\n )}\n >\n <div className=\"w-full overflow-hidden rounded-lg px-4\">\n <div className=\"flex h-[272px] w-full items-center justify-center rounded bg-[var(--ui-background-surface-active)]\">\n {image}\n </div>\n </div>\n <div className=\"flex w-full flex-col items-center gap-1 px-4 text-center\">\n {active ? (\n <DialogTitle className=\"w-full flex-none text-center\">\n {title}\n </DialogTitle>\n ) : (\n <p className=\"w-full text-2xl font-normal leading-8 text-foreground\">\n {title}\n </p>\n )}\n {active ? (\n <DialogDescription className=\"w-full flex-none text-center text-sm leading-6 text-foreground\">\n {description}\n </DialogDescription>\n ) : (\n <p className=\"w-full text-sm leading-6 text-foreground\">\n {description}\n </p>\n )}\n </div>\n </div>\n );\n}\n\nconst DEFAULT_SLIDES: DialogWelcomeSlide[] = [\n { title: 'Title', description: 'Feature description.' },\n { title: 'Title', description: 'Feature description.' },\n { title: 'Title', description: 'Feature description.' },\n];\n\ninterface UseDialogWelcomeCarouselOptions {\n slideCount: number;\n selectedIndexProp?: number;\n onSelectedIndexChange?: (index: number) => void;\n}\n\nfunction useDialogWelcomeCarousel({\n slideCount,\n selectedIndexProp,\n onSelectedIndexChange,\n}: UseDialogWelcomeCarouselOptions) {\n const dir = useDocDir();\n const isControlled = selectedIndexProp !== undefined;\n // Mount Embla already on the (clamped) controlled slide instead of its\n // default 0 — otherwise the initial `onSelect()` below reports a phantom\n // \"slide 0\" before the resync effect corrects it, which a consumer wiring\n // analytics off `onSelectedIndexChange` would log as a real event.\n const initialIndex = Math.min(\n Math.max(selectedIndexProp ?? 0, 0),\n Math.max(slideCount - 1, 0)\n );\n const [emblaRef, emblaApi] = useEmblaCarousel({\n loop: false,\n direction: dir,\n startIndex: initialIndex,\n });\n const [internalIndex, setInternalIndex] = React.useState(0);\n // Two-sided: an out-of-range (e.g. negative) `selectedIndex` must still\n // resolve to a real slide, or no slide would carry the dialog's\n // Title/Description (see dialog-welcome/accessibility.md's one-active-slide\n // invariant).\n const selectedIndex = Math.min(\n Math.max(selectedIndexProp ?? internalIndex, 0),\n Math.max(slideCount - 1, 0)\n );\n\n // `onSelectedIndexChange` is read from a ref, not a `useEffect` dependency,\n // so an inline (non-memoized) consumer callback can't force this effect to\n // re-subscribe — which would call `onSelect()` again on the same slide and,\n // if the consumer's callback triggers a re-render, loop indefinitely.\n const onSelectedIndexChangeRef = React.useRef(onSelectedIndexChange);\n React.useEffect(() => {\n onSelectedIndexChangeRef.current = onSelectedIndexChange;\n }, [onSelectedIndexChange]);\n\n // Read fresh on every Embla event without forcing the subscription effect\n // below to resubscribe (same reasoning as `onSelectedIndexChangeRef`).\n const isControlledRef = React.useRef(isControlled);\n isControlledRef.current = isControlled;\n const selectedIndexRef = React.useRef(selectedIndex);\n selectedIndexRef.current = selectedIndex;\n\n React.useEffect(() => {\n if (!emblaApi) return;\n const onSelect = () => {\n const index = emblaApi.selectedScrollSnap();\n if (isControlledRef.current) {\n if (!onSelectedIndexChangeRef.current) {\n // Embla is draggable regardless of controlled state, so a swipe can\n // still move it physically even though clicks are correctly no-ops\n // in this configuration (controlled with no way to move the prop\n // forward). Snap back instead of leaving the visible slide diverged\n // from the one carrying the dialog's accessible name.\n if (index !== selectedIndexRef.current) {\n emblaApi.scrollTo(selectedIndexRef.current, true);\n }\n return;\n }\n // A click/dot handler reports the new index directly, then the resync\n // effect below drives Embla to match via `scrollTo`, which re-emits\n // this same `select` event. Only forward it when it disagrees with\n // the last known controlled index, or a single navigation double-\n // fires the consumer's `onSelectedIndexChange` (e.g. analytics).\n if (index !== selectedIndexRef.current) {\n onSelectedIndexChangeRef.current(index);\n }\n return;\n }\n setInternalIndex(index);\n onSelectedIndexChangeRef.current?.(index);\n };\n onSelect();\n emblaApi.on('select', onSelect);\n emblaApi.on('reInit', onSelect);\n return () => {\n emblaApi.off('select', onSelect);\n emblaApi.off('reInit', onSelect);\n };\n }, [emblaApi]);\n\n React.useEffect(() => {\n if (selectedIndexProp === undefined || !emblaApi) return;\n if (emblaApi.selectedScrollSnap() !== selectedIndex) {\n // `jump: true` — a controlled `selectedIndex` change snaps instantly\n // rather than animating. Without it, the initial sync on mount races\n // the smooth-scroll animation, so an immediate screenshot (e.g. VR)\n // can catch a mid-scroll frame instead of the settled slide.\n emblaApi.scrollTo(selectedIndex, true);\n }\n }, [emblaApi, selectedIndexProp, selectedIndex]);\n\n // Skip the first time this effect sees a non-null `emblaApi` — Embla was\n // already constructed with that render's `dir` (see `useEmblaCarousel`\n // above), so re-running `reInit` immediately is redundant. Worse, Embla's\n // `reInit` synchronously re-emits `'reInit'` even when nothing changed,\n // which would re-invoke the `onSelect` listener registered by the mount\n // effect above and double-fire `onSelectedIndexChange` on mount. Only a\n // genuine post-mount `dir` change (e.g. `useDocDir`'s SSR-safe resync, or\n // the document's `dir` actually flipping at runtime) should call `reInit`.\n const skipNextReInitRef = React.useRef(true);\n React.useEffect(() => {\n if (!emblaApi) return;\n if (skipNextReInitRef.current) {\n skipNextReInitRef.current = false;\n return;\n }\n emblaApi.reInit({ direction: dir });\n }, [emblaApi, dir]);\n\n // Controlled mode never drives Embla directly from Back/Next/dot clicks —\n // only the resync effect above (keyed to `selectedIndexProp`) does. This\n // keeps Embla's physical position from drifting away from the prop when a\n // consumer passes `selectedIndex` without wiring `onSelectedIndexChange`.\n const handleSelectIndex = React.useCallback(\n (index: number) => {\n if (isControlled) {\n onSelectedIndexChange?.(index);\n } else {\n emblaApi?.scrollTo(index);\n }\n },\n [isControlled, emblaApi, onSelectedIndexChange]\n );\n const handleBack = React.useCallback(() => {\n if (isControlled) {\n onSelectedIndexChange?.(Math.max(selectedIndex - 1, 0));\n } else {\n emblaApi?.scrollPrev();\n }\n }, [isControlled, emblaApi, onSelectedIndexChange, selectedIndex]);\n const handleNext = React.useCallback(() => {\n if (isControlled) {\n onSelectedIndexChange?.(Math.min(selectedIndex + 1, slideCount - 1));\n } else {\n emblaApi?.scrollNext();\n }\n }, [isControlled, emblaApi, onSelectedIndexChange, selectedIndex, slideCount]);\n\n // Check `slideCount - 1` first: for a single-slide carousel, index 0 is\n // both the first AND last slide, and 'end' (unlocking the primary action)\n // must win.\n const footerVariant: DialogFooterCarouselVariant =\n selectedIndex === slideCount - 1\n ? 'end'\n : selectedIndex === 0\n ? 'start'\n : 'middle';\n\n return {\n emblaRef,\n selectedIndex,\n handleSelectIndex,\n handleBack,\n handleNext,\n footerVariant,\n };\n}\n\ninterface ContainerCarouselProps {\n slides: DialogWelcomeSlide[];\n selectedIndex: number;\n emblaRef: ReturnType<typeof useEmblaCarousel>[0];\n footerVariant: DialogFooterCarouselVariant;\n onSelectIndex: (index: number) => void;\n onBack: () => void;\n onNext: () => void;\n onPrimaryAction?: () => void;\n backLabel?: string;\n nextLabel?: string;\n primaryLabel?: string;\n goToSlideLabel?: (index: number, count: number) => string;\n}\n\nfunction ContainerCarousel({\n slides,\n selectedIndex,\n emblaRef,\n footerVariant,\n onSelectIndex,\n onBack,\n onNext,\n onPrimaryAction,\n backLabel,\n nextLabel,\n primaryLabel,\n goToSlideLabel,\n}: ContainerCarouselProps) {\n return (\n <>\n <div ref={emblaRef} className=\"w-full overflow-hidden\">\n <div className=\"flex\">\n {slides.map((slide, index) => (\n <div\n key={index}\n className=\"min-w-0 shrink-0 grow-0 basis-full\"\n aria-hidden={index !== selectedIndex || undefined}\n inert={index !== selectedIndex}\n >\n <DialogWelcomeSlideBody\n image={slide.image}\n title={slide.title}\n description={slide.description}\n active={index === selectedIndex}\n />\n </div>\n ))}\n </div>\n </div>\n <DialogFooterCarousel\n variant={footerVariant}\n slideCount={slides.length}\n selectedIndex={selectedIndex}\n onSelectIndex={onSelectIndex}\n onBack={onBack}\n onNext={onNext}\n onPrimaryAction={onPrimaryAction}\n backLabel={backLabel}\n nextLabel={nextLabel}\n primaryLabel={primaryLabel}\n goToSlideLabel={goToSlideLabel}\n />\n </>\n );\n}\n\ninterface ContainerNoSlidesProps {\n image?: React.ReactNode;\n title: string;\n description: string;\n primaryLabel?: string;\n onPrimaryAction?: () => void;\n closeLabel: string;\n onCloseAction?: () => void;\n}\n\nfunction ContainerNoSlides({\n image,\n title,\n description,\n primaryLabel,\n onPrimaryAction,\n closeLabel,\n onCloseAction,\n}: ContainerNoSlidesProps) {\n return (\n <div className=\"flex w-full flex-col items-center gap-3 pb-4\">\n <DialogWelcomeSlideBody\n image={image}\n title={title}\n description={description}\n active\n withBottomPadding={false}\n />\n <div className=\"flex w-full flex-col items-center gap-2 px-4\">\n <Button onClick={onPrimaryAction}>\n {primaryLabel ?? 'Call to action'}\n </Button>\n <DialogClose\n onClick={onCloseAction}\n render={<Button variant=\"ghost\">{closeLabel}</Button>}\n />\n </div>\n </div>\n );\n}\n\ntype DialogRootProps = React.ComponentPropsWithoutRef<typeof DialogRoot>;\n\nexport interface DialogWelcomeProps extends Omit<DialogRootProps, 'children'> {\n /** Selects the Figma-defined layout. Defaults to `'carousel'`. */\n variant?: DialogWelcomeVariant;\n /** Slides shown one at a time (`variant=\"carousel\"`). Defaults to a 3-slide placeholder. */\n slides?: DialogWelcomeSlide[];\n /** Controls the active slide (`variant=\"carousel\"`). Uncontrolled when omitted. */\n selectedIndex?: number;\n /** Fires whenever the active slide changes (`variant=\"carousel\"`). */\n onSelectedIndexChange?: (index: number) => void;\n /** `Back` button label (`variant=\"carousel\"`). Defaults to `'Back'`. */\n backLabel?: string;\n /** `Next` button label (`variant=\"carousel\"`). Defaults to `'Next'`. */\n nextLabel?: string;\n /** Builds each carousel dot's accessible name (`variant=\"carousel\"`). */\n goToSlideLabel?: (index: number, count: number) => string;\n /** Illustration/media (`variant=\"single\"`). */\n image?: React.ReactNode;\n /** Title (`variant=\"single\"`). Defaults to `'Title'`. */\n title?: string;\n /** Description (`variant=\"single\"`). Defaults to `'Feature description.'`. */\n description?: string;\n /** `Close` link label (`variant=\"single\"`). Defaults to `'Close'`. */\n closeLabel?: string;\n /** Fires when `Close` (`variant=\"single\"`) is activated, before the dialog closes. */\n onCloseAction?: () => void;\n /**\n * Call-to-action button label — the last carousel slide's button\n * (`variant=\"carousel\"`) or the single body's primary button\n * (`variant=\"single\"`). Defaults to `'Call to action'`.\n */\n primaryLabel?: string;\n /** Fires when the call-to-action button is activated. */\n onPrimaryAction?: () => void;\n /** Render inside a portal (forwarded to `DialogContent`). Defaults to `true`. */\n portal?: boolean;\n /** Portal container (forwarded to `DialogContent`). */\n portalContainer?: DialogContentProps['portalContainer'];\n /** Keep the content mounted while closed (forwarded to `DialogContent`). */\n keepMounted?: DialogContentProps['keepMounted'];\n /** Extra classes merged onto the popup container. */\n className?: string;\n}\n\nconst DialogWelcome = React.forwardRef<HTMLDivElement, DialogWelcomeProps>(\n (\n {\n variant = 'carousel',\n slides = DEFAULT_SLIDES,\n selectedIndex: selectedIndexProp,\n onSelectedIndexChange,\n backLabel,\n nextLabel,\n goToSlideLabel,\n image,\n title = 'Title',\n description = 'Feature description.',\n closeLabel = 'Close',\n onCloseAction,\n primaryLabel,\n onPrimaryAction,\n portal,\n portalContainer,\n keepMounted,\n className,\n ...rootProps\n },\n ref\n ) => {\n const isCarousel = variant === 'carousel';\n // An explicit `slides={[]}` would otherwise mount no Title/Description\n // and suppress the footer, leaving the dialog with no accessible name —\n // fall back to the default placeholder slides instead.\n const resolvedSlides = slides.length > 0 ? slides : DEFAULT_SLIDES;\n const slideCount = resolvedSlides.length;\n\n const {\n emblaRef,\n selectedIndex,\n handleSelectIndex,\n handleBack,\n handleNext,\n footerVariant,\n } = useDialogWelcomeCarousel({\n slideCount,\n selectedIndexProp,\n onSelectedIndexChange,\n });\n\n return (\n <DialogRoot {...rootProps}>\n <DialogContent\n ref={ref}\n size=\"sm\"\n portal={portal}\n portalContainer={portalContainer}\n keepMounted={keepMounted}\n className={className}\n >\n {isCarousel ? (\n <ContainerCarousel\n slides={resolvedSlides}\n selectedIndex={selectedIndex}\n emblaRef={emblaRef}\n footerVariant={footerVariant}\n onSelectIndex={handleSelectIndex}\n onBack={handleBack}\n onNext={handleNext}\n onPrimaryAction={onPrimaryAction}\n backLabel={backLabel}\n nextLabel={nextLabel}\n primaryLabel={primaryLabel}\n goToSlideLabel={goToSlideLabel}\n />\n ) : (\n <ContainerNoSlides\n image={image}\n title={title}\n description={description}\n primaryLabel={primaryLabel}\n onPrimaryAction={onPrimaryAction}\n closeLabel={closeLabel}\n onCloseAction={onCloseAction}\n />\n )}\n </DialogContent>\n </DialogRoot>\n );\n }\n);\nDialogWelcome.displayName = 'DialogWelcome';\n\nexport { DialogWelcome };\n"],"names":["DialogWelcomeSlideBody","image","title","description","active","withBottomPadding","jsxs","cn","jsx","DialogTitle","DialogDescription","DEFAULT_SLIDES","useDialogWelcomeCarousel","slideCount","selectedIndexProp","onSelectedIndexChange","dir","useDocDir","isControlled","initialIndex","emblaRef","emblaApi","useEmblaCarousel","internalIndex","setInternalIndex","React","selectedIndex","onSelectedIndexChangeRef","isControlledRef","selectedIndexRef","onSelect","index","_a","skipNextReInitRef","handleSelectIndex","handleBack","handleNext","footerVariant","ContainerCarousel","slides","onSelectIndex","onBack","onNext","onPrimaryAction","backLabel","nextLabel","primaryLabel","goToSlideLabel","Fragment","slide","DialogFooterCarousel","ContainerNoSlides","closeLabel","onCloseAction","Button","DialogClose","DialogWelcome","variant","portal","portalContainer","keepMounted","className","rootProps","ref","isCarousel","resolvedSlides","DialogRoot","DialogContent"],"mappings":"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"}
@@ -1,95 +1,123 @@
1
- import { jsx as s, jsxs as N } from "react/jsx-runtime";
2
- import * as g from "react";
3
- import { BarChart as w, CartesianGrid as A, XAxis as B, YAxis as T, Bar as b } from "recharts";
4
- import { cn as H } from "../../../lib/utils.js";
5
- import { ChartContainer as $, ChartTooltip as j, ChartTooltipContent as C } from "../chart/chart.js";
6
- const v = (l) => Number(l.toFixed(2));
7
- function F(l, i, d) {
8
- const r = l.filter(
9
- (e) => typeof e == "number" && Number.isFinite(e)
1
+ import { jsx as a, jsxs as _ } from "react/jsx-runtime";
2
+ import * as k from "react";
3
+ import { BarChart as E, CartesianGrid as W, XAxis as X, YAxis as Y, Bar as q } from "recharts";
4
+ import { cn as I } from "../../../lib/utils.js";
5
+ import { ChartContainer as J, ChartTooltip as L, ChartTooltipContent as O } from "../chart/chart.js";
6
+ import { resolveAxisDomain as P } from "../chart/chart-format.js";
7
+ const y = (l) => Number(l.toFixed(2));
8
+ function Q(l, e, h) {
9
+ const i = l.filter(
10
+ (o) => typeof o == "number" && Number.isFinite(o)
10
11
  );
11
- if (r.length === 0 || i < 1) return [];
12
- const [c, m] = d ?? [Math.min(...r), Math.max(...r)], t = Math.min(c, m), n = Math.max(c, m), f = t === n ? t + 1 : n, a = (f - t) / i, h = Array.from({ length: i }, (e, o) => {
13
- const u = t + o * a, p = o === i - 1 ? f : t + (o + 1) * a;
14
- return { x0: u, x1: p, label: `${v(u)}–${v(p)}`, count: 0 };
12
+ if (i.length === 0 || e < 1) return [];
13
+ const [c, m] = h ?? [Math.min(...i), Math.max(...i)], t = Math.min(c, m), s = Math.max(c, m), f = t === s ? t + 1 : s, n = (f - t) / e, u = Array.from({ length: e }, (o, r) => {
14
+ const p = t + r * n, v = r === e - 1 ? f : t + (r + 1) * n;
15
+ return { x0: p, x1: v, label: `${y(p)}–${y(v)}`, count: 0 };
15
16
  });
16
- for (const e of r) {
17
- if (e < t || e > f) continue;
18
- let o = Math.floor((e - t) / a);
19
- o >= i && (o = i - 1), h[o].count += 1;
17
+ for (const o of i) {
18
+ if (o < t || o > f) continue;
19
+ let r = Math.floor((o - t) / n);
20
+ r >= e && (r = e - 1), u[r].count += 1;
20
21
  }
21
- return h;
22
+ return u;
22
23
  }
23
- const G = g.forwardRef(
24
+ const R = k.forwardRef(
24
25
  ({
25
26
  className: l,
26
- config: i,
27
- values: d,
28
- dataKey: r = "count",
27
+ config: e,
28
+ values: h,
29
+ dataKey: i = "count",
29
30
  binCount: c = 10,
30
31
  domain: m,
31
32
  xAxisLabel: t,
32
- yAxisLabel: n,
33
+ yAxisLabel: s,
33
34
  yUnit: f,
34
- barRadius: a = 0,
35
- showGrid: h = !0,
36
- showTooltip: e = !0,
37
- tooltipContent: o,
38
- ...u
39
- }, p) => {
40
- const M = t ? { value: t, position: "insideBottom", offset: 0 } : void 0, k = n ? {
41
- value: n,
35
+ barRadius: n = 0,
36
+ showGrid: u = !0,
37
+ showTooltip: o = !0,
38
+ showXAxis: r = !0,
39
+ showYAxis: p = !0,
40
+ xTickFormatter: v,
41
+ yTickFormatter: x,
42
+ xAxisAngle: d,
43
+ xAxisInterval: M,
44
+ yAxisTickCount: N,
45
+ yAxisDomain: w,
46
+ gridDashed: B,
47
+ gridHorizontal: D,
48
+ gridVertical: F,
49
+ tooltipContent: H,
50
+ ...T
51
+ }, C) => {
52
+ const $ = t ? { value: t, position: "insideBottom", offset: 0 } : void 0, b = s ? {
53
+ value: s,
42
54
  angle: -90,
43
55
  position: "insideLeft",
44
56
  style: { textAnchor: "middle" }
45
- } : void 0, y = g.useMemo(
46
- () => F(d, c, m),
47
- [d, c, m]
48
- ).map((x) => ({ label: x.label, [r]: x.count }));
49
- return /* @__PURE__ */ s(
57
+ } : void 0, j = P(w), z = t || d != null ? 30 + (d != null ? 20 : 0) + (t ? 18 : 0) : void 0, G = k.useMemo(
58
+ () => Q(h, c, m),
59
+ [h, c, m]
60
+ ).map((g) => ({ label: g.label, [i]: g.count }));
61
+ return /* @__PURE__ */ a(
50
62
  "div",
51
63
  {
52
- ref: p,
53
- className: H(l),
54
- ...u,
55
- children: /* @__PURE__ */ s(
56
- $,
64
+ ref: C,
65
+ className: I(l),
66
+ ...T,
67
+ children: /* @__PURE__ */ a(
68
+ J,
57
69
  {
58
- config: i,
70
+ config: e,
59
71
  className: "size-full [&_.recharts-label]:fill-foreground",
60
- children: /* @__PURE__ */ N(w, { data: y, barCategoryGap: 0, children: [
61
- h && /* @__PURE__ */ s(A, { vertical: !1 }),
62
- /* @__PURE__ */ s(
63
- B,
72
+ children: /* @__PURE__ */ _(E, { data: G, barCategoryGap: 0, children: [
73
+ u && /* @__PURE__ */ a(
74
+ W,
75
+ {
76
+ horizontal: D ?? !0,
77
+ vertical: F ?? !1,
78
+ strokeDasharray: B ? "3 3" : void 0
79
+ }
80
+ ),
81
+ /* @__PURE__ */ a(
82
+ X,
64
83
  {
65
84
  dataKey: "label",
85
+ hide: !r,
66
86
  tickLine: !1,
67
87
  axisLine: !1,
68
- height: t ? 48 : void 0,
69
- label: M
88
+ tickFormatter: v,
89
+ angle: d,
90
+ interval: M,
91
+ textAnchor: d != null ? d < 0 ? "end" : "start" : void 0,
92
+ height: z,
93
+ label: $
70
94
  }
71
95
  ),
72
- /* @__PURE__ */ s(
73
- T,
96
+ /* @__PURE__ */ a(
97
+ Y,
74
98
  {
75
99
  type: "number",
100
+ hide: !p,
76
101
  tickLine: !1,
77
102
  axisLine: !1,
78
103
  allowDecimals: !1,
79
104
  unit: f,
80
- width: n ? 72 : void 0,
81
- label: k
105
+ tickFormatter: x,
106
+ tickCount: N,
107
+ domain: j,
108
+ width: s ? 72 : void 0,
109
+ label: b
82
110
  }
83
111
  ),
84
- e && /* @__PURE__ */ s(j, { content: o ?? /* @__PURE__ */ s(C, {}) }),
85
- /* @__PURE__ */ s(
86
- b,
112
+ o && /* @__PURE__ */ a(L, { content: H ?? /* @__PURE__ */ a(O, {}) }),
113
+ /* @__PURE__ */ a(
114
+ q,
87
115
  {
88
- dataKey: r,
89
- fill: `var(--color-${r})`,
116
+ dataKey: i,
117
+ fill: `var(--color-${i})`,
90
118
  stroke: "var(--ui-background-surface-primary)",
91
119
  strokeWidth: 1,
92
- radius: a > 0 ? [a, a, 0, 0] : void 0,
120
+ radius: n > 0 ? [n, n, 0, 0] : void 0,
93
121
  isAnimationActive: !1
94
122
  }
95
123
  )
@@ -100,9 +128,9 @@ const G = g.forwardRef(
100
128
  );
101
129
  }
102
130
  );
103
- G.displayName = "Histogram";
131
+ R.displayName = "Histogram";
104
132
  export {
105
- G as Histogram,
106
- F as computeHistogramBins
133
+ R as Histogram,
134
+ Q as computeHistogramBins
107
135
  };
108
136
  //# sourceMappingURL=histogram.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"histogram.js","sources":["../../../../src/components/ui/histogram/histogram.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Bar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n XAxis,\n YAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n type ChartConfig,\n} from '../chart';\n\n// A histogram bins a set of continuous samples into equal-width ranges and plots\n// the frequency of each as contiguous bars — distinct from BarChart, whose bars\n// are pre-categorized. The binning is the component's job (a pure helper), so the\n// consumer passes raw `values`, not pre-aggregated rows. Built on the shared\n// `Chart` primitives; no new tokens (the single series' color is caller-supplied\n// via `config`, same `--color-<key>` mechanism as the other chart types).\n\nexport interface HistogramBin {\n /** Lower bound of the bin (inclusive). */\n x0: number;\n /** Upper bound of the bin (exclusive, except the last bin which is inclusive). */\n x1: number;\n /** Human-readable range label, e.g. `\"0–10\"`. */\n label: string;\n /** How many samples fell in the bin. */\n count: number;\n}\n\nconst roundEdge = (n: number) => Number(n.toFixed(2));\n\n/**\n * Split `values` into `binCount` equal-width bins and count the samples in each.\n * The range is `domain` if given, else the data's [min, max]; values outside the\n * domain are dropped, and the max value lands in the last (inclusive) bin.\n * Returns [] when there's nothing to bin. Exported for unit tests; not part of\n * the package's public API.\n */\nexport function computeHistogramBins(\n values: ReadonlyArray<number>,\n binCount: number,\n domain?: [number, number]\n): HistogramBin[] {\n const nums = values.filter(\n (v): v is number => typeof v === 'number' && Number.isFinite(v)\n );\n if (nums.length === 0 || binCount < 1) return [];\n\n const [d0, d1] = domain ?? [Math.min(...nums), Math.max(...nums)];\n // Normalize an inverted domain ([max, min]) so binning stays robust.\n const min = Math.min(d0, d1);\n const hi = Math.max(d0, d1);\n // A zero-width range (all values equal, or a degenerate domain) can't be\n // divided — widen it by 1 so the single bin has extent.\n const max = min === hi ? min + 1 : hi;\n const width = (max - min) / binCount;\n\n const bins: HistogramBin[] = Array.from({ length: binCount }, (_, i) => {\n const x0 = min + i * width;\n const x1 = i === binCount - 1 ? max : min + (i + 1) * width;\n return { x0, x1, label: `${roundEdge(x0)}–${roundEdge(x1)}`, count: 0 };\n });\n\n for (const v of nums) {\n if (v < min || v > max) continue;\n let idx = Math.floor((v - min) / width);\n if (idx >= binCount) idx = binCount - 1; // the max value\n bins[idx].count += 1;\n }\n return bins;\n}\n\nexport interface HistogramProps\n extends Omit<React.ComponentProps<'div'>, 'children'> {\n /** Raw continuous samples to bin (non-finite values are ignored). */\n values: ReadonlyArray<number>;\n /**\n * Single-series map of `label` / `color`, keyed by `dataKey` (imported from\n * the shared `Chart` primitives). Color is caller-supplied — reference an\n * existing semantic `--ui-*` token; there is no chart palette tier yet.\n */\n config: ChartConfig;\n /** `config` key that colors + labels the frequency bars. */\n dataKey?: string;\n /** Number of equal-width bins. */\n binCount?: number;\n /** Fix the binning range instead of deriving it from the data's min/max. */\n domain?: [number, number];\n /** Title rendered beneath the horizontal (X) axis. */\n xAxisLabel?: string;\n /** Title rendered beside the vertical (Y) axis (rotated). */\n yAxisLabel?: string;\n /** Unit suffix appended to Y-axis tick values (recharts `unit`; the X axis is the bin label). */\n yUnit?: string;\n /** Corner radius on the top of each bar. */\n barRadius?: number;\n showGrid?: boolean;\n showTooltip?: boolean;\n /**\n * Replace the default tooltip. Pass a configured `ChartTooltipContent`\n * (imported from this library) — e.g. with a `formatter` / `labelFormatter` —\n * to customize the tooltip without composing recharts yourself. Ignored when\n * `showTooltip` is false.\n */\n tooltipContent?: React.ComponentProps<typeof ChartTooltip>['content'];\n}\n\nconst Histogram = React.forwardRef<HTMLDivElement, HistogramProps>(\n (\n {\n className,\n config,\n values,\n dataKey = 'count',\n binCount = 10,\n domain,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n barRadius = 0,\n showGrid = true,\n showTooltip = true,\n tooltipContent,\n ...props\n },\n ref\n ) => {\n const xAxisTitle = xAxisLabel\n ? { value: xAxisLabel, position: 'insideBottom' as const, offset: 0 }\n : undefined;\n const yAxisTitle = yAxisLabel\n ? {\n value: yAxisLabel,\n angle: -90,\n position: 'insideLeft' as const,\n style: { textAnchor: 'middle' as const },\n }\n : undefined;\n\n const bins = React.useMemo(\n () => computeHistogramBins(values, binCount, domain),\n [values, binCount, domain]\n );\n // Bars carry the bin `label` as the category and `count` under `dataKey`, so\n // the tooltip resolves the frequency from `config[dataKey]`.\n const data = bins.map((bin) => ({ label: bin.label, [dataKey]: bin.count }));\n\n return (\n <div\n ref={ref}\n className={cn(className)}\n {...props}\n >\n <ChartContainer\n config={config}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsBarChart data={data} barCategoryGap={0}>\n {showGrid && <CartesianGrid vertical={false} />}\n <XAxis\n dataKey=\"label\"\n tickLine={false}\n axisLine={false}\n height={xAxisLabel ? 48 : undefined}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n tickLine={false}\n axisLine={false}\n allowDecimals={false}\n unit={yUnit}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n {showTooltip && (\n <ChartTooltip content={tooltipContent ?? <ChartTooltipContent />} />\n )}\n <Bar\n dataKey={dataKey}\n fill={`var(--color-${dataKey})`}\n // A hairline in the surface color separates the contiguous bars so\n // they don't blend into one mass (same trick as the Treemap cells).\n stroke=\"var(--ui-background-surface-primary)\"\n strokeWidth={1}\n radius={barRadius > 0 ? [barRadius, barRadius, 0, 0] : undefined}\n isAnimationActive={false}\n />\n </RechartsBarChart>\n </ChartContainer>\n </div>\n );\n }\n);\nHistogram.displayName = 'Histogram';\n\nexport { Histogram };\n"],"names":["roundEdge","n","computeHistogramBins","values","binCount","domain","nums","v","d0","d1","min","hi","max","width","bins","_","i","x0","x1","idx","Histogram","React","className","config","dataKey","xAxisLabel","yAxisLabel","yUnit","barRadius","showGrid","showTooltip","tooltipContent","props","ref","xAxisTitle","yAxisTitle","data","bin","jsx","cn","ChartContainer","jsxs","RechartsBarChart","CartesianGrid","XAxis","YAxis","ChartTooltip","ChartTooltipContent","Bar"],"mappings":"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"}
1
+ {"version":3,"file":"histogram.js","sources":["../../../../src/components/ui/histogram/histogram.tsx"],"sourcesContent":["'use client';\n\nimport * as React from 'react';\nimport {\n Bar,\n BarChart as RechartsBarChart,\n CartesianGrid,\n XAxis,\n YAxis,\n} from 'recharts';\n\nimport { cn } from '@/lib/utils';\nimport {\n ChartContainer,\n ChartTooltip,\n ChartTooltipContent,\n resolveAxisDomain,\n type ChartConfig,\n type CartesianChartProps,\n} from '../chart';\n\n// A histogram bins a set of continuous samples into equal-width ranges and plots\n// the frequency of each as contiguous bars — distinct from BarChart, whose bars\n// are pre-categorized. The binning is the component's job (a pure helper), so the\n// consumer passes raw `values`, not pre-aggregated rows. Built on the shared\n// `Chart` primitives; no new tokens (the single series' color is caller-supplied\n// via `config`, same `--color-<key>` mechanism as the other chart types).\n\nexport interface HistogramBin {\n /** Lower bound of the bin (inclusive). */\n x0: number;\n /** Upper bound of the bin (exclusive, except the last bin which is inclusive). */\n x1: number;\n /** Human-readable range label, e.g. `\"0–10\"`. */\n label: string;\n /** How many samples fell in the bin. */\n count: number;\n}\n\nconst roundEdge = (n: number) => Number(n.toFixed(2));\n\n/**\n * Split `values` into `binCount` equal-width bins and count the samples in each.\n * The range is `domain` if given, else the data's [min, max]; values outside the\n * domain are dropped, and the max value lands in the last (inclusive) bin.\n * Returns [] when there's nothing to bin. Exported for unit tests; not part of\n * the package's public API.\n */\nexport function computeHistogramBins(\n values: ReadonlyArray<number>,\n binCount: number,\n domain?: [number, number]\n): HistogramBin[] {\n const nums = values.filter(\n (v): v is number => typeof v === 'number' && Number.isFinite(v)\n );\n if (nums.length === 0 || binCount < 1) return [];\n\n const [d0, d1] = domain ?? [Math.min(...nums), Math.max(...nums)];\n // Normalize an inverted domain ([max, min]) so binning stays robust.\n const min = Math.min(d0, d1);\n const hi = Math.max(d0, d1);\n // A zero-width range (all values equal, or a degenerate domain) can't be\n // divided — widen it by 1 so the single bin has extent.\n const max = min === hi ? min + 1 : hi;\n const width = (max - min) / binCount;\n\n const bins: HistogramBin[] = Array.from({ length: binCount }, (_, i) => {\n const x0 = min + i * width;\n const x1 = i === binCount - 1 ? max : min + (i + 1) * width;\n return { x0, x1, label: `${roundEdge(x0)}–${roundEdge(x1)}`, count: 0 };\n });\n\n for (const v of nums) {\n if (v < min || v > max) continue;\n let idx = Math.floor((v - min) / width);\n if (idx >= binCount) idx = binCount - 1; // the max value\n bins[idx].count += 1;\n }\n return bins;\n}\n\nexport interface HistogramProps\n extends Omit<React.ComponentProps<'div'>, 'children'>,\n CartesianChartProps {\n /** Raw continuous samples to bin (non-finite values are ignored). */\n values: ReadonlyArray<number>;\n /**\n * Single-series map of `label` / `color`, keyed by `dataKey` (imported from\n * the shared `Chart` primitives). Color is caller-supplied — reference an\n * existing semantic `--ui-*` token; there is no chart palette tier yet.\n */\n config: ChartConfig;\n /** `config` key that colors + labels the frequency bars. */\n dataKey?: string;\n /** Number of equal-width bins. */\n binCount?: number;\n /** Fix the binning range instead of deriving it from the data's min/max. */\n domain?: [number, number];\n /** Corner radius on the top of each bar. */\n barRadius?: number;\n}\n\nconst Histogram = React.forwardRef<HTMLDivElement, HistogramProps>(\n (\n {\n className,\n config,\n values,\n dataKey = 'count',\n binCount = 10,\n domain,\n xAxisLabel,\n yAxisLabel,\n yUnit,\n barRadius = 0,\n showGrid = true,\n showTooltip = true,\n showXAxis = true,\n showYAxis = true,\n xTickFormatter,\n yTickFormatter,\n xAxisAngle,\n xAxisInterval,\n yAxisTickCount,\n yAxisDomain,\n gridDashed,\n gridHorizontal,\n gridVertical,\n tooltipContent,\n ...props\n },\n ref\n ) => {\n const xAxisTitle = xAxisLabel\n ? { value: xAxisLabel, position: 'insideBottom' as const, offset: 0 }\n : undefined;\n const yAxisTitle = yAxisLabel\n ? {\n value: yAxisLabel,\n angle: -90,\n position: 'insideLeft' as const,\n style: { textAnchor: 'middle' as const },\n }\n : undefined;\n\n const yDomain = resolveAxisDomain(yAxisDomain);\n\n // Room for the X tick row: recharts' default 30, plus a rotated tick row\n // (+20) and/or the axis title (+18). Additive — both can be present at once,\n // which the old label-or-angle ternary under-allocated.\n const xAxisHeight =\n xAxisLabel || xAxisAngle != null\n ? 30 + (xAxisAngle != null ? 20 : 0) + (xAxisLabel ? 18 : 0)\n : undefined;\n\n const bins = React.useMemo(\n () => computeHistogramBins(values, binCount, domain),\n [values, binCount, domain]\n );\n // Bars carry the bin `label` as the category and `count` under `dataKey`, so\n // the tooltip resolves the frequency from `config[dataKey]`.\n const data = bins.map((bin) => ({ label: bin.label, [dataKey]: bin.count }));\n\n return (\n <div\n ref={ref}\n className={cn(className)}\n {...props}\n >\n <ChartContainer\n config={config}\n className=\"size-full [&_.recharts-label]:fill-foreground\"\n >\n <RechartsBarChart data={data} barCategoryGap={0}>\n {showGrid && (\n <CartesianGrid\n horizontal={gridHorizontal ?? true}\n vertical={gridVertical ?? false}\n strokeDasharray={gridDashed ? '3 3' : undefined}\n />\n )}\n <XAxis\n dataKey=\"label\"\n hide={!showXAxis}\n tickLine={false}\n axisLine={false}\n tickFormatter={xTickFormatter}\n angle={xAxisAngle}\n interval={xAxisInterval}\n textAnchor={\n xAxisAngle != null ? (xAxisAngle < 0 ? 'end' : 'start') : undefined\n }\n height={xAxisHeight}\n label={xAxisTitle}\n />\n <YAxis\n type=\"number\"\n hide={!showYAxis}\n tickLine={false}\n axisLine={false}\n allowDecimals={false}\n unit={yUnit}\n tickFormatter={yTickFormatter}\n tickCount={yAxisTickCount}\n domain={yDomain}\n width={yAxisLabel ? 72 : undefined}\n label={yAxisTitle}\n />\n {showTooltip && (\n <ChartTooltip content={tooltipContent ?? <ChartTooltipContent />} />\n )}\n <Bar\n dataKey={dataKey}\n fill={`var(--color-${dataKey})`}\n // A hairline in the surface color separates the contiguous bars so\n // they don't blend into one mass (same trick as the Treemap cells).\n stroke=\"var(--ui-background-surface-primary)\"\n strokeWidth={1}\n radius={barRadius > 0 ? [barRadius, barRadius, 0, 0] : undefined}\n isAnimationActive={false}\n />\n </RechartsBarChart>\n </ChartContainer>\n </div>\n );\n }\n);\nHistogram.displayName = 'Histogram';\n\nexport { Histogram };\n"],"names":["roundEdge","n","computeHistogramBins","values","binCount","domain","nums","v","d0","d1","min","hi","max","width","bins","_","i","x0","x1","idx","Histogram","React","className","config","dataKey","xAxisLabel","yAxisLabel","yUnit","barRadius","showGrid","showTooltip","showXAxis","showYAxis","xTickFormatter","yTickFormatter","xAxisAngle","xAxisInterval","yAxisTickCount","yAxisDomain","gridDashed","gridHorizontal","gridVertical","tooltipContent","props","ref","xAxisTitle","yAxisTitle","yDomain","resolveAxisDomain","xAxisHeight","data","bin","jsx","cn","ChartContainer","jsxs","RechartsBarChart","CartesianGrid","XAxis","YAxis","ChartTooltip","ChartTooltipContent","Bar"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"input.js","sources":["../../../../src/components/ui/input/input.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\n// Internal primitive: the bare single-line input box behind the public\n// `InputText` field (which is also exported as `Input`). Not exported from the\n// package; consumed by `input-text`. Themed by the dedicated next-gen `--ui-input-text-*`\n// token tier from @acronis-platform/tokens-pd. The box fill (`global-box-color-*`)\n// and the normal border (`normal-box-border-color-*`) are wired per state: idle /\n// hover / focus / disabled. The `normal-box-border-color-*` tier has no `-active`,\n// so focus reuses `-hover` for the border, paired with a 3px `--ui-focus-primary`\n// ring. Value and placeholder text use `global-value-color-*` /\n// `global-placeholder-color-*`. The error state is driven by `aria-invalid` —\n// `error-msg-box-border-color-*` border and, on focus, a `--ui-focus-error` ring —\n// scoped with `not-aria-[invalid]` so it wins over the hover/focus border. Box\n// geometry (32px height, 4px radius, 12px padding-x) comes from\n// `--ui-input-text-global-box-*`. Label, description, and error message are\n// composed by the consumer (a Field component is future work).\nexport type InputBoxProps = React.ComponentPropsWithoutRef<'input'>;\n\nconst InputBox = React.forwardRef<HTMLInputElement, InputBoxProps>(\n ({ className, type = 'text', ...props }, ref) => (\n <input\n ref={ref}\n type={type}\n className={cn(\n 'h-[var(--ui-input-text-global-box-height)] w-full min-w-0 rounded-[var(--ui-input-text-global-box-border-radius)] border bg-[var(--ui-input-text-global-box-color-idle)] border-[var(--ui-input-text-normal-box-border-color-idle)] px-[var(--ui-input-text-global-box-padding-x)] text-sm leading-6 text-[var(--ui-input-text-global-value-color-idle)] transition-colors placeholder:text-[var(--ui-input-text-global-placeholder-color-idle)] focus-visible:outline-none focus-visible:ring-[3px] enabled:not-aria-[invalid=true]:hover:border-[var(--ui-input-text-normal-box-border-color-hover)] enabled:not-aria-[invalid=true]:hover:bg-[var(--ui-input-text-global-box-color-hover)] not-aria-[invalid=true]:focus-visible:border-[var(--ui-input-text-normal-box-border-color-hover)] not-aria-[invalid=true]:focus-visible:ring-[var(--ui-focus-primary)] aria-[invalid=true]:border-[var(--ui-input-text-error-msg-box-border-color-idle)] aria-[invalid=true]:focus-visible:ring-[var(--ui-focus-error)] disabled:cursor-not-allowed disabled:border-[var(--ui-input-text-normal-box-border-color-disabled)] disabled:bg-[var(--ui-input-text-global-box-color-disabled)] disabled:text-[var(--ui-input-text-global-value-color-disabled)] disabled:placeholder:text-[var(--ui-input-text-global-placeholder-color-disabled)]',\n className\n )}\n {...props}\n />\n )\n);\nInputBox.displayName = 'InputBox';\n\nexport { InputBox };\n"],"names":["InputBox","React","className","type","props","ref","jsx","cn"],"mappings":";;;AAoBA,MAAMA,IAAWC,EAAM;AAAA,EACrB,CAAC,EAAE,WAAAC,GAAW,MAAAC,IAAO,QAAQ,GAAGC,EAAA,GAASC,MACvC,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,MAAAF;AAAA,MACA,WAAWI;AAAA,QACT;AAAA,QACAL;AAAA,MAAA;AAAA,MAED,GAAGE;AAAA,IAAA;AAAA,EAAA;AAGV;AACAJ,EAAS,cAAc;"}
1
+ {"version":3,"file":"input.js","sources":["../../../../src/components/ui/input/input.tsx"],"sourcesContent":["import * as React from 'react';\n\nimport { cn } from '@/lib/utils';\n\n// The bare single-line input box behind the public `InputText` field (which is\n// also exported as `Input`). Exported in its own right for pairing with `Field`\n// (`<FieldControl render={<InputBox />} />`) — use `InputText` when a bundled\n// label/description/error is wanted instead. Themed by the dedicated next-gen `--ui-input-text-*`\n// token tier from @acronis-platform/tokens-pd. The box fill (`global-box-color-*`)\n// and the normal border (`normal-box-border-color-*`) are wired per state: idle /\n// hover / focus / disabled. The `normal-box-border-color-*` tier has no `-active`,\n// so focus reuses `-hover` for the border, paired with a 3px `--ui-focus-primary`\n// ring. Value and placeholder text use `global-value-color-*` /\n// `global-placeholder-color-*`. The error state is driven by `aria-invalid` —\n// `error-msg-box-border-color-*` border and, on focus, a `--ui-focus-error` ring —\n// scoped with `not-aria-[invalid]` so it wins over the hover/focus border. Box\n// geometry (32px height, 4px radius, 12px padding-x) comes from\n// `--ui-input-text-global-box-*`. Label, description, and error message are\n// composed by the consumer (a Field component is future work).\nexport type InputBoxProps = React.ComponentPropsWithoutRef<'input'>;\n\nconst InputBox = React.forwardRef<HTMLInputElement, InputBoxProps>(\n ({ className, type = 'text', ...props }, ref) => (\n <input\n ref={ref}\n type={type}\n className={cn(\n 'h-[var(--ui-input-text-global-box-height)] w-full min-w-0 rounded-[var(--ui-input-text-global-box-border-radius)] border bg-[var(--ui-input-text-global-box-color-idle)] border-[var(--ui-input-text-normal-box-border-color-idle)] px-[var(--ui-input-text-global-box-padding-x)] text-sm leading-6 text-[var(--ui-input-text-global-value-color-idle)] transition-colors placeholder:text-[var(--ui-input-text-global-placeholder-color-idle)] focus-visible:outline-none focus-visible:ring-[3px] enabled:not-aria-[invalid=true]:hover:border-[var(--ui-input-text-normal-box-border-color-hover)] enabled:not-aria-[invalid=true]:hover:bg-[var(--ui-input-text-global-box-color-hover)] not-aria-[invalid=true]:focus-visible:border-[var(--ui-input-text-normal-box-border-color-hover)] not-aria-[invalid=true]:focus-visible:ring-[var(--ui-focus-primary)] aria-[invalid=true]:border-[var(--ui-input-text-error-msg-box-border-color-idle)] aria-[invalid=true]:focus-visible:ring-[var(--ui-focus-error)] disabled:cursor-not-allowed disabled:border-[var(--ui-input-text-normal-box-border-color-disabled)] disabled:bg-[var(--ui-input-text-global-box-color-disabled)] disabled:text-[var(--ui-input-text-global-value-color-disabled)] disabled:placeholder:text-[var(--ui-input-text-global-placeholder-color-disabled)]',\n className\n )}\n {...props}\n />\n )\n);\nInputBox.displayName = 'InputBox';\n\nexport { InputBox };\n"],"names":["InputBox","React","className","type","props","ref","jsx","cn"],"mappings":";;;AAqBA,MAAMA,IAAWC,EAAM;AAAA,EACrB,CAAC,EAAE,WAAAC,GAAW,MAAAC,IAAO,QAAQ,GAAGC,EAAA,GAASC,MACvC,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,KAAAD;AAAA,MACA,MAAAF;AAAA,MACA,WAAWI;AAAA,QACT;AAAA,QACAL;AAAA,MAAA;AAAA,MAED,GAAGE;AAAA,IAAA;AAAA,EAAA;AAGV;AACAJ,EAAS,cAAc;"}