@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/components/data/BarChart.d.cts +32 -0
- package/dist/components/data/BarChart.d.ts +33 -0
- package/dist/components/data/BarChart.d.ts.map +1 -0
- package/dist/components/data/ChartFrame.d.cts +62 -0
- package/dist/components/data/ChartFrame.d.ts +63 -0
- package/dist/components/data/ChartFrame.d.ts.map +1 -0
- package/dist/components/data/DonutChart.d.cts +26 -0
- package/dist/components/data/DonutChart.d.ts +27 -0
- package/dist/components/data/DonutChart.d.ts.map +1 -0
- package/dist/components/data/LineChart.d.cts +29 -0
- package/dist/components/data/LineChart.d.ts +30 -0
- package/dist/components/data/LineChart.d.ts.map +1 -0
- package/dist/components/data/chartGeometry.d.cts +67 -0
- package/dist/components/data/chartGeometry.d.ts +68 -0
- package/dist/components/data/chartGeometry.d.ts.map +1 -0
- package/dist/components.css +90 -0
- package/dist/i18n/messages.d.cts +6 -0
- package/dist/i18n/messages.d.ts +6 -0
- package/dist/i18n/messages.d.ts.map +1 -1
- package/dist/index.cjs +574 -71
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +5 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +570 -71
- package/dist/index.js.map +1 -1
- package/dist/tokens/colors.css +36 -3
- package/dist/tokens/themes.css +6 -0
- package/package.json +1 -1
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
|
|
2970
|
+
var import_jsx_runtime51 = require("react/jsx-runtime");
|
|
2472
2971
|
function LinkList({ items, onSelect, className, ...rest }) {
|
|
2473
|
-
return /* @__PURE__ */ (0,
|
|
2474
|
-
item.icon ? /* @__PURE__ */ (0,
|
|
2475
|
-
item.key ? /* @__PURE__ */ (0,
|
|
2476
|
-
item.text ? /* @__PURE__ */ (0,
|
|
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
|
|
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,
|
|
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
|
|
3002
|
+
var import_jsx_runtime53 = require("react/jsx-runtime");
|
|
2504
3003
|
function PageHeader({ title, subtitle, actions, className, ...rest }) {
|
|
2505
|
-
return /* @__PURE__ */ (0,
|
|
2506
|
-
/* @__PURE__ */ (0,
|
|
2507
|
-
/* @__PURE__ */ (0,
|
|
2508
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
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,
|
|
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
|
|
3014
|
+
var import_jsx_runtime54 = require("react/jsx-runtime");
|
|
2516
3015
|
function SectionHeader({ title, meta, actions, className, ...rest }) {
|
|
2517
|
-
return /* @__PURE__ */ (0,
|
|
2518
|
-
/* @__PURE__ */ (0,
|
|
2519
|
-
meta ? /* @__PURE__ */ (0,
|
|
2520
|
-
actions ? /* @__PURE__ */ (0,
|
|
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
|
|
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,
|
|
2529
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2537
|
-
actions ? /* @__PURE__ */ (0,
|
|
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
|
|
3041
|
+
var import_jsx_runtime56 = require("react/jsx-runtime");
|
|
2543
3042
|
function FooterBar({ note, actions, children, className, ...rest }) {
|
|
2544
|
-
return /* @__PURE__ */ (0,
|
|
2545
|
-
note ? /* @__PURE__ */ (0,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
2577
|
-
/* @__PURE__ */ (0,
|
|
2578
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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
|
|
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,
|
|
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,
|
|
2603
|
-
/* @__PURE__ */ (0,
|
|
2604
|
-
/* @__PURE__ */ (0,
|
|
2605
|
-
/* @__PURE__ */ (0,
|
|
2606
|
-
subtitle ? /* @__PURE__ */ (0,
|
|
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,
|
|
3107
|
+
/* @__PURE__ */ (0, import_jsx_runtime58.jsx)(IconButton, { icon: "x", label: msg.sidePanelClose, size: "sm", onPress: onClose })
|
|
2609
3108
|
] }),
|
|
2610
|
-
/* @__PURE__ */ (0,
|
|
2611
|
-
footer ? /* @__PURE__ */ (0,
|
|
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
|
|
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,
|
|
2621
|
-
/* @__PURE__ */ (0,
|
|
2622
|
-
title ? /* @__PURE__ */ (0,
|
|
2623
|
-
children ? /* @__PURE__ */ (0,
|
|
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
|
|
3128
|
+
var React15 = __toESM(require("react"), 1);
|
|
2630
3129
|
var import_react_aria_components31 = require("react-aria-components");
|
|
2631
|
-
var
|
|
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] =
|
|
3156
|
+
const [uncontrolled, setUncontrolled] = React15.useState(defaultValue ?? []);
|
|
2658
3157
|
const files = value ?? uncontrolled;
|
|
2659
|
-
const created =
|
|
2660
|
-
|
|
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,
|
|
2681
|
-
label ? /* @__PURE__ */ (0,
|
|
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,
|
|
3182
|
+
isRequired ? /* @__PURE__ */ (0, import_jsx_runtime60.jsx)("span", { className: "pire-field-req", "aria-hidden": "true", children: "*" }) : null
|
|
2684
3183
|
] }) : null,
|
|
2685
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
2699
|
-
/* @__PURE__ */ (0,
|
|
2700
|
-
/* @__PURE__ */ (0,
|
|
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,
|
|
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,
|
|
2713
|
-
previewUrl ? /* @__PURE__ */ (0,
|
|
2714
|
-
/* @__PURE__ */ (0,
|
|
2715
|
-
/* @__PURE__ */ (0,
|
|
2716
|
-
isDisabled || isReadOnly ? null : /* @__PURE__ */ (0,
|
|
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,
|
|
2727
|
-
description ? /* @__PURE__ */ (0,
|
|
2728
|
-
isInvalid && errorMessage ? /* @__PURE__ */ (0,
|
|
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,
|