ajo-ui 0.1.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 (103) hide show
  1. package/LICENSE +15 -0
  2. package/README.md +126 -0
  3. package/dist/accordion.js +130 -0
  4. package/dist/avatar.js +54 -0
  5. package/dist/calendar.js +2 -0
  6. package/dist/carousel.js +239 -0
  7. package/dist/chart.js +790 -0
  8. package/dist/checkbox-group.js +70 -0
  9. package/dist/checkbox.js +77 -0
  10. package/dist/chunks/bar-CVafh6C1.js +99 -0
  11. package/dist/chunks/calendar-q8jZ8Cxr.js +1923 -0
  12. package/dist/chunks/collection-DtRB63U4.js +111 -0
  13. package/dist/chunks/data-table-DpkWv4y4.js +1039 -0
  14. package/dist/chunks/menu-B45IyHHC.js +704 -0
  15. package/dist/chunks/native-BJdhd9XJ.js +20 -0
  16. package/dist/chunks/popup-C8Bb3l_g.js +459 -0
  17. package/dist/chunks/popup-surface-BDCgtVU0.js +18 -0
  18. package/dist/chunks/position-D6_i_SRn.js +434 -0
  19. package/dist/chunks/virtual-list-B7hjGkjk.js +413 -0
  20. package/dist/collapsible.js +106 -0
  21. package/dist/command.js +263 -0
  22. package/dist/context-menu.js +112 -0
  23. package/dist/data-table.js +5 -0
  24. package/dist/dialog.js +207 -0
  25. package/dist/direction.js +22 -0
  26. package/dist/drawer.js +139 -0
  27. package/dist/field.js +26 -0
  28. package/dist/index.js +38 -0
  29. package/dist/input-date.js +994 -0
  30. package/dist/input-group.js +52 -0
  31. package/dist/input-otp.js +179 -0
  32. package/dist/menu.js +2 -0
  33. package/dist/menubar.js +236 -0
  34. package/dist/message-scroller.js +446 -0
  35. package/dist/navigation-menu.js +330 -0
  36. package/dist/popover.js +307 -0
  37. package/dist/progress.js +39 -0
  38. package/dist/radio-group.js +107 -0
  39. package/dist/resizable.js +172 -0
  40. package/dist/select.js +961 -0
  41. package/dist/sidebar.js +343 -0
  42. package/dist/slider.js +259 -0
  43. package/dist/switch.js +53 -0
  44. package/dist/tabs.js +182 -0
  45. package/dist/toast.js +492 -0
  46. package/dist/toggle-group.js +111 -0
  47. package/dist/toggle.js +52 -0
  48. package/dist/toolbar.js +127 -0
  49. package/dist/tooltip.js +196 -0
  50. package/dist/utils.js +104 -0
  51. package/dist/virtual-list.js +2 -0
  52. package/package.json +250 -0
  53. package/src/accordion.tsx +261 -0
  54. package/src/availability.ts +261 -0
  55. package/src/avatar.tsx +99 -0
  56. package/src/bar.ts +156 -0
  57. package/src/calendar.tsx +1441 -0
  58. package/src/carousel.tsx +424 -0
  59. package/src/chart.tsx +1194 -0
  60. package/src/checkbox-group.tsx +132 -0
  61. package/src/checkbox.tsx +130 -0
  62. package/src/collapsible.tsx +188 -0
  63. package/src/collection.ts +154 -0
  64. package/src/command.tsx +511 -0
  65. package/src/context-menu.tsx +233 -0
  66. package/src/data-table-contract.ts +143 -0
  67. package/src/data-table-model.ts +760 -0
  68. package/src/data-table.tsx +475 -0
  69. package/src/dialog.tsx +393 -0
  70. package/src/direction.tsx +45 -0
  71. package/src/drawer.tsx +251 -0
  72. package/src/field.tsx +61 -0
  73. package/src/index.ts +37 -0
  74. package/src/input-date.tsx +1539 -0
  75. package/src/input-group.tsx +142 -0
  76. package/src/input-otp.tsx +324 -0
  77. package/src/menu-cluster.ts +124 -0
  78. package/src/menu.tsx +1095 -0
  79. package/src/menubar.tsx +459 -0
  80. package/src/message-scroller.tsx +732 -0
  81. package/src/native.ts +26 -0
  82. package/src/navigation-menu.tsx +578 -0
  83. package/src/popover.tsx +519 -0
  84. package/src/popup-surface.tsx +31 -0
  85. package/src/popup.ts +569 -0
  86. package/src/position.ts +523 -0
  87. package/src/progress.tsx +70 -0
  88. package/src/radio-group.tsx +186 -0
  89. package/src/resizable.tsx +310 -0
  90. package/src/segments.ts +922 -0
  91. package/src/select.tsx +1501 -0
  92. package/src/sidebar.tsx +683 -0
  93. package/src/slider.tsx +424 -0
  94. package/src/switch.tsx +104 -0
  95. package/src/tabs.tsx +314 -0
  96. package/src/toast.tsx +923 -0
  97. package/src/toggle-group.tsx +249 -0
  98. package/src/toggle.tsx +91 -0
  99. package/src/toolbar.tsx +212 -0
  100. package/src/tooltip.tsx +359 -0
  101. package/src/utils.ts +204 -0
  102. package/src/virtual-list.tsx +205 -0
  103. package/src/virtual.ts +385 -0
package/dist/chart.js ADDED
@@ -0,0 +1,790 @@
1
+ import { text } from "./utils.js";
2
+ import { n as position, t as pointReference } from "./chunks/position-D6_i_SRn.js";
3
+ import { callRef, clamp, dom, id, statefulRootAttrs } from "ajo-cloves";
4
+ import { context } from "ajo/context";
5
+ import { Fragment, jsx, jsxs } from "ajo/jsx-runtime";
6
+ //#region packages/ajo-ui/src/chart.tsx
7
+ var ChartContext = context(null);
8
+ /** Read the stable identity resolved by the nearest ChartContainer. */
9
+ var ChartIdContext = context(null);
10
+ var DEFAULT_MARGIN = {
11
+ bottom: 32,
12
+ left: 40,
13
+ right: 16,
14
+ top: 16
15
+ };
16
+ var DEFAULT_WIDTH = 640;
17
+ var DEFAULT_HEIGHT = 240;
18
+ var resolveRootChartId = (value, fallback) => value ? `chart-${encodeURIComponent(String(value))}` : fallback;
19
+ var resolve = (value, state) => typeof value === "function" ? value(state) : value;
20
+ var number = (value) => {
21
+ const next = Number(value);
22
+ return Number.isFinite(next) ? next : void 0;
23
+ };
24
+ var colorFor = (key, index, config, palette, override) => override ?? (config[key]?.color || config[key]?.theme ? `var(--color-${key})` : palette[index % palette.length]);
25
+ var seriesEntries = (config, series, data, xKey, palette) => {
26
+ return (series?.length ? series : Object.keys(config).length ? Object.keys(config) : Object.keys(data?.[0] ?? {}).filter((key) => key !== xKey && number(data?.[0]?.[key]) != null)).map((item, index) => {
27
+ const entry = typeof item === "string" ? { key: item } : item;
28
+ return {
29
+ ...entry,
30
+ color: colorFor(entry.key, index, config, palette, entry.color),
31
+ label: entry.label ?? config[entry.key]?.label ?? entry.key
32
+ };
33
+ });
34
+ };
35
+ var defaultFormatLabel = (value, _row, index) => value == null ? `Item ${index + 1}` : String(value);
36
+ var numberFormatter;
37
+ var defaultFormatValue = (value) => (numberFormatter ??= new Intl.NumberFormat()).format(value);
38
+ var labelFor = (chart, row, index) => chart.formatLabel(chart.xKey ? row[chart.xKey] : void 0, row, index);
39
+ var payloadFor = (chart, index, series = chart.series, colors) => {
40
+ const row = chart.data[index] ?? {};
41
+ return series.map((entry, entryIndex) => {
42
+ const value = number(row[entry.key]);
43
+ if (value == null) return void 0;
44
+ return {
45
+ color: colors?.[entryIndex] ?? entry.color,
46
+ formattedValue: chart.formatValue(value, entry.key, row, index),
47
+ index,
48
+ key: entry.key,
49
+ label: entry.label,
50
+ row,
51
+ value
52
+ };
53
+ }).filter(Boolean);
54
+ };
55
+ var sameActiveKeys = (current, index, keys) => current?.index === index && current.items.length === keys.length && current.items.every((item, itemIndex) => item.key === keys[itemIndex]);
56
+ var sameActiveTarget = (current, index, keys) => current?.index === index && current.items.every((item) => keys.includes(item.key));
57
+ var sameActiveValue = (current, next) => {
58
+ if (!current || !next) return current === next;
59
+ return sameActiveKeys(current, next.index, next.items.map((item) => item.key));
60
+ };
61
+ var extent = (chart) => {
62
+ const values = chart.data.flatMap((row) => chart.series.map((entry) => number(row[entry.key])).filter((value) => value != null));
63
+ const min = Math.min(0, ...values);
64
+ const max = Math.max(0, ...values);
65
+ return min === max ? {
66
+ max: max + 1,
67
+ min: min - 1
68
+ } : {
69
+ max,
70
+ min
71
+ };
72
+ };
73
+ var scaled = (value, min, max, top, bottom) => bottom - (value - min) / (max - min) * (bottom - top);
74
+ var plotBox = (chart) => ({
75
+ bottom: chart.height - chart.margin.bottom,
76
+ left: chart.margin.left,
77
+ right: chart.width - chart.margin.right,
78
+ top: chart.margin.top
79
+ });
80
+ var clientPoint = (svg, x, y) => {
81
+ if (!svg.isConnected) return null;
82
+ const matrix = svg.getScreenCTM();
83
+ if (!matrix) return null;
84
+ const point = {
85
+ x: matrix.a * x + matrix.c * y + matrix.e,
86
+ y: matrix.b * x + matrix.d * y + matrix.f
87
+ };
88
+ return Number.isFinite(point.x) && Number.isFinite(point.y) ? point : null;
89
+ };
90
+ var svgPoint = (svg, clientX, clientY) => {
91
+ const matrix = svg.getScreenCTM();
92
+ if (!matrix) return null;
93
+ const determinant = matrix.a * matrix.d - matrix.b * matrix.c;
94
+ if (!Number.isFinite(determinant) || determinant === 0) return null;
95
+ const x = clientX - matrix.e;
96
+ const y = clientY - matrix.f;
97
+ return {
98
+ x: (matrix.d * x - matrix.c * y) / determinant,
99
+ y: (-matrix.b * x + matrix.a * y) / determinant
100
+ };
101
+ };
102
+ var referencePoint = (svg, point) => ({
103
+ svg,
104
+ x: point.x,
105
+ y: point.y
106
+ });
107
+ var plotRef = (chart, ref) => {
108
+ let current = null;
109
+ return (element) => {
110
+ if (current && current !== element) chart.releasePlot(current);
111
+ current = element;
112
+ callRef(ref, element);
113
+ };
114
+ };
115
+ var svgFromEvent = (event) => {
116
+ const current = event.currentTarget;
117
+ if (current instanceof SVGSVGElement) return current;
118
+ if (current?.ownerSVGElement) return current.ownerSVGElement;
119
+ const target = event.target;
120
+ if (target instanceof SVGSVGElement) return target;
121
+ return target?.ownerSVGElement ?? null;
122
+ };
123
+ var renderIcon = (icon, classes) => typeof icon === "function" ? icon({ class: classes }) : icon;
124
+ var axis = (chart, type, yTicks, min, max, axisStroke, axisStrokeOpacity, gridStroke) => {
125
+ const box = plotBox(chart);
126
+ const groupWidth = (box.right - box.left) / chart.data.length;
127
+ const xStep = chart.data.length > 1 ? (box.right - box.left) / (chart.data.length - 1) : 0;
128
+ const rowCenter = (index) => type === "bar" ? box.left + groupWidth * index + groupWidth / 2 : chart.data.length > 1 ? box.left + xStep * index : (box.left + box.right) / 2;
129
+ return /* @__PURE__ */ jsxs("g", {
130
+ "data-slot": "chart-axis",
131
+ children: [
132
+ /* @__PURE__ */ jsx("line", {
133
+ x1: box.left,
134
+ x2: box.right,
135
+ y1: box.bottom,
136
+ y2: box.bottom,
137
+ stroke: axisStroke,
138
+ "stroke-opacity": axisStrokeOpacity
139
+ }),
140
+ /* @__PURE__ */ jsx("line", {
141
+ x1: box.left,
142
+ x2: box.left,
143
+ y1: box.top,
144
+ y2: box.bottom,
145
+ stroke: axisStroke,
146
+ "stroke-opacity": axisStrokeOpacity
147
+ }),
148
+ yTicks.map((tick) => {
149
+ const y = scaled(tick, min, max, box.top, box.bottom);
150
+ return /* @__PURE__ */ jsxs("g", { children: [/* @__PURE__ */ jsx("line", {
151
+ x1: box.left,
152
+ x2: box.right,
153
+ y1: y,
154
+ y2: y,
155
+ stroke: gridStroke
156
+ }), /* @__PURE__ */ jsx("text", {
157
+ x: box.left - 8,
158
+ y: y + 3,
159
+ fill: "currentColor",
160
+ style: "text-anchor:end",
161
+ children: chart.formatValue(tick, "", {}, 0)
162
+ })] }, tick);
163
+ }),
164
+ chart.data.map((row, index) => {
165
+ return /* @__PURE__ */ jsx("text", {
166
+ x: rowCenter(index),
167
+ y: chart.height - 8,
168
+ fill: "currentColor",
169
+ style: "text-anchor:middle",
170
+ children: text(labelFor(chart, row, index)).slice(0, 12)
171
+ }, index);
172
+ })
173
+ ]
174
+ });
175
+ };
176
+ var linePath = (points) => points.map((point, index) => `${index ? "L" : "M"} ${point.x} ${point.y}`).join(" ");
177
+ var areaPath = (points, baseline) => points.length ? `${linePath(points)} L ${points[points.length - 1].x} ${baseline} L ${points[0].x} ${baseline} Z` : "";
178
+ var anglePoint = (center, radius, angle) => ({
179
+ x: center + radius * Math.cos(angle),
180
+ y: center + radius * Math.sin(angle)
181
+ });
182
+ var slicePath = (center, radius, innerRadius, start, end) => {
183
+ const outerStart = anglePoint(center, radius, start);
184
+ const outerEnd = anglePoint(center, radius, end);
185
+ const large = end - start > Math.PI ? 1 : 0;
186
+ if (innerRadius > 0) {
187
+ const innerStart = anglePoint(center, innerRadius, start);
188
+ const innerEnd = anglePoint(center, innerRadius, end);
189
+ return [
190
+ `M ${outerStart.x} ${outerStart.y}`,
191
+ `A ${radius} ${radius} 0 ${large} 1 ${outerEnd.x} ${outerEnd.y}`,
192
+ `L ${innerEnd.x} ${innerEnd.y}`,
193
+ `A ${innerRadius} ${innerRadius} 0 ${large} 0 ${innerStart.x} ${innerStart.y}`,
194
+ "Z"
195
+ ].join(" ");
196
+ }
197
+ return [
198
+ `M ${center} ${center}`,
199
+ `L ${outerStart.x} ${outerStart.y}`,
200
+ `A ${radius} ${radius} 0 ${large} 1 ${outerEnd.x} ${outerEnd.y}`,
201
+ "Z"
202
+ ].join(" ");
203
+ };
204
+ var ChartContainerRoot = function* () {
205
+ let active = null;
206
+ const fallbackId = id("chart");
207
+ let tooltip = null;
208
+ const root = dom(this) ? this : null;
209
+ let activePoint = null;
210
+ let lastClientPoint = null;
211
+ const reference = root ? pointReference(() => activePoint?.svg ?? root, () => {
212
+ const next = activePoint ? clientPoint(activePoint.svg, activePoint.x, activePoint.y) : null;
213
+ if (next) lastClientPoint = next;
214
+ if (lastClientPoint) return lastClientPoint;
215
+ const rect = root.getBoundingClientRect();
216
+ return {
217
+ x: rect.left,
218
+ y: rect.top
219
+ };
220
+ }) : null;
221
+ const geometry = position(this, {
222
+ profile: "chart",
223
+ boundary: () => root,
224
+ elements: () => ({
225
+ reference,
226
+ floating: tooltip,
227
+ arrow: null
228
+ })
229
+ });
230
+ let geometryScheduled = false;
231
+ let geometryRestart = false;
232
+ const report = (error) => {
233
+ if (this.signal.aborted) return;
234
+ queueMicrotask(() => {
235
+ if (!this.signal.aborted) this.throw(error);
236
+ });
237
+ };
238
+ const scheduleGeometry = (restart = false) => {
239
+ geometryRestart ||= restart;
240
+ if (geometryScheduled || this.signal.aborted) return;
241
+ geometryScheduled = true;
242
+ queueMicrotask(() => {
243
+ geometryScheduled = false;
244
+ const shouldRestart = geometryRestart;
245
+ geometryRestart = false;
246
+ if (!active || !activePoint || !tooltip || this.signal.aborted) return;
247
+ (shouldRestart ? geometry.start() : geometry.update()).catch(report);
248
+ });
249
+ };
250
+ const setTooltip = (element) => {
251
+ if (element === tooltip) return;
252
+ geometry.stop();
253
+ tooltip = element;
254
+ if (active && activePoint && element) scheduleGeometry(true);
255
+ };
256
+ const movePoint = (next) => {
257
+ if (!next) return 0;
258
+ if (activePoint?.svg === next.svg && activePoint.x === next.x && activePoint.y === next.y) return 0;
259
+ const retargeted = activePoint != null && activePoint.svg !== next.svg;
260
+ activePoint = next;
261
+ return retargeted ? 2 : 1;
262
+ };
263
+ const setActive = (next, at) => {
264
+ const movement = next ? movePoint(at) : 0;
265
+ const retargeted = movement === 2;
266
+ if (retargeted) geometry.stop();
267
+ if (!next) {
268
+ activePoint = null;
269
+ lastClientPoint = null;
270
+ geometry.stop();
271
+ }
272
+ if (sameActiveValue(active, next)) {
273
+ if (next && movement) scheduleGeometry(movement === 2);
274
+ return;
275
+ }
276
+ const first = active == null && next != null;
277
+ this.next(() => active = next);
278
+ if (next && at) scheduleGeometry(first || retargeted);
279
+ };
280
+ const clearActive = () => setActive(null);
281
+ const releasePlot = (plot) => {
282
+ if (this.signal.aborted || activePoint?.svg !== plot) return;
283
+ const releasedPoint = activePoint;
284
+ geometry.stop();
285
+ activePoint = null;
286
+ lastClientPoint = null;
287
+ queueMicrotask(() => {
288
+ if (this.signal.aborted || activePoint) return;
289
+ if (plot.isConnected) {
290
+ activePoint = releasedPoint;
291
+ if (active && tooltip) scheduleGeometry(true);
292
+ return;
293
+ }
294
+ if (active) clearActive();
295
+ });
296
+ };
297
+ for (const args of this) {
298
+ const chartId = args.chartId ?? resolveRootChartId(args.rootId, fallbackId);
299
+ const data = args.data ?? [];
300
+ const width = args.width ?? DEFAULT_WIDTH;
301
+ const height = args.height ?? DEFAULT_HEIGHT;
302
+ const margin = {
303
+ ...DEFAULT_MARGIN,
304
+ ...args.margin ?? {}
305
+ };
306
+ const type = args.type ?? "bar";
307
+ const chart = {
308
+ active,
309
+ clearActive,
310
+ config: args.config,
311
+ data,
312
+ description: args.description,
313
+ formatLabel: args.formatLabel ?? defaultFormatLabel,
314
+ formatValue: args.formatValue ?? defaultFormatValue,
315
+ height,
316
+ id: chartId,
317
+ label: args.label,
318
+ margin,
319
+ palette: args.palette,
320
+ releasePlot,
321
+ series: seriesEntries(args.config, args.series, data, args.xKey, args.palette),
322
+ setActive,
323
+ setTooltip,
324
+ type,
325
+ width,
326
+ xKey: args.xKey
327
+ };
328
+ ChartContext(chart);
329
+ ChartIdContext(chart.id);
330
+ yield /* @__PURE__ */ jsx(Fragment, { children: args.children });
331
+ }
332
+ };
333
+ /** Unstyled chart root provider for config, data, tooltip, and legend state. */
334
+ var ChartContainer = ({ chartId, children, class: classes, config, data, description, formatLabel, formatValue, height, id, label, margin, palette, series, type, width, xKey, ...attrs }) => {
335
+ return /* @__PURE__ */ jsx(ChartContainerRoot, {
336
+ ...statefulRootAttrs(attrs),
337
+ chartId,
338
+ config,
339
+ data,
340
+ description,
341
+ formatLabel,
342
+ formatValue,
343
+ height,
344
+ margin,
345
+ palette,
346
+ rootId: id,
347
+ series,
348
+ type,
349
+ width,
350
+ xKey,
351
+ "attr:class": classes,
352
+ "attr:data-slot": "chart",
353
+ "attr:id": id,
354
+ label,
355
+ children
356
+ });
357
+ };
358
+ var ChartPlot = ({ axis: showAxis = true, axisStroke, axisStrokeOpacity, barClass, class: classes, grid: showGrid = true, gridStroke, pointClass, pointFill, ref, type, ...attrs }) => {
359
+ const chart = ChartContext();
360
+ if (!chart || !chart.data.length || !chart.series.length) return null;
361
+ const box = plotBox(chart);
362
+ const { max, min } = extent(chart);
363
+ const yTicks = Array.from({ length: 4 }, (_, index) => min + (max - min) / 3 * index);
364
+ const groupWidth = (box.right - box.left) / chart.data.length;
365
+ const xStep = chart.data.length > 1 ? (box.right - box.left) / (chart.data.length - 1) : 0;
366
+ const baseline = scaled(0, min, max, box.top, box.bottom);
367
+ const rowCenter = (index) => type === "bar" ? box.left + groupWidth * index + groupWidth / 2 : chart.data.length > 1 ? box.left + xStep * index : (box.left + box.right) / 2;
368
+ const seriesKeys = chart.series.map((entry) => entry.key);
369
+ const rowY = (index) => Math.min(...chart.series.map((entry) => scaled(number(chart.data[index]?.[entry.key]) ?? 0, min, max, box.top, box.bottom)));
370
+ const rowPoint = (index) => ({
371
+ x: rowCenter(index),
372
+ y: rowY(index)
373
+ });
374
+ const points = (entry) => chart.data.map((row, index) => ({
375
+ x: rowCenter(index),
376
+ y: scaled(number(row[entry.key]) ?? 0, min, max, box.top, box.bottom)
377
+ }));
378
+ const activate = (index, at) => {
379
+ if (sameActiveTarget(chart.active, index, seriesKeys)) {
380
+ chart.setActive(chart.active, at);
381
+ return;
382
+ }
383
+ const items = payloadFor(chart, index);
384
+ if (!items.length) {
385
+ chart.clearActive();
386
+ return;
387
+ }
388
+ const point = rowPoint(index);
389
+ chart.setActive({
390
+ index,
391
+ items,
392
+ label: labelFor(chart, chart.data[index], index),
393
+ x: point.x,
394
+ y: point.y
395
+ }, at);
396
+ };
397
+ const pointerMove = (event) => {
398
+ const svg = event.currentTarget;
399
+ const cursor = svgPoint(svg, event.clientX, event.clientY);
400
+ if (!cursor) {
401
+ chart.clearActive();
402
+ return;
403
+ }
404
+ const sx = cursor.x;
405
+ const index = type === "bar" ? clamp(Math.floor((sx - box.left) / groupWidth), 0, chart.data.length - 1) : xStep === 0 ? 0 : clamp(Math.round((sx - box.left) / xStep), 0, chart.data.length - 1);
406
+ activate(index, referencePoint(svg, rowPoint(index)));
407
+ };
408
+ const focusIn = (event) => {
409
+ const target = event.target;
410
+ const index = Number(target?.getAttribute("data-chart-index"));
411
+ const svg = svgFromEvent(event);
412
+ if (!svg || !Number.isInteger(index)) return;
413
+ activate(index, referencePoint(svg, rowPoint(index)));
414
+ };
415
+ return /* @__PURE__ */ jsxs("svg", {
416
+ ...attrs,
417
+ "aria-describedby": chart.description ? `${chart.id}-description` : void 0,
418
+ "aria-label": chart.label,
419
+ class: classes,
420
+ "data-slot": `chart-${type}`,
421
+ height: chart.height,
422
+ role: "img",
423
+ ref: plotRef(chart, ref),
424
+ viewBox: `0 0 ${chart.width} ${chart.height}`,
425
+ width: "100%",
426
+ xmlns: "http://www.w3.org/2000/svg",
427
+ "set:onfocusin": focusIn,
428
+ "set:onpointerleave": chart.clearActive,
429
+ "set:onpointermove": pointerMove,
430
+ children: [
431
+ chart.label ? /* @__PURE__ */ jsx("title", { children: chart.label }) : null,
432
+ chart.description ? /* @__PURE__ */ jsx("desc", {
433
+ id: `${chart.id}-description`,
434
+ children: chart.description
435
+ }) : null,
436
+ showGrid ? axis(chart, type, yTicks, min, max, axisStroke, axisStrokeOpacity, gridStroke) : showAxis ? axis(chart, type, [], min, max, axisStroke, axisStrokeOpacity, gridStroke) : null,
437
+ type === "bar" ? chart.data.map((row, index) => {
438
+ const barWidth = clamp(groupWidth * .68 / chart.series.length, 6, 42);
439
+ const groupStart = box.left + groupWidth * index + (groupWidth - barWidth * chart.series.length) / 2;
440
+ return chart.series.map((entry, seriesIndex) => {
441
+ const value = number(row[entry.key]) ?? 0;
442
+ const sign = value === 0 ? "zero" : value < 0 ? "negative" : "positive";
443
+ const y = scaled(Math.max(0, value), min, max, box.top, box.bottom);
444
+ const yZero = scaled(Math.min(0, value), min, max, box.top, box.bottom);
445
+ const height = Math.max(1, Math.abs(yZero - y));
446
+ const x = groupStart + seriesIndex * barWidth;
447
+ return /* @__PURE__ */ jsx("rect", {
448
+ "aria-label": `${text(labelFor(chart, row, index))} ${text(entry.label)} ${chart.formatValue(value, entry.key, row, index)}`,
449
+ class: barClass,
450
+ "data-active": chart.active?.index === index ? "true" : void 0,
451
+ "data-chart-index": index,
452
+ "data-chart-sign": sign,
453
+ "data-chart-series": entry.key,
454
+ fill: entry.color,
455
+ focusable: "true",
456
+ height,
457
+ style: `--chart-index:${index}`,
458
+ tabindex: "0",
459
+ width: Math.max(2, barWidth - 2),
460
+ x,
461
+ y: Math.min(y, yZero),
462
+ "set:onfocus": (event) => {
463
+ const svg = svgFromEvent(event);
464
+ const point = rowPoint(index);
465
+ if (svg) activate(index, referencePoint(svg, point));
466
+ },
467
+ "set:onpointerenter": (event) => {
468
+ const svg = svgFromEvent(event);
469
+ const point = rowPoint(index);
470
+ if (svg) activate(index, referencePoint(svg, point));
471
+ }
472
+ }, `${entry.key}-${index}`);
473
+ });
474
+ }) : chart.series.map((entry) => {
475
+ const entryPoints = points(entry);
476
+ return /* @__PURE__ */ jsxs("g", {
477
+ "data-chart-series": entry.key,
478
+ children: [
479
+ type === "area" ? /* @__PURE__ */ jsx("path", {
480
+ d: areaPath(entryPoints, baseline),
481
+ fill: entry.color,
482
+ "fill-opacity": "0.18"
483
+ }) : null,
484
+ /* @__PURE__ */ jsx("path", {
485
+ d: linePath(entryPoints),
486
+ fill: "none",
487
+ pathLength: 1,
488
+ stroke: entry.color,
489
+ "stroke-linecap": "round",
490
+ "stroke-linejoin": "round",
491
+ "stroke-width": "2"
492
+ }),
493
+ entryPoints.map((point, index) => {
494
+ const row = chart.data[index];
495
+ const value = number(row[entry.key]) ?? 0;
496
+ return /* @__PURE__ */ jsx("circle", {
497
+ "aria-label": `${text(labelFor(chart, row, index))} ${text(entry.label)} ${chart.formatValue(value, entry.key, row, index)}`,
498
+ class: pointClass,
499
+ cx: point.x,
500
+ cy: point.y,
501
+ "data-active": chart.active?.index === index ? "true" : void 0,
502
+ "data-chart-index": index,
503
+ fill: pointFill,
504
+ focusable: "true",
505
+ r: "4",
506
+ style: `--chart-index:${index}`,
507
+ stroke: entry.color,
508
+ "stroke-width": "2",
509
+ tabindex: "0",
510
+ "set:onfocus": (event) => {
511
+ const svg = svgFromEvent(event);
512
+ const activePoint = rowPoint(index);
513
+ if (svg) activate(index, referencePoint(svg, activePoint));
514
+ },
515
+ "set:onpointerenter": (event) => {
516
+ const svg = svgFromEvent(event);
517
+ const activePoint = rowPoint(index);
518
+ if (svg) activate(index, referencePoint(svg, activePoint));
519
+ }
520
+ }, `${entry.key}-${index}`);
521
+ })
522
+ ]
523
+ }, entry.key);
524
+ })
525
+ ]
526
+ });
527
+ };
528
+ /** Unstyled SVG bar chart primitive for use inside ChartContainer. */
529
+ var ChartBar = (attrs) => /* @__PURE__ */ jsx(ChartPlot, {
530
+ ...attrs,
531
+ type: "bar"
532
+ });
533
+ /** Unstyled SVG line chart primitive for use inside ChartContainer. */
534
+ var ChartLine = (attrs) => /* @__PURE__ */ jsx(ChartPlot, {
535
+ ...attrs,
536
+ type: "line"
537
+ });
538
+ /** Unstyled SVG area chart primitive for use inside ChartContainer. */
539
+ var ChartArea = (attrs) => /* @__PURE__ */ jsx(ChartPlot, {
540
+ ...attrs,
541
+ type: "area"
542
+ });
543
+ /** Unstyled SVG pie/donut chart primitive for use inside ChartContainer. */
544
+ var ChartPie = ({ centerLabelClass, centerLabelFill, class: classes, innerRadius = 0, ref, sliceStroke, ...attrs }) => {
545
+ const chart = ChartContext();
546
+ if (!chart || !chart.data.length || !chart.series.length) return null;
547
+ const entry = chart.series[0];
548
+ const values = chart.data.map((row) => Math.max(0, number(row[entry.key]) ?? 0));
549
+ const total = values.reduce((sum, value) => sum + value, 0) || 1;
550
+ const size = Math.min(chart.width, chart.height);
551
+ const center = size / 2;
552
+ const radius = center - 12;
553
+ let start = -Math.PI / 2;
554
+ const activate = (index, angle, color, at) => {
555
+ if (sameActiveTarget(chart.active, index, [entry.key])) {
556
+ chart.setActive(chart.active, at);
557
+ return;
558
+ }
559
+ const point = anglePoint(center, radius * .78, angle);
560
+ const row = chart.data[index];
561
+ const value = values[index] ?? 0;
562
+ chart.setActive({
563
+ index,
564
+ items: [{
565
+ color,
566
+ formattedValue: chart.formatValue(value, entry.key, row, index),
567
+ index,
568
+ key: entry.key,
569
+ label: labelFor(chart, row, index),
570
+ row,
571
+ value
572
+ }],
573
+ label: labelFor(chart, row, index),
574
+ x: point.x,
575
+ y: point.y
576
+ }, at);
577
+ };
578
+ const focusIn = (event) => {
579
+ const target = event.target;
580
+ const index = Number(target?.getAttribute("data-chart-index"));
581
+ if (!Number.isInteger(index)) return;
582
+ const svg = svgFromEvent(event);
583
+ if (!svg) return;
584
+ const totalBefore = values.slice(0, index).reduce((sum, value) => sum + value, 0);
585
+ const value = values[index] ?? 0;
586
+ const middle = -Math.PI / 2 + totalBefore / total * Math.PI * 2 + value / total * Math.PI * 2 / 2;
587
+ const point = anglePoint(center, radius * .78, middle);
588
+ activate(index, middle, chart.palette[index % chart.palette.length], referencePoint(svg, point));
589
+ };
590
+ const pointerMove = (event) => {
591
+ const svg = event.currentTarget;
592
+ const cursorPoint = svgPoint(svg, event.clientX, event.clientY);
593
+ if (!cursorPoint) {
594
+ chart.clearActive();
595
+ return;
596
+ }
597
+ const { x, y } = cursorPoint;
598
+ const distance = Math.hypot(x - center, y - center);
599
+ if (distance > radius || distance < innerRadius) {
600
+ chart.clearActive();
601
+ return;
602
+ }
603
+ let angle = Math.atan2(y - center, x - center) + Math.PI / 2;
604
+ if (angle < 0) angle += Math.PI * 2;
605
+ let cursor = 0;
606
+ for (let index = 0; index < values.length; index++) {
607
+ const span = (values[index] ?? 0) / total * Math.PI * 2;
608
+ if (angle <= cursor + span || index === values.length - 1) {
609
+ const middle = -Math.PI / 2 + cursor + span / 2;
610
+ const point = anglePoint(center, radius * .78, middle);
611
+ activate(index, middle, chart.palette[index % chart.palette.length], referencePoint(svg, point));
612
+ return;
613
+ }
614
+ cursor += span;
615
+ }
616
+ };
617
+ return /* @__PURE__ */ jsxs("svg", {
618
+ ...attrs,
619
+ "aria-describedby": chart.description ? `${chart.id}-description` : void 0,
620
+ "aria-label": chart.label,
621
+ class: classes,
622
+ "data-slot": "chart-pie",
623
+ height: chart.height,
624
+ role: "img",
625
+ ref: plotRef(chart, ref),
626
+ viewBox: `0 0 ${size} ${size}`,
627
+ width: "100%",
628
+ xmlns: "http://www.w3.org/2000/svg",
629
+ "set:onfocusin": focusIn,
630
+ "set:onpointerleave": chart.clearActive,
631
+ "set:onpointermove": pointerMove,
632
+ children: [
633
+ chart.label ? /* @__PURE__ */ jsx("title", { children: chart.label }) : null,
634
+ chart.description ? /* @__PURE__ */ jsx("desc", {
635
+ id: `${chart.id}-description`,
636
+ children: chart.description
637
+ }) : null,
638
+ values.map((value, index) => {
639
+ const angle = value / total * Math.PI * 2;
640
+ const end = start + angle;
641
+ const middle = start + angle / 2;
642
+ const color = chart.palette[index % chart.palette.length];
643
+ const path = slicePath(center, radius, innerRadius, start, end);
644
+ const row = chart.data[index];
645
+ start = end;
646
+ return /* @__PURE__ */ jsx("path", {
647
+ "aria-label": `${text(labelFor(chart, row, index))} ${chart.formatValue(value, entry.key, row, index)}`,
648
+ d: path,
649
+ "data-active": chart.active?.index === index ? "true" : void 0,
650
+ "data-chart-index": index,
651
+ fill: color,
652
+ focusable: "true",
653
+ style: `--chart-index:${index}`,
654
+ stroke: sliceStroke,
655
+ "stroke-width": "2",
656
+ tabindex: "0",
657
+ "set:onfocus": (event) => {
658
+ const svg = svgFromEvent(event);
659
+ const point = anglePoint(center, radius * .78, middle);
660
+ if (svg) activate(index, middle, color, referencePoint(svg, point));
661
+ },
662
+ "set:onpointerenter": (event) => {
663
+ const svg = svgFromEvent(event);
664
+ const point = anglePoint(center, radius * .78, middle);
665
+ if (svg) activate(index, middle, color, referencePoint(svg, point));
666
+ }
667
+ }, index);
668
+ }),
669
+ innerRadius > 0 ? /* @__PURE__ */ jsx("text", {
670
+ x: center,
671
+ y: center,
672
+ fill: centerLabelFill,
673
+ class: centerLabelClass,
674
+ style: "text-anchor:middle;dominant-baseline:middle",
675
+ children: chart.formatValue(total, entry.key, {}, 0)
676
+ }) : null
677
+ ]
678
+ });
679
+ };
680
+ /** Unstyled absolute tooltip layer for native chart primitives. */
681
+ var ChartTooltip = ({ children, class: classes, content, ...attrs }) => {
682
+ const chart = ChartContext();
683
+ if (!chart) return null;
684
+ if (!chart.active?.items.length) return null;
685
+ return /* @__PURE__ */ jsx("div", {
686
+ ...attrs,
687
+ class: classes,
688
+ "data-slot": "chart-tooltip",
689
+ ref: chart.setTooltip,
690
+ style: "left:0;top:0",
691
+ children: content ?? children ?? /* @__PURE__ */ jsx(ChartTooltipContent, {})
692
+ }, "chart-tooltip");
693
+ };
694
+ /** Unstyled tooltip body for native chart payloads. */
695
+ var ChartTooltipContent = ({ class: classes, formattedValueClass, formatter, hideIndicator, hideLabel, iconClass, iconWrapperClass, indicator = "dot", indicatorClass, itemClass, itemLabelClass, itemsClass, labelClass, labelFormatter, nestedLabelClass, valueLabelGroupClass, valueRowClass, ...attrs }) => {
696
+ const chart = ChartContext();
697
+ const active = chart?.active;
698
+ if (!chart || !active?.items.length) return null;
699
+ const nestLabel = active.items.length === 1 && indicator !== "dot";
700
+ const state = {
701
+ indicator,
702
+ nestLabel
703
+ };
704
+ return /* @__PURE__ */ jsxs("div", {
705
+ ...attrs,
706
+ class: classes,
707
+ "data-slot": "chart-tooltip-content",
708
+ children: [!hideLabel && !nestLabel ? /* @__PURE__ */ jsx("div", {
709
+ class: labelClass,
710
+ "data-slot": "chart-tooltip-label",
711
+ children: labelFormatter ? labelFormatter(active.label, active.items) : active.label
712
+ }) : null, /* @__PURE__ */ jsx("div", {
713
+ class: itemsClass,
714
+ children: active.items.map((item, index) => {
715
+ const icon = chart.config[item.key]?.icon;
716
+ return /* @__PURE__ */ jsx("div", {
717
+ class: resolve(itemClass, state),
718
+ "data-slot": "chart-tooltip-item",
719
+ children: formatter ? formatter(item.value, item.key, item, index) : /* @__PURE__ */ jsxs(Fragment, { children: [icon && !hideIndicator ? /* @__PURE__ */ jsx("span", {
720
+ "aria-hidden": "true",
721
+ class: iconWrapperClass,
722
+ children: renderIcon(icon, iconClass)
723
+ }) : !hideIndicator ? /* @__PURE__ */ jsx("span", {
724
+ "aria-hidden": "true",
725
+ class: resolve(indicatorClass, state),
726
+ style: `--chart-indicator:${item.color}`
727
+ }) : null, /* @__PURE__ */ jsxs("div", {
728
+ class: resolve(valueRowClass, { nestLabel }),
729
+ children: [/* @__PURE__ */ jsxs("div", {
730
+ class: valueLabelGroupClass,
731
+ children: [!hideLabel && nestLabel ? /* @__PURE__ */ jsx("div", {
732
+ class: nestedLabelClass,
733
+ children: labelFormatter ? labelFormatter(active.label, active.items) : active.label
734
+ }) : null, /* @__PURE__ */ jsx("span", {
735
+ class: itemLabelClass,
736
+ children: item.label
737
+ })]
738
+ }), /* @__PURE__ */ jsx("span", {
739
+ class: formattedValueClass,
740
+ children: item.formattedValue
741
+ })]
742
+ })] })
743
+ }, `${item.key}-${index}`);
744
+ })
745
+ })]
746
+ });
747
+ };
748
+ /** Unstyled legend layer for native chart primitives. */
749
+ var ChartLegend = ({ children, class: classes, content, ...attrs }) => /* @__PURE__ */ jsx("div", {
750
+ ...attrs,
751
+ class: classes,
752
+ "data-slot": "chart-legend",
753
+ children: content ?? children ?? /* @__PURE__ */ jsx(ChartLegendContent, {})
754
+ }, "chart-legend");
755
+ /** Unstyled legend content for native chart payloads. */
756
+ var ChartLegendContent = ({ class: classes, hideIcon, iconClass, iconWrapperClass, itemClass, swatchClass, ...attrs }) => {
757
+ const chart = ChartContext();
758
+ if (!chart) return null;
759
+ const entries = chart.type === "pie" ? chart.data.map((row, index) => ({
760
+ color: chart.palette[index % chart.palette.length],
761
+ icon: void 0,
762
+ key: String(index),
763
+ label: labelFor(chart, row, index)
764
+ })) : chart.series.map((entry) => ({
765
+ color: entry.color,
766
+ icon: chart.config[entry.key]?.icon,
767
+ key: entry.key,
768
+ label: entry.label
769
+ }));
770
+ return /* @__PURE__ */ jsx("div", {
771
+ ...attrs,
772
+ class: classes,
773
+ "data-slot": "chart-legend-content",
774
+ children: entries.map((entry) => /* @__PURE__ */ jsxs("div", {
775
+ class: itemClass,
776
+ "data-slot": "chart-legend-item",
777
+ children: [entry.icon && !hideIcon ? /* @__PURE__ */ jsx("span", {
778
+ "aria-hidden": "true",
779
+ class: iconWrapperClass,
780
+ children: renderIcon(entry.icon, iconClass)
781
+ }) : /* @__PURE__ */ jsx("span", {
782
+ "aria-hidden": "true",
783
+ class: swatchClass,
784
+ style: `background:${entry.color}`
785
+ }), /* @__PURE__ */ jsx("span", { children: entry.label })]
786
+ }, entry.key))
787
+ });
788
+ };
789
+ //#endregion
790
+ export { ChartArea, ChartBar, ChartContainer, ChartIdContext, ChartLegend, ChartLegendContent, ChartLine, ChartPie, ChartTooltip, ChartTooltipContent };