@orianatech/pire 0.10.0 → 0.11.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.cjs CHANGED
@@ -32,6 +32,7 @@ var src_exports = {};
32
32
  __export(src_exports, {
33
33
  Avatar: () => Avatar,
34
34
  Badge: () => Badge,
35
+ BarChart: () => BarChart,
35
36
  Breadcrumb: () => Breadcrumb,
36
37
  Button: () => Button,
37
38
  Card: () => Card,
@@ -44,6 +45,7 @@ __export(src_exports, {
44
45
  DescriptionList: () => DescriptionList,
45
46
  Dialog: () => Dialog,
46
47
  DialogTrigger: () => import_react_aria_components32.DialogTrigger,
48
+ DonutChart: () => DonutChart,
47
49
  EmptyState: () => EmptyState,
48
50
  FileDropZone: () => FileDropZone,
49
51
  FileUpload: () => FileUpload,
@@ -57,6 +59,7 @@ __export(src_exports, {
57
59
  InlineMessage: () => InlineMessage,
58
60
  Input: () => Input,
59
61
  KpiTile: () => KpiTile,
62
+ LineChart: () => LineChart,
60
63
  Link: () => Link,
61
64
  LinkList: () => LinkList,
62
65
  Menu: () => Menu,
@@ -97,6 +100,7 @@ __export(src_exports, {
97
100
  Toast: () => Toast,
98
101
  ToastProvider: () => ToastProvider,
99
102
  Tooltip: () => Tooltip,
103
+ VIZ_SLOT_COUNT: () => VIZ_SLOT_COUNT,
100
104
  ValueHelpDialog: () => ValueHelpDialog,
101
105
  ValueHelpField: () => ValueHelpField,
102
106
  configureIcons: () => configureIcons,
@@ -919,7 +923,10 @@ var enMessages = {
919
923
  fileUploadChoose: "Choose files",
920
924
  fileUploadRemoveNamed: "Remove {name}",
921
925
  fileUploadUploading: "Uploading",
922
- fileDropZonePrompt: "Drag files here, or choose them"
926
+ fileDropZonePrompt: "Drag files here, or choose them",
927
+ chartCategoryHeader: "Category",
928
+ chartNoValue: "No data",
929
+ chartEmpty: "No data for this period"
923
930
  };
924
931
  var esMessages = {
925
932
  filterBarLabel: "Filtros",
@@ -956,7 +963,10 @@ var esMessages = {
956
963
  fileUploadChoose: "Elegir archivos",
957
964
  fileUploadRemoveNamed: "Quitar {name}",
958
965
  fileUploadUploading: "Subiendo",
959
- fileDropZonePrompt: "Arrastr\xE1 archivos ac\xE1, o elegilos"
966
+ fileDropZonePrompt: "Arrastr\xE1 archivos ac\xE1, o elegilos",
967
+ chartCategoryHeader: "Categor\xEDa",
968
+ chartNoValue: "Sin datos",
969
+ chartEmpty: "Sin datos para este per\xEDodo"
960
970
  };
961
971
 
962
972
  // src/i18n/PireIntlProvider.tsx
@@ -2466,20 +2476,509 @@ function Timeline({ entries, reverse = false, className, ...rest }) {
2466
2476
  ] }, entry.id ?? i)) });
2467
2477
  }
2468
2478
 
2479
+ // src/components/data/chartGeometry.ts
2480
+ var VIZ_SLOT_COUNT = 6;
2481
+ var NICE_STEPS = [1, 2, 2.5, 5, 10];
2482
+ function niceStep(rough) {
2483
+ if (!(rough > 0)) return 1;
2484
+ const magnitude = 10 ** Math.floor(Math.log10(rough));
2485
+ const normalized = rough / magnitude;
2486
+ return (NICE_STEPS.find((candidate) => candidate >= normalized) ?? 10) * magnitude;
2487
+ }
2488
+ function linearScale(values, tickCount = 4, startAtZero = true) {
2489
+ const present = values.filter((value) => value != null && Number.isFinite(value));
2490
+ if (present.length === 0) return { min: 0, max: 1, ticks: [0, 1] };
2491
+ let low = Math.min(...present);
2492
+ let high = Math.max(...present);
2493
+ if (startAtZero) {
2494
+ low = Math.min(0, low);
2495
+ high = Math.max(0, high);
2496
+ }
2497
+ if (low === high) {
2498
+ high = low === 0 ? 1 : low + Math.abs(low);
2499
+ }
2500
+ const step = niceStep((high - low) / Math.max(1, tickCount));
2501
+ const EDGE_TOLERANCE = 1e-9;
2502
+ const decimals = Math.max(0, 1 - Math.floor(Math.log10(step)));
2503
+ const toStepPrecision = (value) => Number(value.toFixed(decimals));
2504
+ const min = toStepPrecision(Math.floor(low / step + EDGE_TOLERANCE) * step);
2505
+ const max = toStepPrecision(Math.ceil(high / step - EDGE_TOLERANCE) * step);
2506
+ const stepCount = Math.round((max - min) / step);
2507
+ const ticks = Array.from(
2508
+ { length: stepCount + 1 },
2509
+ (_, index) => toStepPrecision(min + index * step)
2510
+ );
2511
+ return { min, max, ticks };
2512
+ }
2513
+ function scalePosition(value, scale) {
2514
+ const span = scale.max - scale.min;
2515
+ return span === 0 ? 0 : (value - scale.min) / span;
2516
+ }
2517
+ function seriesColor(series, index) {
2518
+ const slot = series.colorIndex ?? index + 1;
2519
+ return slot >= 1 && slot <= VIZ_SLOT_COUNT ? `var(--viz-${slot})` : "var(--viz-other)";
2520
+ }
2521
+ var IS_DEV2 = process.env.NODE_ENV !== "production";
2522
+ var warnedCharts = /* @__PURE__ */ new Set();
2523
+ function warnOnSlotOverflow(series, chartLabel) {
2524
+ if (!IS_DEV2 || warnedCharts.has(chartLabel)) return;
2525
+ if (series.length <= VIZ_SLOT_COUNT) return;
2526
+ warnedCharts.add(chartLabel);
2527
+ console.warn(
2528
+ `[pire] "${chartLabel}" has ${series.length} series but the palette defines ${VIZ_SLOT_COUNT} distinguishable colours. The extras render in one shared neutral. Group the tail into an "Other" series, or split the chart into small multiples.`
2529
+ );
2530
+ }
2531
+ function warnOnDonutShape(series, categoryCount, chartLabel) {
2532
+ if (!IS_DEV2 || warnedCharts.has(`donut:${chartLabel}`)) return;
2533
+ const complaints = [];
2534
+ if (series.length > 1) {
2535
+ complaints.push(`it has ${series.length} series but a donut draws one \u2014 the rest are ignored`);
2536
+ }
2537
+ if (categoryCount > VIZ_SLOT_COUNT) {
2538
+ complaints.push(`it has ${categoryCount} segments and the palette defines ${VIZ_SLOT_COUNT}; past about four, slices stop being readable at all \u2014 group the tail into "Other"`);
2539
+ }
2540
+ if (series[0]?.values.some((value) => value != null && value < 0)) {
2541
+ complaints.push("it contains negative values, which have no part-to-whole meaning \u2014 a signed measure belongs in a bar chart");
2542
+ }
2543
+ if (complaints.length === 0) return;
2544
+ warnedCharts.add(`donut:${chartLabel}`);
2545
+ console.warn(`[pire] DonutChart "${chartLabel}": ${complaints.join("; ")}.`);
2546
+ }
2547
+ function stackTotal(series, categoryIndex) {
2548
+ return series.reduce((total, one) => total + (one.values[categoryIndex] ?? 0), 0);
2549
+ }
2550
+ function flatValues(series) {
2551
+ return series.flatMap((one) => one.values);
2552
+ }
2553
+ function alignToCategories(series, categoryCount) {
2554
+ return series.map((one) => one.values.length <= categoryCount ? one : { ...one, values: one.values.slice(0, categoryCount) });
2555
+ }
2556
+
2557
+ // src/components/data/ChartFrame.tsx
2558
+ var import_jsx_runtime47 = require("react/jsx-runtime");
2559
+ function seriesLegend(series) {
2560
+ return series.map((one, index) => ({
2561
+ key: one.id,
2562
+ label: one.label,
2563
+ color: seriesColor(one, index)
2564
+ }));
2565
+ }
2566
+ var defaultFormatValue = (value) => value.toLocaleString();
2567
+ function ChartFrame({
2568
+ label,
2569
+ title,
2570
+ description,
2571
+ categories,
2572
+ series,
2573
+ formatValue,
2574
+ legend,
2575
+ showDataTable,
2576
+ className,
2577
+ style,
2578
+ children
2579
+ }) {
2580
+ const msg = usePireMessages();
2581
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("figure", { className: cx("pire-chart", className), style, children: [
2582
+ title || description ? /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("figcaption", { className: "pire-chart-head", children: [
2583
+ title ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "pire-chart-title", children: title }) : null,
2584
+ description ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "pire-chart-desc", children: description }) : null
2585
+ ] }) : null,
2586
+ legend && legend.length > 1 ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("ul", { className: "pire-chart-legend", children: legend.map((item) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("li", { className: "pire-chart-legend-item", children: [
2587
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "pire-chart-swatch", style: { background: item.color } }),
2588
+ item.label
2589
+ ] }, item.key)) }) : null,
2590
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: "pire-chart-plot", "aria-hidden": "true", children }),
2591
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: showDataTable ? "pire-chart-table" : "pire-sr-only", children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("table", { children: [
2592
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("caption", { children: label }),
2593
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("tr", { children: [
2594
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("th", { scope: "col", children: msg.chartCategoryHeader }),
2595
+ series.map((one) => /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("th", { scope: "col", children: one.label }, one.id))
2596
+ ] }) }),
2597
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("tbody", { children: categories.map((category, categoryIndex) => (
2598
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2599
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)("tr", { children: [
2600
+ /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("th", { scope: "row", children: category }),
2601
+ series.map((one) => {
2602
+ const value = one.values[categoryIndex];
2603
+ return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("td", { children: value == null ? msg.chartNoValue : formatValue(value) }, one.id);
2604
+ })
2605
+ ] }, categoryIndex)
2606
+ )) })
2607
+ ] }) })
2608
+ ] });
2609
+ }
2610
+
2611
+ // src/components/data/BarChart.tsx
2612
+ var import_jsx_runtime48 = require("react/jsx-runtime");
2613
+ function BarChart({
2614
+ categories,
2615
+ series: rawSeries,
2616
+ title,
2617
+ description,
2618
+ formatValue = defaultFormatValue,
2619
+ height = 260,
2620
+ emptyState,
2621
+ showDataTable,
2622
+ orientation = "horizontal",
2623
+ stacked = false,
2624
+ showValues,
2625
+ className,
2626
+ style,
2627
+ ...rest
2628
+ }) {
2629
+ const label = rest["aria-label"];
2630
+ const msg = usePireMessages();
2631
+ warnOnSlotOverflow(rawSeries, label);
2632
+ const series = alignToCategories(rawSeries, categories.length);
2633
+ const hasData = categories.length > 0 && series.length > 0;
2634
+ const withValues = showValues ?? series.length === 1;
2635
+ const scale = linearScale(
2636
+ stacked ? categories.map((_, index) => stackTotal(series, index)) : flatValues(series)
2637
+ );
2638
+ const sizeOf = (value) => `${scalePosition(value, scale) * 100}%`;
2639
+ const horizontalLabelFor = (categoryIndex) => {
2640
+ if (stacked) return formatValue(stackTotal(series, categoryIndex));
2641
+ const value = series[0].values[categoryIndex];
2642
+ return value == null ? msg.chartNoValue : formatValue(value);
2643
+ };
2644
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2645
+ ChartFrame,
2646
+ {
2647
+ label,
2648
+ title,
2649
+ description,
2650
+ categories,
2651
+ series,
2652
+ formatValue,
2653
+ legend: seriesLegend(series),
2654
+ showDataTable,
2655
+ className,
2656
+ style,
2657
+ children: !hasData ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "pire-chart-empty", children: emptyState ?? msg.chartEmpty }) : /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2658
+ "div",
2659
+ {
2660
+ className: "pire-chart-bars",
2661
+ "data-orientation": orientation,
2662
+ "data-stacked": String(stacked),
2663
+ style: { "--pire-chart-height": `${height}px` },
2664
+ children: categories.map((category, categoryIndex) => (
2665
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2666
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "pire-chart-group", children: [
2667
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "pire-chart-cat", children: category }),
2668
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "pire-chart-track", children: series.map((one, seriesIndex) => {
2669
+ const value = one.values[categoryIndex];
2670
+ if (value == null) return null;
2671
+ return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(
2672
+ "div",
2673
+ {
2674
+ className: "pire-chart-bar",
2675
+ style: {
2676
+ "--pire-bar-size": sizeOf(value),
2677
+ "--pire-bar-color": seriesColor(one, seriesIndex)
2678
+ },
2679
+ children: [
2680
+ withValues && orientation === "vertical" ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "pire-chart-barval", children: formatValue(value) }) : null,
2681
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("span", { className: "pire-chart-tip", role: "presentation", children: [
2682
+ series.length > 1 ? `${one.label}: ` : "",
2683
+ formatValue(value)
2684
+ ] })
2685
+ ]
2686
+ },
2687
+ one.id
2688
+ );
2689
+ }) }),
2690
+ withValues && orientation === "horizontal" ? /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("span", { className: "pire-chart-val", children: horizontalLabelFor(categoryIndex) }) : null
2691
+ ] }, categoryIndex)
2692
+ ))
2693
+ }
2694
+ )
2695
+ }
2696
+ );
2697
+ }
2698
+
2699
+ // src/components/data/LineChart.tsx
2700
+ var React13 = __toESM(require("react"), 1);
2701
+ var import_jsx_runtime49 = require("react/jsx-runtime");
2702
+ var PLOT_INSET = { top: 10, right: 14, bottom: 24, left: 58 };
2703
+ var MARKER_LIMIT = 20;
2704
+ var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React13.useEffect : React13.useLayoutEffect;
2705
+ function useMeasuredWidth() {
2706
+ const ref = React13.useRef(null);
2707
+ const [width, setWidth] = React13.useState(0);
2708
+ useIsomorphicLayoutEffect2(() => {
2709
+ const element = ref.current;
2710
+ if (!element) return;
2711
+ setWidth(element.getBoundingClientRect().width);
2712
+ const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width));
2713
+ observer.observe(element);
2714
+ return () => observer.disconnect();
2715
+ }, []);
2716
+ return [ref, width];
2717
+ }
2718
+ function LineChart({
2719
+ categories,
2720
+ series: rawSeries,
2721
+ title,
2722
+ description,
2723
+ formatValue = defaultFormatValue,
2724
+ height = 260,
2725
+ emptyState,
2726
+ showDataTable,
2727
+ showArea = false,
2728
+ showMarkers,
2729
+ zoomToData = false,
2730
+ className,
2731
+ style,
2732
+ ...rest
2733
+ }) {
2734
+ const label = rest["aria-label"];
2735
+ const msg = usePireMessages();
2736
+ warnOnSlotOverflow(rawSeries, label);
2737
+ const [plotRef, width] = useMeasuredWidth();
2738
+ const series = alignToCategories(rawSeries, categories.length);
2739
+ const hasData = categories.length > 0 && series.length > 0;
2740
+ const withMarkers = showMarkers ?? categories.length <= MARKER_LIMIT;
2741
+ const scale = linearScale(flatValues(series), 4, !zoomToData);
2742
+ const innerWidth = Math.max(0, width - PLOT_INSET.left - PLOT_INSET.right);
2743
+ const innerHeight = Math.max(0, height - PLOT_INSET.top - PLOT_INSET.bottom);
2744
+ const xAt = (index) => PLOT_INSET.left + (categories.length <= 1 ? innerWidth / 2 : index / (categories.length - 1) * innerWidth);
2745
+ const yAt = (value) => PLOT_INSET.top + innerHeight - scalePosition(value, scale) * innerHeight;
2746
+ const pathFor = (values) => {
2747
+ let path = "";
2748
+ let penIsDown = false;
2749
+ values.forEach((value, index) => {
2750
+ if (value == null) {
2751
+ penIsDown = false;
2752
+ return;
2753
+ }
2754
+ path += `${penIsDown ? "L" : "M"}${xAt(index)} ${yAt(value)} `;
2755
+ penIsDown = true;
2756
+ });
2757
+ return path.trim();
2758
+ };
2759
+ const areaFor = (values) => {
2760
+ const present = values.map((value, index) => ({ value, index })).filter((point) => point.value != null);
2761
+ if (present.length < 2) return "";
2762
+ const baseline = PLOT_INSET.top + innerHeight;
2763
+ const line = present.map((point) => `${xAt(point.index)} ${yAt(point.value)}`).join(" L");
2764
+ const last = present[present.length - 1];
2765
+ return `M${xAt(present[0].index)} ${baseline} L${line} L${xAt(last.index)} ${baseline} Z`;
2766
+ };
2767
+ const labelEvery = Math.max(1, Math.ceil(categories.length / Math.max(2, Math.floor(innerWidth / 64))));
2768
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2769
+ ChartFrame,
2770
+ {
2771
+ label,
2772
+ title,
2773
+ description,
2774
+ categories,
2775
+ series,
2776
+ formatValue,
2777
+ legend: seriesLegend(series),
2778
+ showDataTable,
2779
+ className,
2780
+ style,
2781
+ children: !hasData ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "pire-chart-empty", children: emptyState ?? msg.chartEmpty }) : /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { className: "pire-chart-lines", ref: plotRef, style: { height }, children: [
2782
+ width > 0 ? /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)(
2783
+ "svg",
2784
+ {
2785
+ width,
2786
+ height,
2787
+ className: "pire-chart-svg",
2788
+ "aria-hidden": "true",
2789
+ focusable: "false",
2790
+ children: [
2791
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("g", { className: "pire-chart-grid", children: scale.ticks.map((tick) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2792
+ "line",
2793
+ {
2794
+ x1: PLOT_INSET.left,
2795
+ x2: width - PLOT_INSET.right,
2796
+ y1: yAt(tick),
2797
+ y2: yAt(tick)
2798
+ },
2799
+ tick
2800
+ )) }),
2801
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("g", { className: "pire-chart-tick", children: [
2802
+ scale.ticks.map((tick) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2803
+ "text",
2804
+ {
2805
+ x: PLOT_INSET.left - 8,
2806
+ y: yAt(tick),
2807
+ textAnchor: "end",
2808
+ dominantBaseline: "middle",
2809
+ children: formatValue(tick)
2810
+ },
2811
+ tick
2812
+ )),
2813
+ categories.map((category, index) => index % labelEvery === 0 ? (
2814
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2815
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("text", { x: xAt(index), y: height - 6, textAnchor: "middle", children: category }, index)
2816
+ ) : null)
2817
+ ] }),
2818
+ showArea && series[0] ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2819
+ "path",
2820
+ {
2821
+ d: areaFor(series[0].values),
2822
+ className: "pire-chart-area",
2823
+ style: { fill: seriesColor(series[0], 0) }
2824
+ }
2825
+ ) : null,
2826
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("g", { className: "pire-chart-line", fill: "none", children: series.map((one, index) => /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("path", { d: pathFor(one.values), stroke: seriesColor(one, index) }, one.id)) }),
2827
+ withMarkers ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("g", { className: "pire-chart-marker", children: series.map((one, seriesIndex) => one.values.map((value, index) => value == null ? null : (
2828
+ // biome-ignore lint/suspicious/noArrayIndexKey: a series is positional — the index is the point's identity, and category labels repeat.
2829
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2830
+ "circle",
2831
+ {
2832
+ cx: xAt(index),
2833
+ cy: yAt(value),
2834
+ r: 4,
2835
+ fill: seriesColor(one, seriesIndex)
2836
+ },
2837
+ `${one.id}-${index}`
2838
+ )
2839
+ ))) }) : null
2840
+ ]
2841
+ }
2842
+ ) : null,
2843
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)(
2844
+ "div",
2845
+ {
2846
+ className: "pire-chart-hover",
2847
+ style: { inset: `${PLOT_INSET.top}px ${PLOT_INSET.right}px ${PLOT_INSET.bottom}px ${PLOT_INSET.left}px` },
2848
+ children: categories.map((category, categoryIndex) => (
2849
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2850
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "pire-chart-band", children: /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "pire-chart-tip", role: "presentation", children: [
2851
+ /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("strong", { children: category }),
2852
+ series.map((one) => {
2853
+ const value = one.values[categoryIndex];
2854
+ return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("span", { className: "pire-chart-tip-row", children: [
2855
+ one.label,
2856
+ ": ",
2857
+ value == null ? "No data" : formatValue(value)
2858
+ ] }, one.id);
2859
+ })
2860
+ ] }) }, categoryIndex)
2861
+ ))
2862
+ }
2863
+ )
2864
+ ] })
2865
+ }
2866
+ );
2867
+ }
2868
+
2869
+ // src/components/data/DonutChart.tsx
2870
+ var React14 = __toESM(require("react"), 1);
2871
+ var import_jsx_runtime50 = require("react/jsx-runtime");
2872
+ var SEGMENT_GAP_DEGREES = 1.5;
2873
+ function DonutChart({
2874
+ categories,
2875
+ series,
2876
+ title,
2877
+ description,
2878
+ formatValue = defaultFormatValue,
2879
+ height = 220,
2880
+ emptyState,
2881
+ showDataTable,
2882
+ centerLabel,
2883
+ centerCaption,
2884
+ thickness = 28,
2885
+ className,
2886
+ style,
2887
+ ...rest
2888
+ }) {
2889
+ const label = rest["aria-label"];
2890
+ const msg = usePireMessages();
2891
+ const [hoveredIndex, setHoveredIndex] = React14.useState(null);
2892
+ warnOnDonutShape(series, categories.length, label);
2893
+ const values = (series[0]?.values ?? []).slice(0, categories.length);
2894
+ const segments = categories.map((category, index) => ({ category, index, value: values[index] ?? 0 })).filter((segment) => segment.value > 0);
2895
+ const total = segments.reduce((sum, segment) => sum + segment.value, 0);
2896
+ const hasData = segments.length > 0 && total > 0;
2897
+ const size = height;
2898
+ const radius = (size - thickness) / 2;
2899
+ const circumference = 2 * Math.PI * radius;
2900
+ const gapLength = SEGMENT_GAP_DEGREES / 360 * circumference;
2901
+ const legend = segments.map((segment) => ({
2902
+ key: segment.category,
2903
+ label: segment.category,
2904
+ color: colorForSegment(segment.index)
2905
+ }));
2906
+ const hovered = hoveredIndex == null ? null : segments.find((segment) => segment.index === hoveredIndex) ?? null;
2907
+ let arcStart = 0;
2908
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
2909
+ ChartFrame,
2910
+ {
2911
+ label,
2912
+ title,
2913
+ description,
2914
+ categories,
2915
+ series,
2916
+ formatValue,
2917
+ legend,
2918
+ showDataTable,
2919
+ className,
2920
+ style,
2921
+ children: !hasData ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "pire-chart-empty", children: emptyState ?? msg.chartEmpty }) : /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "pire-chart-donut", style: { height: size }, children: [
2922
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
2923
+ "svg",
2924
+ {
2925
+ width: size,
2926
+ height: size,
2927
+ "aria-hidden": "true",
2928
+ focusable: "false",
2929
+ onMouseLeave: () => setHoveredIndex(null),
2930
+ children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("g", { transform: `rotate(-90 ${size / 2} ${size / 2})`, children: segments.map((segment) => {
2931
+ const arcLength = segment.value / total * circumference;
2932
+ const offset = arcStart;
2933
+ arcStart += arcLength;
2934
+ return (
2935
+ // biome-ignore lint/a11y/noStaticElementInteractions: pointer-only enhancement inside an aria-hidden plot — the arcs carry nothing the data table does not, so there is nothing here for a keyboard to reach.
2936
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
2937
+ "circle",
2938
+ {
2939
+ className: "pire-chart-arc",
2940
+ cx: size / 2,
2941
+ cy: size / 2,
2942
+ r: radius,
2943
+ stroke: colorForSegment(segment.index),
2944
+ strokeWidth: thickness,
2945
+ strokeDasharray: `${Math.max(0, arcLength - gapLength)} ${circumference}`,
2946
+ strokeDashoffset: -offset,
2947
+ "data-hovered": hoveredIndex === segment.index ? "true" : void 0,
2948
+ onMouseEnter: () => setHoveredIndex(segment.index)
2949
+ },
2950
+ segment.category
2951
+ )
2952
+ );
2953
+ }) })
2954
+ }
2955
+ ),
2956
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "pire-chart-donut-center", style: { width: size - thickness * 2 - 8 }, children: [
2957
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "pire-chart-donut-value", children: hovered ? formatValue(hovered.value) : centerLabel ?? formatValue(total) }),
2958
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "pire-chart-donut-caption", children: hovered ? hovered.category : centerCaption })
2959
+ ] })
2960
+ ] })
2961
+ }
2962
+ );
2963
+ }
2964
+ function colorForSegment(index) {
2965
+ return index < VIZ_SLOT_COUNT ? `var(--viz-${index + 1})` : "var(--viz-other)";
2966
+ }
2967
+
2469
2968
  // src/components/data/LinkList.tsx
2470
2969
  var import_react_aria_components29 = require("react-aria-components");
2471
- var import_jsx_runtime47 = require("react/jsx-runtime");
2970
+ var import_jsx_runtime51 = require("react/jsx-runtime");
2472
2971
  function LinkList({ items, onSelect, className, ...rest }) {
2473
- return /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("div", { className: cx("pire-linklist", className), role: "list", ...rest, children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime47.jsxs)(import_react_aria_components29.Button, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
2474
- item.icon ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)(Icon, { name: item.icon, size: 16, style: { color: "var(--text-secondary)" } }) : null,
2475
- item.key ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "pire-linklist-key", children: item.key }) : null,
2476
- item.text ? /* @__PURE__ */ (0, import_jsx_runtime47.jsx)("span", { className: "pire-linklist-text", children: item.text }) : null,
2972
+ return /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: cx("pire-linklist", className), role: "list", ...rest, children: items.map((item) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(import_react_aria_components29.Button, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
2973
+ item.icon ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)(Icon, { name: item.icon, size: 16, style: { color: "var(--text-secondary)" } }) : null,
2974
+ item.key ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "pire-linklist-key", children: item.key }) : null,
2975
+ item.text ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { className: "pire-linklist-text", children: item.text }) : null,
2477
2976
  item.trailing
2478
2977
  ] }, item.id)) });
2479
2978
  }
2480
2979
 
2481
2980
  // src/components/layout/PageBand.tsx
2482
- var import_jsx_runtime48 = require("react/jsx-runtime");
2981
+ var import_jsx_runtime52 = require("react/jsx-runtime");
2483
2982
  function PageBand({
2484
2983
  surface = "card",
2485
2984
  hasBorder = true,
@@ -2487,7 +2986,7 @@ function PageBand({
2487
2986
  className,
2488
2987
  ...rest
2489
2988
  }) {
2490
- return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
2989
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(
2491
2990
  "div",
2492
2991
  {
2493
2992
  className: cx("pire-pageband", className),
@@ -2500,56 +2999,56 @@ function PageBand({
2500
2999
  }
2501
3000
 
2502
3001
  // src/components/layout/PageHeader.tsx
2503
- var import_jsx_runtime49 = require("react/jsx-runtime");
3002
+ var import_jsx_runtime53 = require("react/jsx-runtime");
2504
3003
  function PageHeader({ title, subtitle, actions, className, ...rest }) {
2505
- return /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("header", { className: cx("pire-pageheader", className), ...rest, children: [
2506
- /* @__PURE__ */ (0, import_jsx_runtime49.jsxs)("div", { style: { minWidth: 0 }, children: [
2507
- /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("h1", { className: "pire-pageheader-title", children: title }),
2508
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("p", { className: "pire-pageheader-sub", children: subtitle }) : null
3004
+ return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("header", { className: cx("pire-pageheader", className), ...rest, children: [
3005
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)("div", { style: { minWidth: 0 }, children: [
3006
+ /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("h1", { className: "pire-pageheader-title", children: title }),
3007
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("p", { className: "pire-pageheader-sub", children: subtitle }) : null
2509
3008
  ] }),
2510
- actions ? /* @__PURE__ */ (0, import_jsx_runtime49.jsx)("div", { className: "pire-pageheader-actions", children: actions }) : null
3009
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)("div", { className: "pire-pageheader-actions", children: actions }) : null
2511
3010
  ] });
2512
3011
  }
2513
3012
 
2514
3013
  // src/components/layout/SectionHeader.tsx
2515
- var import_jsx_runtime50 = require("react/jsx-runtime");
3014
+ var import_jsx_runtime54 = require("react/jsx-runtime");
2516
3015
  function SectionHeader({ title, meta, actions, className, ...rest }) {
2517
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: cx("pire-sectionhead", className), ...rest, children: [
2518
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "pire-eyebrow", children: title }),
2519
- meta ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { style: { font: "var(--type-caption)", color: "var(--text-tertiary)" }, children: meta }) : null,
2520
- actions ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "pire-sectionhead-actions", children: actions }) : null
3016
+ return /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { className: cx("pire-sectionhead", className), ...rest, children: [
3017
+ /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { className: "pire-eyebrow", children: title }),
3018
+ meta ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("span", { style: { font: "var(--type-caption)", color: "var(--text-tertiary)" }, children: meta }) : null,
3019
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "pire-sectionhead-actions", children: actions }) : null
2521
3020
  ] });
2522
3021
  }
2523
3022
 
2524
3023
  // src/components/layout/SelectionBar.tsx
2525
- var import_jsx_runtime51 = require("react/jsx-runtime");
3024
+ var import_jsx_runtime55 = require("react/jsx-runtime");
2526
3025
  function SelectionBar({ count, noun = "record", children, actions, className, ...rest }) {
2527
3026
  if (!count) return null;
2528
- return /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("div", { className: cx("pire-selectionbar", className), role: "status", "aria-live": "polite", ...rest, children: [
2529
- /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)("span", { className: "pire-selectionbar-count", children: [
3027
+ return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: cx("pire-selectionbar", className), role: "status", "aria-live": "polite", ...rest, children: [
3028
+ /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("span", { className: "pire-selectionbar-count", children: [
2530
3029
  count.toLocaleString(),
2531
3030
  " ",
2532
3031
  noun,
2533
3032
  count === 1 ? "" : "s",
2534
3033
  " selected"
2535
3034
  ] }),
2536
- children ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("span", { style: { color: "var(--text-secondary)", font: "var(--type-caption)" }, children }) : null,
2537
- actions ? /* @__PURE__ */ (0, import_jsx_runtime51.jsx)("div", { className: "pire-selectionbar-actions", children: actions }) : null
3035
+ children ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("span", { style: { color: "var(--text-secondary)", font: "var(--type-caption)" }, children }) : null,
3036
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("div", { className: "pire-selectionbar-actions", children: actions }) : null
2538
3037
  ] });
2539
3038
  }
2540
3039
 
2541
3040
  // src/components/layout/FooterBar.tsx
2542
- var import_jsx_runtime52 = require("react/jsx-runtime");
3041
+ var import_jsx_runtime56 = require("react/jsx-runtime");
2543
3042
  function FooterBar({ note, actions, children, className, ...rest }) {
2544
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("footer", { className: cx("pire-footerbar", className), ...rest, children: [
2545
- note ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("span", { className: "pire-footerbar-note", children: note }) : null,
3043
+ return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("footer", { className: cx("pire-footerbar", className), ...rest, children: [
3044
+ note ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "pire-footerbar-note", children: note }) : null,
2546
3045
  children,
2547
- actions ? /* @__PURE__ */ (0, import_jsx_runtime52.jsx)("div", { className: "pire-footerbar-actions", children: actions }) : null
3046
+ actions ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("div", { className: "pire-footerbar-actions", children: actions }) : null
2548
3047
  ] });
2549
3048
  }
2550
3049
 
2551
3050
  // src/components/patterns/ConfirmDialog.tsx
2552
- var import_jsx_runtime53 = require("react/jsx-runtime");
3051
+ var import_jsx_runtime57 = require("react/jsx-runtime");
2553
3052
  function ConfirmDialog({
2554
3053
  isOpen,
2555
3054
  title,
@@ -2563,7 +3062,7 @@ function ConfirmDialog({
2563
3062
  onConfirm,
2564
3063
  onCancel
2565
3064
  }) {
2566
- return /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(
3065
+ return /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(
2567
3066
  Dialog,
2568
3067
  {
2569
3068
  isOpen,
@@ -2573,12 +3072,12 @@ function ConfirmDialog({
2573
3072
  onClose: onCancel,
2574
3073
  isDismissable: !isBusy,
2575
3074
  showClose: false,
2576
- footer: /* @__PURE__ */ (0, import_jsx_runtime53.jsxs)(import_jsx_runtime53.Fragment, { children: [
2577
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { variant: "tertiary", isDisabled: isBusy, onPress: onCancel, children: cancelLabel }),
2578
- /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(Button, { variant: tone === "danger" ? "danger" : "primary", isDisabled: isBusy, onPress: onConfirm, children: isBusy ? "Working\u2026" : confirmLabel })
3075
+ footer: /* @__PURE__ */ (0, import_jsx_runtime57.jsxs)(import_jsx_runtime57.Fragment, { children: [
3076
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Button, { variant: "tertiary", isDisabled: isBusy, onPress: onCancel, children: cancelLabel }),
3077
+ /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(Button, { variant: tone === "danger" ? "danger" : "primary", isDisabled: isBusy, onPress: onConfirm, children: isBusy ? "Working\u2026" : confirmLabel })
2579
3078
  ] }),
2580
3079
  children: [
2581
- consequence ? /* @__PURE__ */ (0, import_jsx_runtime53.jsx)(InlineMessage, { kind: tone === "danger" ? "error" : "warning", style: { marginBottom: children ? "var(--sp-3)" : 0 }, children: consequence }) : null,
3080
+ consequence ? /* @__PURE__ */ (0, import_jsx_runtime57.jsx)(InlineMessage, { kind: tone === "danger" ? "error" : "warning", style: { marginBottom: children ? "var(--sp-3)" : 0 }, children: consequence }) : null,
2582
3081
  children
2583
3082
  ]
2584
3083
  }
@@ -2587,10 +3086,10 @@ function ConfirmDialog({
2587
3086
 
2588
3087
  // src/components/patterns/SidePanel.tsx
2589
3088
  var import_react_aria_components30 = require("react-aria-components");
2590
- var import_jsx_runtime54 = require("react/jsx-runtime");
3089
+ var import_jsx_runtime58 = require("react/jsx-runtime");
2591
3090
  function SidePanel({ isOpen, title, subtitle, width = 400, children, footer, onClose, className }) {
2592
3091
  const msg = usePireMessages();
2593
- return /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(
3092
+ return /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(
2594
3093
  import_react_aria_components30.ModalOverlay,
2595
3094
  {
2596
3095
  className: "pire-sidepanel-overlay",
@@ -2599,36 +3098,36 @@ function SidePanel({ isOpen, title, subtitle, width = 400, children, footer, onC
2599
3098
  onOpenChange: (o) => {
2600
3099
  if (!o) onClose?.();
2601
3100
  },
2602
- children: /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_aria_components30.Modal, { className: cx("pire-sidepanel", className), style: { width }, children: /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)(import_react_aria_components30.Dialog, { className: "pire-dialog", style: { height: "100%" }, children: [
2603
- /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("header", { className: "pire-dialog-head", children: [
2604
- /* @__PURE__ */ (0, import_jsx_runtime54.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
2605
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(import_react_aria_components30.Heading, { slot: "title", className: "pire-dialog-title", children: title }),
2606
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null
3101
+ children: /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_react_aria_components30.Modal, { className: cx("pire-sidepanel", className), style: { width }, children: /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)(import_react_aria_components30.Dialog, { className: "pire-dialog", style: { height: "100%" }, children: [
3102
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("header", { className: "pire-dialog-head", children: [
3103
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsxs)("div", { style: { flex: 1, minWidth: 0 }, children: [
3104
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(import_react_aria_components30.Heading, { slot: "title", className: "pire-dialog-title", children: title }),
3105
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null
2607
3106
  ] }),
2608
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)(IconButton, { icon: "x", label: msg.sidePanelClose, size: "sm", onPress: onClose })
3107
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)(IconButton, { icon: "x", label: msg.sidePanelClose, size: "sm", onPress: onClose })
2609
3108
  ] }),
2610
- /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("div", { className: "pire-dialog-body", style: { flex: 1 }, children }),
2611
- footer ? /* @__PURE__ */ (0, import_jsx_runtime54.jsx)("footer", { className: "pire-dialog-foot", children: footer }) : null
3109
+ /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("div", { className: "pire-dialog-body", style: { flex: 1 }, children }),
3110
+ footer ? /* @__PURE__ */ (0, import_jsx_runtime58.jsx)("footer", { className: "pire-dialog-foot", children: footer }) : null
2612
3111
  ] }) })
2613
3112
  }
2614
3113
  );
2615
3114
  }
2616
3115
 
2617
3116
  // src/components/patterns/EmptyState.tsx
2618
- var import_jsx_runtime55 = require("react/jsx-runtime");
3117
+ var import_jsx_runtime59 = require("react/jsx-runtime");
2619
3118
  function EmptyState({ icon = "file-text", title, action, compact, children, className, ...rest }) {
2620
- return /* @__PURE__ */ (0, import_jsx_runtime55.jsxs)("div", { className: cx("pire-empty", className), "data-compact": compact ? "true" : void 0, ...rest, children: [
2621
- /* @__PURE__ */ (0, import_jsx_runtime55.jsx)(Icon, { name: icon, size: 24, className: "pire-empty-icon" }),
2622
- title ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { className: "pire-empty-title", style: { margin: 0 }, children: title }) : null,
2623
- children ? /* @__PURE__ */ (0, import_jsx_runtime55.jsx)("p", { className: "pire-empty-body", style: { margin: 0 }, children }) : null,
3119
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: cx("pire-empty", className), "data-compact": compact ? "true" : void 0, ...rest, children: [
3120
+ /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(Icon, { name: icon, size: 24, className: "pire-empty-icon" }),
3121
+ title ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "pire-empty-title", style: { margin: 0 }, children: title }) : null,
3122
+ children ? /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("p", { className: "pire-empty-body", style: { margin: 0 }, children }) : null,
2624
3123
  action
2625
3124
  ] });
2626
3125
  }
2627
3126
 
2628
3127
  // src/components/patterns/FileDropZone.tsx
2629
- var React13 = __toESM(require("react"), 1);
3128
+ var React15 = __toESM(require("react"), 1);
2630
3129
  var import_react_aria_components31 = require("react-aria-components");
2631
- var import_jsx_runtime56 = require("react/jsx-runtime");
3130
+ var import_jsx_runtime60 = require("react/jsx-runtime");
2632
3131
  var isImage2 = (file) => file.type.startsWith("image/");
2633
3132
  function FileDropZone({
2634
3133
  label,
@@ -2654,10 +3153,10 @@ function FileDropZone({
2654
3153
  style
2655
3154
  }) {
2656
3155
  const msg = usePireMessages();
2657
- const [uncontrolled, setUncontrolled] = React13.useState(defaultValue ?? []);
3156
+ const [uncontrolled, setUncontrolled] = React15.useState(defaultValue ?? []);
2658
3157
  const files = value ?? uncontrolled;
2659
- const created = React13.useRef([]);
2660
- React13.useEffect(() => () => {
3158
+ const created = React15.useRef([]);
3159
+ React15.useEffect(() => () => {
2661
3160
  for (const url of created.current) URL.revokeObjectURL(url);
2662
3161
  }, []);
2663
3162
  const commit = (next) => {
@@ -2677,12 +3176,12 @@ function FileDropZone({
2677
3176
  commit(allowsMultiple ? [...files, ...wrapped] : wrapped.slice(0, 1));
2678
3177
  };
2679
3178
  const remove = (target) => commit(files.filter((f) => f.file !== target));
2680
- return /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("div", { className: cx("pire-field", className), style, "data-full-width": String(fullWidth), children: [
2681
- label ? /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("span", { className: "pire-field-label", children: [
3179
+ return /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("div", { className: cx("pire-field", className), style, "data-full-width": String(fullWidth), children: [
3180
+ label ? /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("span", { className: "pire-field-label", children: [
2682
3181
  label,
2683
- isRequired ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
3182
+ isRequired ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
2684
3183
  ] }) : null,
2685
- /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)(
3184
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)(
2686
3185
  import_react_aria_components31.DropZone,
2687
3186
  {
2688
3187
  className: "pire-dropzone",
@@ -2695,25 +3194,25 @@ function FileDropZone({
2695
3194
  accept(dropped);
2696
3195
  },
2697
3196
  children: [
2698
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Icon, { name: "download", size: 24, className: "pire-dropzone-icon" }),
2699
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "pire-dropzone-prompt", children: promptLabel ?? msg.fileDropZonePrompt }),
2700
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
3197
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Icon, { name: "download", size: 24, className: "pire-dropzone-icon" }),
3198
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "pire-dropzone-prompt", children: promptLabel ?? msg.fileDropZonePrompt }),
3199
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
2701
3200
  import_react_aria_components31.FileTrigger,
2702
3201
  {
2703
3202
  acceptedFileTypes,
2704
3203
  allowsMultiple,
2705
3204
  onSelect: (list) => accept(list ? [...list] : []),
2706
- children: /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Button, { variant: "secondary", isDisabled: isDisabled || isReadOnly, children: msg.fileUploadChoose })
3205
+ children: /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Button, { variant: "secondary", isDisabled: isDisabled || isReadOnly, children: msg.fileUploadChoose })
2707
3206
  }
2708
3207
  )
2709
3208
  ]
2710
3209
  }
2711
3210
  ),
2712
- files.length ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("ul", { className: "pire-fileupload-list", children: files.map(({ file, previewUrl }) => /* @__PURE__ */ (0, import_jsx_runtime56.jsxs)("li", { className: "pire-fileupload-item", children: [
2713
- previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("img", { className: "pire-fileupload-thumb", src: previewUrl, alt: "" }) : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(Icon, { name: "file-text", size: 16, className: "pire-fileupload-icon" }),
2714
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "pire-fileupload-name", children: file.name }),
2715
- /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "pire-fileupload-size", children: formatFileSize(file.size) }),
2716
- isDisabled || isReadOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(
3211
+ files.length ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("ul", { className: "pire-fileupload-list", children: files.map(({ file, previewUrl }) => /* @__PURE__ */ (0, import_jsx_runtime60.jsxs)("li", { className: "pire-fileupload-item", children: [
3212
+ previewUrl ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("img", { className: "pire-fileupload-thumb", src: previewUrl, alt: "" }) : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(Icon, { name: "file-text", size: 16, className: "pire-fileupload-icon" }),
3213
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "pire-fileupload-name", children: file.name }),
3214
+ /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "pire-fileupload-size", children: formatFileSize(file.size) }),
3215
+ isDisabled || isReadOnly ? null : /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(
2717
3216
  IconButton,
2718
3217
  {
2719
3218
  icon: "x",
@@ -2723,9 +3222,9 @@ function FileDropZone({
2723
3222
  }
2724
3223
  )
2725
3224
  ] }, `${file.name}-${file.size}-${file.lastModified}`)) }) : null,
2726
- uploadProgress != null ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)(ProgressBar, { value: uploadProgress, label: msg.fileUploadUploading }) : null,
2727
- description ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "pire-field-hint", children: description }) : null,
2728
- isInvalid && errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime56.jsx)("span", { className: "pire-field-error", children: errorMessage }) : null
3225
+ uploadProgress != null ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)(ProgressBar, { value: uploadProgress, label: msg.fileUploadUploading }) : null,
3226
+ description ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "pire-field-hint", children: description }) : null,
3227
+ isInvalid && errorMessage ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "pire-field-error", children: errorMessage }) : null
2729
3228
  ] });
2730
3229
  }
2731
3230
 
@@ -2735,6 +3234,7 @@ var import_react_aria_components32 = require("react-aria-components");
2735
3234
  0 && (module.exports = {
2736
3235
  Avatar,
2737
3236
  Badge,
3237
+ BarChart,
2738
3238
  Breadcrumb,
2739
3239
  Button,
2740
3240
  Card,
@@ -2747,6 +3247,7 @@ var import_react_aria_components32 = require("react-aria-components");
2747
3247
  DescriptionList,
2748
3248
  Dialog,
2749
3249
  DialogTrigger,
3250
+ DonutChart,
2750
3251
  EmptyState,
2751
3252
  FileDropZone,
2752
3253
  FileUpload,
@@ -2760,6 +3261,7 @@ var import_react_aria_components32 = require("react-aria-components");
2760
3261
  InlineMessage,
2761
3262
  Input,
2762
3263
  KpiTile,
3264
+ LineChart,
2763
3265
  Link,
2764
3266
  LinkList,
2765
3267
  Menu,
@@ -2800,6 +3302,7 @@ var import_react_aria_components32 = require("react-aria-components");
2800
3302
  Toast,
2801
3303
  ToastProvider,
2802
3304
  Tooltip,
3305
+ VIZ_SLOT_COUNT,
2803
3306
  ValueHelpDialog,
2804
3307
  ValueHelpField,
2805
3308
  configureIcons,