@tensor_1/react 2.15.0 → 2.17.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.
Files changed (82) hide show
  1. package/README.md +5 -0
  2. package/dist/ChartCore-Do6gRBN3.d.cts +44 -0
  3. package/dist/chart-preset.cjs +56 -12
  4. package/dist/chart-preset.d.cts +2 -2
  5. package/dist/chart-preset.d.ts +1 -1
  6. package/dist/chart-preset.js +4 -1
  7. package/dist/chart.cjs +56 -12
  8. package/dist/chart.d.cts +2 -2
  9. package/dist/chart.d.ts +1 -1
  10. package/dist/chart.js +4 -1
  11. package/dist/components/Alert.js +15 -7
  12. package/dist/components/AppShell.d.ts +3 -1
  13. package/dist/components/AppShell.js +3 -1
  14. package/dist/components/Avatar.js +2 -1
  15. package/dist/components/Button.js +32 -16
  16. package/dist/components/Card.d.ts +3 -1
  17. package/dist/components/Card.js +2 -2
  18. package/dist/components/Chart.d.ts +1 -1
  19. package/dist/components/Chart.js +4 -1
  20. package/dist/components/ChartCore.d.ts +24 -3
  21. package/dist/components/ChartCore.js +53 -12
  22. package/dist/components/CommandPalette.d.ts +4 -2
  23. package/dist/components/CommandPalette.js +66 -13
  24. package/dist/components/Comments.d.ts +5 -1
  25. package/dist/components/Comments.js +1 -1
  26. package/dist/components/Composer.d.ts +8 -1
  27. package/dist/components/Composer.js +7 -2
  28. package/dist/components/DetailLayout.js +1 -1
  29. package/dist/components/Drawer.d.ts +3 -4
  30. package/dist/components/Drawer.js +6 -4
  31. package/dist/components/Field.js +6 -3
  32. package/dist/components/Flow.d.ts +26 -0
  33. package/dist/components/Flow.js +48 -0
  34. package/dist/components/Inbox.d.ts +13 -3
  35. package/dist/components/Inbox.js +62 -3
  36. package/dist/components/Input.d.ts +13 -2
  37. package/dist/components/Input.js +20 -5
  38. package/dist/components/Kanban.d.ts +15 -3
  39. package/dist/components/Kanban.js +42 -10
  40. package/dist/components/Meter.d.ts +3 -1
  41. package/dist/components/Meter.js +9 -1
  42. package/dist/components/Modal.d.ts +4 -5
  43. package/dist/components/Modal.js +4 -4
  44. package/dist/components/NavFavourites.js +11 -0
  45. package/dist/components/PageHeader.d.ts +3 -1
  46. package/dist/components/PageHeader.js +2 -2
  47. package/dist/components/Peek.d.ts +3 -4
  48. package/dist/components/Peek.js +9 -6
  49. package/dist/components/Pipeline.d.ts +25 -0
  50. package/dist/components/Pipeline.js +65 -0
  51. package/dist/components/Progress.d.ts +3 -1
  52. package/dist/components/Progress.js +5 -3
  53. package/dist/components/Radio.d.ts +3 -1
  54. package/dist/components/Radio.js +6 -2
  55. package/dist/components/Spinner.d.ts +3 -1
  56. package/dist/components/Spinner.js +3 -3
  57. package/dist/components/Stat.js +5 -1
  58. package/dist/components/States.d.ts +1 -0
  59. package/dist/components/States.js +7 -1
  60. package/dist/components/Table.d.ts +8 -1
  61. package/dist/components/Table.js +10 -6
  62. package/dist/components/Tabs.d.ts +13 -1
  63. package/dist/components/Tabs.js +79 -4
  64. package/dist/components/Timeline.d.ts +3 -3
  65. package/dist/components/Timeline.js +3 -3
  66. package/dist/components/Toast.js +42 -5
  67. package/dist/components/Tooltip.d.ts +3 -1
  68. package/dist/components/Tooltip.js +44 -5
  69. package/dist/components/Tree.d.ts +2 -0
  70. package/dist/components/Tree.js +26 -4
  71. package/dist/hooks/useDialog.d.ts +1 -1
  72. package/dist/hooks/useDialog.js +17 -2
  73. package/dist/hooks/useTable.d.ts +5 -0
  74. package/dist/hooks/useTable.js +20 -1
  75. package/dist/index.cjs +1191 -626
  76. package/dist/index.d.cts +168 -35
  77. package/dist/index.d.ts +4 -2
  78. package/dist/index.js +8 -1
  79. package/dist/tree-model.d.ts +4 -0
  80. package/dist/tree-model.js +8 -0
  81. package/package.json +1 -1
  82. package/dist/ChartCore-Bt1C84ty.d.cts +0 -22
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);
@@ -57,6 +60,12 @@ function readToken(name) {
57
60
  function uixChartPalette() {
58
61
  return [1, 2, 3, 4, 5, 6, 7, 8].map((i) => readToken(`--uix-chart-${i}`));
59
62
  }
63
+ function motionSafe(option) {
64
+ if (typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches) {
65
+ return { ...option, animation: false };
66
+ }
67
+ return option;
68
+ }
60
69
  function ChartCore({
61
70
  engine,
62
71
  option,
@@ -69,7 +78,11 @@ function ChartCore({
69
78
  tableData,
70
79
  tableHeaders,
71
80
  onReady,
72
- header
81
+ header,
82
+ headerAction,
83
+ footer,
84
+ loading = false,
85
+ empty
73
86
  }) {
74
87
  const containerRef = (0, import_react.useRef)(null);
75
88
  const chartRef = (0, import_react.useRef)(null);
@@ -77,16 +90,23 @@ function ChartCore({
77
90
  const latestOptionRef = (0, import_react.useRef)(option);
78
91
  const onReadyRef = (0, import_react.useRef)(onReady);
79
92
  const tableId = (0, import_react.useId)();
93
+ const hasEmpty = empty != null;
94
+ const hasTextAlternative = Boolean(ariaLabel || title || tableData?.length);
95
+ const hasTextAlternativeRef = (0, import_react.useRef)(hasTextAlternative);
80
96
  latestOptionRef.current = option;
81
97
  onReadyRef.current = onReady;
98
+ hasTextAlternativeRef.current = hasTextAlternative;
82
99
  (0, import_react.useEffect)(() => {
83
100
  const element = containerRef.current;
84
101
  if (!element) return;
85
102
  const chart = engine.init(element, null, { renderer: "svg" });
86
103
  chartRef.current = chart;
87
- chart.setOption(latestOptionRef.current);
104
+ chart.setOption(motionSafe(latestOptionRef.current));
88
105
  appliedOptionRef.current = latestOptionRef.current;
89
106
  onReadyRef.current?.(chart);
107
+ if (!hasTextAlternativeRef.current) {
108
+ console.warn("[uix] Chart has no text alternative \u2014 provide ariaLabel, title, or tableData.");
109
+ }
90
110
  let frame = 0;
91
111
  let width = element.clientWidth;
92
112
  let height2 = element.clientHeight;
@@ -110,23 +130,26 @@ function ChartCore({
110
130
  chartRef.current = null;
111
131
  appliedOptionRef.current = null;
112
132
  };
113
- }, [engine]);
133
+ }, [engine, hasEmpty]);
114
134
  (0, import_react.useEffect)(() => {
115
135
  const chart = chartRef.current;
116
136
  if (!chart || appliedOptionRef.current === option) return;
117
- chart.setOption(option, { notMerge: false });
137
+ chart.setOption(motionSafe(option), { notMerge: false });
118
138
  appliedOptionRef.current = option;
119
139
  }, [option]);
120
140
  const heightValue = typeof height === "number" ? `${height}px` : height;
121
141
  const effectiveAriaLabel = ariaLabel ?? title ?? "Chart";
122
142
  const hasTable = Boolean(tableData?.length && tableHeaders?.length);
123
143
  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
144
+ title != null || subtitle != null || header != null || headerAction != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__header", children: [
145
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__heading", children: [
146
+ header,
147
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__title", children: title }) : null,
148
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__subtitle", children: subtitle }) : null
149
+ ] }),
150
+ headerAction
128
151
  ] }) : null,
129
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
152
+ 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
153
  "div",
131
154
  {
132
155
  ref: containerRef,
@@ -135,11 +158,29 @@ function ChartCore({
135
158
  "aria-label": effectiveAriaLabel,
136
159
  "aria-describedby": hasTable ? tableId : void 0
137
160
  }
138
- ),
139
- hasTable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: tableId, className: "sr-only", "aria-label": `${effectiveAriaLabel} \u2014 data table`, children: [
161
+ ) }),
162
+ hasTable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: tableId, className: "uix-visually-hidden", "aria-label": `${effectiveAriaLabel} \u2014 data table`, children: [
140
163
  /* @__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
164
  /* @__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
165
+ ] }) : null,
166
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__footer", children: footer })
167
+ ] });
168
+ }
169
+ function ChartMetric({ value, label, delta, deltaTone = "neutral", className, ...props }) {
170
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart__metric", className), ...props, children: [
171
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-value", children: value }),
172
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-label", children: label }),
173
+ delta != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__delta", "data-tone": deltaTone, children: delta })
174
+ ] });
175
+ }
176
+ function ChartLegend({ children, className, ...props }) {
177
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cx("uix-legend", className), ...props, children });
178
+ }
179
+ function ChartLegendItem({ label, color, swatch = "block", className, style, ...props }) {
180
+ const mergedStyle = color ? { "--legend-color": color, ...style } : style;
181
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: cx("uix-legend__item", className), style: mergedStyle, ...props, children: [
182
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cx("uix-legend__swatch", swatch !== "block" && `uix-legend__swatch--${swatch}`), "aria-hidden": "true" }),
183
+ label
143
184
  ] });
144
185
  }
145
186
 
@@ -164,5 +205,8 @@ function Chart(props) {
164
205
  // Annotate the CommonJS export names for ESM import in node:
165
206
  0 && (module.exports = {
166
207
  Chart,
208
+ ChartLegend,
209
+ ChartLegendItem,
210
+ ChartMetric,
167
211
  uixChartPalette
168
212
  });
@@ -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);
@@ -55,6 +58,12 @@ function readToken(name) {
55
58
  function uixChartPalette() {
56
59
  return [1, 2, 3, 4, 5, 6, 7, 8].map((i) => readToken(`--uix-chart-${i}`));
57
60
  }
61
+ function motionSafe(option) {
62
+ if (typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches) {
63
+ return { ...option, animation: false };
64
+ }
65
+ return option;
66
+ }
58
67
  function ChartCore({
59
68
  engine,
60
69
  option,
@@ -67,7 +76,11 @@ function ChartCore({
67
76
  tableData,
68
77
  tableHeaders,
69
78
  onReady,
70
- header
79
+ header,
80
+ headerAction,
81
+ footer,
82
+ loading = false,
83
+ empty
71
84
  }) {
72
85
  const containerRef = (0, import_react.useRef)(null);
73
86
  const chartRef = (0, import_react.useRef)(null);
@@ -75,16 +88,23 @@ function ChartCore({
75
88
  const latestOptionRef = (0, import_react.useRef)(option);
76
89
  const onReadyRef = (0, import_react.useRef)(onReady);
77
90
  const tableId = (0, import_react.useId)();
91
+ const hasEmpty = empty != null;
92
+ const hasTextAlternative = Boolean(ariaLabel || title || tableData?.length);
93
+ const hasTextAlternativeRef = (0, import_react.useRef)(hasTextAlternative);
78
94
  latestOptionRef.current = option;
79
95
  onReadyRef.current = onReady;
96
+ hasTextAlternativeRef.current = hasTextAlternative;
80
97
  (0, import_react.useEffect)(() => {
81
98
  const element = containerRef.current;
82
99
  if (!element) return;
83
100
  const chart = engine.init(element, null, { renderer: "svg" });
84
101
  chartRef.current = chart;
85
- chart.setOption(latestOptionRef.current);
102
+ chart.setOption(motionSafe(latestOptionRef.current));
86
103
  appliedOptionRef.current = latestOptionRef.current;
87
104
  onReadyRef.current?.(chart);
105
+ if (!hasTextAlternativeRef.current) {
106
+ console.warn("[uix] Chart has no text alternative \u2014 provide ariaLabel, title, or tableData.");
107
+ }
88
108
  let frame = 0;
89
109
  let width = element.clientWidth;
90
110
  let height2 = element.clientHeight;
@@ -108,23 +128,26 @@ function ChartCore({
108
128
  chartRef.current = null;
109
129
  appliedOptionRef.current = null;
110
130
  };
111
- }, [engine]);
131
+ }, [engine, hasEmpty]);
112
132
  (0, import_react.useEffect)(() => {
113
133
  const chart = chartRef.current;
114
134
  if (!chart || appliedOptionRef.current === option) return;
115
- chart.setOption(option, { notMerge: false });
135
+ chart.setOption(motionSafe(option), { notMerge: false });
116
136
  appliedOptionRef.current = option;
117
137
  }, [option]);
118
138
  const heightValue = typeof height === "number" ? `${height}px` : height;
119
139
  const effectiveAriaLabel = ariaLabel ?? title ?? "Chart";
120
140
  const hasTable = Boolean(tableData?.length && tableHeaders?.length);
121
141
  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
142
+ title != null || subtitle != null || header != null || headerAction != null ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__header", children: [
143
+ /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: "uix-chart__heading", children: [
144
+ header,
145
+ title ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__title", children: title }) : null,
146
+ subtitle ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__subtitle", children: subtitle }) : null
147
+ ] }),
148
+ headerAction
126
149
  ] }) : null,
127
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
150
+ 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
151
  "div",
129
152
  {
130
153
  ref: containerRef,
@@ -133,11 +156,29 @@ function ChartCore({
133
156
  "aria-label": effectiveAriaLabel,
134
157
  "aria-describedby": hasTable ? tableId : void 0
135
158
  }
136
- ),
137
- hasTable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: tableId, className: "sr-only", "aria-label": `${effectiveAriaLabel} \u2014 data table`, children: [
159
+ ) }),
160
+ hasTable ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("table", { id: tableId, className: "uix-visually-hidden", "aria-label": `${effectiveAriaLabel} \u2014 data table`, children: [
138
161
  /* @__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
162
  /* @__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
163
+ ] }) : null,
164
+ footer != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__footer", children: footer })
165
+ ] });
166
+ }
167
+ function ChartMetric({ value, label, delta, deltaTone = "neutral", className, ...props }) {
168
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { className: cx("uix-chart__metric", className), ...props, children: [
169
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-value", children: value }),
170
+ label != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__metric-label", children: label }),
171
+ delta != null && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "uix-chart__delta", "data-tone": deltaTone, children: delta })
172
+ ] });
173
+ }
174
+ function ChartLegend({ children, className, ...props }) {
175
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ul", { className: cx("uix-legend", className), ...props, children });
176
+ }
177
+ function ChartLegendItem({ label, color, swatch = "block", className, style, ...props }) {
178
+ const mergedStyle = color ? { "--legend-color": color, ...style } : style;
179
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { className: cx("uix-legend__item", className), style: mergedStyle, ...props, children: [
180
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { className: cx("uix-legend__swatch", swatch !== "block" && `uix-legend__swatch--${swatch}`), "aria-hidden": "true" }),
181
+ label
141
182
  ] });
142
183
  }
143
184
 
@@ -149,5 +190,8 @@ function Chart(props) {
149
190
  // Annotate the CommonJS export names for ESM import in node:
150
191
  0 && (module.exports = {
151
192
  Chart,
193
+ ChartLegend,
194
+ ChartLegendItem,
195
+ ChartMetric,
152
196
  uixChartPalette
153
197
  });
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,13 +1,21 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { cx } from "../cx.js";
3
3
  function Alert({ tone, title, icon, children, className, ...props }) {
4
- return /* @__PURE__ */ jsxs("div", { className: cx("uix-alert", tone && tone !== "neutral" && `uix-alert--${tone}`, className), ...props, children: [
5
- icon && /* @__PURE__ */ jsx("div", { className: "uix-alert__icon", children: icon }),
6
- /* @__PURE__ */ jsxs("div", { children: [
7
- title && /* @__PURE__ */ jsx("div", { className: "uix-alert__title", children: title }),
8
- children && /* @__PURE__ */ jsx("div", { className: "uix-alert__body", children })
9
- ] })
10
- ] });
4
+ return /* @__PURE__ */ jsxs(
5
+ "div",
6
+ {
7
+ className: cx("uix-alert", tone && tone !== "neutral" && `uix-alert--${tone}`, className),
8
+ role: tone === "danger" || tone === "warning" ? "alert" : "status",
9
+ ...props,
10
+ children: [
11
+ icon && /* @__PURE__ */ jsx("div", { className: "uix-alert__icon", children: icon }),
12
+ /* @__PURE__ */ jsxs("div", { children: [
13
+ title && /* @__PURE__ */ jsx("div", { className: "uix-alert__title", children: title }),
14
+ children && /* @__PURE__ */ jsx("div", { className: "uix-alert__body", children })
15
+ ] })
16
+ ]
17
+ }
18
+ );
11
19
  }
12
20
  export {
13
21
  Alert
@@ -17,10 +17,12 @@ interface AppShellProps extends HTMLAttributes<HTMLDivElement> {
17
17
  onExitFocus?: () => void;
18
18
  /** Drop the content gutter so a genuinely wide table runs edge-to-edge. */
19
19
  mainBleed?: boolean;
20
+ /** id given to `<main>` and targeted by the skip link. Override on collision (UIX-A11Y-2). */
21
+ mainId?: string;
20
22
  sidebar?: ReactNode;
21
23
  topbar?: ReactNode;
22
24
  children?: ReactNode;
23
25
  }
24
- declare function AppShell({ nav, collapsed, focus, onExitFocus, mainBleed, sidebar, topbar, children, className, ...props }: AppShellProps): react.JSX.Element;
26
+ declare function AppShell({ nav, collapsed, focus, onExitFocus, mainBleed, mainId, sidebar, topbar, children, className, ...props }: AppShellProps): react.JSX.Element;
25
27
 
26
28
  export { AppShell, type AppShellProps, type ShellNav };
@@ -8,6 +8,7 @@ function AppShell({
8
8
  focus,
9
9
  onExitFocus,
10
10
  mainBleed,
11
+ mainId = "uix-main",
11
12
  sidebar,
12
13
  topbar,
13
14
  children,
@@ -32,9 +33,10 @@ function AppShell({
32
33
  "data-focus": focus || void 0,
33
34
  ...props,
34
35
  children: [
36
+ /* @__PURE__ */ jsx("a", { className: "uix-skiplink", href: `#${mainId}`, children: "Skip to content" }),
35
37
  sidebar && /* @__PURE__ */ jsx("div", { className: "uix-shell__sidebar", children: sidebar }),
36
38
  topbar && /* @__PURE__ */ jsx("div", { className: "uix-shell__topbar", children: topbar }),
37
- /* @__PURE__ */ jsx("main", { className: cx("uix-shell__main", mainBleed && "uix-shell__main--bleed"), children }),
39
+ /* @__PURE__ */ jsx("main", { id: mainId, tabIndex: -1, className: cx("uix-shell__main", mainBleed && "uix-shell__main--bleed"), children }),
38
40
  focus && onExitFocus && /* @__PURE__ */ jsx("div", { className: "uix-shell__focus-exit", children: /* @__PURE__ */ jsx("button", { type: "button", className: "uix-btn uix-btn--secondary uix-btn--sm", onClick: onExitFocus, children: "Esc \xB7 Exit focus" }) })
39
41
  ]
40
42
  }
@@ -3,7 +3,8 @@ import { cx } from "../cx.js";
3
3
  function Avatar({ size = "md", src, alt, children, status, className, ...props }) {
4
4
  return /* @__PURE__ */ jsxs("span", { className: cx("uix-avatar", size !== "md" && `uix-avatar--${size}`, className), ...props, children: [
5
5
  src ? /* @__PURE__ */ jsx("img", { src, alt: alt ?? "" }) : children,
6
- status && /* @__PURE__ */ jsx("span", { className: "uix-avatar__status" })
6
+ status && /* @__PURE__ */ jsx("span", { className: "uix-avatar__status", "aria-hidden": "true" }),
7
+ status && /* @__PURE__ */ jsx("span", { className: "uix-visually-hidden", children: "online" })
7
8
  ] });
8
9
  }
9
10
  function AvatarGroup({ children, className, ...props }) {
@@ -1,24 +1,40 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
2
  import { forwardRef } from "react";
3
3
  import { cx } from "../cx.js";
4
+ let warnedIconButton = false;
4
5
  const Button = forwardRef(
5
- ({ variant = "secondary", size = "md", icon = false, loading = false, className, children, disabled, ...props }, ref) => /* @__PURE__ */ jsx(
6
- "button",
7
- {
8
- ref,
9
- className: cx(
10
- "uix-btn",
11
- `uix-btn--${variant}`,
12
- size !== "md" && `uix-btn--${size}`,
13
- icon && "uix-btn--icon",
14
- className
15
- ),
16
- disabled: disabled || loading,
17
- "data-loading": loading || void 0,
18
- ...props,
19
- children
6
+ ({ variant = "secondary", size = "md", icon = false, loading = false, className, children, disabled, onClick, ...props }, ref) => {
7
+ if (!warnedIconButton && icon && children == null && !props["aria-label"] && !props["aria-labelledby"] && typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
8
+ warnedIconButton = true;
9
+ console.warn("uix: icon-only <Button> has no accessible name \u2014 pass aria-label or aria-labelledby.");
20
10
  }
21
- )
11
+ return /* @__PURE__ */ jsx(
12
+ "button",
13
+ {
14
+ ref,
15
+ className: cx(
16
+ "uix-btn",
17
+ `uix-btn--${variant}`,
18
+ size !== "md" && `uix-btn--${size}`,
19
+ icon && "uix-btn--icon",
20
+ className
21
+ ),
22
+ disabled,
23
+ "aria-disabled": loading || void 0,
24
+ "aria-busy": loading || void 0,
25
+ "data-loading": loading || void 0,
26
+ onClick: loading || onClick ? (e) => {
27
+ if (loading) {
28
+ e.preventDefault();
29
+ return;
30
+ }
31
+ onClick?.(e);
32
+ } : void 0,
33
+ ...props,
34
+ children
35
+ }
36
+ );
37
+ }
22
38
  );
23
39
  Button.displayName = "Button";
24
40
  function ButtonGroup({ children, className }) {
@@ -3,12 +3,14 @@ import { HTMLAttributes, ReactNode, AnchorHTMLAttributes } from 'react';
3
3
 
4
4
  interface CardProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {
5
5
  title?: ReactNode;
6
+ /** Element for the title — pick a real heading to slot the card into the page outline (UIX-A11Y-4). Default `div` keeps legacy rendering. */
7
+ titleAs?: 'h2' | 'h3' | 'h4' | 'div';
6
8
  subtitle?: ReactNode;
7
9
  headerAction?: ReactNode;
8
10
  footer?: ReactNode;
9
11
  children?: ReactNode;
10
12
  }
11
- declare function Card({ title, subtitle, headerAction, footer, children, className, ...props }: CardProps): react.JSX.Element;
13
+ declare function Card({ title, titleAs: TitleTag, subtitle, headerAction, footer, children, className, ...props }: CardProps): react.JSX.Element;
12
14
  interface CardLinkProps extends Omit<AnchorHTMLAttributes<HTMLAnchorElement>, 'title'> {
13
15
  title?: ReactNode;
14
16
  subtitle?: ReactNode;
@@ -1,11 +1,11 @@
1
1
  import { jsx, jsxs } from "react/jsx-runtime";
2
2
  import { cx } from "../cx.js";
3
- function Card({ title, subtitle, headerAction, footer, children, className, ...props }) {
3
+ function Card({ title, titleAs: TitleTag = "div", subtitle, headerAction, footer, children, className, ...props }) {
4
4
  const hasHeader = title != null || subtitle != null || headerAction != null;
5
5
  return /* @__PURE__ */ jsxs("div", { className: cx("uix-card", className), ...props, children: [
6
6
  hasHeader && /* @__PURE__ */ jsxs("div", { className: "uix-card__header", children: [
7
7
  /* @__PURE__ */ jsxs("div", { style: { flex: 1 }, children: [
8
- title && /* @__PURE__ */ jsx("div", { className: "uix-card__title", children: title }),
8
+ title && /* @__PURE__ */ jsx(TitleTag, { className: "uix-card__title", children: title }),
9
9
  subtitle && /* @__PURE__ */ jsx("div", { className: "uix-card__subtitle", children: subtitle })
10
10
  ] }),
11
11
  headerAction
@@ -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 };