@orianatech/pire 0.10.0 → 0.12.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
@@ -835,7 +835,10 @@ var enMessages = {
835
835
  fileUploadChoose: "Choose files",
836
836
  fileUploadRemoveNamed: "Remove {name}",
837
837
  fileUploadUploading: "Uploading",
838
- fileDropZonePrompt: "Drag files here, or choose them"
838
+ fileDropZonePrompt: "Drag files here, or choose them",
839
+ chartCategoryHeader: "Category",
840
+ chartNoValue: "No data",
841
+ chartEmpty: "No data for this period"
839
842
  };
840
843
  var esMessages = {
841
844
  filterBarLabel: "Filtros",
@@ -872,7 +875,10 @@ var esMessages = {
872
875
  fileUploadChoose: "Elegir archivos",
873
876
  fileUploadRemoveNamed: "Quitar {name}",
874
877
  fileUploadUploading: "Subiendo",
875
- fileDropZonePrompt: "Arrastr\xE1 archivos ac\xE1, o elegilos"
878
+ fileDropZonePrompt: "Arrastr\xE1 archivos ac\xE1, o elegilos",
879
+ chartCategoryHeader: "Categor\xEDa",
880
+ chartNoValue: "Sin datos",
881
+ chartEmpty: "Sin datos para este per\xEDodo"
876
882
  };
877
883
 
878
884
  // src/i18n/PireIntlProvider.tsx
@@ -2459,20 +2465,509 @@ function Timeline({ entries, reverse = false, className, ...rest }) {
2459
2465
  ] }, entry.id ?? i)) });
2460
2466
  }
2461
2467
 
2468
+ // src/components/data/chartGeometry.ts
2469
+ var VIZ_SLOT_COUNT = 6;
2470
+ var NICE_STEPS = [1, 2, 2.5, 5, 10];
2471
+ function niceStep(rough) {
2472
+ if (!(rough > 0)) return 1;
2473
+ const magnitude = 10 ** Math.floor(Math.log10(rough));
2474
+ const normalized = rough / magnitude;
2475
+ return (NICE_STEPS.find((candidate) => candidate >= normalized) ?? 10) * magnitude;
2476
+ }
2477
+ function linearScale(values, tickCount = 4, startAtZero = true) {
2478
+ const present = values.filter((value) => value != null && Number.isFinite(value));
2479
+ if (present.length === 0) return { min: 0, max: 1, ticks: [0, 1] };
2480
+ let low = Math.min(...present);
2481
+ let high = Math.max(...present);
2482
+ if (startAtZero) {
2483
+ low = Math.min(0, low);
2484
+ high = Math.max(0, high);
2485
+ }
2486
+ if (low === high) {
2487
+ high = low === 0 ? 1 : low + Math.abs(low);
2488
+ }
2489
+ const step = niceStep((high - low) / Math.max(1, tickCount));
2490
+ const EDGE_TOLERANCE = 1e-9;
2491
+ const decimals = Math.max(0, 1 - Math.floor(Math.log10(step)));
2492
+ const toStepPrecision = (value) => Number(value.toFixed(decimals));
2493
+ const min = toStepPrecision(Math.floor(low / step + EDGE_TOLERANCE) * step);
2494
+ const max = toStepPrecision(Math.ceil(high / step - EDGE_TOLERANCE) * step);
2495
+ const stepCount = Math.round((max - min) / step);
2496
+ const ticks = Array.from(
2497
+ { length: stepCount + 1 },
2498
+ (_, index) => toStepPrecision(min + index * step)
2499
+ );
2500
+ return { min, max, ticks };
2501
+ }
2502
+ function scalePosition(value, scale) {
2503
+ const span = scale.max - scale.min;
2504
+ return span === 0 ? 0 : (value - scale.min) / span;
2505
+ }
2506
+ function seriesColor(series, index) {
2507
+ const slot = series.colorIndex ?? index + 1;
2508
+ return slot >= 1 && slot <= VIZ_SLOT_COUNT ? `var(--viz-${slot})` : "var(--viz-other)";
2509
+ }
2510
+ var IS_DEV2 = process.env.NODE_ENV !== "production";
2511
+ var warnedCharts = /* @__PURE__ */ new Set();
2512
+ function warnOnSlotOverflow(series, chartLabel) {
2513
+ if (!IS_DEV2 || warnedCharts.has(chartLabel)) return;
2514
+ if (series.length <= VIZ_SLOT_COUNT) return;
2515
+ warnedCharts.add(chartLabel);
2516
+ console.warn(
2517
+ `[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.`
2518
+ );
2519
+ }
2520
+ function warnOnDonutShape(series, categoryCount, chartLabel) {
2521
+ if (!IS_DEV2 || warnedCharts.has(`donut:${chartLabel}`)) return;
2522
+ const complaints = [];
2523
+ if (series.length > 1) {
2524
+ complaints.push(`it has ${series.length} series but a donut draws one \u2014 the rest are ignored`);
2525
+ }
2526
+ if (categoryCount > VIZ_SLOT_COUNT) {
2527
+ 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"`);
2528
+ }
2529
+ if (series[0]?.values.some((value) => value != null && value < 0)) {
2530
+ complaints.push("it contains negative values, which have no part-to-whole meaning \u2014 a signed measure belongs in a bar chart");
2531
+ }
2532
+ if (complaints.length === 0) return;
2533
+ warnedCharts.add(`donut:${chartLabel}`);
2534
+ console.warn(`[pire] DonutChart "${chartLabel}": ${complaints.join("; ")}.`);
2535
+ }
2536
+ function stackTotal(series, categoryIndex) {
2537
+ return series.reduce((total, one) => total + (one.values[categoryIndex] ?? 0), 0);
2538
+ }
2539
+ function flatValues(series) {
2540
+ return series.flatMap((one) => one.values);
2541
+ }
2542
+ function alignToCategories(series, categoryCount) {
2543
+ return series.map((one) => one.values.length <= categoryCount ? one : { ...one, values: one.values.slice(0, categoryCount) });
2544
+ }
2545
+
2546
+ // src/components/data/ChartFrame.tsx
2547
+ import { jsx as jsx47, jsxs as jsxs40 } from "react/jsx-runtime";
2548
+ function seriesLegend(series) {
2549
+ return series.map((one, index) => ({
2550
+ key: one.id,
2551
+ label: one.label,
2552
+ color: seriesColor(one, index)
2553
+ }));
2554
+ }
2555
+ var defaultFormatValue = (value) => value.toLocaleString();
2556
+ function ChartFrame({
2557
+ label,
2558
+ title,
2559
+ description,
2560
+ categories,
2561
+ series,
2562
+ formatValue,
2563
+ legend,
2564
+ showDataTable,
2565
+ className,
2566
+ style,
2567
+ children
2568
+ }) {
2569
+ const msg = usePireMessages();
2570
+ return /* @__PURE__ */ jsxs40("figure", { className: cx("pire-chart", className), style, children: [
2571
+ title || description ? /* @__PURE__ */ jsxs40("figcaption", { className: "pire-chart-head", children: [
2572
+ title ? /* @__PURE__ */ jsx47("span", { className: "pire-chart-title", children: title }) : null,
2573
+ description ? /* @__PURE__ */ jsx47("span", { className: "pire-chart-desc", children: description }) : null
2574
+ ] }) : null,
2575
+ legend && legend.length > 1 ? /* @__PURE__ */ jsx47("ul", { className: "pire-chart-legend", children: legend.map((item) => /* @__PURE__ */ jsxs40("li", { className: "pire-chart-legend-item", children: [
2576
+ /* @__PURE__ */ jsx47("span", { className: "pire-chart-swatch", style: { background: item.color } }),
2577
+ item.label
2578
+ ] }, item.key)) }) : null,
2579
+ /* @__PURE__ */ jsx47("div", { className: "pire-chart-plot", "aria-hidden": "true", children }),
2580
+ /* @__PURE__ */ jsx47("div", { className: showDataTable ? "pire-chart-table" : "pire-sr-only", children: /* @__PURE__ */ jsxs40("table", { children: [
2581
+ /* @__PURE__ */ jsx47("caption", { children: label }),
2582
+ /* @__PURE__ */ jsx47("thead", { children: /* @__PURE__ */ jsxs40("tr", { children: [
2583
+ /* @__PURE__ */ jsx47("th", { scope: "col", children: msg.chartCategoryHeader }),
2584
+ series.map((one) => /* @__PURE__ */ jsx47("th", { scope: "col", children: one.label }, one.id))
2585
+ ] }) }),
2586
+ /* @__PURE__ */ jsx47("tbody", { children: categories.map((category, categoryIndex) => (
2587
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2588
+ /* @__PURE__ */ jsxs40("tr", { children: [
2589
+ /* @__PURE__ */ jsx47("th", { scope: "row", children: category }),
2590
+ series.map((one) => {
2591
+ const value = one.values[categoryIndex];
2592
+ return /* @__PURE__ */ jsx47("td", { children: value == null ? msg.chartNoValue : formatValue(value) }, one.id);
2593
+ })
2594
+ ] }, categoryIndex)
2595
+ )) })
2596
+ ] }) })
2597
+ ] });
2598
+ }
2599
+
2600
+ // src/components/data/BarChart.tsx
2601
+ import { jsx as jsx48, jsxs as jsxs41 } from "react/jsx-runtime";
2602
+ function BarChart({
2603
+ categories,
2604
+ series: rawSeries,
2605
+ title,
2606
+ description,
2607
+ formatValue = defaultFormatValue,
2608
+ height = 260,
2609
+ emptyState,
2610
+ showDataTable,
2611
+ orientation = "horizontal",
2612
+ stacked = false,
2613
+ showValues,
2614
+ className,
2615
+ style,
2616
+ ...rest
2617
+ }) {
2618
+ const label = rest["aria-label"];
2619
+ const msg = usePireMessages();
2620
+ warnOnSlotOverflow(rawSeries, label);
2621
+ const series = alignToCategories(rawSeries, categories.length);
2622
+ const hasData = categories.length > 0 && series.length > 0;
2623
+ const withValues = showValues ?? series.length === 1;
2624
+ const scale = linearScale(
2625
+ stacked ? categories.map((_, index) => stackTotal(series, index)) : flatValues(series)
2626
+ );
2627
+ const sizeOf = (value) => `${scalePosition(value, scale) * 100}%`;
2628
+ const horizontalLabelFor = (categoryIndex) => {
2629
+ if (stacked) return formatValue(stackTotal(series, categoryIndex));
2630
+ const value = series[0].values[categoryIndex];
2631
+ return value == null ? msg.chartNoValue : formatValue(value);
2632
+ };
2633
+ return /* @__PURE__ */ jsx48(
2634
+ ChartFrame,
2635
+ {
2636
+ label,
2637
+ title,
2638
+ description,
2639
+ categories,
2640
+ series,
2641
+ formatValue,
2642
+ legend: seriesLegend(series),
2643
+ showDataTable,
2644
+ className,
2645
+ style,
2646
+ children: !hasData ? /* @__PURE__ */ jsx48("div", { className: "pire-chart-empty", children: emptyState ?? msg.chartEmpty }) : /* @__PURE__ */ jsx48(
2647
+ "div",
2648
+ {
2649
+ className: "pire-chart-bars",
2650
+ "data-orientation": orientation,
2651
+ "data-stacked": String(stacked),
2652
+ style: { "--pire-chart-height": `${height}px` },
2653
+ children: categories.map((category, categoryIndex) => (
2654
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2655
+ /* @__PURE__ */ jsxs41("div", { className: "pire-chart-group", children: [
2656
+ /* @__PURE__ */ jsx48("span", { className: "pire-chart-cat", children: category }),
2657
+ /* @__PURE__ */ jsx48("div", { className: "pire-chart-track", children: series.map((one, seriesIndex) => {
2658
+ const value = one.values[categoryIndex];
2659
+ if (value == null) return null;
2660
+ return /* @__PURE__ */ jsxs41(
2661
+ "div",
2662
+ {
2663
+ className: "pire-chart-bar",
2664
+ style: {
2665
+ "--pire-bar-size": sizeOf(value),
2666
+ "--pire-bar-color": seriesColor(one, seriesIndex)
2667
+ },
2668
+ children: [
2669
+ withValues && orientation === "vertical" ? /* @__PURE__ */ jsx48("span", { className: "pire-chart-barval", children: formatValue(value) }) : null,
2670
+ /* @__PURE__ */ jsxs41("span", { className: "pire-chart-tip", role: "presentation", children: [
2671
+ series.length > 1 ? `${one.label}: ` : "",
2672
+ formatValue(value)
2673
+ ] })
2674
+ ]
2675
+ },
2676
+ one.id
2677
+ );
2678
+ }) }),
2679
+ withValues && orientation === "horizontal" ? /* @__PURE__ */ jsx48("span", { className: "pire-chart-val", children: horizontalLabelFor(categoryIndex) }) : null
2680
+ ] }, categoryIndex)
2681
+ ))
2682
+ }
2683
+ )
2684
+ }
2685
+ );
2686
+ }
2687
+
2688
+ // src/components/data/LineChart.tsx
2689
+ import * as React13 from "react";
2690
+ import { jsx as jsx49, jsxs as jsxs42 } from "react/jsx-runtime";
2691
+ var PLOT_INSET = { top: 10, right: 14, bottom: 24, left: 58 };
2692
+ var MARKER_LIMIT = 20;
2693
+ var useIsomorphicLayoutEffect2 = typeof window === "undefined" ? React13.useEffect : React13.useLayoutEffect;
2694
+ function useMeasuredWidth() {
2695
+ const ref = React13.useRef(null);
2696
+ const [width, setWidth] = React13.useState(0);
2697
+ useIsomorphicLayoutEffect2(() => {
2698
+ const element = ref.current;
2699
+ if (!element) return;
2700
+ setWidth(element.getBoundingClientRect().width);
2701
+ const observer = new ResizeObserver(([entry]) => setWidth(entry.contentRect.width));
2702
+ observer.observe(element);
2703
+ return () => observer.disconnect();
2704
+ }, []);
2705
+ return [ref, width];
2706
+ }
2707
+ function LineChart({
2708
+ categories,
2709
+ series: rawSeries,
2710
+ title,
2711
+ description,
2712
+ formatValue = defaultFormatValue,
2713
+ height = 260,
2714
+ emptyState,
2715
+ showDataTable,
2716
+ showArea = false,
2717
+ showMarkers,
2718
+ zoomToData = false,
2719
+ className,
2720
+ style,
2721
+ ...rest
2722
+ }) {
2723
+ const label = rest["aria-label"];
2724
+ const msg = usePireMessages();
2725
+ warnOnSlotOverflow(rawSeries, label);
2726
+ const [plotRef, width] = useMeasuredWidth();
2727
+ const series = alignToCategories(rawSeries, categories.length);
2728
+ const hasData = categories.length > 0 && series.length > 0;
2729
+ const withMarkers = showMarkers ?? categories.length <= MARKER_LIMIT;
2730
+ const scale = linearScale(flatValues(series), 4, !zoomToData);
2731
+ const innerWidth = Math.max(0, width - PLOT_INSET.left - PLOT_INSET.right);
2732
+ const innerHeight = Math.max(0, height - PLOT_INSET.top - PLOT_INSET.bottom);
2733
+ const xAt = (index) => PLOT_INSET.left + (categories.length <= 1 ? innerWidth / 2 : index / (categories.length - 1) * innerWidth);
2734
+ const yAt = (value) => PLOT_INSET.top + innerHeight - scalePosition(value, scale) * innerHeight;
2735
+ const pathFor = (values) => {
2736
+ let path = "";
2737
+ let penIsDown = false;
2738
+ values.forEach((value, index) => {
2739
+ if (value == null) {
2740
+ penIsDown = false;
2741
+ return;
2742
+ }
2743
+ path += `${penIsDown ? "L" : "M"}${xAt(index)} ${yAt(value)} `;
2744
+ penIsDown = true;
2745
+ });
2746
+ return path.trim();
2747
+ };
2748
+ const areaFor = (values) => {
2749
+ const present = values.map((value, index) => ({ value, index })).filter((point) => point.value != null);
2750
+ if (present.length < 2) return "";
2751
+ const baseline = PLOT_INSET.top + innerHeight;
2752
+ const line = present.map((point) => `${xAt(point.index)} ${yAt(point.value)}`).join(" L");
2753
+ const last = present[present.length - 1];
2754
+ return `M${xAt(present[0].index)} ${baseline} L${line} L${xAt(last.index)} ${baseline} Z`;
2755
+ };
2756
+ const labelEvery = Math.max(1, Math.ceil(categories.length / Math.max(2, Math.floor(innerWidth / 64))));
2757
+ return /* @__PURE__ */ jsx49(
2758
+ ChartFrame,
2759
+ {
2760
+ label,
2761
+ title,
2762
+ description,
2763
+ categories,
2764
+ series,
2765
+ formatValue,
2766
+ legend: seriesLegend(series),
2767
+ showDataTable,
2768
+ className,
2769
+ style,
2770
+ children: !hasData ? /* @__PURE__ */ jsx49("div", { className: "pire-chart-empty", children: emptyState ?? msg.chartEmpty }) : /* @__PURE__ */ jsxs42("div", { className: "pire-chart-lines", ref: plotRef, style: { height }, children: [
2771
+ width > 0 ? /* @__PURE__ */ jsxs42(
2772
+ "svg",
2773
+ {
2774
+ width,
2775
+ height,
2776
+ className: "pire-chart-svg",
2777
+ "aria-hidden": "true",
2778
+ focusable: "false",
2779
+ children: [
2780
+ /* @__PURE__ */ jsx49("g", { className: "pire-chart-grid", children: scale.ticks.map((tick) => /* @__PURE__ */ jsx49(
2781
+ "line",
2782
+ {
2783
+ x1: PLOT_INSET.left,
2784
+ x2: width - PLOT_INSET.right,
2785
+ y1: yAt(tick),
2786
+ y2: yAt(tick)
2787
+ },
2788
+ tick
2789
+ )) }),
2790
+ /* @__PURE__ */ jsxs42("g", { className: "pire-chart-tick", children: [
2791
+ scale.ticks.map((tick) => /* @__PURE__ */ jsx49(
2792
+ "text",
2793
+ {
2794
+ x: PLOT_INSET.left - 8,
2795
+ y: yAt(tick),
2796
+ textAnchor: "end",
2797
+ dominantBaseline: "middle",
2798
+ children: formatValue(tick)
2799
+ },
2800
+ tick
2801
+ )),
2802
+ categories.map((category, index) => index % labelEvery === 0 ? (
2803
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2804
+ /* @__PURE__ */ jsx49("text", { x: xAt(index), y: height - 6, textAnchor: "middle", children: category }, index)
2805
+ ) : null)
2806
+ ] }),
2807
+ showArea && series[0] ? /* @__PURE__ */ jsx49(
2808
+ "path",
2809
+ {
2810
+ d: areaFor(series[0].values),
2811
+ className: "pire-chart-area",
2812
+ style: { fill: seriesColor(series[0], 0) }
2813
+ }
2814
+ ) : null,
2815
+ /* @__PURE__ */ jsx49("g", { className: "pire-chart-line", fill: "none", children: series.map((one, index) => /* @__PURE__ */ jsx49("path", { d: pathFor(one.values), stroke: seriesColor(one, index) }, one.id)) }),
2816
+ withMarkers ? /* @__PURE__ */ jsx49("g", { className: "pire-chart-marker", children: series.map((one, seriesIndex) => one.values.map((value, index) => value == null ? null : (
2817
+ // biome-ignore lint/suspicious/noArrayIndexKey: a series is positional — the index is the point's identity, and category labels repeat.
2818
+ /* @__PURE__ */ jsx49(
2819
+ "circle",
2820
+ {
2821
+ cx: xAt(index),
2822
+ cy: yAt(value),
2823
+ r: 4,
2824
+ fill: seriesColor(one, seriesIndex)
2825
+ },
2826
+ `${one.id}-${index}`
2827
+ )
2828
+ ))) }) : null
2829
+ ]
2830
+ }
2831
+ ) : null,
2832
+ /* @__PURE__ */ jsx49(
2833
+ "div",
2834
+ {
2835
+ className: "pire-chart-hover",
2836
+ style: { inset: `${PLOT_INSET.top}px ${PLOT_INSET.right}px ${PLOT_INSET.bottom}px ${PLOT_INSET.left}px` },
2837
+ children: categories.map((category, categoryIndex) => (
2838
+ // biome-ignore lint/suspicious/noArrayIndexKey: categories are positional and repeat legitimately (two quarters both labelled "Q1").
2839
+ /* @__PURE__ */ jsx49("div", { className: "pire-chart-band", children: /* @__PURE__ */ jsxs42("span", { className: "pire-chart-tip", role: "presentation", children: [
2840
+ /* @__PURE__ */ jsx49("strong", { children: category }),
2841
+ series.map((one) => {
2842
+ const value = one.values[categoryIndex];
2843
+ return /* @__PURE__ */ jsxs42("span", { className: "pire-chart-tip-row", children: [
2844
+ one.label,
2845
+ ": ",
2846
+ value == null ? "No data" : formatValue(value)
2847
+ ] }, one.id);
2848
+ })
2849
+ ] }) }, categoryIndex)
2850
+ ))
2851
+ }
2852
+ )
2853
+ ] })
2854
+ }
2855
+ );
2856
+ }
2857
+
2858
+ // src/components/data/DonutChart.tsx
2859
+ import * as React14 from "react";
2860
+ import { jsx as jsx50, jsxs as jsxs43 } from "react/jsx-runtime";
2861
+ var SEGMENT_GAP_DEGREES = 1.5;
2862
+ function DonutChart({
2863
+ categories,
2864
+ series,
2865
+ title,
2866
+ description,
2867
+ formatValue = defaultFormatValue,
2868
+ height = 220,
2869
+ emptyState,
2870
+ showDataTable,
2871
+ centerLabel,
2872
+ centerCaption,
2873
+ thickness = 28,
2874
+ className,
2875
+ style,
2876
+ ...rest
2877
+ }) {
2878
+ const label = rest["aria-label"];
2879
+ const msg = usePireMessages();
2880
+ const [hoveredIndex, setHoveredIndex] = React14.useState(null);
2881
+ warnOnDonutShape(series, categories.length, label);
2882
+ const values = (series[0]?.values ?? []).slice(0, categories.length);
2883
+ const segments = categories.map((category, index) => ({ category, index, value: values[index] ?? 0 })).filter((segment) => segment.value > 0);
2884
+ const total = segments.reduce((sum, segment) => sum + segment.value, 0);
2885
+ const hasData = segments.length > 0 && total > 0;
2886
+ const size = height;
2887
+ const radius = (size - thickness) / 2;
2888
+ const circumference = 2 * Math.PI * radius;
2889
+ const gapLength = SEGMENT_GAP_DEGREES / 360 * circumference;
2890
+ const legend = segments.map((segment) => ({
2891
+ key: segment.category,
2892
+ label: segment.category,
2893
+ color: colorForSegment(segment.index)
2894
+ }));
2895
+ const hovered = hoveredIndex == null ? null : segments.find((segment) => segment.index === hoveredIndex) ?? null;
2896
+ let arcStart = 0;
2897
+ return /* @__PURE__ */ jsx50(
2898
+ ChartFrame,
2899
+ {
2900
+ label,
2901
+ title,
2902
+ description,
2903
+ categories,
2904
+ series,
2905
+ formatValue,
2906
+ legend,
2907
+ showDataTable,
2908
+ className,
2909
+ style,
2910
+ children: !hasData ? /* @__PURE__ */ jsx50("div", { className: "pire-chart-empty", children: emptyState ?? msg.chartEmpty }) : /* @__PURE__ */ jsxs43("div", { className: "pire-chart-donut", style: { height: size }, children: [
2911
+ /* @__PURE__ */ jsx50(
2912
+ "svg",
2913
+ {
2914
+ width: size,
2915
+ height: size,
2916
+ "aria-hidden": "true",
2917
+ focusable: "false",
2918
+ onMouseLeave: () => setHoveredIndex(null),
2919
+ children: /* @__PURE__ */ jsx50("g", { transform: `rotate(-90 ${size / 2} ${size / 2})`, children: segments.map((segment) => {
2920
+ const arcLength = segment.value / total * circumference;
2921
+ const offset = arcStart;
2922
+ arcStart += arcLength;
2923
+ return (
2924
+ // 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.
2925
+ /* @__PURE__ */ jsx50(
2926
+ "circle",
2927
+ {
2928
+ className: "pire-chart-arc",
2929
+ cx: size / 2,
2930
+ cy: size / 2,
2931
+ r: radius,
2932
+ stroke: colorForSegment(segment.index),
2933
+ strokeWidth: thickness,
2934
+ strokeDasharray: `${Math.max(0, arcLength - gapLength)} ${circumference}`,
2935
+ strokeDashoffset: -offset,
2936
+ "data-hovered": hoveredIndex === segment.index ? "true" : void 0,
2937
+ onMouseEnter: () => setHoveredIndex(segment.index)
2938
+ },
2939
+ segment.category
2940
+ )
2941
+ );
2942
+ }) })
2943
+ }
2944
+ ),
2945
+ /* @__PURE__ */ jsxs43("div", { className: "pire-chart-donut-center", style: { width: size - thickness * 2 - 8 }, children: [
2946
+ /* @__PURE__ */ jsx50("span", { className: "pire-chart-donut-value", children: hovered ? formatValue(hovered.value) : centerLabel ?? formatValue(total) }),
2947
+ /* @__PURE__ */ jsx50("span", { className: "pire-chart-donut-caption", children: hovered ? hovered.category : centerCaption })
2948
+ ] })
2949
+ ] })
2950
+ }
2951
+ );
2952
+ }
2953
+ function colorForSegment(index) {
2954
+ return index < VIZ_SLOT_COUNT ? `var(--viz-${index + 1})` : "var(--viz-other)";
2955
+ }
2956
+
2462
2957
  // src/components/data/LinkList.tsx
2463
2958
  import { Button as AriaButton12 } from "react-aria-components";
2464
- import { jsx as jsx47, jsxs as jsxs40 } from "react/jsx-runtime";
2959
+ import { jsx as jsx51, jsxs as jsxs44 } from "react/jsx-runtime";
2465
2960
  function LinkList({ items, onSelect, className, ...rest }) {
2466
- return /* @__PURE__ */ jsx47("div", { className: cx("pire-linklist", className), role: "list", ...rest, children: items.map((item) => /* @__PURE__ */ jsxs40(AriaButton12, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
2467
- item.icon ? /* @__PURE__ */ jsx47(Icon, { name: item.icon, size: 16, style: { color: "var(--text-secondary)" } }) : null,
2468
- item.key ? /* @__PURE__ */ jsx47("span", { className: "pire-linklist-key", children: item.key }) : null,
2469
- item.text ? /* @__PURE__ */ jsx47("span", { className: "pire-linklist-text", children: item.text }) : null,
2961
+ return /* @__PURE__ */ jsx51("div", { className: cx("pire-linklist", className), role: "list", ...rest, children: items.map((item) => /* @__PURE__ */ jsx51("div", { role: "listitem", className: "pire-linklist-row", children: /* @__PURE__ */ jsxs44(AriaButton12, { className: "pire-linklist-item", onPress: () => onSelect?.(item.id), children: [
2962
+ item.icon ? /* @__PURE__ */ jsx51(Icon, { name: item.icon, size: 16, style: { color: "var(--text-secondary)" } }) : null,
2963
+ item.key ? /* @__PURE__ */ jsx51("span", { className: "pire-linklist-key", children: item.key }) : null,
2964
+ item.text ? /* @__PURE__ */ jsx51("span", { className: "pire-linklist-text", children: item.text }) : null,
2470
2965
  item.trailing
2471
- ] }, item.id)) });
2966
+ ] }) }, item.id)) });
2472
2967
  }
2473
2968
 
2474
2969
  // src/components/layout/PageBand.tsx
2475
- import { jsx as jsx48 } from "react/jsx-runtime";
2970
+ import { jsx as jsx52 } from "react/jsx-runtime";
2476
2971
  function PageBand({
2477
2972
  surface = "card",
2478
2973
  hasBorder = true,
@@ -2480,7 +2975,7 @@ function PageBand({
2480
2975
  className,
2481
2976
  ...rest
2482
2977
  }) {
2483
- return /* @__PURE__ */ jsx48(
2978
+ return /* @__PURE__ */ jsx52(
2484
2979
  "div",
2485
2980
  {
2486
2981
  className: cx("pire-pageband", className),
@@ -2493,56 +2988,56 @@ function PageBand({
2493
2988
  }
2494
2989
 
2495
2990
  // src/components/layout/PageHeader.tsx
2496
- import { jsx as jsx49, jsxs as jsxs41 } from "react/jsx-runtime";
2991
+ import { jsx as jsx53, jsxs as jsxs45 } from "react/jsx-runtime";
2497
2992
  function PageHeader({ title, subtitle, actions, className, ...rest }) {
2498
- return /* @__PURE__ */ jsxs41("header", { className: cx("pire-pageheader", className), ...rest, children: [
2499
- /* @__PURE__ */ jsxs41("div", { style: { minWidth: 0 }, children: [
2500
- /* @__PURE__ */ jsx49("h1", { className: "pire-pageheader-title", children: title }),
2501
- subtitle ? /* @__PURE__ */ jsx49("p", { className: "pire-pageheader-sub", children: subtitle }) : null
2993
+ return /* @__PURE__ */ jsxs45("header", { className: cx("pire-pageheader", className), ...rest, children: [
2994
+ /* @__PURE__ */ jsxs45("div", { style: { minWidth: 0 }, children: [
2995
+ /* @__PURE__ */ jsx53("h1", { className: "pire-pageheader-title", children: title }),
2996
+ subtitle ? /* @__PURE__ */ jsx53("p", { className: "pire-pageheader-sub", children: subtitle }) : null
2502
2997
  ] }),
2503
- actions ? /* @__PURE__ */ jsx49("div", { className: "pire-pageheader-actions", children: actions }) : null
2998
+ actions ? /* @__PURE__ */ jsx53("div", { className: "pire-pageheader-actions", children: actions }) : null
2504
2999
  ] });
2505
3000
  }
2506
3001
 
2507
3002
  // src/components/layout/SectionHeader.tsx
2508
- import { jsx as jsx50, jsxs as jsxs42 } from "react/jsx-runtime";
3003
+ import { jsx as jsx54, jsxs as jsxs46 } from "react/jsx-runtime";
2509
3004
  function SectionHeader({ title, meta, actions, className, ...rest }) {
2510
- return /* @__PURE__ */ jsxs42("div", { className: cx("pire-sectionhead", className), ...rest, children: [
2511
- /* @__PURE__ */ jsx50("span", { className: "pire-eyebrow", children: title }),
2512
- meta ? /* @__PURE__ */ jsx50("span", { style: { font: "var(--type-caption)", color: "var(--text-tertiary)" }, children: meta }) : null,
2513
- actions ? /* @__PURE__ */ jsx50("div", { className: "pire-sectionhead-actions", children: actions }) : null
3005
+ return /* @__PURE__ */ jsxs46("div", { className: cx("pire-sectionhead", className), ...rest, children: [
3006
+ /* @__PURE__ */ jsx54("span", { className: "pire-eyebrow", children: title }),
3007
+ meta ? /* @__PURE__ */ jsx54("span", { style: { font: "var(--type-caption)", color: "var(--text-tertiary)" }, children: meta }) : null,
3008
+ actions ? /* @__PURE__ */ jsx54("div", { className: "pire-sectionhead-actions", children: actions }) : null
2514
3009
  ] });
2515
3010
  }
2516
3011
 
2517
3012
  // src/components/layout/SelectionBar.tsx
2518
- import { jsx as jsx51, jsxs as jsxs43 } from "react/jsx-runtime";
3013
+ import { jsx as jsx55, jsxs as jsxs47 } from "react/jsx-runtime";
2519
3014
  function SelectionBar({ count, noun = "record", children, actions, className, ...rest }) {
2520
3015
  if (!count) return null;
2521
- return /* @__PURE__ */ jsxs43("div", { className: cx("pire-selectionbar", className), role: "status", "aria-live": "polite", ...rest, children: [
2522
- /* @__PURE__ */ jsxs43("span", { className: "pire-selectionbar-count", children: [
3016
+ return /* @__PURE__ */ jsxs47("div", { className: cx("pire-selectionbar", className), role: "status", "aria-live": "polite", ...rest, children: [
3017
+ /* @__PURE__ */ jsxs47("span", { className: "pire-selectionbar-count", children: [
2523
3018
  count.toLocaleString(),
2524
3019
  " ",
2525
3020
  noun,
2526
3021
  count === 1 ? "" : "s",
2527
3022
  " selected"
2528
3023
  ] }),
2529
- children ? /* @__PURE__ */ jsx51("span", { style: { color: "var(--text-secondary)", font: "var(--type-caption)" }, children }) : null,
2530
- actions ? /* @__PURE__ */ jsx51("div", { className: "pire-selectionbar-actions", children: actions }) : null
3024
+ children ? /* @__PURE__ */ jsx55("span", { style: { color: "var(--text-secondary)", font: "var(--type-caption)" }, children }) : null,
3025
+ actions ? /* @__PURE__ */ jsx55("div", { className: "pire-selectionbar-actions", children: actions }) : null
2531
3026
  ] });
2532
3027
  }
2533
3028
 
2534
3029
  // src/components/layout/FooterBar.tsx
2535
- import { jsx as jsx52, jsxs as jsxs44 } from "react/jsx-runtime";
3030
+ import { jsx as jsx56, jsxs as jsxs48 } from "react/jsx-runtime";
2536
3031
  function FooterBar({ note, actions, children, className, ...rest }) {
2537
- return /* @__PURE__ */ jsxs44("footer", { className: cx("pire-footerbar", className), ...rest, children: [
2538
- note ? /* @__PURE__ */ jsx52("span", { className: "pire-footerbar-note", children: note }) : null,
3032
+ return /* @__PURE__ */ jsxs48("footer", { className: cx("pire-footerbar", className), ...rest, children: [
3033
+ note ? /* @__PURE__ */ jsx56("span", { className: "pire-footerbar-note", children: note }) : null,
2539
3034
  children,
2540
- actions ? /* @__PURE__ */ jsx52("div", { className: "pire-footerbar-actions", children: actions }) : null
3035
+ actions ? /* @__PURE__ */ jsx56("div", { className: "pire-footerbar-actions", children: actions }) : null
2541
3036
  ] });
2542
3037
  }
2543
3038
 
2544
3039
  // src/components/patterns/ConfirmDialog.tsx
2545
- import { Fragment as Fragment4, jsx as jsx53, jsxs as jsxs45 } from "react/jsx-runtime";
3040
+ import { Fragment as Fragment4, jsx as jsx57, jsxs as jsxs49 } from "react/jsx-runtime";
2546
3041
  function ConfirmDialog({
2547
3042
  isOpen,
2548
3043
  title,
@@ -2556,7 +3051,7 @@ function ConfirmDialog({
2556
3051
  onConfirm,
2557
3052
  onCancel
2558
3053
  }) {
2559
- return /* @__PURE__ */ jsxs45(
3054
+ return /* @__PURE__ */ jsxs49(
2560
3055
  Dialog,
2561
3056
  {
2562
3057
  isOpen,
@@ -2566,12 +3061,12 @@ function ConfirmDialog({
2566
3061
  onClose: onCancel,
2567
3062
  isDismissable: !isBusy,
2568
3063
  showClose: false,
2569
- footer: /* @__PURE__ */ jsxs45(Fragment4, { children: [
2570
- /* @__PURE__ */ jsx53(Button, { variant: "tertiary", isDisabled: isBusy, onPress: onCancel, children: cancelLabel }),
2571
- /* @__PURE__ */ jsx53(Button, { variant: tone === "danger" ? "danger" : "primary", isDisabled: isBusy, onPress: onConfirm, children: isBusy ? "Working\u2026" : confirmLabel })
3064
+ footer: /* @__PURE__ */ jsxs49(Fragment4, { children: [
3065
+ /* @__PURE__ */ jsx57(Button, { variant: "tertiary", isDisabled: isBusy, onPress: onCancel, children: cancelLabel }),
3066
+ /* @__PURE__ */ jsx57(Button, { variant: tone === "danger" ? "danger" : "primary", isDisabled: isBusy, onPress: onConfirm, children: isBusy ? "Working\u2026" : confirmLabel })
2572
3067
  ] }),
2573
3068
  children: [
2574
- consequence ? /* @__PURE__ */ jsx53(InlineMessage, { kind: tone === "danger" ? "error" : "warning", style: { marginBottom: children ? "var(--sp-3)" : 0 }, children: consequence }) : null,
3069
+ consequence ? /* @__PURE__ */ jsx57(InlineMessage, { kind: tone === "danger" ? "error" : "warning", style: { marginBottom: children ? "var(--sp-3)" : 0 }, children: consequence }) : null,
2575
3070
  children
2576
3071
  ]
2577
3072
  }
@@ -2580,10 +3075,10 @@ function ConfirmDialog({
2580
3075
 
2581
3076
  // src/components/patterns/SidePanel.tsx
2582
3077
  import { ModalOverlay as ModalOverlay2, Modal as Modal2, Dialog as AriaDialog4, Heading as Heading5 } from "react-aria-components";
2583
- import { jsx as jsx54, jsxs as jsxs46 } from "react/jsx-runtime";
3078
+ import { jsx as jsx58, jsxs as jsxs50 } from "react/jsx-runtime";
2584
3079
  function SidePanel({ isOpen, title, subtitle, width = 400, children, footer, onClose, className }) {
2585
3080
  const msg = usePireMessages();
2586
- return /* @__PURE__ */ jsx54(
3081
+ return /* @__PURE__ */ jsx58(
2587
3082
  ModalOverlay2,
2588
3083
  {
2589
3084
  className: "pire-sidepanel-overlay",
@@ -2592,36 +3087,36 @@ function SidePanel({ isOpen, title, subtitle, width = 400, children, footer, onC
2592
3087
  onOpenChange: (o) => {
2593
3088
  if (!o) onClose?.();
2594
3089
  },
2595
- children: /* @__PURE__ */ jsx54(Modal2, { className: cx("pire-sidepanel", className), style: { width }, children: /* @__PURE__ */ jsxs46(AriaDialog4, { className: "pire-dialog", style: { height: "100%" }, children: [
2596
- /* @__PURE__ */ jsxs46("header", { className: "pire-dialog-head", children: [
2597
- /* @__PURE__ */ jsxs46("div", { style: { flex: 1, minWidth: 0 }, children: [
2598
- /* @__PURE__ */ jsx54(Heading5, { slot: "title", className: "pire-dialog-title", children: title }),
2599
- subtitle ? /* @__PURE__ */ jsx54("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null
3090
+ children: /* @__PURE__ */ jsx58(Modal2, { className: cx("pire-sidepanel", className), style: { width }, children: /* @__PURE__ */ jsxs50(AriaDialog4, { className: "pire-dialog", style: { height: "100%" }, children: [
3091
+ /* @__PURE__ */ jsxs50("header", { className: "pire-dialog-head", children: [
3092
+ /* @__PURE__ */ jsxs50("div", { style: { flex: 1, minWidth: 0 }, children: [
3093
+ /* @__PURE__ */ jsx58(Heading5, { slot: "title", className: "pire-dialog-title", children: title }),
3094
+ subtitle ? /* @__PURE__ */ jsx58("p", { className: "pire-dialog-sub", style: { margin: 0 }, children: subtitle }) : null
2600
3095
  ] }),
2601
- /* @__PURE__ */ jsx54(IconButton, { icon: "x", label: msg.sidePanelClose, size: "sm", onPress: onClose })
3096
+ /* @__PURE__ */ jsx58(IconButton, { icon: "x", label: msg.sidePanelClose, size: "sm", onPress: onClose })
2602
3097
  ] }),
2603
- /* @__PURE__ */ jsx54("div", { className: "pire-dialog-body", style: { flex: 1 }, children }),
2604
- footer ? /* @__PURE__ */ jsx54("footer", { className: "pire-dialog-foot", children: footer }) : null
3098
+ /* @__PURE__ */ jsx58("div", { className: "pire-dialog-body", style: { flex: 1 }, children }),
3099
+ footer ? /* @__PURE__ */ jsx58("footer", { className: "pire-dialog-foot", children: footer }) : null
2605
3100
  ] }) })
2606
3101
  }
2607
3102
  );
2608
3103
  }
2609
3104
 
2610
3105
  // src/components/patterns/EmptyState.tsx
2611
- import { jsx as jsx55, jsxs as jsxs47 } from "react/jsx-runtime";
3106
+ import { jsx as jsx59, jsxs as jsxs51 } from "react/jsx-runtime";
2612
3107
  function EmptyState({ icon = "file-text", title, action, compact, children, className, ...rest }) {
2613
- return /* @__PURE__ */ jsxs47("div", { className: cx("pire-empty", className), "data-compact": compact ? "true" : void 0, ...rest, children: [
2614
- /* @__PURE__ */ jsx55(Icon, { name: icon, size: 24, className: "pire-empty-icon" }),
2615
- title ? /* @__PURE__ */ jsx55("p", { className: "pire-empty-title", style: { margin: 0 }, children: title }) : null,
2616
- children ? /* @__PURE__ */ jsx55("p", { className: "pire-empty-body", style: { margin: 0 }, children }) : null,
3108
+ return /* @__PURE__ */ jsxs51("div", { className: cx("pire-empty", className), "data-compact": compact ? "true" : void 0, ...rest, children: [
3109
+ /* @__PURE__ */ jsx59(Icon, { name: icon, size: 24, className: "pire-empty-icon" }),
3110
+ title ? /* @__PURE__ */ jsx59("p", { className: "pire-empty-title", style: { margin: 0 }, children: title }) : null,
3111
+ children ? /* @__PURE__ */ jsx59("p", { className: "pire-empty-body", style: { margin: 0 }, children }) : null,
2617
3112
  action
2618
3113
  ] });
2619
3114
  }
2620
3115
 
2621
3116
  // src/components/patterns/FileDropZone.tsx
2622
- import * as React13 from "react";
3117
+ import * as React15 from "react";
2623
3118
  import { DropZone, FileTrigger as FileTrigger2, isFileDropItem } from "react-aria-components";
2624
- import { jsx as jsx56, jsxs as jsxs48 } from "react/jsx-runtime";
3119
+ import { jsx as jsx60, jsxs as jsxs52 } from "react/jsx-runtime";
2625
3120
  var isImage2 = (file) => file.type.startsWith("image/");
2626
3121
  function FileDropZone({
2627
3122
  label,
@@ -2647,10 +3142,10 @@ function FileDropZone({
2647
3142
  style
2648
3143
  }) {
2649
3144
  const msg = usePireMessages();
2650
- const [uncontrolled, setUncontrolled] = React13.useState(defaultValue ?? []);
3145
+ const [uncontrolled, setUncontrolled] = React15.useState(defaultValue ?? []);
2651
3146
  const files = value ?? uncontrolled;
2652
- const created = React13.useRef([]);
2653
- React13.useEffect(() => () => {
3147
+ const created = React15.useRef([]);
3148
+ React15.useEffect(() => () => {
2654
3149
  for (const url of created.current) URL.revokeObjectURL(url);
2655
3150
  }, []);
2656
3151
  const commit = (next) => {
@@ -2670,12 +3165,12 @@ function FileDropZone({
2670
3165
  commit(allowsMultiple ? [...files, ...wrapped] : wrapped.slice(0, 1));
2671
3166
  };
2672
3167
  const remove = (target) => commit(files.filter((f) => f.file !== target));
2673
- return /* @__PURE__ */ jsxs48("div", { className: cx("pire-field", className), style, "data-full-width": String(fullWidth), children: [
2674
- label ? /* @__PURE__ */ jsxs48("span", { className: "pire-field-label", children: [
3168
+ return /* @__PURE__ */ jsxs52("div", { className: cx("pire-field", className), style, "data-full-width": String(fullWidth), children: [
3169
+ label ? /* @__PURE__ */ jsxs52("span", { className: "pire-field-label", children: [
2675
3170
  label,
2676
- isRequired ? /* @__PURE__ */ jsx56("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
3171
+ isRequired ? /* @__PURE__ */ jsx60("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
2677
3172
  ] }) : null,
2678
- /* @__PURE__ */ jsxs48(
3173
+ /* @__PURE__ */ jsxs52(
2679
3174
  DropZone,
2680
3175
  {
2681
3176
  className: "pire-dropzone",
@@ -2688,25 +3183,25 @@ function FileDropZone({
2688
3183
  accept(dropped);
2689
3184
  },
2690
3185
  children: [
2691
- /* @__PURE__ */ jsx56(Icon, { name: "download", size: 24, className: "pire-dropzone-icon" }),
2692
- /* @__PURE__ */ jsx56("span", { className: "pire-dropzone-prompt", children: promptLabel ?? msg.fileDropZonePrompt }),
2693
- /* @__PURE__ */ jsx56(
3186
+ /* @__PURE__ */ jsx60(Icon, { name: "download", size: 24, className: "pire-dropzone-icon" }),
3187
+ /* @__PURE__ */ jsx60("span", { className: "pire-dropzone-prompt", children: promptLabel ?? msg.fileDropZonePrompt }),
3188
+ /* @__PURE__ */ jsx60(
2694
3189
  FileTrigger2,
2695
3190
  {
2696
3191
  acceptedFileTypes,
2697
3192
  allowsMultiple,
2698
3193
  onSelect: (list) => accept(list ? [...list] : []),
2699
- children: /* @__PURE__ */ jsx56(Button, { variant: "secondary", isDisabled: isDisabled || isReadOnly, children: msg.fileUploadChoose })
3194
+ children: /* @__PURE__ */ jsx60(Button, { variant: "secondary", isDisabled: isDisabled || isReadOnly, children: msg.fileUploadChoose })
2700
3195
  }
2701
3196
  )
2702
3197
  ]
2703
3198
  }
2704
3199
  ),
2705
- files.length ? /* @__PURE__ */ jsx56("ul", { className: "pire-fileupload-list", children: files.map(({ file, previewUrl }) => /* @__PURE__ */ jsxs48("li", { className: "pire-fileupload-item", children: [
2706
- previewUrl ? /* @__PURE__ */ jsx56("img", { className: "pire-fileupload-thumb", src: previewUrl, alt: "" }) : /* @__PURE__ */ jsx56(Icon, { name: "file-text", size: 16, className: "pire-fileupload-icon" }),
2707
- /* @__PURE__ */ jsx56("span", { className: "pire-fileupload-name", children: file.name }),
2708
- /* @__PURE__ */ jsx56("span", { className: "pire-fileupload-size", children: formatFileSize(file.size) }),
2709
- isDisabled || isReadOnly ? null : /* @__PURE__ */ jsx56(
3200
+ files.length ? /* @__PURE__ */ jsx60("ul", { className: "pire-fileupload-list", children: files.map(({ file, previewUrl }) => /* @__PURE__ */ jsxs52("li", { className: "pire-fileupload-item", children: [
3201
+ previewUrl ? /* @__PURE__ */ jsx60("img", { className: "pire-fileupload-thumb", src: previewUrl, alt: "" }) : /* @__PURE__ */ jsx60(Icon, { name: "file-text", size: 16, className: "pire-fileupload-icon" }),
3202
+ /* @__PURE__ */ jsx60("span", { className: "pire-fileupload-name", children: file.name }),
3203
+ /* @__PURE__ */ jsx60("span", { className: "pire-fileupload-size", children: formatFileSize(file.size) }),
3204
+ isDisabled || isReadOnly ? null : /* @__PURE__ */ jsx60(
2710
3205
  IconButton,
2711
3206
  {
2712
3207
  icon: "x",
@@ -2716,9 +3211,9 @@ function FileDropZone({
2716
3211
  }
2717
3212
  )
2718
3213
  ] }, `${file.name}-${file.size}-${file.lastModified}`)) }) : null,
2719
- uploadProgress != null ? /* @__PURE__ */ jsx56(ProgressBar, { value: uploadProgress, label: msg.fileUploadUploading }) : null,
2720
- description ? /* @__PURE__ */ jsx56("span", { className: "pire-field-hint", children: description }) : null,
2721
- isInvalid && errorMessage ? /* @__PURE__ */ jsx56("span", { className: "pire-field-error", children: errorMessage }) : null
3214
+ uploadProgress != null ? /* @__PURE__ */ jsx60(ProgressBar, { value: uploadProgress, label: msg.fileUploadUploading }) : null,
3215
+ description ? /* @__PURE__ */ jsx60("span", { className: "pire-field-hint", children: description }) : null,
3216
+ isInvalid && errorMessage ? /* @__PURE__ */ jsx60("span", { className: "pire-field-error", children: errorMessage }) : null
2722
3217
  ] });
2723
3218
  }
2724
3219
 
@@ -2727,6 +3222,7 @@ import { DialogTrigger, MenuTrigger as MenuTrigger2, SubmenuTrigger, Popover as
2727
3222
  export {
2728
3223
  Avatar,
2729
3224
  Badge,
3225
+ BarChart,
2730
3226
  Breadcrumb,
2731
3227
  Button,
2732
3228
  Card,
@@ -2739,6 +3235,7 @@ export {
2739
3235
  DescriptionList,
2740
3236
  Dialog,
2741
3237
  DialogTrigger,
3238
+ DonutChart,
2742
3239
  EmptyState,
2743
3240
  FileDropZone,
2744
3241
  FileUpload,
@@ -2752,6 +3249,7 @@ export {
2752
3249
  InlineMessage,
2753
3250
  Input,
2754
3251
  KpiTile,
3252
+ LineChart,
2755
3253
  Link,
2756
3254
  LinkList,
2757
3255
  Menu,
@@ -2792,6 +3290,7 @@ export {
2792
3290
  Toast,
2793
3291
  ToastProvider,
2794
3292
  Tooltip,
3293
+ VIZ_SLOT_COUNT,
2795
3294
  ValueHelpDialog,
2796
3295
  ValueHelpField,
2797
3296
  configureIcons,