@tensor_1/react 2.15.0 → 2.16.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/README.md CHANGED
@@ -37,6 +37,11 @@ For common line, bar, and pie charts, the tree-shaken preset avoids shipping the
37
37
  import { Chart } from "@tensor_1/react/chart/preset";
38
38
  ```
39
39
 
40
+ Both chart entries also export `ChartMetric`, `ChartLegend`, and `ChartLegendItem` for consistent analytical card
41
+ chrome. `Chart` supports `headerAction`, `footer`, `loading`, `empty`, and an accessible table equivalent. For
42
+ workflow surfaces, the main entry exports `Pipeline`/`PipelineStage` (compact or detailed operational rail) and
43
+ `Flow`/`FlowNode` (consumer-owned graph geometry with explicit text states).
44
+
40
45
  Large fixed-height tables can use `useVirtualRows(rows, { rowHeight })`; attach its `containerRef` to
41
46
  `TableWrap` and render the returned row window between spacer rows.
42
47
 
@@ -0,0 +1,44 @@
1
+ import * as react from 'react';
2
+ import { CSSProperties, ReactNode, HTMLAttributes } from 'react';
3
+ import { EChartsOption, ECharts } from 'echarts';
4
+
5
+ declare function uixChartPalette(): string[];
6
+ interface ChartTableRow {
7
+ [key: string]: string | number;
8
+ }
9
+ interface ChartProps {
10
+ option: EChartsOption;
11
+ title?: string;
12
+ subtitle?: string;
13
+ height?: string | number;
14
+ className?: string;
15
+ style?: CSSProperties;
16
+ ariaLabel?: string;
17
+ tableData?: ChartTableRow[];
18
+ tableHeaders?: string[];
19
+ onReady?: (chart: ECharts) => void;
20
+ header?: ReactNode;
21
+ headerAction?: ReactNode;
22
+ footer?: ReactNode;
23
+ loading?: boolean;
24
+ empty?: ReactNode;
25
+ }
26
+ interface ChartMetricProps extends HTMLAttributes<HTMLDivElement> {
27
+ value: ReactNode;
28
+ label?: ReactNode;
29
+ delta?: ReactNode;
30
+ deltaTone?: 'neutral' | 'positive' | 'negative' | 'warning';
31
+ }
32
+ declare function ChartMetric({ value, label, delta, deltaTone, className, ...props }: ChartMetricProps): react.JSX.Element;
33
+ interface ChartLegendProps extends HTMLAttributes<HTMLUListElement> {
34
+ children?: ReactNode;
35
+ }
36
+ declare function ChartLegend({ children, className, ...props }: ChartLegendProps): react.JSX.Element;
37
+ interface ChartLegendItemProps extends HTMLAttributes<HTMLLIElement> {
38
+ label: ReactNode;
39
+ color?: string;
40
+ swatch?: 'block' | 'line' | 'dash';
41
+ }
42
+ declare function ChartLegendItem({ label, color, swatch, className, style, ...props }: ChartLegendItemProps): react.JSX.Element;
43
+
44
+ export { type ChartProps as C, ChartLegend as a, ChartLegendItem as b, type ChartLegendItemProps as c, type ChartLegendProps as d, ChartMetric as e, type ChartMetricProps as f, type ChartTableRow as g, uixChartPalette as u };
@@ -32,6 +32,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
32
32
  var chart_preset_exports = {};
33
33
  __export(chart_preset_exports, {
34
34
  Chart: () => Chart,
35
+ ChartLegend: () => ChartLegend,
36
+ ChartLegendItem: () => ChartLegendItem,
37
+ ChartMetric: () => ChartMetric,
35
38
  uixChartPalette: () => uixChartPalette
36
39
  });
37
40
  module.exports = __toCommonJS(chart_preset_exports);
@@ -69,7 +72,11 @@ function ChartCore({
69
72
  tableData,
70
73
  tableHeaders,
71
74
  onReady,
72
- header
75
+ header,
76
+ headerAction,
77
+ footer,
78
+ loading = false,
79
+ empty
73
80
  }) {
74
81
  const containerRef = (0, import_react.useRef)(null);
75
82
  const chartRef = (0, import_react.useRef)(null);
@@ -77,6 +84,7 @@ function ChartCore({
77
84
  const latestOptionRef = (0, import_react.useRef)(option);
78
85
  const onReadyRef = (0, import_react.useRef)(onReady);
79
86
  const tableId = (0, import_react.useId)();
87
+ const hasEmpty = empty != null;
80
88
  latestOptionRef.current = option;
81
89
  onReadyRef.current = onReady;
82
90
  (0, import_react.useEffect)(() => {
@@ -110,7 +118,7 @@ function ChartCore({
110
118
  chartRef.current = null;
111
119
  appliedOptionRef.current = null;
112
120
  };
113
- }, [engine]);
121
+ }, [engine, hasEmpty]);
114
122
  (0, import_react.useEffect)(() => {
115
123
  const chart = chartRef.current;
116
124
  if (!chart || appliedOptionRef.current === option) return;
@@ -121,12 +129,15 @@ function ChartCore({
121
129
  const effectiveAriaLabel = ariaLabel ?? title ?? "Chart";
122
130
  const hasTable = Boolean(tableData?.length && tableHeaders?.length);
123
131
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart", className), style, children: [
124
- title != null || subtitle != null || header != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
125
- header,
126
- title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__title", children: title }) : null,
127
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__subtitle", children: subtitle }) : null
132
+ title != null || subtitle != null || header != null || headerAction != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__header", children: [
133
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__heading", children: [
134
+ header,
135
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__title", children: title }) : null,
136
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__subtitle", children: subtitle }) : null
137
+ ] }),
138
+ headerAction
128
139
  ] }) : null,
129
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
140
+ hasEmpty ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__plot", "data-empty": true, children: empty }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__plot", "data-loading": loading || void 0, "aria-busy": loading || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
130
141
  "div",
131
142
  {
132
143
  ref: containerRef,
@@ -135,11 +146,29 @@ function ChartCore({
135
146
  "aria-label": effectiveAriaLabel,
136
147
  "aria-describedby": hasTable ? tableId : void 0
137
148
  }
138
- ),
149
+ ) }),
139
150
  hasTable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: tableId, className: "sr-only", "aria-label": `${effectiveAriaLabel} \u2014 data table`, children: [
140
151
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: label }, label)) }) }),
141
152
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: tableData.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: row[label] }, label)) }, index)) })
142
- ] }) : null
153
+ ] }) : null,
154
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__footer", children: footer })
155
+ ] });
156
+ }
157
+ function ChartMetric({ value, label, delta, deltaTone = "neutral", className, ...props }) {
158
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart__metric", className), ...props, children: [
159
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-value", children: value }),
160
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-label", children: label }),
161
+ delta != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__delta", "data-tone": deltaTone, children: delta })
162
+ ] });
163
+ }
164
+ function ChartLegend({ children, className, ...props }) {
165
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cx("uix-legend", className), ...props, children });
166
+ }
167
+ function ChartLegendItem({ label, color, swatch = "block", className, style, ...props }) {
168
+ const mergedStyle = color ? { "--legend-color": color, ...style } : style;
169
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: cx("uix-legend__item", className), style: mergedStyle, ...props, children: [
170
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cx("uix-legend__swatch", swatch !== "block" && `uix-legend__swatch--${swatch}`), "aria-hidden": "true" }),
171
+ label
143
172
  ] });
144
173
  }
145
174
 
@@ -164,5 +193,8 @@ function Chart(props) {
164
193
  // Annotate the CommonJS export names for ESM import in node:
165
194
  0 && (module.exports = {
166
195
  Chart,
196
+ ChartLegend,
197
+ ChartLegendItem,
198
+ ChartMetric,
167
199
  uixChartPalette
168
200
  });
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
- import { C as ChartProps } from './ChartCore-Bt1C84ty.cjs';
3
- export { a as ChartTableRow, u as uixChartPalette } from './ChartCore-Bt1C84ty.cjs';
2
+ import { C as ChartProps } from './ChartCore-Do6gRBN3.cjs';
3
+ export { a as ChartLegend, b as ChartLegendItem, c as ChartLegendItemProps, d as ChartLegendProps, e as ChartMetric, f as ChartMetricProps, g as ChartTableRow, u as uixChartPalette } from './ChartCore-Do6gRBN3.cjs';
4
4
  import 'echarts';
5
5
 
6
6
  /** Lean SVG adapter: line, bar, pie, dataset, grid, legend, title, and tooltip. */
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ChartProps } from './components/ChartCore.js';
3
- export { ChartTableRow, uixChartPalette } from './components/ChartCore.js';
3
+ export { ChartLegend, ChartLegendItem, ChartLegendItemProps, ChartLegendProps, ChartMetric, ChartMetricProps, ChartTableRow, uixChartPalette } from './components/ChartCore.js';
4
4
  import 'echarts';
5
5
 
6
6
  /** Lean SVG adapter: line, bar, pie, dataset, grid, legend, title, and tooltip. */
@@ -28,8 +28,11 @@ const presetEngine = echarts;
28
28
  function Chart(props) {
29
29
  return /* @__PURE__ */ jsx(ChartCore, { ...props, engine: presetEngine });
30
30
  }
31
- import { uixChartPalette } from "./components/ChartCore.js";
31
+ import { ChartLegend, ChartLegendItem, ChartMetric, uixChartPalette } from "./components/ChartCore.js";
32
32
  export {
33
33
  Chart,
34
+ ChartLegend,
35
+ ChartLegendItem,
36
+ ChartMetric,
34
37
  uixChartPalette
35
38
  };
package/dist/chart.cjs CHANGED
@@ -31,6 +31,9 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var chart_exports = {};
32
32
  __export(chart_exports, {
33
33
  Chart: () => Chart,
34
+ ChartLegend: () => ChartLegend,
35
+ ChartLegendItem: () => ChartLegendItem,
36
+ ChartMetric: () => ChartMetric,
34
37
  uixChartPalette: () => uixChartPalette
35
38
  });
36
39
  module.exports = __toCommonJS(chart_exports);
@@ -67,7 +70,11 @@ function ChartCore({
67
70
  tableData,
68
71
  tableHeaders,
69
72
  onReady,
70
- header
73
+ header,
74
+ headerAction,
75
+ footer,
76
+ loading = false,
77
+ empty
71
78
  }) {
72
79
  const containerRef = (0, import_react.useRef)(null);
73
80
  const chartRef = (0, import_react.useRef)(null);
@@ -75,6 +82,7 @@ function ChartCore({
75
82
  const latestOptionRef = (0, import_react.useRef)(option);
76
83
  const onReadyRef = (0, import_react.useRef)(onReady);
77
84
  const tableId = (0, import_react.useId)();
85
+ const hasEmpty = empty != null;
78
86
  latestOptionRef.current = option;
79
87
  onReadyRef.current = onReady;
80
88
  (0, import_react.useEffect)(() => {
@@ -108,7 +116,7 @@ function ChartCore({
108
116
  chartRef.current = null;
109
117
  appliedOptionRef.current = null;
110
118
  };
111
- }, [engine]);
119
+ }, [engine, hasEmpty]);
112
120
  (0, import_react.useEffect)(() => {
113
121
  const chart = chartRef.current;
114
122
  if (!chart || appliedOptionRef.current === option) return;
@@ -119,12 +127,15 @@ function ChartCore({
119
127
  const effectiveAriaLabel = ariaLabel ?? title ?? "Chart";
120
128
  const hasTable = Boolean(tableData?.length && tableHeaders?.length);
121
129
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart", className), style, children: [
122
- title != null || subtitle != null || header != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
123
- header,
124
- title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__title", children: title }) : null,
125
- subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__subtitle", children: subtitle }) : null
130
+ title != null || subtitle != null || header != null || headerAction != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__header", children: [
131
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__heading", children: [
132
+ header,
133
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__title", children: title }) : null,
134
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__subtitle", children: subtitle }) : null
135
+ ] }),
136
+ headerAction
126
137
  ] }) : null,
127
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
138
+ hasEmpty ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__plot", "data-empty": true, children: empty }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__plot", "data-loading": loading || void 0, "aria-busy": loading || void 0, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
128
139
  "div",
129
140
  {
130
141
  ref: containerRef,
@@ -133,11 +144,29 @@ function ChartCore({
133
144
  "aria-label": effectiveAriaLabel,
134
145
  "aria-describedby": hasTable ? tableId : void 0
135
146
  }
136
- ),
147
+ ) }),
137
148
  hasTable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: tableId, className: "sr-only", "aria-label": `${effectiveAriaLabel} \u2014 data table`, children: [
138
149
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("thead", { children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("th", { scope: "col", children: label }, label)) }) }),
139
150
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tbody", { children: tableData.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)("td", { children: row[label] }, label)) }, index)) })
140
- ] }) : null
151
+ ] }) : null,
152
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__footer", children: footer })
153
+ ] });
154
+ }
155
+ function ChartMetric({ value, label, delta, deltaTone = "neutral", className, ...props }) {
156
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart__metric", className), ...props, children: [
157
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-value", children: value }),
158
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-label", children: label }),
159
+ delta != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__delta", "data-tone": deltaTone, children: delta })
160
+ ] });
161
+ }
162
+ function ChartLegend({ children, className, ...props }) {
163
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cx("uix-legend", className), ...props, children });
164
+ }
165
+ function ChartLegendItem({ label, color, swatch = "block", className, style, ...props }) {
166
+ const mergedStyle = color ? { "--legend-color": color, ...style } : style;
167
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: cx("uix-legend__item", className), style: mergedStyle, ...props, children: [
168
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cx("uix-legend__swatch", swatch !== "block" && `uix-legend__swatch--${swatch}`), "aria-hidden": "true" }),
169
+ label
141
170
  ] });
142
171
  }
143
172
 
@@ -149,5 +178,8 @@ function Chart(props) {
149
178
  // Annotate the CommonJS export names for ESM import in node:
150
179
  0 && (module.exports = {
151
180
  Chart,
181
+ ChartLegend,
182
+ ChartLegendItem,
183
+ ChartMetric,
152
184
  uixChartPalette
153
185
  });
package/dist/chart.d.cts CHANGED
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
- import { C as ChartProps } from './ChartCore-Bt1C84ty.cjs';
3
- export { a as ChartTableRow, u as uixChartPalette } from './ChartCore-Bt1C84ty.cjs';
2
+ import { C as ChartProps } from './ChartCore-Do6gRBN3.cjs';
3
+ export { a as ChartLegend, b as ChartLegendItem, c as ChartLegendItemProps, d as ChartLegendProps, e as ChartMetric, f as ChartMetricProps, g as ChartTableRow, u as uixChartPalette } from './ChartCore-Do6gRBN3.cjs';
4
4
  import 'echarts';
5
5
 
6
6
  /** Full-compatibility adapter. Use `@tensor_1/react/chart/preset` for the lean preset. */
package/dist/chart.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  export { Chart } from './components/Chart.js';
2
- export { ChartProps, ChartTableRow, uixChartPalette } from './components/ChartCore.js';
2
+ export { ChartLegend, ChartLegendItem, ChartLegendItemProps, ChartLegendProps, ChartMetric, ChartMetricProps, ChartProps, ChartTableRow, uixChartPalette } from './components/ChartCore.js';
3
3
  import 'react';
4
4
  import 'echarts';
package/dist/chart.js CHANGED
@@ -1,5 +1,8 @@
1
- import { Chart, uixChartPalette } from "./components/Chart.js";
1
+ import { Chart, ChartLegend, ChartLegendItem, ChartMetric, uixChartPalette } from "./components/Chart.js";
2
2
  export {
3
3
  Chart,
4
+ ChartLegend,
5
+ ChartLegendItem,
6
+ ChartMetric,
4
7
  uixChartPalette
5
8
  };
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
2
  import { ChartProps } from './ChartCore.js';
3
- export { ChartTableRow, uixChartPalette } from './ChartCore.js';
3
+ export { ChartLegend, ChartLegendItem, ChartLegendItemProps, ChartLegendProps, ChartMetric, ChartMetricProps, ChartTableRow, uixChartPalette } from './ChartCore.js';
4
4
  import 'echarts';
5
5
 
6
6
  /** Full-compatibility adapter. Use `@tensor_1/react/chart/preset` for the lean preset. */
@@ -2,11 +2,14 @@
2
2
  import { jsx } from "react/jsx-runtime";
3
3
  import * as echarts from "echarts";
4
4
  import { ChartCore } from "./ChartCore.js";
5
- import { uixChartPalette } from "./ChartCore.js";
5
+ import { ChartLegend, ChartLegendItem, ChartMetric, uixChartPalette } from "./ChartCore.js";
6
6
  function Chart(props) {
7
7
  return /* @__PURE__ */ jsx(ChartCore, { ...props, engine: echarts });
8
8
  }
9
9
  export {
10
10
  Chart,
11
+ ChartLegend,
12
+ ChartLegendItem,
13
+ ChartMetric,
11
14
  uixChartPalette
12
15
  };
@@ -1,5 +1,5 @@
1
1
  import * as react from 'react';
2
- import { CSSProperties, ReactNode } from 'react';
2
+ import { CSSProperties, ReactNode, HTMLAttributes } from 'react';
3
3
  import { EChartsOption, ECharts } from 'echarts';
4
4
 
5
5
  interface ChartEngine {
@@ -23,11 +23,32 @@ interface ChartProps {
23
23
  tableHeaders?: string[];
24
24
  onReady?: (chart: ECharts) => void;
25
25
  header?: ReactNode;
26
+ headerAction?: ReactNode;
27
+ footer?: ReactNode;
28
+ loading?: boolean;
29
+ empty?: ReactNode;
26
30
  }
27
31
  interface ChartCoreProps extends ChartProps {
28
32
  engine: ChartEngine;
29
33
  }
30
34
  /** Shared chart lifecycle. Runtime adapters only choose the ECharts build. */
31
- declare function ChartCore({ engine, option, title, subtitle, height, className, style, ariaLabel, tableData, tableHeaders, onReady, header, }: ChartCoreProps): react.JSX.Element;
35
+ declare function ChartCore({ engine, option, title, subtitle, height, className, style, ariaLabel, tableData, tableHeaders, onReady, header, headerAction, footer, loading, empty, }: ChartCoreProps): react.JSX.Element;
36
+ interface ChartMetricProps extends HTMLAttributes<HTMLDivElement> {
37
+ value: ReactNode;
38
+ label?: ReactNode;
39
+ delta?: ReactNode;
40
+ deltaTone?: 'neutral' | 'positive' | 'negative' | 'warning';
41
+ }
42
+ declare function ChartMetric({ value, label, delta, deltaTone, className, ...props }: ChartMetricProps): react.JSX.Element;
43
+ interface ChartLegendProps extends HTMLAttributes<HTMLUListElement> {
44
+ children?: ReactNode;
45
+ }
46
+ declare function ChartLegend({ children, className, ...props }: ChartLegendProps): react.JSX.Element;
47
+ interface ChartLegendItemProps extends HTMLAttributes<HTMLLIElement> {
48
+ label: ReactNode;
49
+ color?: string;
50
+ swatch?: 'block' | 'line' | 'dash';
51
+ }
52
+ declare function ChartLegendItem({ label, color, swatch, className, style, ...props }: ChartLegendItemProps): react.JSX.Element;
32
53
 
33
- export { ChartCore, type ChartEngine, type ChartProps, type ChartTableRow, uixChartPalette };
54
+ export { ChartCore, type ChartEngine, ChartLegend, ChartLegendItem, type ChartLegendItemProps, type ChartLegendProps, ChartMetric, type ChartMetricProps, type ChartProps, type ChartTableRow, uixChartPalette };
@@ -21,7 +21,11 @@ function ChartCore({
21
21
  tableData,
22
22
  tableHeaders,
23
23
  onReady,
24
- header
24
+ header,
25
+ headerAction,
26
+ footer,
27
+ loading = false,
28
+ empty
25
29
  }) {
26
30
  const containerRef = useRef(null);
27
31
  const chartRef = useRef(null);
@@ -29,6 +33,7 @@ function ChartCore({
29
33
  const latestOptionRef = useRef(option);
30
34
  const onReadyRef = useRef(onReady);
31
35
  const tableId = useId();
36
+ const hasEmpty = empty != null;
32
37
  latestOptionRef.current = option;
33
38
  onReadyRef.current = onReady;
34
39
  useEffect(() => {
@@ -62,7 +67,7 @@ function ChartCore({
62
67
  chartRef.current = null;
63
68
  appliedOptionRef.current = null;
64
69
  };
65
- }, [engine]);
70
+ }, [engine, hasEmpty]);
66
71
  useEffect(() => {
67
72
  const chart = chartRef.current;
68
73
  if (!chart || appliedOptionRef.current === option) return;
@@ -73,12 +78,15 @@ function ChartCore({
73
78
  const effectiveAriaLabel = ariaLabel ?? title ?? "Chart";
74
79
  const hasTable = Boolean(tableData?.length && tableHeaders?.length);
75
80
  return /* @__PURE__ */ jsxs("div", { className: cx("uix-chart", className), style, children: [
76
- title != null || subtitle != null || header != null ? /* @__PURE__ */ jsxs("div", { children: [
77
- header,
78
- title ? /* @__PURE__ */ jsx("div", { className: "uix-chart__title", children: title }) : null,
79
- subtitle ? /* @__PURE__ */ jsx("div", { className: "uix-chart__subtitle", children: subtitle }) : null
81
+ title != null || subtitle != null || header != null || headerAction != null ? /* @__PURE__ */ jsxs("div", { className: "uix-chart__header", children: [
82
+ /* @__PURE__ */ jsxs("div", { className: "uix-chart__heading", children: [
83
+ header,
84
+ title ? /* @__PURE__ */ jsx("div", { className: "uix-chart__title", children: title }) : null,
85
+ subtitle ? /* @__PURE__ */ jsx("div", { className: "uix-chart__subtitle", children: subtitle }) : null
86
+ ] }),
87
+ headerAction
80
88
  ] }) : null,
81
- /* @__PURE__ */ jsx(
89
+ hasEmpty ? /* @__PURE__ */ jsx("div", { className: "uix-chart__plot", "data-empty": true, children: empty }) : /* @__PURE__ */ jsx("div", { className: "uix-chart__plot", "data-loading": loading || void 0, "aria-busy": loading || void 0, children: /* @__PURE__ */ jsx(
82
90
  "div",
83
91
  {
84
92
  ref: containerRef,
@@ -87,14 +95,35 @@ function ChartCore({
87
95
  "aria-label": effectiveAriaLabel,
88
96
  "aria-describedby": hasTable ? tableId : void 0
89
97
  }
90
- ),
98
+ ) }),
91
99
  hasTable ? /* @__PURE__ */ jsxs("table", { id: tableId, className: "sr-only", "aria-label": `${effectiveAriaLabel} \u2014 data table`, children: [
92
100
  /* @__PURE__ */ jsx("thead", { children: /* @__PURE__ */ jsx("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ jsx("th", { scope: "col", children: label }, label)) }) }),
93
101
  /* @__PURE__ */ jsx("tbody", { children: tableData.map((row, index) => /* @__PURE__ */ jsx("tr", { children: tableHeaders.map((label) => /* @__PURE__ */ jsx("td", { children: row[label] }, label)) }, index)) })
94
- ] }) : null
102
+ ] }) : null,
103
+ footer != null && /* @__PURE__ */ jsx("div", { className: "uix-chart__footer", children: footer })
104
+ ] });
105
+ }
106
+ function ChartMetric({ value, label, delta, deltaTone = "neutral", className, ...props }) {
107
+ return /* @__PURE__ */ jsxs("div", { className: cx("uix-chart__metric", className), ...props, children: [
108
+ /* @__PURE__ */ jsx("div", { className: "uix-chart__metric-value", children: value }),
109
+ label != null && /* @__PURE__ */ jsx("div", { className: "uix-chart__metric-label", children: label }),
110
+ delta != null && /* @__PURE__ */ jsx("div", { className: "uix-chart__delta", "data-tone": deltaTone, children: delta })
111
+ ] });
112
+ }
113
+ function ChartLegend({ children, className, ...props }) {
114
+ return /* @__PURE__ */ jsx("ul", { className: cx("uix-legend", className), ...props, children });
115
+ }
116
+ function ChartLegendItem({ label, color, swatch = "block", className, style, ...props }) {
117
+ const mergedStyle = color ? { "--legend-color": color, ...style } : style;
118
+ return /* @__PURE__ */ jsxs("li", { className: cx("uix-legend__item", className), style: mergedStyle, ...props, children: [
119
+ /* @__PURE__ */ jsx("span", { className: cx("uix-legend__swatch", swatch !== "block" && `uix-legend__swatch--${swatch}`), "aria-hidden": "true" }),
120
+ label
95
121
  ] });
96
122
  }
97
123
  export {
98
124
  ChartCore,
125
+ ChartLegend,
126
+ ChartLegendItem,
127
+ ChartMetric,
99
128
  uixChartPalette
100
129
  };
@@ -0,0 +1,26 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ type FlowVariant = 'linear' | 'branch' | 'loop' | 'mindmap' | 'canvas';
5
+ type FlowNodeState = 'pending' | 'active' | 'running' | 'done' | 'error';
6
+ interface FlowProps extends HTMLAttributes<HTMLDivElement> {
7
+ variant?: FlowVariant;
8
+ panel?: boolean;
9
+ children?: ReactNode;
10
+ }
11
+ /** Presentational workflow surface. Consumers provide graph geometry and connectors. */
12
+ declare function Flow({ variant, panel, children, className, role, ...props }: FlowProps): react.JSX.Element;
13
+ interface FlowNodeProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
14
+ title: ReactNode;
15
+ state?: FlowNodeState;
16
+ stateLabel?: ReactNode;
17
+ eyebrow?: ReactNode;
18
+ meta?: ReactNode;
19
+ icon?: ReactNode;
20
+ footer?: ReactNode;
21
+ wide?: boolean;
22
+ }
23
+ /** Workflow node with explicit text state and optional operational metadata. */
24
+ declare function FlowNode({ title, state, stateLabel, eyebrow, meta, icon, footer, wide, className, ...props }: FlowNodeProps): react.JSX.Element;
25
+
26
+ export { Flow, FlowNode, type FlowNodeProps, type FlowNodeState, type FlowProps, type FlowVariant };
@@ -0,0 +1,48 @@
1
+ import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { cx } from "../cx.js";
3
+ function Flow({ variant = "linear", panel = false, children, className, role = "group", ...props }) {
4
+ return /* @__PURE__ */ jsx(
5
+ "div",
6
+ {
7
+ className: cx("uix-flow", `uix-flow--${variant}`, panel && "uix-flow--panel", className),
8
+ role,
9
+ ...props,
10
+ children
11
+ }
12
+ );
13
+ }
14
+ const FLOW_STATE_LABELS = {
15
+ pending: "Pending",
16
+ active: "Active",
17
+ running: "Running",
18
+ done: "Done",
19
+ error: "Error"
20
+ };
21
+ function FlowNode({
22
+ title,
23
+ state = "pending",
24
+ stateLabel,
25
+ eyebrow,
26
+ meta,
27
+ icon,
28
+ footer,
29
+ wide = false,
30
+ className,
31
+ ...props
32
+ }) {
33
+ const resolvedStateLabel = stateLabel ?? FLOW_STATE_LABELS[state];
34
+ return /* @__PURE__ */ jsxs("div", { className: cx("uix-node", `uix-node--${state}`, icon == null && "uix-node--no-icon", wide && "uix-node--wide", className), ...props, children: [
35
+ icon != null && /* @__PURE__ */ jsx("span", { className: "uix-node__icon", "aria-hidden": "true", children: icon }),
36
+ /* @__PURE__ */ jsxs("div", { className: "uix-node__body", children: [
37
+ eyebrow != null && /* @__PURE__ */ jsx("div", { className: "uix-node__eyebrow", children: eyebrow }),
38
+ /* @__PURE__ */ jsx("div", { className: "uix-node__title", children: title }),
39
+ meta != null && /* @__PURE__ */ jsx("div", { className: "uix-node__meta", children: meta }),
40
+ /* @__PURE__ */ jsx("div", { className: "uix-node__status", children: resolvedStateLabel })
41
+ ] }),
42
+ footer != null && /* @__PURE__ */ jsx("div", { className: "uix-node__footer", children: footer })
43
+ ] });
44
+ }
45
+ export {
46
+ Flow,
47
+ FlowNode
48
+ };
@@ -0,0 +1,25 @@
1
+ import * as react from 'react';
2
+ import { HTMLAttributes, ReactNode } from 'react';
3
+
4
+ type PipelineStageState = 'pending' | 'waiting' | 'active' | 'current' | 'running' | 'done' | 'complete' | 'blocked' | 'failed' | 'error';
5
+ interface PipelineProps extends HTMLAttributes<HTMLOListElement> {
6
+ detailed?: boolean;
7
+ children?: ReactNode;
8
+ }
9
+ /** Ordered progress rail. Consumers own workflow meaning; UIx owns stage semantics and presentation. */
10
+ declare function Pipeline({ detailed, children, className, tabIndex, ...props }: PipelineProps): react.JSX.Element;
11
+ interface PipelineStageProps extends Omit<HTMLAttributes<HTMLLIElement>, 'title'> {
12
+ label: ReactNode;
13
+ state?: PipelineStageState;
14
+ stateLabel?: ReactNode;
15
+ description?: ReactNode;
16
+ meta?: ReactNode;
17
+ marker?: ReactNode;
18
+ detailed?: boolean;
19
+ /** Marks the stage as the current position independently of its operational state. */
20
+ current?: boolean;
21
+ }
22
+ /** One pipeline stage. `stateLabel` keeps status explicit instead of relying on colour. */
23
+ declare function PipelineStage({ label, state, stateLabel, description, meta, marker, detailed, current: currentProp, className, ...props }: PipelineStageProps): react.JSX.Element;
24
+
25
+ export { Pipeline, type PipelineProps, PipelineStage, type PipelineStageProps, type PipelineStageState };
@@ -0,0 +1,65 @@
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { Children, cloneElement, isValidElement } from "react";
3
+ import { cx } from "../cx.js";
4
+ function Pipeline({ detailed = false, children, className, tabIndex, ...props }) {
5
+ const stages = detailed ? Children.map(children, (child) => isValidElement(child) && child.type === PipelineStage ? cloneElement(child, { detailed: child.props.detailed ?? true }) : child) : children;
6
+ return /* @__PURE__ */ jsx(
7
+ "ol",
8
+ {
9
+ className: cx("uix-pipeline", detailed && "uix-pipeline--detailed", className),
10
+ tabIndex: tabIndex ?? (detailed ? 0 : void 0),
11
+ ...props,
12
+ children: stages
13
+ }
14
+ );
15
+ }
16
+ const DEFAULT_STATE_LABELS = {
17
+ pending: "Pending",
18
+ waiting: "Waiting",
19
+ active: "Active",
20
+ current: "Current",
21
+ running: "Running",
22
+ done: "Done",
23
+ complete: "Complete",
24
+ blocked: "Blocked",
25
+ failed: "Failed",
26
+ error: "Error"
27
+ };
28
+ function PipelineStage({
29
+ label,
30
+ state = "pending",
31
+ stateLabel,
32
+ description,
33
+ meta,
34
+ marker,
35
+ detailed = false,
36
+ current: currentProp,
37
+ className,
38
+ ...props
39
+ }) {
40
+ const current = currentProp ?? (state === "active" || state === "current" || state === "running");
41
+ const resolvedStateLabel = stateLabel ?? DEFAULT_STATE_LABELS[state];
42
+ const showDetails = detailed || description != null || meta != null || marker != null;
43
+ return /* @__PURE__ */ jsx(
44
+ "li",
45
+ {
46
+ className: cx("uix-pipeline__stage", className),
47
+ "data-state": state,
48
+ "aria-current": current ? "step" : void 0,
49
+ ...props,
50
+ children: showDetails ? /* @__PURE__ */ jsxs(Fragment, { children: [
51
+ /* @__PURE__ */ jsx("span", { className: "uix-pipeline__marker", "aria-hidden": "true", children: marker }),
52
+ /* @__PURE__ */ jsxs("div", { className: "uix-pipeline__content", children: [
53
+ /* @__PURE__ */ jsx("div", { className: "uix-pipeline__eyebrow", children: /* @__PURE__ */ jsx("span", { className: "uix-pipeline__state", children: resolvedStateLabel }) }),
54
+ /* @__PURE__ */ jsx("div", { className: "uix-pipeline__title", children: label }),
55
+ description != null && /* @__PURE__ */ jsx("div", { className: "uix-pipeline__description", children: description }),
56
+ meta != null && /* @__PURE__ */ jsx("div", { className: "uix-pipeline__meta", children: meta })
57
+ ] })
58
+ ] }) : label
59
+ }
60
+ );
61
+ }
62
+ export {
63
+ Pipeline,
64
+ PipelineStage
65
+ };