@classic-homes/charts-react 0.2.2 → 0.4.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.
package/dist/index.js CHANGED
@@ -1,5 +1,10 @@
1
1
  // src/components/base/ChartContainer.tsx
2
2
  import * as React4 from "react";
3
+ import {
4
+ chartFilename,
5
+ downloadCsv,
6
+ downloadFile
7
+ } from "@classic-homes/charts-core";
3
8
 
4
9
  // src/lib/utils.ts
5
10
  import { clsx } from "clsx";
@@ -83,7 +88,7 @@ var ChartError = React2.forwardRef(
83
88
  {
84
89
  type: "button",
85
90
  onClick: onRetry,
86
- className: "rounded-md bg-destructive px-3 py-1.5 text-xs font-medium text-destructive-foreground transition-colors hover:bg-destructive/90",
91
+ className: "rounded-md bg-destructive px-3 py-1.5 text-xs font-medium text-destructive-foreground hover:bg-destructive/90",
87
92
  children: "Retry"
88
93
  }
89
94
  )
@@ -139,20 +144,64 @@ var ChartEmpty = React3.forwardRef(
139
144
  );
140
145
  ChartEmpty.displayName = "ChartEmpty";
141
146
 
142
- // src/components/base/ChartContainer.tsx
147
+ // src/components/base/ChartDataTable.tsx
148
+ import {
149
+ formatTableCell
150
+ } from "@classic-homes/charts-core";
143
151
  import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
152
+ function ChartDataTable({
153
+ table,
154
+ caption,
155
+ format,
156
+ srOnly = false,
157
+ className
158
+ }) {
159
+ return /* @__PURE__ */ jsx4(
160
+ "div",
161
+ {
162
+ "data-testid": "chart-data-table",
163
+ className: cn(srOnly ? "sr-only" : "max-h-80 overflow-auto", className),
164
+ children: /* @__PURE__ */ jsxs4("table", { className: "w-full border-collapse text-sm", children: [
165
+ /* @__PURE__ */ jsx4("caption", { className: srOnly ? void 0 : "sr-only", children: caption }),
166
+ /* @__PURE__ */ jsx4("thead", { children: /* @__PURE__ */ jsx4("tr", { children: table.headers.map((header, column) => /* @__PURE__ */ jsx4(
167
+ "th",
168
+ {
169
+ scope: "col",
170
+ className: cn(
171
+ "sticky top-0 border-b border-border bg-card px-3 py-2 font-medium text-muted-foreground",
172
+ column === 0 ? "text-left" : "text-right"
173
+ ),
174
+ children: header
175
+ },
176
+ column
177
+ )) }) }),
178
+ /* @__PURE__ */ jsx4("tbody", { children: table.rows.map((row, rowIndex) => /* @__PURE__ */ jsx4("tr", { className: "border-b border-border last:border-0", children: row.map(
179
+ (cell, column) => column === 0 ? /* @__PURE__ */ jsx4(
180
+ "th",
181
+ {
182
+ scope: "row",
183
+ className: "px-3 py-1.5 text-left font-normal text-foreground",
184
+ children: formatTableCell(table, cell, column, format)
185
+ },
186
+ column
187
+ ) : /* @__PURE__ */ jsx4("td", { className: "px-3 py-1.5 text-right tabular-nums text-foreground", children: formatTableCell(table, cell, column, format) }, column)
188
+ ) }, rowIndex)) })
189
+ ] })
190
+ }
191
+ );
192
+ }
193
+
194
+ // src/components/base/ChartContainer.tsx
195
+ import { Fragment, jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
144
196
  var CHART_ONLY_PROPS = [
145
- "minHeight",
146
- "maxHeight",
147
197
  "rowHeight",
148
198
  "showLegend",
149
199
  "showGrid",
150
200
  "valueFormat",
151
201
  "locale",
152
202
  "onReady",
203
+ "onHover",
153
204
  "events",
154
- "showDataTable",
155
- "exportable",
156
205
  "patterns",
157
206
  "referenceLines",
158
207
  "referenceBands",
@@ -165,11 +214,15 @@ function domProps(props) {
165
214
  for (const key of CHART_ONLY_PROPS) delete rest[key];
166
215
  return rest;
167
216
  }
217
+ var SR_TABLE_MAX_ROWS = 500;
218
+ var buttonClass = "rounded-md px-2 py-1 text-xs font-medium text-muted-foreground hover:bg-accent hover:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring";
168
219
  var ChartContainer = React4.forwardRef(
169
220
  ({
170
221
  title,
171
222
  description,
172
223
  height = 400,
224
+ minHeight,
225
+ maxHeight,
173
226
  loading,
174
227
  error,
175
228
  empty,
@@ -179,16 +232,24 @@ var ChartContainer = React4.forwardRef(
179
232
  wrapperClassName,
180
233
  legend,
181
234
  legendPosition = "bottom",
235
+ dataTable,
236
+ showDataTable = "sr-only",
237
+ format,
238
+ exportable,
239
+ exportImage,
182
240
  children,
183
241
  ...props
184
242
  }, ref) => {
185
243
  const heightStyle = typeof height === "number" ? `${height}px` : height;
186
- const descriptionId = `${React4.useId()}-desc`;
244
+ const uid = React4.useId();
245
+ const descriptionId = `${uid}-desc`;
246
+ const tableId = `${uid}-table`;
247
+ const [tableOpen, setTableOpen] = React4.useState(false);
187
248
  if (loading) {
188
- return /* @__PURE__ */ jsx4(ChartSkeleton, { height, className: wrapperClassName });
249
+ return /* @__PURE__ */ jsx5(ChartSkeleton, { height, className: wrapperClassName });
189
250
  }
190
251
  if (error) {
191
- return /* @__PURE__ */ jsx4(
252
+ return /* @__PURE__ */ jsx5(
192
253
  ChartError,
193
254
  {
194
255
  message: error,
@@ -199,9 +260,19 @@ var ChartContainer = React4.forwardRef(
199
260
  );
200
261
  }
201
262
  if (empty) {
202
- return /* @__PURE__ */ jsx4(ChartEmpty, { message: emptyMessage, height, className: wrapperClassName });
263
+ return /* @__PURE__ */ jsx5(ChartEmpty, { message: emptyMessage, height, className: wrapperClassName });
203
264
  }
204
- const chart = /* @__PURE__ */ jsxs4(
265
+ const exportConfig = exportable ? exportable === true ? {} : exportable : void 0;
266
+ const canExportImage = !!exportConfig && exportConfig.image !== false && !!exportImage;
267
+ const canExportCsv = !!exportConfig && exportConfig.csv !== false && !!dataTable;
268
+ const filename = exportConfig?.filename ?? chartFilename(title);
269
+ const toggleTable = showDataTable === true && !!dataTable;
270
+ const toolbar = canExportImage || canExportCsv || toggleTable;
271
+ const downloadImage = () => {
272
+ const url = exportImage?.();
273
+ if (url) downloadFile(url, `${filename}.png`);
274
+ };
275
+ const chart = (chartClassName) => /* @__PURE__ */ jsxs5(
205
276
  "div",
206
277
  {
207
278
  ref,
@@ -209,37 +280,95 @@ var ChartContainer = React4.forwardRef(
209
280
  "aria-label": title,
210
281
  "aria-describedby": description ? descriptionId : void 0,
211
282
  "data-testid": "chart-container",
212
- className: legend ? "min-h-0 min-w-0 flex-1" : cn("rounded-lg border border-border bg-card", wrapperClassName),
283
+ className: chartClassName,
213
284
  ...domProps(props),
214
285
  children: [
215
- description && /* @__PURE__ */ jsx4("span", { id: descriptionId, className: "sr-only", children: description }),
216
- /* @__PURE__ */ jsx4("div", { className: cn("h-full w-full", className), style: { height: heightStyle }, children })
286
+ description && /* @__PURE__ */ jsx5("span", { id: descriptionId, className: "sr-only", children: description }),
287
+ /* @__PURE__ */ jsx5(
288
+ "div",
289
+ {
290
+ className: cn("h-full w-full", className),
291
+ style: {
292
+ height: heightStyle,
293
+ minHeight: minHeight !== void 0 ? `${minHeight}px` : void 0,
294
+ maxHeight: maxHeight !== void 0 ? `${maxHeight}px` : void 0
295
+ },
296
+ children
297
+ }
298
+ )
217
299
  ]
218
300
  }
219
301
  );
220
- if (!legend) return chart;
302
+ const srTable = dataTable && showDataTable === "sr-only" && dataTable.rows.length <= SR_TABLE_MAX_ROWS ? /* @__PURE__ */ jsx5(ChartDataTable, { table: dataTable, caption: `${title} data`, format, srOnly: true }) : null;
303
+ if (!legend && !toolbar) {
304
+ return /* @__PURE__ */ jsxs5(Fragment, { children: [
305
+ chart(cn("rounded-lg border border-border bg-card", wrapperClassName)),
306
+ srTable
307
+ ] });
308
+ }
221
309
  const side = legendPosition === "left" || legendPosition === "right";
222
310
  const leading = legendPosition === "top" || legendPosition === "left";
223
- const legendNode = /* @__PURE__ */ jsx4(
311
+ const legendNode = legend ? /* @__PURE__ */ jsx5(
224
312
  "div",
225
313
  {
226
314
  "data-testid": "chart-legend",
227
315
  className: cn("flex shrink-0 p-2", side ? "items-center" : "justify-center"),
228
316
  children: legend
229
317
  }
230
- );
231
- return /* @__PURE__ */ jsxs4(
318
+ ) : null;
319
+ return /* @__PURE__ */ jsxs5(
232
320
  "div",
233
321
  {
234
- className: cn(
235
- "flex rounded-lg border border-border bg-card",
236
- side ? "flex-row" : "flex-col",
237
- wrapperClassName
238
- ),
322
+ "data-testid": "chart-frame",
323
+ className: cn("flex flex-col rounded-lg border border-border bg-card", wrapperClassName),
239
324
  children: [
240
- leading && legendNode,
241
- chart,
242
- !leading && legendNode
325
+ toolbar && /* @__PURE__ */ jsxs5(
326
+ "div",
327
+ {
328
+ "data-testid": "chart-toolbar",
329
+ className: "flex justify-end gap-1 px-2 pt-2 print:hidden",
330
+ children: [
331
+ toggleTable && /* @__PURE__ */ jsx5(
332
+ "button",
333
+ {
334
+ type: "button",
335
+ className: buttonClass,
336
+ "aria-expanded": tableOpen,
337
+ "aria-controls": tableId,
338
+ onClick: () => setTableOpen((open) => !open),
339
+ children: tableOpen ? "Hide data" : "Show data"
340
+ }
341
+ ),
342
+ canExportImage && /* @__PURE__ */ jsx5(
343
+ "button",
344
+ {
345
+ type: "button",
346
+ className: buttonClass,
347
+ "aria-label": `Download ${title} as PNG`,
348
+ onClick: downloadImage,
349
+ children: "PNG"
350
+ }
351
+ ),
352
+ canExportCsv && /* @__PURE__ */ jsx5(
353
+ "button",
354
+ {
355
+ type: "button",
356
+ className: buttonClass,
357
+ "aria-label": `Download ${title} data as CSV`,
358
+ onClick: () => downloadCsv(dataTable, filename),
359
+ children: "CSV"
360
+ }
361
+ )
362
+ ]
363
+ }
364
+ ),
365
+ /* @__PURE__ */ jsxs5("div", { className: cn("flex min-h-0 flex-1", side ? "flex-row" : "flex-col"), children: [
366
+ leading && legendNode,
367
+ chart("min-h-0 min-w-0 flex-1"),
368
+ !leading && legendNode
369
+ ] }),
370
+ toggleTable && /* @__PURE__ */ jsx5("div", { id: tableId, hidden: !tableOpen, className: "border-t border-border p-2", children: tableOpen && /* @__PURE__ */ jsx5(ChartDataTable, { table: dataTable, caption: `${title} data`, format }) }),
371
+ srTable
243
372
  ]
244
373
  }
245
374
  );
@@ -249,11 +378,11 @@ ChartContainer.displayName = "ChartContainer";
249
378
 
250
379
  // src/components/base/ChartLegend.tsx
251
380
  import * as React5 from "react";
252
- import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
381
+ import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
253
382
  var ChartLegend = React5.forwardRef(
254
383
  ({ items, toggle, position = "bottom", chartTitle, orientation, className }, ref) => {
255
384
  const vertical = (orientation ?? (position === "left" || position === "right" ? "vertical" : "horizontal")) === "vertical";
256
- return /* @__PURE__ */ jsx5(
385
+ return /* @__PURE__ */ jsx6(
257
386
  "ul",
258
387
  {
259
388
  ref,
@@ -263,7 +392,7 @@ var ChartLegend = React5.forwardRef(
263
392
  vertical ? "flex-col" : "flex-wrap justify-center",
264
393
  className
265
394
  ),
266
- children: items.map((item) => /* @__PURE__ */ jsx5("li", { children: /* @__PURE__ */ jsxs5(
395
+ children: items.map((item) => /* @__PURE__ */ jsx6("li", { children: /* @__PURE__ */ jsxs6(
267
396
  "button",
268
397
  {
269
398
  type: "button",
@@ -274,7 +403,7 @@ var ChartLegend = React5.forwardRef(
274
403
  item.visible ? "text-foreground" : "text-muted-foreground line-through"
275
404
  ),
276
405
  children: [
277
- /* @__PURE__ */ jsx5(
406
+ /* @__PURE__ */ jsx6(
278
407
  "span",
279
408
  {
280
409
  "aria-hidden": "true",
@@ -302,29 +431,90 @@ import {
302
431
  LegendComponent,
303
432
  TitleComponent
304
433
  } from "echarts/components";
305
- import { CanvasRenderer } from "echarts/renderers";
434
+ import { CanvasRenderer as CanvasRenderer2 } from "echarts/renderers";
306
435
  import {
307
436
  buildAxis,
308
437
  buildDataLabel,
438
+ buildDataZoom,
309
439
  buildLegend,
310
440
  buildTooltip,
441
+ categoryTable,
442
+ chartFormatters,
311
443
  generateLineChartDescription,
312
444
  getChartColors,
313
445
  hasPointLabels,
314
446
  gridInset,
315
447
  mergeChartOption,
448
+ resolveValueFormatter,
316
449
  seriesLabelLookup,
317
450
  THEME_DARK as THEME_DARK2,
318
- withPointLabels
451
+ toPercentStack,
452
+ withPointLabels,
453
+ withReferenceMarks,
454
+ withZoomInset
319
455
  } from "@classic-homes/charts-core";
320
456
 
457
+ // src/lib/events.ts
458
+ var raw = (params) => params ?? {};
459
+ function toDataPointParams(params, fallbackType) {
460
+ const p = raw(params);
461
+ return {
462
+ type: p.type || fallbackType,
463
+ componentType: p.componentType || "series",
464
+ seriesIndex: p.seriesIndex,
465
+ seriesName: p.seriesName || "",
466
+ dataIndex: p.dataIndex ?? 0,
467
+ name: p.name || "",
468
+ value: p.value,
469
+ color: typeof p.color === "string" ? p.color : void 0,
470
+ event: p.event?.event
471
+ };
472
+ }
473
+ function toSliceParams(params, fallbackType) {
474
+ const p = raw(params);
475
+ return {
476
+ type: p.type || fallbackType,
477
+ componentType: p.componentType || "series",
478
+ seriesIndex: p.seriesIndex,
479
+ seriesName: p.seriesName,
480
+ dataIndex: p.dataIndex,
481
+ name: p.name || "",
482
+ value: p.value,
483
+ percent: p.percent,
484
+ color: typeof p.color === "string" ? p.color : void 0,
485
+ event: p.event?.event
486
+ };
487
+ }
488
+ function chartEvents(events, mapped) {
489
+ const merged = { ...events };
490
+ for (const [name, handler] of Object.entries(mapped)) {
491
+ if (!handler) continue;
492
+ const own = events?.[name];
493
+ merged[name] = own ? (params) => {
494
+ handler(params);
495
+ own(params);
496
+ } : handler;
497
+ }
498
+ return merged;
499
+ }
500
+
321
501
  // src/hooks/useChart.ts
322
- import { useEffect as useEffect4, useRef } from "react";
502
+ import { useCallback, useEffect as useEffect4, useRef, useState as useState5 } from "react";
323
503
  import * as echarts2 from "echarts/core";
504
+ import {
505
+ AriaComponent,
506
+ DataZoomInsideComponent,
507
+ DataZoomSliderComponent,
508
+ DatasetComponent,
509
+ GraphicComponent,
510
+ MarkAreaComponent,
511
+ MarkLineComponent
512
+ } from "echarts/components";
513
+ import { CanvasRenderer } from "echarts/renderers";
324
514
  import { getReplaceMerge } from "@classic-homes/charts-core";
325
515
 
326
516
  // src/hooks/useChartTheme.ts
327
- import { useEffect, useState } from "react";
517
+ import { useEffect, useState as useState2 } from "react";
328
518
  import * as echarts from "echarts/core";
329
519
  import { lightTheme, darkTheme, THEME_LIGHT, THEME_DARK } from "@classic-homes/charts-core";
330
520
  var themesRegistered = false;
@@ -342,7 +532,7 @@ function resolveTheme(preference) {
342
532
  return document.documentElement.classList.contains("dark") ? THEME_DARK : THEME_LIGHT;
343
533
  }
344
534
  function useChartTheme(preference = "auto") {
345
- const [currentTheme, setCurrentTheme] = useState(() => resolveTheme(preference));
535
+ const [currentTheme, setCurrentTheme] = useState2(() => resolveTheme(preference));
346
536
  useEffect(() => {
347
537
  registerClassicThemes();
348
538
  const updateTheme = () => setCurrentTheme(resolveTheme(preference));
@@ -367,10 +557,10 @@ function useChartTheme(preference = "auto") {
367
557
  }
368
558
 
369
559
  // src/hooks/useChartResize.ts
370
- import { useEffect as useEffect2, useLayoutEffect, useState as useState2 } from "react";
560
+ import { useEffect as useEffect2, useLayoutEffect, useState as useState3 } from "react";
371
561
  var useIsomorphicLayoutEffect = typeof window === "undefined" ? useEffect2 : useLayoutEffect;
372
562
  function useRefElement(ref) {
373
- const [element, setElement] = useState2(null);
563
+ const [element, setElement] = useState3(null);
374
564
  useIsomorphicLayoutEffect(() => {
375
565
  setElement(ref.current);
376
566
  });
@@ -399,9 +589,9 @@ function useChartResize(chartRef, containerRef) {
399
589
  }
400
590
 
401
591
  // src/hooks/useReducedMotion.ts
402
- import { useState as useState3, useEffect as useEffect3 } from "react";
592
+ import { useState as useState4, useEffect as useEffect3 } from "react";
403
593
  function useReducedMotion() {
404
- const [reducedMotion, setReducedMotion] = useState3(false);
594
+ const [reducedMotion, setReducedMotion] = useState4(false);
405
595
  useEffect3(() => {
406
596
  const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
407
597
  setReducedMotion(mediaQuery.matches);
@@ -417,6 +607,23 @@ function useReducedMotion() {
417
607
  }
418
608
 
419
609
  // src/hooks/useChart.ts
610
+ echarts2.use([
611
+ AriaComponent,
612
+ DataZoomInsideComponent,
613
+ DataZoomSliderComponent,
614
+ DatasetComponent,
615
+ GraphicComponent,
616
+ MarkAreaComponent,
617
+ MarkLineComponent,
618
+ CanvasRenderer
619
+ ]);
620
+ var registerEchartsModules = (modules) => echarts2.use(modules);
621
+ function exportChartImage(chart, { type = "png", pixelRatio = 2, backgroundColor } = {}) {
622
+ if (!chart || chart.isDisposed()) return null;
623
+ const background = backgroundColor ?? (typeof document !== "undefined" ? getComputedStyle(chart.getDom()).getPropertyValue("--card").trim() : "");
624
+ const color = !background ? "#ffffff" : /^[\d.]+\s/.test(background) ? `hsl(${background})` : background;
625
+ return chart.getDataURL({ type, pixelRatio, backgroundColor: color });
626
+ }
420
627
  var isComponentType = (mainType) => echarts2.ComponentModel.hasClass(mainType);
421
628
  function applyOption(chart, prev, next) {
422
629
  chart.setOption(next, {
@@ -424,56 +631,116 @@ function applyOption(chart, prev, next) {
424
631
  lazyUpdate: true
425
632
  });
426
633
  }
634
+ function captureState(chart) {
635
+ if (chart.isDisposed()) return null;
636
+ const option = chart.getOption();
637
+ const selected = option.legend?.[0]?.selected ?? {};
638
+ return {
639
+ hidden: Object.keys(selected).filter((name) => selected[name] === false),
640
+ zoom: (option.dataZoom ?? []).map(({ start, end }) => ({ start, end }))
641
+ };
642
+ }
643
+ function restoreState(chart, state) {
644
+ if (!state) return;
645
+ for (const name of state.hidden) chart.dispatchAction({ type: "legendUnSelect", name });
646
+ state.zoom.forEach(({ start, end }, dataZoomIndex) => {
647
+ if (start !== void 0 && end !== void 0 && (start !== 0 || end !== 100)) {
648
+ chart.dispatchAction({ type: "dataZoom", dataZoomIndex, start, end });
649
+ }
650
+ });
651
+ }
427
652
  function useChart({
428
653
  option,
429
654
  theme = "auto",
430
655
  animation,
431
- onReady
656
+ patterns,
657
+ events,
658
+ onReady,
659
+ onCreated
432
660
  }) {
433
661
  const containerRef = useRef(null);
434
662
  const container = useRefElement(containerRef);
435
663
  const chartRef = useRef(null);
664
+ const [chart, setChart] = useState5(null);
436
665
  const currentTheme = useChartTheme(theme);
437
666
  const reducedMotion = useReducedMotion();
438
667
  const onReadyRef = useRef(onReady);
439
668
  onReadyRef.current = onReady;
669
+ const onCreatedRef = useRef(onCreated);
670
+ onCreatedRef.current = onCreated;
671
+ const eventsRef = useRef(events);
672
+ eventsRef.current = events;
440
673
  const optionRef = useRef(option);
441
674
  optionRef.current = {
442
675
  ...option,
443
676
  // Reduced motion always wins over the animation prop
444
- animation: (animation ?? true) && !reducedMotion
677
+ animation: (animation ?? true) && !reducedMotion,
678
+ // Labels stay off: the container already describes the chart
679
+ ...patterns && {
680
+ aria: { enabled: true, label: { enabled: false }, decal: { show: true } }
681
+ }
445
682
  };
446
683
  const appliedRef = useRef(null);
684
+ const carriedRef = useRef(null);
447
685
  useEffect4(() => {
448
686
  if (!container) return;
449
- const chart = echarts2.init(container, currentTheme);
450
- chartRef.current = chart;
451
- applyOption(chart, null, optionRef.current);
687
+ const instance = echarts2.init(container, currentTheme);
688
+ chartRef.current = instance;
689
+ onReadyRef.current?.(instance);
690
+ applyOption(instance, null, optionRef.current);
452
691
  appliedRef.current = optionRef.current;
453
- onReadyRef.current?.(chart);
692
+ const carried = carriedRef.current;
693
+ carriedRef.current = null;
694
+ if (carried) instance.setOption({}, { lazyUpdate: false });
695
+ restoreState(instance, carried);
696
+ onCreatedRef.current?.(instance);
697
+ setChart(instance);
454
698
  return () => {
455
- chart.dispose();
456
- if (chartRef.current === chart) {
699
+ carriedRef.current = captureState(instance);
700
+ instance.dispose();
701
+ if (chartRef.current === instance) {
457
702
  chartRef.current = null;
458
703
  }
704
+ setChart((current) => current === instance ? null : current);
459
705
  };
460
706
  }, [container, currentTheme]);
461
707
  useEffect4(() => {
462
- const chart = chartRef.current;
463
- if (!chart || chart.isDisposed()) return;
464
- applyOption(chart, appliedRef.current, optionRef.current);
708
+ const instance = chartRef.current;
709
+ if (!instance || instance.isDisposed()) return;
710
+ applyOption(instance, appliedRef.current, optionRef.current);
465
711
  appliedRef.current = optionRef.current;
466
- }, [option, animation, reducedMotion]);
712
+ }, [option, animation, reducedMotion, patterns]);
713
+ const eventNames = JSON.stringify(
714
+ Object.keys(events ?? {}).filter((name) => events?.[name]).sort()
715
+ );
716
+ useEffect4(() => {
717
+ if (!chart || chart.isDisposed()) return;
718
+ const bound = JSON.parse(eventNames).map((name) => {
719
+ const listener = (params) => eventsRef.current?.[name]?.(params);
720
+ chart.on(name, listener);
721
+ return [name, listener];
722
+ });
723
+ return () => {
724
+ if (chart.isDisposed()) return;
725
+ for (const [name, listener] of bound) chart.off(name, listener);
726
+ };
727
+ }, [chart, eventNames]);
467
728
  useChartResize(chartRef, containerRef);
729
+ const exportImage = useCallback(
730
+ (options) => exportChartImage(chartRef.current, options),
731
+ []
732
+ );
468
733
  return {
469
734
  chartRef,
470
735
  containerRef,
471
- currentTheme
736
+ chart,
737
+ currentTheme,
738
+ exportImage
472
739
  };
473
740
  }
474
741
 
475
742
  // src/hooks/useChartLegend.ts
476
- import { useCallback, useRef as useRef3, useState as useState4 } from "react";
743
+ import { useCallback as useCallback2, useRef as useRef3, useState as useState6 } from "react";
477
744
  import {
478
745
  getLegendItems
479
746
  } from "@classic-homes/charts-core";
@@ -503,9 +770,9 @@ function useChartLegend({
503
770
  onLegendChange
504
771
  }) {
505
772
  const chartRef = useRef3(null);
506
- const [visible, setVisible] = useState4({});
773
+ const [visible, setVisible] = useState6({});
507
774
  const latest = useLatestRef({ onLegendChange });
508
- const attach = useCallback(
775
+ const attach = useCallback2(
509
776
  (chart) => {
510
777
  chartRef.current = chart;
511
778
  setVisible({});
@@ -541,14 +808,14 @@ function useChartLegend({
541
808
  }
542
809
 
543
810
  // src/components/core/LineChart.tsx
544
- import { jsx as jsx6 } from "react/jsx-runtime";
811
+ import { jsx as jsx7 } from "react/jsx-runtime";
545
812
  echarts3.use([
546
813
  EChartsLineChart,
547
814
  GridComponent,
548
815
  TooltipComponent,
549
816
  LegendComponent,
550
817
  TitleComponent,
551
- CanvasRenderer
818
+ CanvasRenderer2
552
819
  ]);
553
820
  var LineChart = React6.forwardRef(
554
821
  ({
@@ -556,6 +823,8 @@ var LineChart = React6.forwardRef(
556
823
  description,
557
824
  data,
558
825
  height = 400,
826
+ minHeight,
827
+ maxHeight,
559
828
  loading,
560
829
  error,
561
830
  emptyMessage,
@@ -568,22 +837,34 @@ var LineChart = React6.forwardRef(
568
837
  areaFilled = false,
569
838
  showDataPoints = false,
570
839
  stacked = false,
840
+ connectNulls = false,
571
841
  showLabels = false,
842
+ valueFormat,
843
+ locale,
572
844
  labelFormatter,
573
845
  xAxisConfig,
574
846
  yAxisConfig,
847
+ referenceLines,
848
+ referenceBands,
849
+ dataZoom,
575
850
  tooltipFormatter,
576
851
  tooltipValueFormatter,
577
852
  legend: legendConfig,
578
853
  renderLegend,
579
854
  onLegendChange,
580
855
  option: optionOverride,
856
+ onReady,
857
+ events,
858
+ showDataTable,
859
+ exportable,
860
+ patterns,
581
861
  onClick,
582
862
  onHover,
583
863
  class: className,
584
864
  ...props
585
865
  }, ref) => {
586
866
  const isEmpty = !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length);
867
+ const isPercent = stacked === "percent";
587
868
  const currentTheme = useChartTheme(theme);
588
869
  const chartColors = getChartColors(currentTheme);
589
870
  const legend = useChartLegend({
@@ -595,10 +876,41 @@ var LineChart = React6.forwardRef(
595
876
  onLegendChange
596
877
  });
597
878
  const customLegend = renderLegend !== void 0;
879
+ const builtInLegend = showLegend && !customLegend;
598
880
  const option = React6.useMemo(() => {
599
881
  if (isEmpty) return {};
882
+ const formatters = chartFormatters({
883
+ valueFormat: isPercent ? "percentValue" : valueFormat,
884
+ locale,
885
+ tooltipValueFormatter,
886
+ labelFormatter
887
+ });
888
+ const plotted = isPercent ? toPercentStack(data.series) : data.series;
600
889
  const getLabel = seriesLabelLookup(data.series);
601
890
  const showSymbol = showDataPoints || showLabels || hasPointLabels(data.series);
891
+ const legendBottom = builtInLegend && (legendConfig?.position ?? "bottom") === "bottom";
892
+ const series = data.series.map((source, index) => ({
893
+ name: source.name,
894
+ type: "line",
895
+ data: withPointLabels(plotted[index].data, source.labels, formatters.label, {
896
+ position: "top"
897
+ }),
898
+ smooth,
899
+ showSymbol,
900
+ symbolSize: showDataPoints ? 6 : 0,
901
+ connectNulls,
902
+ stack: stacked ? "Total" : void 0,
903
+ areaStyle: areaFilled ? { opacity: 0.3 } : void 0,
904
+ itemStyle: source.color ? { color: source.color } : void 0,
905
+ label: buildDataLabel({ show: true, position: "top" }, void 0, {
906
+ show: showLabels,
907
+ formatter: formatters.label,
908
+ getLabel
909
+ }),
910
+ emphasis: {
911
+ focus: "series"
912
+ }
913
+ }));
602
914
  return mergeChartOption(
603
915
  {
604
916
  grid: {
@@ -606,7 +918,11 @@ var LineChart = React6.forwardRef(
606
918
  right: "4%",
607
919
  bottom: "3%",
608
920
  containLabel: true,
609
- ...gridInset(legendConfig, showLegend && !customLegend, xAxisConfig, yAxisConfig)
921
+ ...withZoomInset(
922
+ gridInset(legendConfig, builtInLegend, xAxisConfig, yAxisConfig),
923
+ dataZoom,
924
+ "x"
925
+ )
610
926
  },
611
927
  tooltip: buildTooltip(
612
928
  {
@@ -621,7 +937,7 @@ var LineChart = React6.forwardRef(
621
937
  {
622
938
  show: showTooltip,
623
939
  formatter: tooltipFormatter,
624
- valueFormatter: tooltipValueFormatter,
940
+ valueFormatter: formatters.tooltip,
625
941
  getLabel
626
942
  }
627
943
  ),
@@ -630,6 +946,7 @@ var LineChart = React6.forwardRef(
630
946
  legendConfig,
631
947
  { show: showLegend, custom: customLegend }
632
948
  ),
949
+ dataZoom: buildDataZoom(dataZoom, "x", legendBottom ? 36 : 0),
633
950
  xAxis: buildAxis(
634
951
  {
635
952
  type: "category",
@@ -644,31 +961,19 @@ var LineChart = React6.forwardRef(
644
961
  yAxis: buildAxis(
645
962
  {
646
963
  type: "value",
964
+ ...isPercent && { max: 100 },
647
965
  splitLine: {
648
966
  show: showGrid
649
967
  }
650
968
  },
651
- yAxisConfig
969
+ formatters.axis(yAxisConfig)
652
970
  ),
653
- series: data.series.map((series) => ({
654
- name: series.name,
655
- type: "line",
656
- data: withPointLabels(series.data, series.labels, labelFormatter, { position: "top" }),
657
- smooth,
658
- showSymbol,
659
- symbolSize: showDataPoints ? 6 : 0,
660
- stack: stacked ? "Total" : void 0,
661
- areaStyle: areaFilled ? { opacity: 0.3 } : void 0,
662
- itemStyle: series.color ? { color: series.color } : void 0,
663
- label: buildDataLabel({ show: true, position: "top" }, void 0, {
664
- show: showLabels,
665
- formatter: labelFormatter,
666
- getLabel
667
- }),
668
- emphasis: {
669
- focus: "series"
670
- }
671
- }))
971
+ series: withReferenceMarks(series, referenceLines, referenceBands, {
972
+ valueAxis: "y",
973
+ format: formatters.format,
974
+ color: chartColors.reference,
975
+ bandColor: chartColors.referenceBand
976
+ })
672
977
  },
673
978
  optionOverride
674
979
  );
@@ -682,62 +987,48 @@ var LineChart = React6.forwardRef(
682
987
  areaFilled,
683
988
  showDataPoints,
684
989
  stacked,
990
+ isPercent,
991
+ connectNulls,
685
992
  chartColors,
686
993
  showLabels,
994
+ valueFormat,
995
+ locale,
687
996
  labelFormatter,
688
997
  xAxisConfig,
689
998
  yAxisConfig,
999
+ referenceLines,
1000
+ referenceBands,
1001
+ dataZoom,
690
1002
  tooltipFormatter,
691
1003
  tooltipValueFormatter,
692
1004
  legendConfig,
693
1005
  customLegend,
1006
+ builtInLegend,
694
1007
  optionOverride
695
1008
  ]);
696
- const latest = useLatestRef({ onClick, onHover });
697
- const { containerRef } = useChart({
1009
+ const { containerRef, exportImage } = useChart({
698
1010
  option,
699
1011
  theme: currentTheme === THEME_DARK2 ? "dark" : "light",
700
1012
  animation,
701
- onReady: (chart) => {
702
- legend.attach(chart);
703
- chart.on("click", (params) => {
704
- const { onClick: onClick2 } = latest.current;
705
- if (!onClick2) return;
706
- onClick2({
707
- type: params.type || "click",
708
- componentType: params.componentType || "series",
709
- seriesIndex: params.seriesIndex,
710
- seriesName: params.seriesName || "",
711
- dataIndex: params.dataIndex || 0,
712
- name: params.name || "",
713
- value: params.value,
714
- color: params.color
715
- });
716
- });
717
- chart.on("mouseover", (params) => {
718
- const { onHover: onHover2 } = latest.current;
719
- if (!onHover2) return;
720
- onHover2({
721
- type: params.type || "mouseover",
722
- componentType: params.componentType || "series",
723
- seriesIndex: params.seriesIndex,
724
- seriesName: params.seriesName || "",
725
- dataIndex: params.dataIndex || 0,
726
- name: params.name || "",
727
- value: params.value,
728
- color: params.color
729
- });
730
- });
731
- }
1013
+ patterns,
1014
+ events: chartEvents(events, {
1015
+ click: onClick && ((params) => onClick(toDataPointParams(params, "click"))),
1016
+ mouseover: onHover && ((params) => onHover(toDataPointParams(params, "mouseover")))
1017
+ }),
1018
+ onReady: legend.attach,
1019
+ onCreated: onReady
732
1020
  });
733
- const accessibilityDescription = description || (!isEmpty ? generateLineChartDescription(title, data) : void 0);
734
- return /* @__PURE__ */ jsx6(
1021
+ const format = resolveValueFormatter(valueFormat, locale);
1022
+ const accessibilityDescription = description || (!isEmpty ? generateLineChartDescription(title, data, format) : void 0);
1023
+ return /* @__PURE__ */ jsx7(
735
1024
  ChartContainer,
736
1025
  {
737
1026
  ref,
738
1027
  title,
739
1028
  description: accessibilityDescription,
740
1029
  height,
1030
+ minHeight,
1031
+ maxHeight,
741
1032
  loading,
742
1033
  error,
743
1034
  empty: isEmpty,
@@ -745,8 +1036,13 @@ var LineChart = React6.forwardRef(
745
1036
  className: cn(className),
746
1037
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
747
1038
  legendPosition: legendConfig?.position,
1039
+ dataTable: isEmpty ? void 0 : categoryTable(data),
1040
+ showDataTable,
1041
+ format,
1042
+ exportable,
1043
+ exportImage,
748
1044
  ...props,
749
- children: /* @__PURE__ */ jsx6("div", { ref: containerRef, className: "h-full w-full" })
1045
+ children: /* @__PURE__ */ jsx7("div", { ref: containerRef, className: "h-full w-full" })
750
1046
  }
751
1047
  );
752
1048
  }
@@ -763,27 +1059,39 @@ import {
763
1059
  LegendComponent as LegendComponent2,
764
1060
  TitleComponent as TitleComponent2
765
1061
  } from "echarts/components";
766
- import { CanvasRenderer as CanvasRenderer2 } from "echarts/renderers";
1062
+ import { CanvasRenderer as CanvasRenderer3 } from "echarts/renderers";
767
1063
  import {
768
1064
  buildAxis as buildAxis2,
769
1065
  buildDataLabel as buildDataLabel2,
1066
+ buildDataZoom as buildDataZoom2,
770
1067
  buildLegend as buildLegend2,
1068
+ buildStackTotalSeries,
771
1069
  buildTooltip as buildTooltip2,
1070
+ categoryTable as categoryTable2,
1071
+ chartFormatters as chartFormatters2,
1072
+ formatValue,
772
1073
  generateBarChartDescription,
773
1074
  getChartColors as getChartColors2,
774
1075
  gridInset as gridInset2,
775
1076
  mergeChartOption as mergeChartOption2,
1077
+ resolveChartHeight,
1078
+ resolveValueFormatter as resolveValueFormatter2,
776
1079
  seriesLabelLookup as seriesLabelLookup2,
777
- withPointLabels as withPointLabels2
1080
+ stackTotals,
1081
+ toPercentStack as toPercentStack2,
1082
+ withEndLabelInset,
1083
+ withPointLabels as withPointLabels2,
1084
+ withReferenceMarks as withReferenceMarks2,
1085
+ withZoomInset as withZoomInset2
778
1086
  } from "@classic-homes/charts-core";
779
- import { jsx as jsx7 } from "react/jsx-runtime";
1087
+ import { jsx as jsx8 } from "react/jsx-runtime";
780
1088
  echarts4.use([
781
1089
  EChartsBarChart,
782
1090
  GridComponent2,
783
1091
  TooltipComponent2,
784
1092
  LegendComponent2,
785
1093
  TitleComponent2,
786
- CanvasRenderer2
1094
+ CanvasRenderer3
787
1095
  ]);
788
1096
  var BarChart = React7.forwardRef(
789
1097
  ({
@@ -791,6 +1099,9 @@ var BarChart = React7.forwardRef(
791
1099
  description,
792
1100
  data,
793
1101
  height = 400,
1102
+ minHeight,
1103
+ maxHeight,
1104
+ rowHeight,
794
1105
  loading,
795
1106
  error,
796
1107
  emptyMessage,
@@ -802,33 +1113,55 @@ var BarChart = React7.forwardRef(
802
1113
  orientation = "vertical",
803
1114
  stacked = false,
804
1115
  showValues = false,
1116
+ showTotal = false,
1117
+ valueFormat,
1118
+ locale,
805
1119
  labelFormatter,
806
1120
  xAxisConfig,
807
1121
  yAxisConfig,
1122
+ referenceLines,
1123
+ referenceBands,
1124
+ dataZoom,
808
1125
  tooltipFormatter,
809
1126
  tooltipValueFormatter,
810
1127
  legend: legendConfig,
811
1128
  renderLegend,
812
1129
  onLegendChange,
813
1130
  option: optionOverride,
1131
+ onReady,
1132
+ events,
1133
+ showDataTable,
1134
+ exportable,
1135
+ patterns,
814
1136
  onClick,
1137
+ onHover,
815
1138
  class: className,
816
1139
  ...props
817
1140
  }, ref) => {
818
1141
  const isEmpty = !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length);
819
1142
  const isHorizontal = orientation === "horizontal";
1143
+ const isPercent = stacked === "percent";
820
1144
  const currentTheme = useChartTheme(theme);
1145
+ const chartColors = getChartColors2(currentTheme);
821
1146
  const legend = useChartLegend({
822
1147
  names: data?.series?.map((s) => s.name) ?? [],
823
1148
  colors: data?.series?.map((s) => s.color) ?? [],
824
- palette: getChartColors2(currentTheme).series,
1149
+ palette: chartColors.series,
825
1150
  config: legendConfig,
826
1151
  title,
827
1152
  onLegendChange
828
1153
  });
829
1154
  const customLegend = renderLegend !== void 0;
1155
+ const builtInLegend = showLegend && !customLegend;
830
1156
  const option = React7.useMemo(() => {
831
1157
  if (isEmpty) return {};
1158
+ const formatters = chartFormatters2({
1159
+ valueFormat: isPercent ? "percentValue" : valueFormat,
1160
+ locale,
1161
+ tooltipValueFormatter,
1162
+ labelFormatter
1163
+ });
1164
+ const plotted = isPercent ? toPercentStack2(data.series) : data.series;
832
1165
  const categoryAxis = {
833
1166
  type: "category",
834
1167
  data: data.categories,
@@ -840,11 +1173,40 @@ var BarChart = React7.forwardRef(
840
1173
  };
841
1174
  const valueAxis = {
842
1175
  type: "value",
1176
+ ...isPercent && { max: 100 },
843
1177
  splitLine: {
844
1178
  show: showGrid
845
1179
  }
846
1180
  };
847
1181
  const getLabel = seriesLabelLookup2(data.series);
1182
+ const labelPosition = isHorizontal ? "right" : "top";
1183
+ const zoomAxis = isHorizontal ? "y" : "x";
1184
+ const legendBottom = builtInLegend && (legendConfig?.position ?? "bottom") === "bottom";
1185
+ const series = data.series.map((source, index) => ({
1186
+ name: source.name,
1187
+ type: "bar",
1188
+ data: withPointLabels2(plotted[index].data, source.labels, formatters.label, {
1189
+ position: labelPosition
1190
+ }),
1191
+ stack: stacked ? "Total" : void 0,
1192
+ itemStyle: source.color ? { color: source.color } : void 0,
1193
+ label: buildDataLabel2({ show: true, position: labelPosition }, void 0, {
1194
+ show: showValues,
1195
+ formatter: formatters.label,
1196
+ getLabel
1197
+ }),
1198
+ emphasis: {
1199
+ focus: "series"
1200
+ }
1201
+ }));
1202
+ const format2 = resolveValueFormatter2(valueFormat, locale);
1203
+ const stackedSeries = data.series.map((s) => ({ data: s.data }));
1204
+ const totalSeries = showTotal ? buildStackTotalSeries(data.categories, stackedSeries, {
1205
+ stacked,
1206
+ position: labelPosition,
1207
+ format: format2
1208
+ }) : [];
1209
+ const endLabels = !isHorizontal ? [] : totalSeries.length ? [...stackTotals(stackedSeries, stacked).values()].flat().map((t) => formatValue(t, format2)) : showValues ? plotted.flatMap((s) => s.data.map((value) => formatValue(value, formatters.format))) : [];
848
1210
  return mergeChartOption2(
849
1211
  {
850
1212
  grid: {
@@ -852,7 +1214,14 @@ var BarChart = React7.forwardRef(
852
1214
  right: "4%",
853
1215
  bottom: "3%",
854
1216
  containLabel: true,
855
- ...gridInset2(legendConfig, showLegend && !customLegend, xAxisConfig, yAxisConfig)
1217
+ ...withZoomInset2(
1218
+ withEndLabelInset(
1219
+ gridInset2(legendConfig, builtInLegend, xAxisConfig, yAxisConfig),
1220
+ endLabels
1221
+ ),
1222
+ dataZoom,
1223
+ zoomAxis
1224
+ )
856
1225
  },
857
1226
  tooltip: buildTooltip2(
858
1227
  {
@@ -864,7 +1233,7 @@ var BarChart = React7.forwardRef(
864
1233
  {
865
1234
  show: showTooltip,
866
1235
  formatter: tooltipFormatter,
867
- valueFormatter: tooltipValueFormatter,
1236
+ valueFormatter: formatters.tooltip,
868
1237
  getLabel
869
1238
  }
870
1239
  ),
@@ -873,28 +1242,22 @@ var BarChart = React7.forwardRef(
873
1242
  legendConfig,
874
1243
  { show: showLegend, custom: customLegend }
875
1244
  ),
876
- xAxis: buildAxis2(isHorizontal ? valueAxis : categoryAxis, xAxisConfig),
877
- yAxis: buildAxis2(isHorizontal ? categoryAxis : valueAxis, yAxisConfig),
878
- series: data.series.map((series) => ({
879
- name: series.name,
880
- type: "bar",
881
- data: withPointLabels2(series.data, series.labels, labelFormatter, {
882
- position: isHorizontal ? "right" : "top"
883
- }),
884
- stack: stacked ? "Total" : void 0,
885
- itemStyle: series.color ? { color: series.color } : void 0,
886
- label: buildDataLabel2(
887
- {
888
- show: true,
889
- position: isHorizontal ? "right" : "top"
890
- },
891
- void 0,
892
- { show: showValues, formatter: labelFormatter, getLabel }
893
- ),
894
- emphasis: {
895
- focus: "series"
896
- }
897
- }))
1245
+ dataZoom: buildDataZoom2(dataZoom, zoomAxis, legendBottom ? 36 : 0),
1246
+ xAxis: buildAxis2(
1247
+ isHorizontal ? valueAxis : categoryAxis,
1248
+ isHorizontal ? formatters.axis(xAxisConfig) : xAxisConfig
1249
+ ),
1250
+ yAxis: buildAxis2(
1251
+ isHorizontal ? categoryAxis : valueAxis,
1252
+ isHorizontal ? yAxisConfig : formatters.axis(yAxisConfig)
1253
+ ),
1254
+ series: withReferenceMarks2([...series, ...totalSeries], referenceLines, referenceBands, {
1255
+ valueAxis: isHorizontal ? "x" : "y",
1256
+ inverse: isHorizontal,
1257
+ format: formatters.format,
1258
+ color: chartColors.reference,
1259
+ bandColor: chartColors.referenceBand
1260
+ })
898
1261
  },
899
1262
  optionOverride
900
1263
  );
@@ -905,48 +1268,55 @@ var BarChart = React7.forwardRef(
905
1268
  showLegend,
906
1269
  showGrid,
907
1270
  isHorizontal,
1271
+ isPercent,
908
1272
  stacked,
909
1273
  showValues,
1274
+ showTotal,
1275
+ valueFormat,
1276
+ locale,
910
1277
  labelFormatter,
911
1278
  xAxisConfig,
912
1279
  yAxisConfig,
1280
+ referenceLines,
1281
+ referenceBands,
1282
+ dataZoom,
913
1283
  tooltipFormatter,
914
1284
  tooltipValueFormatter,
915
1285
  legendConfig,
916
1286
  customLegend,
1287
+ builtInLegend,
1288
+ chartColors,
917
1289
  optionOverride
918
1290
  ]);
919
- const latest = useLatestRef({ onClick });
920
- const { containerRef } = useChart({
1291
+ const { containerRef, exportImage } = useChart({
921
1292
  option,
922
1293
  theme,
923
1294
  animation,
924
- onReady: (chart) => {
925
- legend.attach(chart);
926
- chart.on("click", (params) => {
927
- const { onClick: onClick2 } = latest.current;
928
- if (!onClick2) return;
929
- onClick2({
930
- type: params.type || "click",
931
- componentType: params.componentType || "series",
932
- seriesIndex: params.seriesIndex,
933
- seriesName: params.seriesName || "",
934
- dataIndex: params.dataIndex || 0,
935
- name: params.name || "",
936
- value: params.value,
937
- color: params.color
938
- });
939
- });
940
- }
1295
+ patterns,
1296
+ events: chartEvents(events, {
1297
+ click: onClick && ((params) => onClick(toDataPointParams(params, "click"))),
1298
+ mouseover: onHover && ((params) => onHover(toDataPointParams(params, "mouseover")))
1299
+ }),
1300
+ onReady: legend.attach,
1301
+ onCreated: onReady
941
1302
  });
942
- const accessibilityDescription = description || (!isEmpty ? generateBarChartDescription(title, data) : void 0);
943
- return /* @__PURE__ */ jsx7(
1303
+ const format = resolveValueFormatter2(valueFormat, locale);
1304
+ const accessibilityDescription = description || (!isEmpty ? generateBarChartDescription(title, data, format) : void 0);
1305
+ const resolvedHeight = isHorizontal ? resolveChartHeight(height, data?.categories?.length ?? 0, {
1306
+ rowHeight,
1307
+ minHeight,
1308
+ maxHeight,
1309
+ chrome: 56 + (builtInLegend ? 36 : 0) + (dataZoom ? 36 : 0)
1310
+ }) : height === "auto" ? 400 : height;
1311
+ return /* @__PURE__ */ jsx8(
944
1312
  ChartContainer,
945
1313
  {
946
1314
  ref,
947
1315
  title,
948
1316
  description: accessibilityDescription,
949
- height,
1317
+ height: resolvedHeight,
1318
+ minHeight,
1319
+ maxHeight,
950
1320
  loading,
951
1321
  error,
952
1322
  empty: isEmpty,
@@ -954,8 +1324,13 @@ var BarChart = React7.forwardRef(
954
1324
  className: cn(className),
955
1325
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
956
1326
  legendPosition: legendConfig?.position,
1327
+ dataTable: isEmpty ? void 0 : categoryTable2(data),
1328
+ showDataTable,
1329
+ format,
1330
+ exportable,
1331
+ exportImage,
957
1332
  ...props,
958
- children: /* @__PURE__ */ jsx7("div", { ref: containerRef, className: "h-full w-full" })
1333
+ children: /* @__PURE__ */ jsx8("div", { ref: containerRef, className: "h-full w-full" })
959
1334
  }
960
1335
  );
961
1336
  }
@@ -967,7 +1342,7 @@ import * as React8 from "react";
967
1342
  import * as echarts5 from "echarts/core";
968
1343
  import { PieChart as EChartsPieChart } from "echarts/charts";
969
1344
  import { TooltipComponent as TooltipComponent3, LegendComponent as LegendComponent3, TitleComponent as TitleComponent3 } from "echarts/components";
970
- import { CanvasRenderer as CanvasRenderer3 } from "echarts/renderers";
1345
+ import { CanvasRenderer as CanvasRenderer4 } from "echarts/renderers";
971
1346
  import {
972
1347
  buildDataLabel as buildDataLabel3,
973
1348
  buildLegend as buildLegend3,
@@ -979,16 +1354,20 @@ import {
979
1354
  itemLabelLookup,
980
1355
  legendCenter,
981
1356
  mergeChartOption as mergeChartOption3,
982
- pointLabel
1357
+ pointLabel,
1358
+ resolveValueFormatter as resolveValueFormatter3,
1359
+ sliceTable
983
1360
  } from "@classic-homes/charts-core";
984
- import { jsx as jsx8 } from "react/jsx-runtime";
985
- echarts5.use([EChartsPieChart, TooltipComponent3, LegendComponent3, TitleComponent3, CanvasRenderer3]);
1361
+ import { jsx as jsx9 } from "react/jsx-runtime";
1362
+ echarts5.use([EChartsPieChart, TooltipComponent3, LegendComponent3, TitleComponent3, CanvasRenderer4]);
986
1363
  var PieChart = React8.forwardRef(
987
1364
  ({
988
1365
  title,
989
1366
  description,
990
1367
  data,
991
1368
  height = 400,
1369
+ minHeight,
1370
+ maxHeight,
992
1371
  loading,
993
1372
  error,
994
1373
  emptyMessage,
@@ -999,6 +1378,8 @@ var PieChart = React8.forwardRef(
999
1378
  showLabels = true,
1000
1379
  labelPosition = "outside",
1001
1380
  innerRadius = 0,
1381
+ valueFormat,
1382
+ locale,
1002
1383
  labelFormatter,
1003
1384
  tooltipFormatter,
1004
1385
  tooltipValueFormatter,
@@ -1006,6 +1387,11 @@ var PieChart = React8.forwardRef(
1006
1387
  renderLegend,
1007
1388
  onLegendChange,
1008
1389
  option: optionOverride,
1390
+ onReady,
1391
+ events,
1392
+ showDataTable,
1393
+ exportable,
1394
+ patterns,
1009
1395
  onClick,
1010
1396
  class: className,
1011
1397
  ...props
@@ -1021,9 +1407,14 @@ var PieChart = React8.forwardRef(
1021
1407
  onLegendChange
1022
1408
  });
1023
1409
  const customLegend = renderLegend !== void 0;
1410
+ const format = React8.useMemo(
1411
+ () => resolveValueFormatter3(valueFormat, locale),
1412
+ [valueFormat, locale]
1413
+ );
1414
+ const tooltipValues = tooltipValueFormatter ?? format;
1024
1415
  const option = React8.useMemo(() => {
1025
1416
  if (isEmpty) return {};
1026
- const valueFormatter = tooltipFormatter === void 0 ? tooltipValueFormatter : void 0;
1417
+ const valueFormatter = tooltipFormatter === void 0 ? tooltipValues : void 0;
1027
1418
  const tooltipBase = {
1028
1419
  trigger: "item",
1029
1420
  formatter: valueFormatter ? (params) => {
@@ -1036,7 +1427,7 @@ var PieChart = React8.forwardRef(
1036
1427
  tooltip: buildTooltip3(tooltipBase, {
1037
1428
  show: showTooltip,
1038
1429
  formatter: tooltipFormatter,
1039
- valueFormatter: tooltipValueFormatter,
1430
+ valueFormatter: tooltipValues,
1040
1431
  getLabel: itemLabelLookup(data)
1041
1432
  }),
1042
1433
  legend: buildLegend3(
@@ -1088,40 +1479,32 @@ var PieChart = React8.forwardRef(
1088
1479
  title,
1089
1480
  labelFormatter,
1090
1481
  tooltipFormatter,
1091
- tooltipValueFormatter,
1482
+ tooltipValues,
1092
1483
  legendConfig,
1093
1484
  customLegend,
1094
1485
  optionOverride
1095
1486
  ]);
1096
- const latest = useLatestRef({ onClick });
1097
- const { containerRef } = useChart({
1487
+ const { containerRef, exportImage } = useChart({
1098
1488
  option,
1099
1489
  theme,
1100
1490
  animation,
1101
- onReady: (chart) => {
1102
- legend.attach(chart);
1103
- chart.on("click", (params) => {
1104
- const { onClick: onClick2 } = latest.current;
1105
- if (!onClick2) return;
1106
- onClick2({
1107
- type: params.type || "click",
1108
- componentType: params.componentType || "series",
1109
- name: params.name || "",
1110
- value: params.value,
1111
- percent: params.percent,
1112
- color: params.color
1113
- });
1114
- });
1115
- }
1491
+ patterns,
1492
+ events: chartEvents(events, {
1493
+ click: onClick && ((params) => onClick(toSliceParams(params, "click")))
1494
+ }),
1495
+ onReady: legend.attach,
1496
+ onCreated: onReady
1116
1497
  });
1117
1498
  const accessibilityDescription = description || (!isEmpty ? generatePieChartDescription(title, data, false) : void 0);
1118
- return /* @__PURE__ */ jsx8(
1499
+ return /* @__PURE__ */ jsx9(
1119
1500
  ChartContainer,
1120
1501
  {
1121
1502
  ref,
1122
1503
  title,
1123
1504
  description: accessibilityDescription,
1124
1505
  height,
1506
+ minHeight,
1507
+ maxHeight,
1125
1508
  loading,
1126
1509
  error,
1127
1510
  empty: isEmpty,
@@ -1129,8 +1512,13 @@ var PieChart = React8.forwardRef(
1129
1512
  className: cn(className),
1130
1513
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
1131
1514
  legendPosition: legendConfig?.position,
1515
+ dataTable: isEmpty ? void 0 : sliceTable(data),
1516
+ showDataTable,
1517
+ format,
1518
+ exportable,
1519
+ exportImage,
1132
1520
  ...props,
1133
- children: /* @__PURE__ */ jsx8("div", { ref: containerRef, className: "h-full w-full" })
1521
+ children: /* @__PURE__ */ jsx9("div", { ref: containerRef, className: "h-full w-full" })
1134
1522
  }
1135
1523
  );
1136
1524
  }
@@ -1147,29 +1535,37 @@ import {
1147
1535
  LegendComponent as LegendComponent4,
1148
1536
  TitleComponent as TitleComponent4
1149
1537
  } from "echarts/components";
1150
- import { CanvasRenderer as CanvasRenderer4 } from "echarts/renderers";
1538
+ import { CanvasRenderer as CanvasRenderer5 } from "echarts/renderers";
1151
1539
  import {
1152
1540
  buildAxis as buildAxis3,
1153
1541
  buildDataLabel as buildDataLabel4,
1542
+ buildDataZoom as buildDataZoom3,
1154
1543
  buildLegend as buildLegend4,
1155
1544
  buildTooltip as buildTooltip4,
1545
+ categoryTable as categoryTable3,
1546
+ chartFormatters as chartFormatters3,
1156
1547
  colorWithAlpha,
1548
+ generateAreaChartDescription,
1157
1549
  getChartColors as getChartColors4,
1158
1550
  hasPointLabels as hasPointLabels2,
1159
1551
  gridInset as gridInset3,
1160
1552
  mergeChartOption as mergeChartOption4,
1553
+ resolveValueFormatter as resolveValueFormatter4,
1161
1554
  seriesLabelLookup as seriesLabelLookup3,
1162
1555
  THEME_DARK as THEME_DARK3,
1163
- withPointLabels as withPointLabels3
1556
+ toPercentStack as toPercentStack3,
1557
+ withPointLabels as withPointLabels3,
1558
+ withReferenceMarks as withReferenceMarks3,
1559
+ withZoomInset as withZoomInset3
1164
1560
  } from "@classic-homes/charts-core";
1165
- import { jsx as jsx9 } from "react/jsx-runtime";
1561
+ import { jsx as jsx10 } from "react/jsx-runtime";
1166
1562
  echarts6.use([
1167
1563
  EChartsLineChart2,
1168
1564
  GridComponent3,
1169
1565
  TooltipComponent4,
1170
1566
  LegendComponent4,
1171
1567
  TitleComponent4,
1172
- CanvasRenderer4
1568
+ CanvasRenderer5
1173
1569
  ]);
1174
1570
  var AreaChart = React9.forwardRef(
1175
1571
  ({
@@ -1177,6 +1573,8 @@ var AreaChart = React9.forwardRef(
1177
1573
  description,
1178
1574
  data,
1179
1575
  height = 400,
1576
+ minHeight,
1577
+ maxHeight,
1180
1578
  loading,
1181
1579
  error,
1182
1580
  emptyMessage,
@@ -1187,22 +1585,35 @@ var AreaChart = React9.forwardRef(
1187
1585
  showGrid = true,
1188
1586
  smooth = false,
1189
1587
  stacked = false,
1588
+ connectNulls = false,
1190
1589
  gradient = true,
1191
1590
  showLabels = false,
1591
+ valueFormat,
1592
+ locale,
1192
1593
  labelFormatter,
1193
1594
  xAxisConfig,
1194
1595
  yAxisConfig,
1596
+ referenceLines,
1597
+ referenceBands,
1598
+ dataZoom,
1195
1599
  tooltipFormatter,
1196
1600
  tooltipValueFormatter,
1197
1601
  legend: legendConfig,
1198
1602
  renderLegend,
1199
1603
  onLegendChange,
1200
1604
  option: optionOverride,
1605
+ onReady,
1606
+ events,
1607
+ showDataTable,
1608
+ exportable,
1609
+ patterns,
1201
1610
  onClick,
1611
+ onHover,
1202
1612
  class: className,
1203
1613
  ...props
1204
1614
  }, ref) => {
1205
1615
  const isEmpty = !data?.categories?.length || !data?.series?.length || data.series.every((s) => !s.data?.length);
1616
+ const isPercent = stacked === "percent";
1206
1617
  const currentTheme = useChartTheme(theme);
1207
1618
  const chartColors = getChartColors4(currentTheme);
1208
1619
  const legend = useChartLegend({
@@ -1214,10 +1625,49 @@ var AreaChart = React9.forwardRef(
1214
1625
  onLegendChange
1215
1626
  });
1216
1627
  const customLegend = renderLegend !== void 0;
1628
+ const builtInLegend = showLegend && !customLegend;
1217
1629
  const option = React9.useMemo(() => {
1218
1630
  if (isEmpty) return {};
1631
+ const formatters = chartFormatters3({
1632
+ valueFormat: isPercent ? "percentValue" : valueFormat,
1633
+ locale,
1634
+ tooltipValueFormatter,
1635
+ labelFormatter
1636
+ });
1637
+ const plotted = isPercent ? toPercentStack3(data.series) : data.series;
1219
1638
  const getLabel = seriesLabelLookup3(data.series);
1220
1639
  const showSymbol = showLabels || hasPointLabels2(data.series);
1640
+ const legendBottom = builtInLegend && (legendConfig?.position ?? "bottom") === "bottom";
1641
+ const series = data.series.map((source, index) => {
1642
+ const base = source.color || chartColors.series[index % chartColors.series.length];
1643
+ return {
1644
+ name: source.name,
1645
+ type: "line",
1646
+ data: withPointLabels3(plotted[index].data, source.labels, formatters.label, {
1647
+ position: "top"
1648
+ }),
1649
+ smooth,
1650
+ connectNulls,
1651
+ stack: stacked ? "Total" : void 0,
1652
+ areaStyle: gradient ? {
1653
+ opacity: 0.8,
1654
+ color: new echarts6.graphic.LinearGradient(0, 0, 0, 1, [
1655
+ { offset: 0, color: colorWithAlpha(base, 0.8) },
1656
+ { offset: 1, color: colorWithAlpha(base, 0.1) }
1657
+ ])
1658
+ } : { opacity: 0.5 },
1659
+ itemStyle: source.color ? { color: source.color } : void 0,
1660
+ label: buildDataLabel4({ show: true, position: "top" }, void 0, {
1661
+ show: showLabels,
1662
+ formatter: formatters.label,
1663
+ getLabel
1664
+ }),
1665
+ emphasis: {
1666
+ focus: "series"
1667
+ },
1668
+ showSymbol
1669
+ };
1670
+ });
1221
1671
  return mergeChartOption4(
1222
1672
  {
1223
1673
  grid: {
@@ -1225,7 +1675,11 @@ var AreaChart = React9.forwardRef(
1225
1675
  right: "4%",
1226
1676
  bottom: "3%",
1227
1677
  containLabel: true,
1228
- ...gridInset3(legendConfig, showLegend && !customLegend, xAxisConfig, yAxisConfig)
1678
+ ...withZoomInset3(
1679
+ gridInset3(legendConfig, builtInLegend, xAxisConfig, yAxisConfig),
1680
+ dataZoom,
1681
+ "x"
1682
+ )
1229
1683
  },
1230
1684
  tooltip: buildTooltip4(
1231
1685
  {
@@ -1240,7 +1694,7 @@ var AreaChart = React9.forwardRef(
1240
1694
  {
1241
1695
  show: showTooltip,
1242
1696
  formatter: tooltipFormatter,
1243
- valueFormatter: tooltipValueFormatter,
1697
+ valueFormatter: formatters.tooltip,
1244
1698
  getLabel
1245
1699
  }
1246
1700
  ),
@@ -1249,6 +1703,7 @@ var AreaChart = React9.forwardRef(
1249
1703
  legendConfig,
1250
1704
  { show: showLegend, custom: customLegend }
1251
1705
  ),
1706
+ dataZoom: buildDataZoom3(dataZoom, "x", legendBottom ? 36 : 0),
1252
1707
  xAxis: buildAxis3(
1253
1708
  {
1254
1709
  type: "category",
@@ -1260,40 +1715,18 @@ var AreaChart = React9.forwardRef(
1260
1715
  yAxis: buildAxis3(
1261
1716
  {
1262
1717
  type: "value",
1718
+ ...isPercent && { max: 100 },
1263
1719
  splitLine: {
1264
1720
  show: showGrid
1265
1721
  }
1266
1722
  },
1267
- yAxisConfig
1723
+ formatters.axis(yAxisConfig)
1268
1724
  ),
1269
- series: data.series.map((series, index) => {
1270
- const base = series.color || chartColors.series[index % chartColors.series.length];
1271
- return {
1272
- name: series.name,
1273
- type: "line",
1274
- data: withPointLabels3(series.data, series.labels, labelFormatter, {
1275
- position: "top"
1276
- }),
1277
- smooth,
1278
- stack: stacked ? "Total" : void 0,
1279
- areaStyle: gradient ? {
1280
- opacity: 0.8,
1281
- color: new echarts6.graphic.LinearGradient(0, 0, 0, 1, [
1282
- { offset: 0, color: colorWithAlpha(base, 0.8) },
1283
- { offset: 1, color: colorWithAlpha(base, 0.1) }
1284
- ])
1285
- } : { opacity: 0.5 },
1286
- itemStyle: series.color ? { color: series.color } : void 0,
1287
- label: buildDataLabel4({ show: true, position: "top" }, void 0, {
1288
- show: showLabels,
1289
- formatter: labelFormatter,
1290
- getLabel
1291
- }),
1292
- emphasis: {
1293
- focus: "series"
1294
- },
1295
- showSymbol
1296
- };
1725
+ series: withReferenceMarks3(series, referenceLines, referenceBands, {
1726
+ valueAxis: "y",
1727
+ format: formatters.format,
1728
+ color: chartColors.reference,
1729
+ bandColor: chartColors.referenceBand
1297
1730
  })
1298
1731
  },
1299
1732
  optionOverride
@@ -1306,49 +1739,49 @@ var AreaChart = React9.forwardRef(
1306
1739
  showGrid,
1307
1740
  smooth,
1308
1741
  stacked,
1742
+ isPercent,
1743
+ connectNulls,
1309
1744
  gradient,
1310
1745
  chartColors,
1311
1746
  showLabels,
1747
+ valueFormat,
1748
+ locale,
1312
1749
  labelFormatter,
1313
1750
  xAxisConfig,
1314
1751
  yAxisConfig,
1752
+ referenceLines,
1753
+ referenceBands,
1754
+ dataZoom,
1315
1755
  tooltipFormatter,
1316
1756
  tooltipValueFormatter,
1317
1757
  legendConfig,
1318
1758
  customLegend,
1759
+ builtInLegend,
1319
1760
  optionOverride
1320
1761
  ]);
1321
- const latest = useLatestRef({ onClick });
1322
- const { containerRef } = useChart({
1762
+ const { containerRef, exportImage } = useChart({
1323
1763
  option,
1324
1764
  theme: currentTheme === THEME_DARK3 ? "dark" : "light",
1325
1765
  animation,
1326
- onReady: (chart) => {
1327
- legend.attach(chart);
1328
- chart.on("click", (params) => {
1329
- const { onClick: onClick2 } = latest.current;
1330
- if (!onClick2) return;
1331
- onClick2({
1332
- type: params.type || "click",
1333
- componentType: params.componentType || "series",
1334
- seriesIndex: params.seriesIndex,
1335
- seriesName: params.seriesName || "",
1336
- dataIndex: params.dataIndex || 0,
1337
- name: params.name || "",
1338
- value: params.value,
1339
- color: params.color
1340
- });
1341
- });
1342
- }
1766
+ patterns,
1767
+ events: chartEvents(events, {
1768
+ click: onClick && ((params) => onClick(toDataPointParams(params, "click"))),
1769
+ mouseover: onHover && ((params) => onHover(toDataPointParams(params, "mouseover")))
1770
+ }),
1771
+ onReady: legend.attach,
1772
+ onCreated: onReady
1343
1773
  });
1344
- const accessibilityDescription = description || (!isEmpty ? `${title}. Area chart with ${data.categories.length} data points across ${data.series.length} series.` : void 0);
1345
- return /* @__PURE__ */ jsx9(
1774
+ const format = resolveValueFormatter4(valueFormat, locale);
1775
+ const accessibilityDescription = description || (!isEmpty ? generateAreaChartDescription(title, data, format) : void 0);
1776
+ return /* @__PURE__ */ jsx10(
1346
1777
  ChartContainer,
1347
1778
  {
1348
1779
  ref,
1349
1780
  title,
1350
1781
  description: accessibilityDescription,
1351
1782
  height,
1783
+ minHeight,
1784
+ maxHeight,
1352
1785
  loading,
1353
1786
  error,
1354
1787
  empty: isEmpty,
@@ -1356,8 +1789,13 @@ var AreaChart = React9.forwardRef(
1356
1789
  className: cn(className),
1357
1790
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
1358
1791
  legendPosition: legendConfig?.position,
1792
+ dataTable: isEmpty ? void 0 : categoryTable3(data),
1793
+ showDataTable,
1794
+ format,
1795
+ exportable,
1796
+ exportImage,
1359
1797
  ...props,
1360
- children: /* @__PURE__ */ jsx9("div", { ref: containerRef, className: "h-full w-full" })
1798
+ children: /* @__PURE__ */ jsx10("div", { ref: containerRef, className: "h-full w-full" })
1361
1799
  }
1362
1800
  );
1363
1801
  }
@@ -1374,22 +1812,26 @@ import {
1374
1812
  LegendComponent as LegendComponent5,
1375
1813
  TitleComponent as TitleComponent5
1376
1814
  } from "echarts/components";
1377
- import { CanvasRenderer as CanvasRenderer5 } from "echarts/renderers";
1815
+ import { CanvasRenderer as CanvasRenderer6 } from "echarts/renderers";
1378
1816
  import {
1379
1817
  buildAxis as buildAxis4,
1380
1818
  buildDataLabel as buildDataLabel5,
1381
1819
  buildLegend as buildLegend5,
1382
1820
  buildTooltip as buildTooltip5,
1821
+ chartFormatters as chartFormatters4,
1383
1822
  escapeHtml as escapeHtml2,
1384
1823
  formatTooltipValue as formatTooltipValue2,
1385
1824
  generateScatterChartDescription,
1386
1825
  getChartColors as getChartColors5,
1387
1826
  gridInset as gridInset4,
1388
1827
  mergeChartOption as mergeChartOption5,
1828
+ resolveValueFormatter as resolveValueFormatter5,
1829
+ scatterTable,
1389
1830
  seriesLabelLookup as seriesLabelLookup4,
1390
- withPointLabels as withPointLabels4
1831
+ withPointLabels as withPointLabels4,
1832
+ withReferenceMarks as withReferenceMarks4
1391
1833
  } from "@classic-homes/charts-core";
1392
- import { jsx as jsx10 } from "react/jsx-runtime";
1834
+ import { jsx as jsx11 } from "react/jsx-runtime";
1393
1835
  echarts7.use([
1394
1836
  EChartsScatterChart,
1395
1837
  // Trend lines are line series
@@ -1398,7 +1840,7 @@ echarts7.use([
1398
1840
  TooltipComponent5,
1399
1841
  LegendComponent5,
1400
1842
  TitleComponent5,
1401
- CanvasRenderer5
1843
+ CanvasRenderer6
1402
1844
  ]);
1403
1845
  var ScatterChart = React10.forwardRef(
1404
1846
  ({
@@ -1406,6 +1848,8 @@ var ScatterChart = React10.forwardRef(
1406
1848
  description,
1407
1849
  data,
1408
1850
  height = 400,
1851
+ minHeight,
1852
+ maxHeight,
1409
1853
  loading,
1410
1854
  error,
1411
1855
  emptyMessage,
@@ -1417,25 +1861,36 @@ var ScatterChart = React10.forwardRef(
1417
1861
  showTrendLine = false,
1418
1862
  symbolSize = 10,
1419
1863
  showLabels = false,
1864
+ valueFormat,
1865
+ locale,
1420
1866
  labelFormatter,
1421
1867
  xAxisConfig,
1422
1868
  yAxisConfig,
1869
+ referenceLines,
1870
+ referenceBands,
1423
1871
  tooltipFormatter,
1424
1872
  tooltipValueFormatter,
1425
1873
  legend: legendConfig,
1426
1874
  renderLegend,
1427
1875
  onLegendChange,
1428
1876
  option: optionOverride,
1877
+ onReady,
1878
+ events,
1879
+ showDataTable,
1880
+ exportable,
1881
+ patterns,
1429
1882
  onClick,
1883
+ onHover,
1430
1884
  class: className,
1431
1885
  ...props
1432
1886
  }, ref) => {
1433
1887
  const isEmpty = !data?.series?.length || data.series.every((s) => !s.data?.length);
1434
1888
  const currentTheme = useChartTheme(theme);
1889
+ const chartColors = getChartColors5(currentTheme);
1435
1890
  const legend = useChartLegend({
1436
1891
  names: data?.series?.map((s) => s.name) ?? [],
1437
1892
  colors: data?.series?.map((s) => s.color) ?? [],
1438
- palette: getChartColors5(currentTheme).series,
1893
+ palette: chartColors.series,
1439
1894
  config: legendConfig,
1440
1895
  title,
1441
1896
  onLegendChange
@@ -1443,16 +1898,22 @@ var ScatterChart = React10.forwardRef(
1443
1898
  const customLegend = renderLegend !== void 0;
1444
1899
  const option = React10.useMemo(() => {
1445
1900
  if (isEmpty) return {};
1901
+ const formatters = chartFormatters4({
1902
+ valueFormat,
1903
+ locale,
1904
+ tooltipValueFormatter,
1905
+ labelFormatter
1906
+ });
1446
1907
  const getLabel = seriesLabelLookup4(data.series);
1447
1908
  const series = data.series.map((s) => ({
1448
1909
  name: s.name,
1449
1910
  type: "scatter",
1450
- data: withPointLabels4(s.data, s.labels, labelFormatter, { position: "top" }),
1911
+ data: withPointLabels4(s.data, s.labels, formatters.label, { position: "top" }),
1451
1912
  symbolSize: typeof symbolSize === "function" ? symbolSize : symbolSize,
1452
1913
  itemStyle: s.color ? { color: s.color } : void 0,
1453
1914
  label: buildDataLabel5({ show: true, position: "top" }, void 0, {
1454
1915
  show: showLabels,
1455
- formatter: labelFormatter,
1916
+ formatter: formatters.label,
1456
1917
  getLabel
1457
1918
  }),
1458
1919
  emphasis: {
@@ -1517,15 +1978,15 @@ var ScatterChart = React10.forwardRef(
1517
1978
  formatter: (params) => {
1518
1979
  const p = params;
1519
1980
  if (!p.value) return "";
1520
- const x = formatTooltipValue2(p.value[0], tooltipValueFormatter);
1521
- const y = formatTooltipValue2(p.value[1], tooltipValueFormatter);
1981
+ const x = formatTooltipValue2(p.value[0], formatters.tooltip);
1982
+ const y = formatTooltipValue2(p.value[1], formatters.tooltip);
1522
1983
  return `${escapeHtml2(p.seriesName)}<br/>X: ${escapeHtml2(x)}<br/>Y: ${escapeHtml2(y)}`;
1523
1984
  }
1524
1985
  },
1525
1986
  {
1526
1987
  show: showTooltip,
1527
1988
  formatter: tooltipFormatter,
1528
- valueFormatter: tooltipValueFormatter,
1989
+ valueFormatter: formatters.tooltip,
1529
1990
  getLabel
1530
1991
  }
1531
1992
  ),
@@ -1550,9 +2011,19 @@ var ScatterChart = React10.forwardRef(
1550
2011
  show: showGrid
1551
2012
  }
1552
2013
  },
1553
- yAxisConfig
2014
+ formatters.axis(yAxisConfig)
1554
2015
  ),
1555
- series
2016
+ series: withReferenceMarks4(
2017
+ series,
2018
+ referenceLines,
2019
+ referenceBands,
2020
+ {
2021
+ valueAxis: "y",
2022
+ format: formatters.format,
2023
+ color: chartColors.reference,
2024
+ bandColor: chartColors.referenceBand
2025
+ }
2026
+ )
1556
2027
  },
1557
2028
  optionOverride
1558
2029
  );
@@ -1565,46 +2036,42 @@ var ScatterChart = React10.forwardRef(
1565
2036
  showTrendLine,
1566
2037
  symbolSize,
1567
2038
  showLabels,
2039
+ valueFormat,
2040
+ locale,
1568
2041
  labelFormatter,
1569
2042
  xAxisConfig,
1570
2043
  yAxisConfig,
2044
+ referenceLines,
2045
+ referenceBands,
2046
+ chartColors,
1571
2047
  tooltipFormatter,
1572
2048
  tooltipValueFormatter,
1573
2049
  legendConfig,
1574
2050
  customLegend,
1575
2051
  optionOverride
1576
2052
  ]);
1577
- const latest = useLatestRef({ onClick });
1578
- const { containerRef } = useChart({
2053
+ const { containerRef, exportImage } = useChart({
1579
2054
  option,
1580
2055
  theme,
1581
2056
  animation,
1582
- onReady: (chart) => {
1583
- legend.attach(chart);
1584
- chart.on("click", (params) => {
1585
- const { onClick: onClick2 } = latest.current;
1586
- if (!onClick2) return;
1587
- onClick2({
1588
- type: params.type || "click",
1589
- componentType: params.componentType || "series",
1590
- seriesIndex: params.seriesIndex,
1591
- seriesName: params.seriesName || "",
1592
- dataIndex: params.dataIndex || 0,
1593
- name: params.name || "",
1594
- value: params.value,
1595
- color: params.color
1596
- });
1597
- });
1598
- }
2057
+ patterns,
2058
+ events: chartEvents(events, {
2059
+ click: onClick && ((params) => onClick(toDataPointParams(params, "click"))),
2060
+ mouseover: onHover && ((params) => onHover(toDataPointParams(params, "mouseover")))
2061
+ }),
2062
+ onReady: legend.attach,
2063
+ onCreated: onReady
1599
2064
  });
1600
2065
  const accessibilityDescription = description || (!isEmpty ? generateScatterChartDescription(title, data) : void 0);
1601
- return /* @__PURE__ */ jsx10(
2066
+ return /* @__PURE__ */ jsx11(
1602
2067
  ChartContainer,
1603
2068
  {
1604
2069
  ref,
1605
2070
  title,
1606
2071
  description: accessibilityDescription,
1607
2072
  height,
2073
+ minHeight,
2074
+ maxHeight,
1608
2075
  loading,
1609
2076
  error,
1610
2077
  empty: isEmpty,
@@ -1612,8 +2079,13 @@ var ScatterChart = React10.forwardRef(
1612
2079
  className: cn(className),
1613
2080
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
1614
2081
  legendPosition: legendConfig?.position,
2082
+ dataTable: isEmpty ? void 0 : scatterTable(data, xAxisConfig?.name, yAxisConfig?.name),
2083
+ showDataTable,
2084
+ format: resolveValueFormatter5(valueFormat, locale),
2085
+ exportable,
2086
+ exportImage,
1615
2087
  ...props,
1616
- children: /* @__PURE__ */ jsx10("div", { ref: containerRef, className: "h-full w-full" })
2088
+ children: /* @__PURE__ */ jsx11("div", { ref: containerRef, className: "h-full w-full" })
1617
2089
  }
1618
2090
  );
1619
2091
  }
@@ -1625,7 +2097,7 @@ import * as React11 from "react";
1625
2097
  import * as echarts8 from "echarts/core";
1626
2098
  import { PieChart as EChartsPieChart2 } from "echarts/charts";
1627
2099
  import { TooltipComponent as TooltipComponent6, LegendComponent as LegendComponent6, TitleComponent as TitleComponent6 } from "echarts/components";
1628
- import { CanvasRenderer as CanvasRenderer6 } from "echarts/renderers";
2100
+ import { CanvasRenderer as CanvasRenderer7 } from "echarts/renderers";
1629
2101
  import {
1630
2102
  buildDataLabel as buildDataLabel6,
1631
2103
  buildLegend as buildLegend6,
@@ -1639,16 +2111,20 @@ import {
1639
2111
  legendCenter as legendCenter2,
1640
2112
  mergeChartOption as mergeChartOption6,
1641
2113
  pointLabel as pointLabel2,
2114
+ resolveValueFormatter as resolveValueFormatter6,
2115
+ sliceTable as sliceTable2,
1642
2116
  THEME_DARK as THEME_DARK4
1643
2117
  } from "@classic-homes/charts-core";
1644
- import { jsx as jsx11 } from "react/jsx-runtime";
1645
- echarts8.use([EChartsPieChart2, TooltipComponent6, LegendComponent6, TitleComponent6, CanvasRenderer6]);
2118
+ import { jsx as jsx12 } from "react/jsx-runtime";
2119
+ echarts8.use([EChartsPieChart2, TooltipComponent6, LegendComponent6, TitleComponent6, CanvasRenderer7]);
1646
2120
  var DonutChart = React11.forwardRef(
1647
2121
  ({
1648
2122
  title,
1649
2123
  description,
1650
2124
  data,
1651
2125
  height = 400,
2126
+ minHeight,
2127
+ maxHeight,
1652
2128
  loading,
1653
2129
  error,
1654
2130
  emptyMessage,
@@ -1661,6 +2137,8 @@ var DonutChart = React11.forwardRef(
1661
2137
  innerRadius = "50%",
1662
2138
  centerLabel,
1663
2139
  centerValue,
2140
+ valueFormat,
2141
+ locale,
1664
2142
  labelFormatter,
1665
2143
  tooltipFormatter,
1666
2144
  tooltipValueFormatter,
@@ -1668,6 +2146,11 @@ var DonutChart = React11.forwardRef(
1668
2146
  renderLegend,
1669
2147
  onLegendChange,
1670
2148
  option: optionOverride,
2149
+ onReady,
2150
+ events,
2151
+ showDataTable,
2152
+ exportable,
2153
+ patterns,
1671
2154
  onClick,
1672
2155
  class: className,
1673
2156
  ...props
@@ -1684,6 +2167,11 @@ var DonutChart = React11.forwardRef(
1684
2167
  onLegendChange
1685
2168
  });
1686
2169
  const customLegend = renderLegend !== void 0;
2170
+ const format = React11.useMemo(
2171
+ () => resolveValueFormatter6(valueFormat, locale),
2172
+ [valueFormat, locale]
2173
+ );
2174
+ const tooltipValues = tooltipValueFormatter ?? format;
1687
2175
  const option = React11.useMemo(() => {
1688
2176
  if (isEmpty) return {};
1689
2177
  const pieCenter = legendCenter2(legendConfig, showLegend && !customLegend, ["50%", "45%"]);
@@ -1730,7 +2218,7 @@ var DonutChart = React11.forwardRef(
1730
2218
  )
1731
2219
  );
1732
2220
  }
1733
- const valueFormatter = tooltipFormatter === void 0 ? tooltipValueFormatter : void 0;
2221
+ const valueFormatter = tooltipFormatter === void 0 ? tooltipValues : void 0;
1734
2222
  const tooltipBase = {
1735
2223
  trigger: "item",
1736
2224
  formatter: valueFormatter ? (params) => {
@@ -1743,7 +2231,7 @@ var DonutChart = React11.forwardRef(
1743
2231
  tooltip: buildTooltip6(tooltipBase, {
1744
2232
  show: showTooltip,
1745
2233
  formatter: tooltipFormatter,
1746
- valueFormatter: tooltipValueFormatter,
2234
+ valueFormatter: tooltipValues,
1747
2235
  getLabel: itemLabelLookup2(data)
1748
2236
  }),
1749
2237
  legend: buildLegend6(
@@ -1803,40 +2291,32 @@ var DonutChart = React11.forwardRef(
1803
2291
  chartColors,
1804
2292
  labelFormatter,
1805
2293
  tooltipFormatter,
1806
- tooltipValueFormatter,
2294
+ tooltipValues,
1807
2295
  legendConfig,
1808
2296
  customLegend,
1809
2297
  optionOverride
1810
2298
  ]);
1811
- const latest = useLatestRef({ onClick });
1812
- const { containerRef } = useChart({
2299
+ const { containerRef, exportImage } = useChart({
1813
2300
  option,
1814
2301
  theme: currentTheme === THEME_DARK4 ? "dark" : "light",
1815
2302
  animation,
1816
- onReady: (chart) => {
1817
- legend.attach(chart);
1818
- chart.on("click", (params) => {
1819
- const { onClick: onClick2 } = latest.current;
1820
- if (!onClick2) return;
1821
- onClick2({
1822
- type: params.type || "click",
1823
- componentType: params.componentType || "series",
1824
- name: params.name || "",
1825
- value: params.value,
1826
- percent: params.percent,
1827
- color: params.color
1828
- });
1829
- });
1830
- }
2303
+ patterns,
2304
+ events: chartEvents(events, {
2305
+ click: onClick && ((params) => onClick(toSliceParams(params, "click")))
2306
+ }),
2307
+ onReady: legend.attach,
2308
+ onCreated: onReady
1831
2309
  });
1832
2310
  const accessibilityDescription = description || (!isEmpty ? generatePieChartDescription2(title, data, true) : void 0);
1833
- return /* @__PURE__ */ jsx11(
2311
+ return /* @__PURE__ */ jsx12(
1834
2312
  ChartContainer,
1835
2313
  {
1836
2314
  ref,
1837
2315
  title,
1838
2316
  description: accessibilityDescription,
1839
2317
  height,
2318
+ minHeight,
2319
+ maxHeight,
1840
2320
  loading,
1841
2321
  error,
1842
2322
  empty: isEmpty,
@@ -1844,8 +2324,13 @@ var DonutChart = React11.forwardRef(
1844
2324
  className: cn(className),
1845
2325
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
1846
2326
  legendPosition: legendConfig?.position,
2327
+ dataTable: isEmpty ? void 0 : sliceTable2(data),
2328
+ showDataTable,
2329
+ format,
2330
+ exportable,
2331
+ exportImage,
1847
2332
  ...props,
1848
- children: /* @__PURE__ */ jsx11("div", { ref: containerRef, className: "h-full w-full" })
2333
+ children: /* @__PURE__ */ jsx12("div", { ref: containerRef, className: "h-full w-full" })
1849
2334
  }
1850
2335
  );
1851
2336
  }
@@ -1862,23 +2347,25 @@ import {
1862
2347
  TitleComponent as TitleComponent7,
1863
2348
  RadarComponent
1864
2349
  } from "echarts/components";
1865
- import { CanvasRenderer as CanvasRenderer7 } from "echarts/renderers";
2350
+ import { CanvasRenderer as CanvasRenderer8 } from "echarts/renderers";
1866
2351
  import {
1867
2352
  buildDataLabel as buildDataLabel7,
1868
2353
  buildLegend as buildLegend7,
1869
2354
  buildTooltip as buildTooltip7,
1870
2355
  getChartColors as getChartColors7,
1871
2356
  legendCenter as legendCenter3,
1872
- mergeChartOption as mergeChartOption7
2357
+ mergeChartOption as mergeChartOption7,
2358
+ radarTable,
2359
+ resolveValueFormatter as resolveValueFormatter7
1873
2360
  } from "@classic-homes/charts-core";
1874
- import { jsx as jsx12 } from "react/jsx-runtime";
2361
+ import { jsx as jsx13 } from "react/jsx-runtime";
1875
2362
  echarts9.use([
1876
2363
  EChartsRadarChart,
1877
2364
  TooltipComponent7,
1878
2365
  LegendComponent7,
1879
2366
  TitleComponent7,
1880
2367
  RadarComponent,
1881
- CanvasRenderer7
2368
+ CanvasRenderer8
1882
2369
  ]);
1883
2370
  var RadarChart = React12.forwardRef(
1884
2371
  ({
@@ -1887,6 +2374,8 @@ var RadarChart = React12.forwardRef(
1887
2374
  data,
1888
2375
  indicators,
1889
2376
  height = 400,
2377
+ minHeight,
2378
+ maxHeight,
1890
2379
  loading,
1891
2380
  error,
1892
2381
  emptyMessage,
@@ -1896,6 +2385,8 @@ var RadarChart = React12.forwardRef(
1896
2385
  showTooltip = true,
1897
2386
  shape = "polygon",
1898
2387
  showLabels = false,
2388
+ valueFormat,
2389
+ locale,
1899
2390
  labelFormatter,
1900
2391
  tooltipFormatter,
1901
2392
  tooltipValueFormatter,
@@ -1903,6 +2394,11 @@ var RadarChart = React12.forwardRef(
1903
2394
  renderLegend,
1904
2395
  onLegendChange,
1905
2396
  option: optionOverride,
2397
+ onReady,
2398
+ events,
2399
+ showDataTable,
2400
+ exportable,
2401
+ patterns,
1906
2402
  onClick,
1907
2403
  class: className,
1908
2404
  ...props
@@ -1918,6 +2414,11 @@ var RadarChart = React12.forwardRef(
1918
2414
  onLegendChange
1919
2415
  });
1920
2416
  const customLegend = renderLegend !== void 0;
2417
+ const format = React12.useMemo(
2418
+ () => resolveValueFormatter7(valueFormat, locale),
2419
+ [valueFormat, locale]
2420
+ );
2421
+ const valueFormatter = tooltipValueFormatter ?? format;
1921
2422
  const option = React12.useMemo(() => {
1922
2423
  if (isEmpty) return {};
1923
2424
  return mergeChartOption7(
@@ -1929,7 +2430,7 @@ var RadarChart = React12.forwardRef(
1929
2430
  {
1930
2431
  show: showTooltip,
1931
2432
  formatter: tooltipFormatter,
1932
- valueFormatter: tooltipValueFormatter
2433
+ valueFormatter
1933
2434
  }
1934
2435
  ),
1935
2436
  legend: buildLegend7(
@@ -1976,22 +2477,20 @@ var RadarChart = React12.forwardRef(
1976
2477
  showLabels,
1977
2478
  labelFormatter,
1978
2479
  tooltipFormatter,
1979
- tooltipValueFormatter,
2480
+ valueFormatter,
1980
2481
  legendConfig,
1981
2482
  customLegend,
1982
2483
  optionOverride
1983
2484
  ]);
1984
- const latest = useLatestRef({ onClick });
1985
- const { containerRef } = useChart({
2485
+ const { containerRef, exportImage } = useChart({
1986
2486
  option,
1987
2487
  theme,
1988
2488
  animation,
1989
- onReady: (chart) => {
1990
- legend.attach(chart);
1991
- chart.on("click", (params) => {
1992
- const { onClick: onClick2 } = latest.current;
1993
- if (!onClick2) return;
1994
- onClick2({
2489
+ patterns,
2490
+ events: chartEvents(events, {
2491
+ click: onClick && ((params) => {
2492
+ if (!onClick) return;
2493
+ onClick({
1995
2494
  type: params.type || "click",
1996
2495
  componentType: params.componentType || "series",
1997
2496
  seriesIndex: params.seriesIndex,
@@ -2001,17 +2500,21 @@ var RadarChart = React12.forwardRef(
2001
2500
  value: params.value,
2002
2501
  color: params.color
2003
2502
  });
2004
- });
2005
- }
2503
+ })
2504
+ }),
2505
+ onReady: legend.attach,
2506
+ onCreated: onReady
2006
2507
  });
2007
2508
  const accessibilityDescription = description || (!isEmpty ? `${title}. Radar chart with ${indicators.length} dimensions comparing ${data.series.length} series.` : void 0);
2008
- return /* @__PURE__ */ jsx12(
2509
+ return /* @__PURE__ */ jsx13(
2009
2510
  ChartContainer,
2010
2511
  {
2011
2512
  ref,
2012
2513
  title,
2013
2514
  description: accessibilityDescription,
2014
2515
  height,
2516
+ minHeight,
2517
+ maxHeight,
2015
2518
  loading,
2016
2519
  error,
2017
2520
  empty: isEmpty,
@@ -2019,8 +2522,13 @@ var RadarChart = React12.forwardRef(
2019
2522
  className: cn(className),
2020
2523
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
2021
2524
  legendPosition: legendConfig?.position,
2525
+ dataTable: isEmpty ? void 0 : radarTable(data, indicators),
2526
+ showDataTable,
2527
+ format,
2528
+ exportable,
2529
+ exportImage,
2022
2530
  ...props,
2023
- children: /* @__PURE__ */ jsx12("div", { ref: containerRef, className: "h-full w-full" })
2531
+ children: /* @__PURE__ */ jsx13("div", { ref: containerRef, className: "h-full w-full" })
2024
2532
  }
2025
2533
  );
2026
2534
  }
@@ -2032,7 +2540,7 @@ import * as React13 from "react";
2032
2540
  import * as echarts10 from "echarts/core";
2033
2541
  import { FunnelChart as EChartsFunnelChart } from "echarts/charts";
2034
2542
  import { TooltipComponent as TooltipComponent8, LegendComponent as LegendComponent8, TitleComponent as TitleComponent8 } from "echarts/components";
2035
- import { CanvasRenderer as CanvasRenderer8 } from "echarts/renderers";
2543
+ import { CanvasRenderer as CanvasRenderer9 } from "echarts/renderers";
2036
2544
  import {
2037
2545
  buildDataLabel as buildDataLabel8,
2038
2546
  buildLegend as buildLegend8,
@@ -2042,15 +2550,17 @@ import {
2042
2550
  getChartColors as getChartColors8,
2043
2551
  itemLabelLookup as itemLabelLookup3,
2044
2552
  mergeChartOption as mergeChartOption8,
2045
- pointLabel as pointLabel3
2553
+ pointLabel as pointLabel3,
2554
+ resolveValueFormatter as resolveValueFormatter8,
2555
+ sliceTable as sliceTable3
2046
2556
  } from "@classic-homes/charts-core";
2047
- import { jsx as jsx13 } from "react/jsx-runtime";
2557
+ import { jsx as jsx14 } from "react/jsx-runtime";
2048
2558
  echarts10.use([
2049
2559
  EChartsFunnelChart,
2050
2560
  TooltipComponent8,
2051
2561
  LegendComponent8,
2052
2562
  TitleComponent8,
2053
- CanvasRenderer8
2563
+ CanvasRenderer9
2054
2564
  ]);
2055
2565
  var FunnelChart = React13.forwardRef(
2056
2566
  ({
@@ -2058,6 +2568,8 @@ var FunnelChart = React13.forwardRef(
2058
2568
  description,
2059
2569
  data,
2060
2570
  height = 400,
2571
+ minHeight,
2572
+ maxHeight,
2061
2573
  loading,
2062
2574
  error,
2063
2575
  emptyMessage,
@@ -2068,6 +2580,8 @@ var FunnelChart = React13.forwardRef(
2068
2580
  sort = "descending",
2069
2581
  orientation = "vertical",
2070
2582
  showLabels = true,
2583
+ valueFormat,
2584
+ locale,
2071
2585
  labelFormatter,
2072
2586
  tooltipFormatter,
2073
2587
  tooltipValueFormatter,
@@ -2075,6 +2589,11 @@ var FunnelChart = React13.forwardRef(
2075
2589
  renderLegend,
2076
2590
  onLegendChange,
2077
2591
  option: optionOverride,
2592
+ onReady,
2593
+ events,
2594
+ showDataTable,
2595
+ exportable,
2596
+ patterns,
2078
2597
  onClick,
2079
2598
  class: className,
2080
2599
  ...props
@@ -2090,15 +2609,20 @@ var FunnelChart = React13.forwardRef(
2090
2609
  onLegendChange
2091
2610
  });
2092
2611
  const customLegend = renderLegend !== void 0;
2612
+ const format = React13.useMemo(
2613
+ () => resolveValueFormatter8(valueFormat, locale),
2614
+ [valueFormat, locale]
2615
+ );
2616
+ const valueFormatter = tooltipValueFormatter ?? format;
2093
2617
  const option = React13.useMemo(() => {
2094
2618
  if (isEmpty) return {};
2095
2619
  const getLabel = itemLabelLookup3(data);
2096
- const valueFormatter = tooltipFormatter === void 0 ? tooltipValueFormatter : void 0;
2620
+ const templateFormatter = tooltipFormatter === void 0 ? valueFormatter : void 0;
2097
2621
  const tooltipBase = {
2098
2622
  trigger: "item",
2099
- formatter: valueFormatter ? (params) => {
2623
+ formatter: templateFormatter ? (params) => {
2100
2624
  const p = params;
2101
- return `${escapeHtml4(p.seriesName)} <br/>${escapeHtml4(p.name)}: ${escapeHtml4(formatTooltipValue4(p.value, valueFormatter))}`;
2625
+ return `${escapeHtml4(p.seriesName)} <br/>${escapeHtml4(p.name)}: ${escapeHtml4(formatTooltipValue4(p.value, templateFormatter))}`;
2102
2626
  } : "{a} <br/>{b}: {c}"
2103
2627
  };
2104
2628
  return mergeChartOption8(
@@ -2106,7 +2630,7 @@ var FunnelChart = React13.forwardRef(
2106
2630
  tooltip: buildTooltip8(tooltipBase, {
2107
2631
  show: showTooltip,
2108
2632
  formatter: tooltipFormatter,
2109
- valueFormatter: tooltipValueFormatter,
2633
+ valueFormatter,
2110
2634
  getLabel
2111
2635
  }),
2112
2636
  legend: buildLegend8(
@@ -2169,39 +2693,41 @@ var FunnelChart = React13.forwardRef(
2169
2693
  title,
2170
2694
  labelFormatter,
2171
2695
  tooltipFormatter,
2172
- tooltipValueFormatter,
2696
+ valueFormatter,
2173
2697
  legendConfig,
2174
2698
  customLegend,
2175
2699
  optionOverride
2176
2700
  ]);
2177
- const latest = useLatestRef({ onClick });
2178
- const { containerRef } = useChart({
2701
+ const { containerRef, exportImage } = useChart({
2179
2702
  option,
2180
2703
  theme,
2181
2704
  animation,
2182
- onReady: (chart) => {
2183
- legend.attach(chart);
2184
- chart.on("click", (params) => {
2185
- const { onClick: onClick2 } = latest.current;
2186
- if (!onClick2) return;
2187
- onClick2({
2705
+ patterns,
2706
+ events: chartEvents(events, {
2707
+ click: onClick && ((params) => {
2708
+ if (!onClick) return;
2709
+ onClick({
2188
2710
  type: params.type || "click",
2189
2711
  componentType: params.componentType || "series",
2190
2712
  name: params.name || "",
2191
2713
  value: params.value,
2192
2714
  color: params.color
2193
2715
  });
2194
- });
2195
- }
2716
+ })
2717
+ }),
2718
+ onReady: legend.attach,
2719
+ onCreated: onReady
2196
2720
  });
2197
2721
  const accessibilityDescription = description || (!isEmpty ? `${title}. Funnel chart with ${data.length} stages.` : void 0);
2198
- return /* @__PURE__ */ jsx13(
2722
+ return /* @__PURE__ */ jsx14(
2199
2723
  ChartContainer,
2200
2724
  {
2201
2725
  ref,
2202
2726
  title,
2203
2727
  description: accessibilityDescription,
2204
2728
  height,
2729
+ minHeight,
2730
+ maxHeight,
2205
2731
  loading,
2206
2732
  error,
2207
2733
  empty: isEmpty,
@@ -2209,8 +2735,13 @@ var FunnelChart = React13.forwardRef(
2209
2735
  className: cn(className),
2210
2736
  legend: !isEmpty && renderLegend ? renderLegend(legend.renderProps) : void 0,
2211
2737
  legendPosition: legendConfig?.position,
2738
+ dataTable: isEmpty ? void 0 : sliceTable3(data, "Stage"),
2739
+ showDataTable,
2740
+ format,
2741
+ exportable,
2742
+ exportImage,
2212
2743
  ...props,
2213
- children: /* @__PURE__ */ jsx13("div", { ref: containerRef, className: "h-full w-full" })
2744
+ children: /* @__PURE__ */ jsx14("div", { ref: containerRef, className: "h-full w-full" })
2214
2745
  }
2215
2746
  );
2216
2747
  }
@@ -2222,15 +2753,16 @@ import * as React14 from "react";
2222
2753
  import * as echarts11 from "echarts/core";
2223
2754
  import { GaugeChart as EChartsGaugeChart } from "echarts/charts";
2224
2755
  import { TitleComponent as TitleComponent9, TooltipComponent as TooltipComponent9 } from "echarts/components";
2225
- import { CanvasRenderer as CanvasRenderer9 } from "echarts/renderers";
2756
+ import { CanvasRenderer as CanvasRenderer10 } from "echarts/renderers";
2226
2757
  import {
2227
2758
  buildTooltip as buildTooltip9,
2228
2759
  getChartColors as getChartColors9,
2229
2760
  mergeChartOption as mergeChartOption9,
2761
+ resolveValueFormatter as resolveValueFormatter9,
2230
2762
  THEME_DARK as THEME_DARK5
2231
2763
  } from "@classic-homes/charts-core";
2232
- import { jsx as jsx14 } from "react/jsx-runtime";
2233
- echarts11.use([EChartsGaugeChart, TitleComponent9, TooltipComponent9, CanvasRenderer9]);
2764
+ import { jsx as jsx15 } from "react/jsx-runtime";
2765
+ echarts11.use([EChartsGaugeChart, TitleComponent9, TooltipComponent9, CanvasRenderer10]);
2234
2766
  var GaugeChart = React14.forwardRef(
2235
2767
  ({
2236
2768
  title,
@@ -2239,6 +2771,8 @@ var GaugeChart = React14.forwardRef(
2239
2771
  min = 0,
2240
2772
  max = 100,
2241
2773
  height = 400,
2774
+ minHeight,
2775
+ maxHeight,
2242
2776
  loading,
2243
2777
  error,
2244
2778
  emptyMessage,
@@ -2246,11 +2780,18 @@ var GaugeChart = React14.forwardRef(
2246
2780
  animation = true,
2247
2781
  splitNumber = 10,
2248
2782
  showProgress = true,
2249
- formatValue,
2783
+ formatValue: formatValue2,
2250
2784
  showTooltip = true,
2785
+ valueFormat,
2786
+ locale,
2251
2787
  tooltipFormatter,
2252
2788
  tooltipValueFormatter,
2253
2789
  option: optionOverride,
2790
+ onReady,
2791
+ events,
2792
+ showDataTable,
2793
+ exportable,
2794
+ patterns,
2254
2795
  onClick,
2255
2796
  class: className,
2256
2797
  ...props
@@ -2258,6 +2799,11 @@ var GaugeChart = React14.forwardRef(
2258
2799
  const currentTheme = useChartTheme(theme);
2259
2800
  const chartColors = getChartColors9(currentTheme);
2260
2801
  const reducedMotion = useReducedMotion();
2802
+ const format = React14.useMemo(
2803
+ () => resolveValueFormatter9(valueFormat, locale),
2804
+ [valueFormat, locale]
2805
+ );
2806
+ const valueFormatter = formatValue2 ?? format;
2261
2807
  const option = React14.useMemo(() => {
2262
2808
  return mergeChartOption9(
2263
2809
  {
@@ -2329,7 +2875,7 @@ var GaugeChart = React14.forwardRef(
2329
2875
  fontSize: 28,
2330
2876
  fontWeight: "bold",
2331
2877
  offsetCenter: [0, "40%"],
2332
- formatter: formatValue || "{value}"
2878
+ formatter: valueFormatter || "{value}"
2333
2879
  },
2334
2880
  data: [
2335
2881
  {
@@ -2348,7 +2894,7 @@ var GaugeChart = React14.forwardRef(
2348
2894
  max,
2349
2895
  splitNumber,
2350
2896
  showProgress,
2351
- formatValue,
2897
+ valueFormatter,
2352
2898
  title,
2353
2899
  animation,
2354
2900
  reducedMotion,
@@ -2358,16 +2904,15 @@ var GaugeChart = React14.forwardRef(
2358
2904
  tooltipValueFormatter,
2359
2905
  optionOverride
2360
2906
  ]);
2361
- const latest = useLatestRef({ onClick });
2362
- const { containerRef } = useChart({
2907
+ const { containerRef, exportImage } = useChart({
2363
2908
  option,
2364
2909
  theme: currentTheme === THEME_DARK5 ? "dark" : "light",
2365
2910
  animation,
2366
- onReady: (chart) => {
2367
- chart.on("click", (params) => {
2368
- const { onClick: onClick2 } = latest.current;
2369
- if (!onClick2) return;
2370
- onClick2({
2911
+ patterns,
2912
+ events: chartEvents(events, {
2913
+ click: onClick && ((params) => {
2914
+ if (!onClick) return;
2915
+ onClick({
2371
2916
  type: params.type || "click",
2372
2917
  componentType: params.componentType || "series",
2373
2918
  seriesIndex: params.seriesIndex,
@@ -2377,23 +2922,35 @@ var GaugeChart = React14.forwardRef(
2377
2922
  value: params.value,
2378
2923
  color: params.color
2379
2924
  });
2380
- });
2381
- }
2925
+ })
2926
+ }),
2927
+ onCreated: onReady
2382
2928
  });
2383
- const accessibilityDescription = description || `${title}. Gauge showing value ${value} on scale from ${min} to ${max}.`;
2384
- return /* @__PURE__ */ jsx14(
2929
+ const show = (n) => valueFormatter ? valueFormatter(n) : String(n);
2930
+ const accessibilityDescription = description || `${title}. Gauge showing value ${show(value)} on scale from ${show(min)} to ${show(max)}.`;
2931
+ return /* @__PURE__ */ jsx15(
2385
2932
  ChartContainer,
2386
2933
  {
2387
2934
  ref,
2388
2935
  title,
2389
2936
  description: accessibilityDescription,
2390
2937
  height,
2938
+ minHeight,
2939
+ maxHeight,
2391
2940
  loading,
2392
2941
  error,
2393
2942
  emptyMessage,
2394
2943
  className: cn(className),
2944
+ dataTable: {
2945
+ headers: ["Metric", "Value", "Minimum", "Maximum"],
2946
+ rows: [[title, value, min, max]]
2947
+ },
2948
+ showDataTable,
2949
+ format,
2950
+ exportable,
2951
+ exportImage,
2395
2952
  ...props,
2396
- children: /* @__PURE__ */ jsx14("div", { ref: containerRef, className: "h-full w-full" })
2953
+ children: /* @__PURE__ */ jsx15("div", { ref: containerRef, className: "h-full w-full" })
2397
2954
  }
2398
2955
  );
2399
2956
  }
@@ -2410,23 +2967,25 @@ import {
2410
2967
  TitleComponent as TitleComponent10,
2411
2968
  VisualMapComponent
2412
2969
  } from "echarts/components";
2413
- import { CanvasRenderer as CanvasRenderer10 } from "echarts/renderers";
2970
+ import { CanvasRenderer as CanvasRenderer11 } from "echarts/renderers";
2414
2971
  import {
2415
2972
  buildAxis as buildAxis5,
2416
2973
  buildDataLabel as buildDataLabel9,
2417
2974
  buildTooltip as buildTooltip10,
2418
2975
  escapeHtml as escapeHtml5,
2419
2976
  formatTooltipValue as formatTooltipValue5,
2420
- mergeChartOption as mergeChartOption10
2977
+ mergeChartOption as mergeChartOption10,
2978
+ resolveValueFormatter as resolveValueFormatter10,
2979
+ heatmapTable
2421
2980
  } from "@classic-homes/charts-core";
2422
- import { jsx as jsx15 } from "react/jsx-runtime";
2981
+ import { jsx as jsx16 } from "react/jsx-runtime";
2423
2982
  echarts12.use([
2424
2983
  EChartsHeatmapChart,
2425
2984
  GridComponent5,
2426
2985
  TooltipComponent10,
2427
2986
  TitleComponent10,
2428
2987
  VisualMapComponent,
2429
- CanvasRenderer10
2988
+ CanvasRenderer11
2430
2989
  ]);
2431
2990
  var HeatmapChart = React15.forwardRef(
2432
2991
  ({
@@ -2436,6 +2995,8 @@ var HeatmapChart = React15.forwardRef(
2436
2995
  xAxis,
2437
2996
  yAxis,
2438
2997
  height = 400,
2998
+ minHeight,
2999
+ maxHeight,
2439
3000
  loading,
2440
3001
  error,
2441
3002
  emptyMessage,
@@ -2446,9 +3007,16 @@ var HeatmapChart = React15.forwardRef(
2446
3007
  labelFormatter,
2447
3008
  xAxisConfig,
2448
3009
  yAxisConfig,
3010
+ valueFormat,
3011
+ locale,
2449
3012
  tooltipFormatter,
2450
3013
  tooltipValueFormatter,
2451
3014
  option: optionOverride,
3015
+ onReady,
3016
+ events,
3017
+ showDataTable,
3018
+ exportable,
3019
+ patterns,
2452
3020
  onClick,
2453
3021
  class: className,
2454
3022
  ...props
@@ -2462,6 +3030,11 @@ var HeatmapChart = React15.forwardRef(
2462
3030
  }
2463
3031
  const minValue = data?.min ?? dataMin;
2464
3032
  const maxValue = data?.max ?? dataMax;
3033
+ const format = React15.useMemo(
3034
+ () => resolveValueFormatter10(valueFormat, locale),
3035
+ [valueFormat, locale]
3036
+ );
3037
+ const valueFormatter = tooltipValueFormatter ?? format;
2465
3038
  const option = React15.useMemo(() => {
2466
3039
  if (isEmpty) return {};
2467
3040
  return mergeChartOption10(
@@ -2473,13 +3046,13 @@ var HeatmapChart = React15.forwardRef(
2473
3046
  const p = params;
2474
3047
  if (!p.value) return "";
2475
3048
  const [xIdx, yIdx, value] = p.value;
2476
- return `${escapeHtml5(xAxis[xIdx])} / ${escapeHtml5(yAxis[yIdx])}: ${escapeHtml5(formatTooltipValue5(value, tooltipValueFormatter))}`;
3049
+ return `${escapeHtml5(xAxis[xIdx])} / ${escapeHtml5(yAxis[yIdx])}: ${escapeHtml5(formatTooltipValue5(value, valueFormatter))}`;
2477
3050
  }
2478
3051
  },
2479
3052
  {
2480
3053
  show: showTooltip,
2481
3054
  formatter: tooltipFormatter,
2482
- valueFormatter: tooltipValueFormatter
3055
+ valueFormatter
2483
3056
  }
2484
3057
  ),
2485
3058
  grid: {
@@ -2514,7 +3087,8 @@ var HeatmapChart = React15.forwardRef(
2514
3087
  calculable: true,
2515
3088
  orient: "vertical",
2516
3089
  right: "0%",
2517
- top: "center"
3090
+ top: "center",
3091
+ formatter: valueFormatter ? (value) => valueFormatter(value) : void 0
2518
3092
  },
2519
3093
  series: [
2520
3094
  {
@@ -2550,46 +3124,53 @@ var HeatmapChart = React15.forwardRef(
2550
3124
  xAxisConfig,
2551
3125
  yAxisConfig,
2552
3126
  tooltipFormatter,
2553
- tooltipValueFormatter,
3127
+ valueFormatter,
2554
3128
  optionOverride
2555
3129
  ]);
2556
- const latest = useLatestRef({ onClick, xAxis, yAxis });
2557
- const { containerRef } = useChart({
3130
+ const { containerRef, exportImage } = useChart({
2558
3131
  option,
2559
3132
  theme,
2560
3133
  animation,
2561
- onReady: (chart) => {
2562
- chart.on("click", (params) => {
2563
- const { onClick: onClick2, xAxis: xAxis2, yAxis: yAxis2 } = latest.current;
2564
- if (!onClick2) return;
3134
+ patterns,
3135
+ events: chartEvents(events, {
3136
+ click: onClick && ((params) => {
3137
+ if (!onClick) return;
2565
3138
  const [xIdx, yIdx, value] = params.value || [0, 0, 0];
2566
- onClick2({
3139
+ onClick({
2567
3140
  type: params.type || "click",
2568
3141
  componentType: params.componentType || "series",
2569
3142
  xIndex: xIdx,
2570
3143
  yIndex: yIdx,
2571
- xLabel: xAxis2[xIdx],
2572
- yLabel: yAxis2[yIdx],
3144
+ xLabel: xAxis[xIdx],
3145
+ yLabel: yAxis[yIdx],
2573
3146
  value
2574
3147
  });
2575
- });
2576
- }
3148
+ })
3149
+ }),
3150
+ onCreated: onReady
2577
3151
  });
2578
3152
  const accessibilityDescription = description || (!isEmpty ? `${title}. Heatmap with ${xAxis.length} columns and ${yAxis.length} rows.` : void 0);
2579
- return /* @__PURE__ */ jsx15(
3153
+ return /* @__PURE__ */ jsx16(
2580
3154
  ChartContainer,
2581
3155
  {
2582
3156
  ref,
2583
3157
  title,
2584
3158
  description: accessibilityDescription,
2585
3159
  height,
3160
+ minHeight,
3161
+ maxHeight,
2586
3162
  loading,
2587
3163
  error,
2588
3164
  empty: isEmpty,
2589
3165
  emptyMessage,
2590
3166
  className: cn(className),
3167
+ dataTable: isEmpty ? void 0 : heatmapTable(data, xAxis, yAxis),
3168
+ showDataTable,
3169
+ format,
3170
+ exportable,
3171
+ exportImage,
2591
3172
  ...props,
2592
- children: /* @__PURE__ */ jsx15("div", { ref: containerRef, className: "h-full w-full" })
3173
+ children: /* @__PURE__ */ jsx16("div", { ref: containerRef, className: "h-full w-full" })
2593
3174
  }
2594
3175
  );
2595
3176
  }
@@ -2601,7 +3182,7 @@ import * as React16 from "react";
2601
3182
  import * as echarts13 from "echarts/core";
2602
3183
  import { TreemapChart as EChartsTreemapChart } from "echarts/charts";
2603
3184
  import { TooltipComponent as TooltipComponent11, TitleComponent as TitleComponent11 } from "echarts/components";
2604
- import { CanvasRenderer as CanvasRenderer11 } from "echarts/renderers";
3185
+ import { CanvasRenderer as CanvasRenderer12 } from "echarts/renderers";
2605
3186
  import {
2606
3187
  buildDataLabel as buildDataLabel10,
2607
3188
  buildTooltip as buildTooltip11,
@@ -2609,12 +3190,14 @@ import {
2609
3190
  formatTooltipValue as formatTooltipValue6,
2610
3191
  getChartColors as getChartColors10,
2611
3192
  mergeChartOption as mergeChartOption11,
3193
+ resolveValueFormatter as resolveValueFormatter11,
3194
+ treemapTable,
2612
3195
  nameLabelLookup,
2613
3196
  pointLabel as pointLabel4,
2614
3197
  THEME_DARK as THEME_DARK6
2615
3198
  } from "@classic-homes/charts-core";
2616
- import { jsx as jsx16 } from "react/jsx-runtime";
2617
- echarts13.use([EChartsTreemapChart, TooltipComponent11, TitleComponent11, CanvasRenderer11]);
3199
+ import { jsx as jsx17 } from "react/jsx-runtime";
3200
+ echarts13.use([EChartsTreemapChart, TooltipComponent11, TitleComponent11, CanvasRenderer12]);
2618
3201
  var TreemapChart = React16.forwardRef(
2619
3202
  ({
2620
3203
  title,
@@ -2622,6 +3205,8 @@ var TreemapChart = React16.forwardRef(
2622
3205
  data,
2623
3206
  levels,
2624
3207
  height = 400,
3208
+ minHeight,
3209
+ maxHeight,
2625
3210
  loading,
2626
3211
  error,
2627
3212
  emptyMessage,
@@ -2629,9 +3214,16 @@ var TreemapChart = React16.forwardRef(
2629
3214
  animation = true,
2630
3215
  showTooltip = true,
2631
3216
  labelFormatter,
3217
+ valueFormat,
3218
+ locale,
2632
3219
  tooltipFormatter,
2633
3220
  tooltipValueFormatter,
2634
3221
  option: optionOverride,
3222
+ onReady,
3223
+ events,
3224
+ showDataTable,
3225
+ exportable,
3226
+ patterns,
2635
3227
  onClick,
2636
3228
  class: className,
2637
3229
  ...props
@@ -2639,6 +3231,11 @@ var TreemapChart = React16.forwardRef(
2639
3231
  const isEmpty = !data?.length;
2640
3232
  const currentTheme = useChartTheme(theme);
2641
3233
  const chartColors = getChartColors10(currentTheme);
3234
+ const format = React16.useMemo(
3235
+ () => resolveValueFormatter11(valueFormat, locale),
3236
+ [valueFormat, locale]
3237
+ );
3238
+ const valueFormatter = tooltipValueFormatter ?? format;
2642
3239
  const option = React16.useMemo(() => {
2643
3240
  if (isEmpty) return {};
2644
3241
  const toNode = (node) => ({
@@ -2652,13 +3249,13 @@ var TreemapChart = React16.forwardRef(
2652
3249
  {
2653
3250
  formatter: (params) => {
2654
3251
  const p = params;
2655
- return `${escapeHtml6(p.name)}: ${escapeHtml6(formatTooltipValue6(p.value, tooltipValueFormatter))}`;
3252
+ return `${escapeHtml6(p.name)}: ${escapeHtml6(formatTooltipValue6(p.value, valueFormatter))}`;
2656
3253
  }
2657
3254
  },
2658
3255
  {
2659
3256
  show: showTooltip,
2660
3257
  formatter: tooltipFormatter,
2661
- valueFormatter: tooltipValueFormatter
3258
+ valueFormatter
2662
3259
  }
2663
3260
  ),
2664
3261
  series: [
@@ -2718,20 +3315,19 @@ var TreemapChart = React16.forwardRef(
2718
3315
  chartColors,
2719
3316
  labelFormatter,
2720
3317
  tooltipFormatter,
2721
- tooltipValueFormatter,
3318
+ valueFormatter,
2722
3319
  optionOverride
2723
3320
  ]);
2724
- const latest = useLatestRef({ onClick });
2725
- const { containerRef } = useChart({
3321
+ const { containerRef, exportImage } = useChart({
2726
3322
  option,
2727
3323
  theme: currentTheme === THEME_DARK6 ? "dark" : "light",
2728
3324
  animation,
2729
- onReady: (chart) => {
2730
- chart.on("click", (params) => {
2731
- const { onClick: onClick2 } = latest.current;
2732
- if (!onClick2) return;
3325
+ patterns,
3326
+ events: chartEvents(events, {
3327
+ click: onClick && ((params) => {
3328
+ if (!onClick) return;
2733
3329
  const treePathInfo = params.treePathInfo || [];
2734
- onClick2({
3330
+ onClick({
2735
3331
  type: params.type || "click",
2736
3332
  componentType: params.componentType || "series",
2737
3333
  name: params.name || "",
@@ -2739,24 +3335,32 @@ var TreemapChart = React16.forwardRef(
2739
3335
  path: treePathInfo.map((item) => item.name || ""),
2740
3336
  depth: treePathInfo.length - 1
2741
3337
  });
2742
- });
2743
- }
3338
+ })
3339
+ }),
3340
+ onCreated: onReady
2744
3341
  });
2745
3342
  const accessibilityDescription = description || (!isEmpty ? `${title}. Treemap chart showing hierarchical data.` : void 0);
2746
- return /* @__PURE__ */ jsx16(
3343
+ return /* @__PURE__ */ jsx17(
2747
3344
  ChartContainer,
2748
3345
  {
2749
3346
  ref,
2750
3347
  title,
2751
3348
  description: accessibilityDescription,
2752
3349
  height,
3350
+ minHeight,
3351
+ maxHeight,
2753
3352
  loading,
2754
3353
  error,
2755
3354
  empty: isEmpty,
2756
3355
  emptyMessage,
2757
3356
  className: cn(className),
3357
+ dataTable: isEmpty ? void 0 : treemapTable(data),
3358
+ showDataTable,
3359
+ format,
3360
+ exportable,
3361
+ exportImage,
2758
3362
  ...props,
2759
- children: /* @__PURE__ */ jsx16("div", { ref: containerRef, className: "h-full w-full" })
3363
+ children: /* @__PURE__ */ jsx17("div", { ref: containerRef, className: "h-full w-full" })
2760
3364
  }
2761
3365
  );
2762
3366
  }
@@ -2776,15 +3380,17 @@ import {
2776
3380
  TitleComponent as TitleComponent12,
2777
3381
  DataZoomComponent
2778
3382
  } from "echarts/components";
2779
- import { CanvasRenderer as CanvasRenderer12 } from "echarts/renderers";
3383
+ import { CanvasRenderer as CanvasRenderer13 } from "echarts/renderers";
2780
3384
  import {
2781
3385
  buildAxis as buildAxis6,
2782
3386
  buildTooltip as buildTooltip12,
2783
3387
  getChartColors as getChartColors11,
2784
3388
  mergeChartOption as mergeChartOption12,
3389
+ resolveValueFormatter as resolveValueFormatter12,
3390
+ candlestickTable,
2785
3391
  THEME_DARK as THEME_DARK7
2786
3392
  } from "@classic-homes/charts-core";
2787
- import { jsx as jsx17 } from "react/jsx-runtime";
3393
+ import { jsx as jsx18 } from "react/jsx-runtime";
2788
3394
  echarts14.use([
2789
3395
  EChartsCandlestickChart,
2790
3396
  EChartsBarChart2,
@@ -2792,7 +3398,7 @@ echarts14.use([
2792
3398
  TooltipComponent12,
2793
3399
  TitleComponent12,
2794
3400
  DataZoomComponent,
2795
- CanvasRenderer12
3401
+ CanvasRenderer13
2796
3402
  ]);
2797
3403
  var CandlestickChart = React17.forwardRef(
2798
3404
  ({
@@ -2800,6 +3406,8 @@ var CandlestickChart = React17.forwardRef(
2800
3406
  description,
2801
3407
  data,
2802
3408
  height = 400,
3409
+ minHeight,
3410
+ maxHeight,
2803
3411
  loading,
2804
3412
  error,
2805
3413
  emptyMessage,
@@ -2807,11 +3415,19 @@ var CandlestickChart = React17.forwardRef(
2807
3415
  animation = true,
2808
3416
  showTooltip = true,
2809
3417
  showVolume = false,
3418
+ zoomStart = 80,
2810
3419
  xAxisConfig,
2811
3420
  yAxisConfig,
3421
+ valueFormat,
3422
+ locale,
2812
3423
  tooltipFormatter,
2813
3424
  tooltipValueFormatter,
2814
3425
  option: optionOverride,
3426
+ onReady,
3427
+ events,
3428
+ showDataTable,
3429
+ exportable,
3430
+ patterns,
2815
3431
  onClick,
2816
3432
  class: className,
2817
3433
  ...props
@@ -2819,6 +3435,11 @@ var CandlestickChart = React17.forwardRef(
2819
3435
  const isEmpty = !data?.dates?.length || !data?.data?.length;
2820
3436
  const currentTheme = useChartTheme(theme);
2821
3437
  const chartColors = getChartColors11(currentTheme);
3438
+ const format = React17.useMemo(
3439
+ () => resolveValueFormatter12(valueFormat, locale),
3440
+ [valueFormat, locale]
3441
+ );
3442
+ const valueFormatter = tooltipValueFormatter ?? format;
2822
3443
  const option = React17.useMemo(() => {
2823
3444
  if (isEmpty) return {};
2824
3445
  const candlestickData = data.data.map((item) => [item.open, item.close, item.low, item.high]);
@@ -2921,7 +3542,7 @@ var CandlestickChart = React17.forwardRef(
2921
3542
  {
2922
3543
  show: showTooltip,
2923
3544
  formatter: tooltipFormatter,
2924
- valueFormatter: tooltipValueFormatter
3545
+ valueFormatter
2925
3546
  }
2926
3547
  ),
2927
3548
  grid: gridArr,
@@ -2930,14 +3551,14 @@ var CandlestickChart = React17.forwardRef(
2930
3551
  dataZoom: [
2931
3552
  {
2932
3553
  type: "inside",
2933
- start: 80,
3554
+ start: zoomStart,
2934
3555
  end: 100
2935
3556
  },
2936
3557
  {
2937
3558
  show: true,
2938
3559
  type: "slider",
2939
3560
  top: "90%",
2940
- start: 80,
3561
+ start: zoomStart,
2941
3562
  end: 100
2942
3563
  }
2943
3564
  ],
@@ -2950,54 +3571,62 @@ var CandlestickChart = React17.forwardRef(
2950
3571
  isEmpty,
2951
3572
  showTooltip,
2952
3573
  showVolume,
3574
+ zoomStart,
2953
3575
  title,
2954
3576
  chartColors,
2955
3577
  xAxisConfig,
2956
3578
  yAxisConfig,
2957
3579
  tooltipFormatter,
2958
- tooltipValueFormatter,
3580
+ valueFormatter,
2959
3581
  optionOverride
2960
3582
  ]);
2961
- const latest = useLatestRef({ onClick, data });
2962
- const { containerRef } = useChart({
3583
+ const { containerRef, exportImage } = useChart({
2963
3584
  option,
2964
3585
  theme: currentTheme === THEME_DARK7 ? "dark" : "light",
2965
3586
  animation,
2966
- onReady: (chart) => {
2967
- chart.on("click", (params) => {
2968
- const { onClick: onClick2, data: data2 } = latest.current;
2969
- if (!onClick2) return;
3587
+ patterns,
3588
+ events: chartEvents(events, {
3589
+ click: onClick && ((params) => {
3590
+ if (!onClick) return;
2970
3591
  const dataIndex = params.dataIndex || 0;
2971
- const item = data2.data[dataIndex];
3592
+ const item = data.data[dataIndex];
2972
3593
  if (!item) return;
2973
- onClick2({
3594
+ onClick({
2974
3595
  type: params.type || "click",
2975
3596
  componentType: params.componentType || "series",
2976
- date: data2.dates[dataIndex],
3597
+ date: data.dates[dataIndex],
2977
3598
  open: item.open,
2978
3599
  close: item.close,
2979
3600
  high: item.high,
2980
3601
  low: item.low,
2981
- volume: data2.volume?.[dataIndex]
3602
+ volume: data.volume?.[dataIndex]
2982
3603
  });
2983
- });
2984
- }
3604
+ })
3605
+ }),
3606
+ onCreated: onReady
2985
3607
  });
2986
3608
  const accessibilityDescription = description || (!isEmpty ? `${title}. Candlestick chart with ${data.dates.length} data points.` : void 0);
2987
- return /* @__PURE__ */ jsx17(
3609
+ return /* @__PURE__ */ jsx18(
2988
3610
  ChartContainer,
2989
3611
  {
2990
3612
  ref,
2991
3613
  title,
2992
3614
  description: accessibilityDescription,
2993
3615
  height,
3616
+ minHeight,
3617
+ maxHeight,
2994
3618
  loading,
2995
3619
  error,
2996
3620
  empty: isEmpty,
2997
3621
  emptyMessage,
2998
3622
  className: cn(className),
3623
+ dataTable: isEmpty ? void 0 : candlestickTable(data),
3624
+ showDataTable,
3625
+ format,
3626
+ exportable,
3627
+ exportImage,
2999
3628
  ...props,
3000
- children: /* @__PURE__ */ jsx17("div", { ref: containerRef, className: "h-full w-full" })
3629
+ children: /* @__PURE__ */ jsx18("div", { ref: containerRef, className: "h-full w-full" })
3001
3630
  }
3002
3631
  );
3003
3632
  }
@@ -3009,22 +3638,26 @@ import * as React18 from "react";
3009
3638
  import * as echarts15 from "echarts/core";
3010
3639
  import { SankeyChart as EChartsSankeyChart } from "echarts/charts";
3011
3640
  import { TooltipComponent as TooltipComponent13, TitleComponent as TitleComponent13 } from "echarts/components";
3012
- import { CanvasRenderer as CanvasRenderer13 } from "echarts/renderers";
3641
+ import { CanvasRenderer as CanvasRenderer14 } from "echarts/renderers";
3013
3642
  import {
3014
3643
  buildDataLabel as buildDataLabel11,
3015
3644
  buildTooltip as buildTooltip13,
3016
3645
  mergeChartOption as mergeChartOption13,
3646
+ resolveValueFormatter as resolveValueFormatter13,
3647
+ sankeyTable,
3017
3648
  nameLabelLookup as nameLabelLookup2,
3018
3649
  pointLabel as pointLabel5
3019
3650
  } from "@classic-homes/charts-core";
3020
- import { jsx as jsx18 } from "react/jsx-runtime";
3021
- echarts15.use([EChartsSankeyChart, TooltipComponent13, TitleComponent13, CanvasRenderer13]);
3651
+ import { jsx as jsx19 } from "react/jsx-runtime";
3652
+ echarts15.use([EChartsSankeyChart, TooltipComponent13, TitleComponent13, CanvasRenderer14]);
3022
3653
  var SankeyChart = React18.forwardRef(
3023
3654
  ({
3024
3655
  title,
3025
3656
  description,
3026
3657
  data,
3027
3658
  height = 400,
3659
+ minHeight,
3660
+ maxHeight,
3028
3661
  loading,
3029
3662
  error,
3030
3663
  emptyMessage,
@@ -3033,14 +3666,26 @@ var SankeyChart = React18.forwardRef(
3033
3666
  showTooltip = true,
3034
3667
  orient = "horizontal",
3035
3668
  labelFormatter,
3669
+ valueFormat,
3670
+ locale,
3036
3671
  tooltipFormatter,
3037
3672
  tooltipValueFormatter,
3038
3673
  option: optionOverride,
3674
+ onReady,
3675
+ events,
3676
+ showDataTable,
3677
+ exportable,
3678
+ patterns,
3039
3679
  onClick,
3040
3680
  class: className,
3041
3681
  ...props
3042
3682
  }, ref) => {
3043
3683
  const isEmpty = !data?.nodes?.length || !data?.links?.length;
3684
+ const format = React18.useMemo(
3685
+ () => resolveValueFormatter13(valueFormat, locale),
3686
+ [valueFormat, locale]
3687
+ );
3688
+ const valueFormatter = tooltipValueFormatter ?? format;
3044
3689
  const option = React18.useMemo(() => {
3045
3690
  if (isEmpty) return {};
3046
3691
  return mergeChartOption13(
@@ -3053,7 +3698,7 @@ var SankeyChart = React18.forwardRef(
3053
3698
  {
3054
3699
  show: showTooltip,
3055
3700
  formatter: tooltipFormatter,
3056
- valueFormatter: tooltipValueFormatter
3701
+ valueFormatter
3057
3702
  }
3058
3703
  ),
3059
3704
  series: [
@@ -3096,20 +3741,19 @@ var SankeyChart = React18.forwardRef(
3096
3741
  orient,
3097
3742
  labelFormatter,
3098
3743
  tooltipFormatter,
3099
- tooltipValueFormatter,
3744
+ valueFormatter,
3100
3745
  optionOverride
3101
3746
  ]);
3102
- const latest = useLatestRef({ onClick });
3103
- const { containerRef } = useChart({
3747
+ const { containerRef, exportImage } = useChart({
3104
3748
  option,
3105
3749
  theme,
3106
3750
  animation,
3107
- onReady: (chart) => {
3108
- chart.on("click", (params) => {
3109
- const { onClick: onClick2 } = latest.current;
3110
- if (!onClick2) return;
3751
+ patterns,
3752
+ events: chartEvents(events, {
3753
+ click: onClick && ((params) => {
3754
+ if (!onClick) return;
3111
3755
  const isEdge = params.dataType === "edge";
3112
- onClick2({
3756
+ onClick({
3113
3757
  type: params.type || "click",
3114
3758
  componentType: params.componentType || "series",
3115
3759
  dataType: isEdge ? "edge" : "node",
@@ -3118,24 +3762,32 @@ var SankeyChart = React18.forwardRef(
3118
3762
  source: isEdge ? params.data?.source : void 0,
3119
3763
  target: isEdge ? params.data?.target : void 0
3120
3764
  });
3121
- });
3122
- }
3765
+ })
3766
+ }),
3767
+ onCreated: onReady
3123
3768
  });
3124
3769
  const accessibilityDescription = description || (!isEmpty ? `${title}. Sankey diagram with ${data.nodes.length} nodes and ${data.links.length} links.` : void 0);
3125
- return /* @__PURE__ */ jsx18(
3770
+ return /* @__PURE__ */ jsx19(
3126
3771
  ChartContainer,
3127
3772
  {
3128
3773
  ref,
3129
3774
  title,
3130
3775
  description: accessibilityDescription,
3131
3776
  height,
3777
+ minHeight,
3778
+ maxHeight,
3132
3779
  loading,
3133
3780
  error,
3134
3781
  empty: isEmpty,
3135
3782
  emptyMessage,
3136
3783
  className: cn(className),
3784
+ dataTable: isEmpty ? void 0 : sankeyTable(data),
3785
+ showDataTable,
3786
+ format,
3787
+ exportable,
3788
+ exportImage,
3137
3789
  ...props,
3138
- children: /* @__PURE__ */ jsx18("div", { ref: containerRef, className: "h-full w-full" })
3790
+ children: /* @__PURE__ */ jsx19("div", { ref: containerRef, className: "h-full w-full" })
3139
3791
  }
3140
3792
  );
3141
3793
  }
@@ -3146,6 +3798,7 @@ export {
3146
3798
  BarChart,
3147
3799
  CandlestickChart,
3148
3800
  ChartContainer,
3801
+ ChartDataTable,
3149
3802
  ChartEmpty,
3150
3803
  ChartError,
3151
3804
  ChartLegend,
@@ -3161,7 +3814,9 @@ export {
3161
3814
  ScatterChart,
3162
3815
  TreemapChart,
3163
3816
  cn,
3817
+ exportChartImage,
3164
3818
  registerClassicThemes,
3819
+ registerEchartsModules,
3165
3820
  useChart,
3166
3821
  useChartLegend,
3167
3822
  useChartResize,