@tensor_1/react 2.30.0 → 2.32.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 (122) hide show
  1. package/README.md +430 -0
  2. package/dist/attachment-labels.d.ts +16 -0
  3. package/dist/attachment-labels.js +9 -0
  4. package/dist/calendar-model.d.ts +141 -1
  5. package/dist/calendar-model.js +200 -11
  6. package/dist/chart-preset.cjs +127 -7
  7. package/dist/chart-preset.d.cts +2 -2
  8. package/dist/chart-preset.d.ts +1 -0
  9. package/dist/chart-preset.js +6 -1
  10. package/dist/chart-theme-Cl0IrkKQ.d.cts +112 -0
  11. package/dist/chart-theme.d.ts +51 -0
  12. package/dist/chart-theme.js +99 -0
  13. package/dist/chart.cjs +127 -7
  14. package/dist/chart.d.cts +2 -2
  15. package/dist/chart.d.ts +1 -0
  16. package/dist/chart.js +6 -2
  17. package/dist/components/Alert.d.ts +17 -1
  18. package/dist/components/Alert.js +9 -4
  19. package/dist/components/AlertDismiss.d.ts +14 -0
  20. package/dist/components/AlertDismiss.js +11 -0
  21. package/dist/components/Attachment.d.ts +58 -0
  22. package/dist/components/Attachment.js +69 -0
  23. package/dist/components/AttachmentParts.d.ts +24 -0
  24. package/dist/components/AttachmentParts.js +20 -0
  25. package/dist/components/Chart.d.ts +1 -0
  26. package/dist/components/Chart.js +6 -1
  27. package/dist/components/ChartCore.d.ts +6 -1
  28. package/dist/components/ChartCore.js +23 -5
  29. package/dist/components/Chip.d.ts +17 -2
  30. package/dist/components/Chip.js +35 -11
  31. package/dist/components/ChipRemove.d.ts +17 -0
  32. package/dist/components/ChipRemove.js +13 -0
  33. package/dist/components/CollapsibleParts.d.ts +29 -0
  34. package/dist/components/CollapsibleParts.js +20 -0
  35. package/dist/components/CollapsibleSection.d.ts +30 -3
  36. package/dist/components/CollapsibleSection.js +7 -11
  37. package/dist/components/CollapsibleSectionState.d.ts +1 -1
  38. package/dist/components/CollapsibleSectionState.js +54 -27
  39. package/dist/components/DashboardGrid.d.ts +60 -0
  40. package/dist/components/DashboardGrid.js +40 -0
  41. package/dist/components/DateRangePicker.d.ts +7 -1
  42. package/dist/components/DateRangePicker.js +5 -1
  43. package/dist/components/DescriptionList.d.ts +12 -1
  44. package/dist/components/DescriptionList.js +5 -5
  45. package/dist/components/Dialogs.d.ts +24 -3
  46. package/dist/components/Dialogs.js +74 -16
  47. package/dist/components/EntityPicker.d.ts +56 -0
  48. package/dist/components/EntityPicker.js +168 -0
  49. package/dist/components/FileIcon.d.ts +9 -0
  50. package/dist/components/FileIcon.js +17 -0
  51. package/dist/components/FileUpload.d.ts +95 -0
  52. package/dist/components/FileUpload.js +145 -0
  53. package/dist/components/FilterEditor.d.ts +55 -0
  54. package/dist/components/FilterEditor.js +186 -0
  55. package/dist/components/Heartbeat.d.ts +31 -0
  56. package/dist/components/Heartbeat.js +28 -0
  57. package/dist/components/Lightbox.d.ts +45 -0
  58. package/dist/components/Lightbox.js +102 -0
  59. package/dist/components/Menu.d.ts +53 -5
  60. package/dist/components/Menu.js +104 -4
  61. package/dist/components/Meter.d.ts +7 -3
  62. package/dist/components/Meter.js +2 -1
  63. package/dist/components/Popover.d.ts +21 -2
  64. package/dist/components/Popover.js +94 -17
  65. package/dist/components/Prose.d.ts +6 -2
  66. package/dist/components/Prose.js +1 -1
  67. package/dist/components/RuleBuilder.d.ts +52 -4
  68. package/dist/components/RuleBuilder.js +109 -24
  69. package/dist/components/SchedulingCalendar.d.ts +142 -11
  70. package/dist/components/SchedulingCalendar.js +234 -57
  71. package/dist/components/SchedulingTimeline.d.ts +1 -0
  72. package/dist/components/SearchSuggest.d.ts +6 -2
  73. package/dist/components/SearchSuggest.js +4 -0
  74. package/dist/components/Segmented.d.ts +17 -3
  75. package/dist/components/Segmented.js +59 -5
  76. package/dist/components/Select.d.ts +66 -2
  77. package/dist/components/Select.js +800 -10
  78. package/dist/components/Spinner.d.ts +2 -1
  79. package/dist/components/Spinner.js +1 -1
  80. package/dist/components/StatusPill.d.ts +8 -2
  81. package/dist/components/StatusPill.js +2 -2
  82. package/dist/components/Steps.d.ts +28 -4
  83. package/dist/components/Steps.js +46 -16
  84. package/dist/components/TableControls.js +4 -3
  85. package/dist/components/Tabs.d.ts +7 -2
  86. package/dist/components/Tabs.js +14 -1
  87. package/dist/components/TextDiff.d.ts +49 -0
  88. package/dist/components/TextDiff.js +124 -0
  89. package/dist/{emoji-image-6mPZ15Zy.d.cts → emoji-image-DjCKpdwE.d.cts} +1 -1
  90. package/dist/emoji.cjs +169 -27
  91. package/dist/emoji.d.cts +3 -3
  92. package/dist/file-model.d.ts +56 -0
  93. package/dist/file-model.js +52 -0
  94. package/dist/filter-model.d.ts +112 -0
  95. package/dist/filter-model.js +103 -0
  96. package/dist/hooks/useAnchoredPosition.d.ts +24 -1
  97. package/dist/hooks/useAnchoredPosition.js +58 -8
  98. package/dist/hooks/useVirtualRows.d.ts +17 -2
  99. package/dist/hooks/useVirtualRows.js +6 -5
  100. package/dist/icons/Icon.d.ts +14 -14
  101. package/dist/index.cjs +4938 -1631
  102. package/dist/index.d.cts +1622 -178
  103. package/dist/index.d.ts +20 -6
  104. package/dist/index.js +88 -4
  105. package/dist/labels-context.d.ts +28 -0
  106. package/dist/{overlay-position-Cjv5E7mn.d.cts → overlay-position-2Afke51l.d.cts} +20 -0
  107. package/dist/overlay-position.d.ts +20 -0
  108. package/dist/overlay-position.js +17 -2
  109. package/dist/rich-text.cjs +169 -27
  110. package/dist/rich-text.d.cts +3 -3
  111. package/dist/rule-builder-model.d.ts +34 -2
  112. package/dist/rule-builder-model.js +48 -12
  113. package/dist/scheduling-calendar-model.d.ts +66 -0
  114. package/dist/scheduling-calendar-model.js +82 -0
  115. package/dist/select-model.d.ts +80 -0
  116. package/dist/select-model.js +109 -0
  117. package/dist/table-engine.d.ts +7 -0
  118. package/dist/table-engine.js +2 -1
  119. package/dist/text-diff-model.d.ts +71 -0
  120. package/dist/text-diff-model.js +261 -0
  121. package/package.json +1 -1
  122. package/dist/ChartCore-DzWe10bN.d.cts +0 -59
@@ -38,17 +38,148 @@ function buildMonthGrid(month, weekStartsOn = 1) {
38
38
  };
39
39
  });
40
40
  }
41
+ const FORMATTER_CACHE_LIMIT = 64;
42
+ const formatterCache = /* @__PURE__ */ new Map();
43
+ function cachedDateTimeFormat(locale, options = {}) {
44
+ const shape = Object.keys(options).sort().map((key2) => [key2, options[key2]]);
45
+ const key = JSON.stringify([locale ?? null, shape]);
46
+ let formatter = formatterCache.get(key);
47
+ if (!formatter) {
48
+ formatter = new Intl.DateTimeFormat(locale, options);
49
+ if (formatterCache.size >= FORMATTER_CACHE_LIMIT) formatterCache.delete(formatterCache.keys().next().value);
50
+ formatterCache.set(key, formatter);
51
+ }
52
+ return formatter;
53
+ }
54
+ const partsFormatter = (timeZone) => cachedDateTimeFormat("en-US", {
55
+ timeZone,
56
+ hourCycle: "h23",
57
+ year: "numeric",
58
+ month: "2-digit",
59
+ day: "2-digit",
60
+ hour: "2-digit",
61
+ minute: "2-digit",
62
+ second: "2-digit"
63
+ });
64
+ function toInstant(value) {
65
+ const ms = value instanceof Date ? value.getTime() : typeof value === "number" ? value : Date.parse(value);
66
+ if (Number.isNaN(ms)) throw new TypeError(`Invalid instant: ${String(value)}`);
67
+ return ms;
68
+ }
69
+ function wallClock(ms, timeZone) {
70
+ const wall = { year: 0, month: 0, day: 0, hour: 0, minute: 0, second: 0 };
71
+ for (const part of partsFormatter(timeZone).formatToParts(new Date(ms))) {
72
+ if (part.type in wall) wall[part.type] = Number(part.value);
73
+ }
74
+ return wall;
75
+ }
76
+ const wallKey = (wall) => `${String(wall.year).padStart(4, "0")}-${String(wall.month).padStart(2, "0")}-${String(wall.day).padStart(2, "0")}`;
77
+ const wallAsUtc = (wall) => Date.UTC(wall.year, wall.month - 1, wall.day, wall.hour, wall.minute, wall.second);
78
+ const wholeSecond = (ms) => Math.floor(ms / 1e3) * 1e3;
79
+ function offsetAt(ms, timeZone) {
80
+ return wallAsUtc(wallClock(ms, timeZone)) - wholeSecond(ms);
81
+ }
82
+ function formatOffset(offset) {
83
+ const sign = offset < 0 ? "-" : "+";
84
+ const minutes = Math.round(Math.abs(offset) / 6e4);
85
+ return `${sign}${String(Math.floor(minutes / 60)).padStart(2, "0")}:${String(minutes % 60).padStart(2, "0")}`;
86
+ }
41
87
  function zonedDateKey(instant, timeZone) {
42
- const date = instant instanceof Date ? instant : new Date(instant);
43
- if (Number.isNaN(date.getTime())) throw new TypeError(`Invalid instant: ${String(instant)}`);
44
- const parts = new Intl.DateTimeFormat("en-CA", {
45
- timeZone,
46
- year: "numeric",
47
- month: "2-digit",
48
- day: "2-digit"
49
- }).formatToParts(date);
50
- const get = (type) => parts.find((part) => part.type === type)?.value ?? "";
51
- return `${get("year")}-${get("month")}-${get("day")}`;
88
+ return wallKey(wallClock(toInstant(instant), timeZone));
89
+ }
90
+ function zonedTimeOfDay(instant, timeZone) {
91
+ const wall = wallClock(toInstant(instant), timeZone);
92
+ return `${String(wall.hour).padStart(2, "0")}:${String(wall.minute).padStart(2, "0")}`;
93
+ }
94
+ function checkedDateKey(value) {
95
+ if (toDateKey(fromDateKey(value)) !== value) throw new TypeError(`Invalid ISO date: ${value}`);
96
+ return value;
97
+ }
98
+ const DAY_START_CACHE_LIMIT = 2048;
99
+ const dayStartCache = /* @__PURE__ */ new Map();
100
+ function zonedDayStart(dateKey, timeZone) {
101
+ const cacheKey = `${timeZone} ${dateKey}`;
102
+ const cached = dayStartCache.get(cacheKey);
103
+ if (cached !== void 0) return cached;
104
+ const midnightUtc = fromDateKey(checkedDateKey(dateKey)).getTime();
105
+ let lo = (midnightUtc - 30 * 36e5) / 1e3;
106
+ let hi = (midnightUtc + 30 * 36e5) / 1e3;
107
+ const keyAt = (seconds) => wallKey(wallClock(seconds * 1e3, timeZone));
108
+ if (keyAt(lo) >= dateKey || keyAt(hi) < dateKey) throw new RangeError(`Cannot find the start of ${dateKey} in ${timeZone}`);
109
+ while (hi - lo > 1) {
110
+ const mid = Math.floor((lo + hi) / 2);
111
+ if (keyAt(mid) >= dateKey) hi = mid;
112
+ else lo = mid;
113
+ }
114
+ const start = hi * 1e3;
115
+ if (dayStartCache.size >= DAY_START_CACHE_LIMIT) dayStartCache.delete(dayStartCache.keys().next().value);
116
+ dayStartCache.set(cacheKey, start);
117
+ return start;
118
+ }
119
+ function zonedDayBounds(dateKey, timeZone) {
120
+ return { start: new Date(zonedDayStart(dateKey, timeZone)), end: new Date(zonedDayStart(addCalendarDays(dateKey, 1), timeZone)) };
121
+ }
122
+ function zonedHourSlots(dateKey, timeZone) {
123
+ const dayStart = zonedDayStart(dateKey, timeZone);
124
+ const dayEnd = zonedDayStart(addCalendarDays(dateKey, 1), timeZone);
125
+ const QUARTER = 15 * 6e4;
126
+ const slots = [];
127
+ let at = dayStart;
128
+ while (at < dayEnd) {
129
+ const wall = wallClock(at, timeZone);
130
+ if (wall.minute === 0 && wall.second === 0) {
131
+ slots.push({ at, hour: wall.hour });
132
+ at += 36e5;
133
+ } else {
134
+ at = dayStart + (Math.floor((at - dayStart) / QUARTER) + 1) * QUARTER;
135
+ }
136
+ }
137
+ const counts = /* @__PURE__ */ new Map();
138
+ for (const slot of slots) counts.set(slot.hour, (counts.get(slot.hour) ?? 0) + 1);
139
+ return slots.map(({ at: ms, hour }) => ({
140
+ instant: new Date(ms),
141
+ label: String(hour).padStart(2, "0"),
142
+ offsetLabel: (counts.get(hour) ?? 0) > 1 ? formatOffset(offsetAt(ms, timeZone)) : null
143
+ }));
144
+ }
145
+ function addZonedDays(instant, days, timeZone) {
146
+ if (!Number.isInteger(days)) throw new RangeError(`addZonedDays needs a whole number of days, got ${days}`);
147
+ const ms = toInstant(instant);
148
+ const fraction = ms - wholeSecond(ms);
149
+ const wall = wallClock(ms, timeZone);
150
+ const sourceOffset = wallAsUtc(wall) - wholeSecond(ms);
151
+ const target = fromDateKey(addCalendarDays(wallKey(wall), days));
152
+ const targetWall = Date.UTC(target.getUTCFullYear(), target.getUTCMonth(), target.getUTCDate(), wall.hour, wall.minute, wall.second);
153
+ const before = offsetAt(targetWall - 864e5, timeZone);
154
+ const after = offsetAt(targetWall + 864e5, timeZone);
155
+ const valid = [.../* @__PURE__ */ new Set([sourceOffset, before, after])].filter((offset) => offsetAt(targetWall - offset, timeZone) === offset).sort((a, b) => b - a);
156
+ if (valid.length) {
157
+ const offset = valid.includes(sourceOffset) ? sourceOffset : valid[0];
158
+ return { instant: new Date(targetWall - offset + fraction), adjusted: null };
159
+ }
160
+ return { instant: new Date(targetWall - before + fraction), adjusted: "gap_forward" };
161
+ }
162
+ function zonedDaySpan(start, end, timeZone) {
163
+ const from = toInstant(start);
164
+ const to = toInstant(end);
165
+ if (to <= from) {
166
+ throw new RangeError(`zonedDaySpan: end (${new Date(to).toISOString()}) must be after start (${new Date(from).toISOString()}); the interval is inverted or empty`);
167
+ }
168
+ return { start: zonedDateKey(new Date(from), timeZone), end: addCalendarDays(zonedDateKey(new Date(to - 1), timeZone), 1) };
169
+ }
170
+ function enumerateDateKeys(span, options = {}) {
171
+ const limit = options.limit ?? 370;
172
+ if (!(limit === Infinity || Number.isInteger(limit) && limit >= 0)) throw new RangeError(`enumerateDateKeys: limit must be a non-negative integer or Infinity, got ${limit}`);
173
+ checkedDateKey(span.start);
174
+ checkedDateKey(span.end);
175
+ if (span.end < span.start) throw new RangeError(`enumerateDateKeys: end (${span.end}) is before start (${span.start}); the span is inverted`);
176
+ const dates = [];
177
+ let current = span.start;
178
+ while (current < span.end && dates.length < limit) {
179
+ dates.push(current);
180
+ current = addCalendarDays(current, 1);
181
+ }
182
+ return { dates, truncated: current < span.end };
52
183
  }
53
184
  function zonedDateSpan(start, end, timeZone) {
54
185
  const startKey = zonedDateKey(start, timeZone);
@@ -64,6 +195,55 @@ function enumerateDateSpan(span, limit = 370) {
64
195
  }
65
196
  return dates;
66
197
  }
198
+ function packLanes(intervals, maxLanes, options = {}) {
199
+ if (!(maxLanes === Infinity || Number.isInteger(maxLanes) && maxLanes >= 0)) throw new RangeError(`packLanes: maxLanes must be a non-negative integer, got ${maxLanes}`);
200
+ const order = options.order ?? "start";
201
+ if (order !== "start" && order !== "given") throw new TypeError(`packLanes: unknown order ${String(order)}`);
202
+ const seen = /* @__PURE__ */ new Set();
203
+ const items = intervals.map((interval) => {
204
+ if (seen.has(interval.id)) throw new TypeError(`packLanes: duplicate id ${interval.id}`);
205
+ seen.add(interval.id);
206
+ const start = toInstant(interval.start);
207
+ const end = toInstant(interval.end);
208
+ if (end < start) throw new RangeError(`packLanes: interval ${interval.id} ends before it starts`);
209
+ return { id: interval.id, start, end: end === start ? start + 1 : end };
210
+ });
211
+ const byStart = [...items].sort((a, b) => a.start - b.start || a.end - b.end || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
212
+ const clusterOf = /* @__PURE__ */ new Map();
213
+ const clusters = [];
214
+ let reach = -Infinity;
215
+ for (const item of byStart) {
216
+ if (item.start >= reach) clusters.push({ ids: [], laneCount: 0, overflow: 0 });
217
+ reach = Math.max(reach, item.end);
218
+ clusters[clusters.length - 1].ids.push(item.id);
219
+ clusterOf.set(item.id, clusters.length - 1);
220
+ }
221
+ const occupied = [];
222
+ const lanes = {};
223
+ for (const item of order === "start" ? byStart : items) {
224
+ let lane = null;
225
+ for (let index = 0; index < Math.min(maxLanes, occupied.length + 1); index++) {
226
+ if (!(occupied[index] ?? []).some((other) => item.start < other.end && other.start < item.end)) {
227
+ lane = index;
228
+ break;
229
+ }
230
+ }
231
+ const cluster = clusters[clusterOf.get(item.id)];
232
+ if (lane === null) cluster.overflow++;
233
+ else {
234
+ (occupied[lane] ?? (occupied[lane] = [])).push(item);
235
+ cluster.laneCount = Math.max(cluster.laneCount, lane + 1);
236
+ }
237
+ lanes[item.id] = { lane, cluster: clusterOf.get(item.id) };
238
+ }
239
+ return { lanes, clusters, overflow: clusters.reduce((sum, cluster) => sum + cluster.overflow, 0) };
240
+ }
241
+ function rankOverflow(items, compare, n) {
242
+ if (!(n === Infinity || Number.isInteger(n) && n >= 0)) throw new RangeError(`rankOverflow: n must be a non-negative integer, got ${n}`);
243
+ const sorted = [...items].sort(compare);
244
+ const visible = sorted.slice(0, n);
245
+ return { visible, hidden: sorted.length - visible.length };
246
+ }
67
247
  function selectRangeDate(current, date) {
68
248
  if (!current.start || current.end) return { start: date };
69
249
  return date < current.start ? { start: date, end: current.start } : { start: current.start, end: date };
@@ -77,13 +257,22 @@ function isDateUnavailable(date, options) {
77
257
  export {
78
258
  addCalendarDays,
79
259
  addCalendarMonths,
260
+ addZonedDays,
80
261
  buildMonthGrid,
262
+ cachedDateTimeFormat,
263
+ enumerateDateKeys,
81
264
  enumerateDateSpan,
82
265
  isDateInRange,
83
266
  isDateUnavailable,
267
+ packLanes,
268
+ rankOverflow,
84
269
  selectRangeDate,
85
270
  startOfMonth,
86
271
  toDateKey,
87
272
  zonedDateKey,
88
- zonedDateSpan
273
+ zonedDateSpan,
274
+ zonedDayBounds,
275
+ zonedDaySpan,
276
+ zonedHourSlots,
277
+ zonedTimeOfDay
89
278
  };
@@ -36,7 +36,11 @@ __export(chart_preset_exports, {
36
36
  ChartLegendItem: () => ChartLegendItem,
37
37
  ChartMetric: () => ChartMetric,
38
38
  DEFAULT_CHART_LABELS: () => DEFAULT_CHART_LABELS,
39
- uixChartPalette: () => uixChartPalette
39
+ mergeChartTheme: () => mergeChartTheme,
40
+ uixChartAreaGradient: () => uixChartAreaGradient,
41
+ uixChartPalette: () => uixChartPalette,
42
+ uixChartTheme: () => uixChartTheme,
43
+ uixChartTokens: () => uixChartTokens
40
44
  });
41
45
  module.exports = __toCommonJS(chart_preset_exports);
42
46
  var echarts = __toESM(require("echarts/core"), 1);
@@ -52,6 +56,101 @@ function cx(...args) {
52
56
  return args.filter(Boolean).join(" ");
53
57
  }
54
58
 
59
+ // src/chart-theme.ts
60
+ function reader(source) {
61
+ if (typeof source === "function") return source;
62
+ if (typeof getComputedStyle === "undefined" || typeof document === "undefined") return () => "";
63
+ const style = getComputedStyle(source ?? document.documentElement);
64
+ return (token) => style.getPropertyValue(token).trim();
65
+ }
66
+ function uixChartTokens(source) {
67
+ const read = reader(source);
68
+ const t = (name) => read(`--uix-${name}`);
69
+ const unquote = (font) => font.replace(/"/g, "");
70
+ return {
71
+ palette: [1, 2, 3, 4, 5, 6, 7, 8].map((i) => t(`chart-${i}`)),
72
+ neutral: t("chart-neutral"),
73
+ grid: t("chart-grid"),
74
+ axis: t("chart-axis"),
75
+ reference: t("chart-reference"),
76
+ zoneWarning: t("chart-zone-warning"),
77
+ zoneDanger: t("chart-zone-danger"),
78
+ forecastBand: t("chart-forecast-band"),
79
+ event: t("chart-event"),
80
+ partial: t("chart-partial"),
81
+ comparison: t("chart-comparison"),
82
+ surface: t("surface"),
83
+ text: t("text"),
84
+ textMuted: t("text-muted"),
85
+ border: t("border-strong"),
86
+ fontSans: unquote(t("font-sans")),
87
+ fontMono: unquote(t("font-mono"))
88
+ };
89
+ }
90
+ function uixChartTheme(source) {
91
+ const k = uixChartTokens(source);
92
+ const read = reader(source);
93
+ const axis = {
94
+ axisLine: { lineStyle: { color: k.axis } },
95
+ axisTick: { show: false },
96
+ axisLabel: { color: k.textMuted, fontFamily: k.fontMono, fontSize: 11 },
97
+ splitLine: { lineStyle: { color: k.grid, type: "solid", width: 1 } }
98
+ };
99
+ return {
100
+ color: k.palette,
101
+ backgroundColor: "transparent",
102
+ textStyle: { color: k.textMuted, fontFamily: k.fontSans, fontSize: 12 },
103
+ title: { textStyle: { color: k.text, fontFamily: k.fontSans }, subtextStyle: { color: k.textMuted, fontFamily: k.fontSans } },
104
+ legend: { textStyle: { color: k.textMuted, fontFamily: k.fontSans, fontSize: 12 }, icon: "roundRect", itemWidth: 10, itemHeight: 6, itemGap: 12 },
105
+ tooltip: {
106
+ backgroundColor: k.surface,
107
+ borderColor: k.border,
108
+ borderWidth: 1,
109
+ padding: [8, 10],
110
+ textStyle: { color: k.text, fontFamily: k.fontSans, fontSize: 12 },
111
+ extraCssText: `border-radius:${read("--uix-radius-sm")};box-shadow:${read("--uix-shadow-popover")}`,
112
+ axisPointer: { lineStyle: { color: k.reference, width: 1 }, crossStyle: { color: k.reference }, shadowStyle: { color: k.forecastBand } }
113
+ },
114
+ xAxis: axis,
115
+ yAxis: axis
116
+ };
117
+ }
118
+ function uixChartAreaGradient(color) {
119
+ const alpha = (opacity) => {
120
+ const hex = color.replace("#", "");
121
+ if (!/^[0-9a-f]{6}$/i.test(hex)) return color;
122
+ const [r, g, b] = hex.match(/.{2}/g).map((channel) => Number.parseInt(channel, 16));
123
+ return `rgba(${r},${g},${b},${opacity})`;
124
+ };
125
+ return {
126
+ type: "linear",
127
+ x: 0,
128
+ y: 0,
129
+ x2: 0,
130
+ y2: 1,
131
+ colorStops: [{ offset: 0, color: alpha(0.28) }, { offset: 0.72, color: alpha(0.06) }, { offset: 1, color: alpha(0) }]
132
+ };
133
+ }
134
+ var isPlainObject = (value) => value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
135
+ function deepMerge(base, over) {
136
+ if (over === void 0) return base;
137
+ if (!isPlainObject(base) || !isPlainObject(over)) return over;
138
+ const out = { ...base };
139
+ for (const key of Object.keys(over)) out[key] = deepMerge(base[key], over[key]);
140
+ return out;
141
+ }
142
+ var STYLED_ONLY = ["xAxis", "yAxis", "legend", "title"];
143
+ function mergeChartTheme(theme, option) {
144
+ const merged = deepMerge(theme, option);
145
+ const source = option;
146
+ const base = theme;
147
+ for (const key of STYLED_ONLY) {
148
+ if (Array.isArray(source[key])) merged[key] = source[key].map((axis) => deepMerge(base[key], axis));
149
+ else if (!(key in source)) delete merged[key];
150
+ }
151
+ return merged;
152
+ }
153
+
55
154
  // src/components/ChartCore.tsx
56
155
  var import_jsx_runtime = require("react/jsx-runtime");
57
156
  function readToken(name) {
@@ -61,6 +160,9 @@ function readToken(name) {
61
160
  function uixChartPalette() {
62
161
  return [1, 2, 3, 4, 5, 6, 7, 8].map((i) => readToken(`--uix-chart-${i}`));
63
162
  }
163
+ function themed(option, theme, element) {
164
+ return theme === "none" ? option : mergeChartTheme(uixChartTheme(element), option);
165
+ }
64
166
  function motionSafe(option) {
65
167
  if (typeof matchMedia !== "undefined" && matchMedia("(prefers-reduced-motion: reduce)").matches) {
66
168
  return { ...option, animation: false };
@@ -89,7 +191,8 @@ function ChartCore({
89
191
  footer,
90
192
  loading = false,
91
193
  empty,
92
- labels: labelOverrides
194
+ labels: labelOverrides,
195
+ theme = "uix"
93
196
  }) {
94
197
  const labels = { ...DEFAULT_CHART_LABELS, ...labelOverrides };
95
198
  const containerRef = (0, import_react.useRef)(null);
@@ -101,7 +204,9 @@ function ChartCore({
101
204
  const hasEmpty = empty != null;
102
205
  const hasTextAlternative = Boolean(ariaLabel || title || tableData?.length);
103
206
  const hasTextAlternativeRef = (0, import_react.useRef)(hasTextAlternative);
207
+ const themeRef = (0, import_react.useRef)(theme);
104
208
  latestOptionRef.current = option;
209
+ themeRef.current = theme;
105
210
  onReadyRef.current = onReady;
106
211
  hasTextAlternativeRef.current = hasTextAlternative;
107
212
  (0, import_react.useEffect)(() => {
@@ -109,9 +214,17 @@ function ChartCore({
109
214
  if (!element) return;
110
215
  const chart = engine.init(element, null, { renderer: "svg" });
111
216
  chartRef.current = chart;
112
- chart.setOption(motionSafe(latestOptionRef.current));
217
+ chart.setOption(motionSafe(themed(latestOptionRef.current, themeRef.current, element)));
113
218
  appliedOptionRef.current = latestOptionRef.current;
114
219
  onReadyRef.current?.(chart);
220
+ const retheme = () => {
221
+ if (themeRef.current === "none") return;
222
+ chart.setOption(motionSafe(themed(latestOptionRef.current, themeRef.current, element)));
223
+ };
224
+ const themeObserver = typeof MutationObserver === "undefined" ? null : new MutationObserver(retheme);
225
+ themeObserver?.observe(document.documentElement, { attributes: true, attributeFilter: ["class", "data-theme"] });
226
+ const scheme = typeof matchMedia === "undefined" ? null : matchMedia("(prefers-color-scheme: dark)");
227
+ scheme?.addEventListener?.("change", retheme);
115
228
  if (!hasTextAlternativeRef.current) {
116
229
  console.warn("[uix] Chart has no text alternative \u2014 provide ariaLabel, title, or tableData.");
117
230
  }
@@ -133,6 +246,8 @@ function ChartCore({
133
246
  observer.observe(element);
134
247
  return () => {
135
248
  observer.disconnect();
249
+ themeObserver?.disconnect();
250
+ scheme?.removeEventListener?.("change", retheme);
136
251
  if (frame) cancelAnimationFrame(frame);
137
252
  chart.dispose();
138
253
  chartRef.current = null;
@@ -141,10 +256,11 @@ function ChartCore({
141
256
  }, [engine, hasEmpty]);
142
257
  (0, import_react.useEffect)(() => {
143
258
  const chart = chartRef.current;
144
- if (!chart || appliedOptionRef.current === option) return;
145
- chart.setOption(motionSafe(option), { notMerge: false });
259
+ const element = containerRef.current;
260
+ if (!chart || !element || appliedOptionRef.current === option) return;
261
+ chart.setOption(motionSafe(themed(option, theme, element)), { notMerge: false });
146
262
  appliedOptionRef.current = option;
147
- }, [option]);
263
+ }, [option, theme]);
148
264
  const heightValue = typeof height === "number" ? `${height}px` : height;
149
265
  const effectiveAriaLabel = ariaLabel ?? title ?? labels.chart;
150
266
  const hasTable = Boolean(tableData?.length && tableHeaders?.length);
@@ -220,5 +336,9 @@ function Chart(props) {
220
336
  ChartLegendItem,
221
337
  ChartMetric,
222
338
  DEFAULT_CHART_LABELS,
223
- uixChartPalette
339
+ mergeChartTheme,
340
+ uixChartAreaGradient,
341
+ uixChartPalette,
342
+ uixChartTheme,
343
+ uixChartTokens
224
344
  });
@@ -1,6 +1,6 @@
1
1
  import * as react from 'react';
2
- import { C as ChartProps } from './ChartCore-DzWe10bN.cjs';
3
- export { a as ChartLabels, b as ChartLegend, c as ChartLegendItem, d as ChartLegendItemProps, e as ChartLegendProps, f as ChartMetric, g as ChartMetricProps, h as ChartTableRow, D as DEFAULT_CHART_LABELS, u as uixChartPalette } from './ChartCore-DzWe10bN.cjs';
2
+ import { C as ChartProps } from './chart-theme-Cl0IrkKQ.cjs';
3
+ export { a as ChartLabels, b as ChartLegend, c as ChartLegendItem, d as ChartLegendItemProps, e as ChartLegendProps, f as ChartMetric, g as ChartMetricProps, h as ChartTableRow, i as ChartTokenSource, D as DEFAULT_CHART_LABELS, U as UixChartTokens, m as mergeChartTheme, u as uixChartAreaGradient, j as uixChartPalette, k as uixChartTheme, l as uixChartTokens } from './chart-theme-Cl0IrkKQ.cjs';
4
4
  import 'echarts';
5
5
 
6
6
  /** Lean SVG adapter: line, bar, pie, dataset, grid, legend, title, and tooltip. */
@@ -1,6 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ChartProps } from './components/ChartCore.js';
3
3
  export { ChartLabels, ChartLegend, ChartLegendItem, ChartLegendItemProps, ChartLegendProps, ChartMetric, ChartMetricProps, ChartTableRow, DEFAULT_CHART_LABELS, uixChartPalette } from './components/ChartCore.js';
4
+ export { ChartTokenSource, UixChartTokens, mergeChartTheme, uixChartAreaGradient, uixChartTheme, uixChartTokens } from './chart-theme.js';
4
5
  import 'echarts';
5
6
 
6
7
  /** Lean SVG adapter: line, bar, pie, dataset, grid, legend, title, and tooltip. */
@@ -29,11 +29,16 @@ function Chart(props) {
29
29
  return /* @__PURE__ */ jsx(ChartCore, { ...props, engine: presetEngine });
30
30
  }
31
31
  import { ChartLegend, ChartLegendItem, ChartMetric, DEFAULT_CHART_LABELS, uixChartPalette } from "./components/ChartCore.js";
32
+ import { mergeChartTheme, uixChartAreaGradient, uixChartTheme, uixChartTokens } from "./chart-theme.js";
32
33
  export {
33
34
  Chart,
34
35
  ChartLegend,
35
36
  ChartLegendItem,
36
37
  ChartMetric,
37
38
  DEFAULT_CHART_LABELS,
38
- uixChartPalette
39
+ mergeChartTheme,
40
+ uixChartAreaGradient,
41
+ uixChartPalette,
42
+ uixChartTheme,
43
+ uixChartTokens
39
44
  };
@@ -0,0 +1,112 @@
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
+ /**
10
+ * Every word the chart renders itself (TENSOR RX-125, UIX-04 / UIX-05). The
11
+ * loading text used to live in CSS `content:`, where nothing could translate it.
12
+ */
13
+ interface ChartLabels {
14
+ /** Shown (and announced inside the busy region) while `loading`. */
15
+ loading: ReactNode;
16
+ /** Accessible name when neither `ariaLabel` nor `title` is given. */
17
+ chart: string;
18
+ /** Appended to the chart's name for its data-table alternative. */
19
+ dataTableSuffix: string;
20
+ }
21
+ declare const DEFAULT_CHART_LABELS: ChartLabels;
22
+ interface ChartProps {
23
+ option: EChartsOption;
24
+ title?: string;
25
+ subtitle?: string;
26
+ height?: string | number;
27
+ className?: string;
28
+ style?: CSSProperties;
29
+ ariaLabel?: string;
30
+ tableData?: ChartTableRow[];
31
+ tableHeaders?: string[];
32
+ onReady?: (chart: ECharts) => void;
33
+ header?: ReactNode;
34
+ headerAction?: ReactNode;
35
+ footer?: ReactNode;
36
+ loading?: boolean;
37
+ empty?: ReactNode;
38
+ /** Translatable words; English defaults in {@link DEFAULT_CHART_LABELS}. */
39
+ labels?: Partial<ChartLabels>;
40
+ /**
41
+ * `'uix'` (default) merges {@link uixChartTheme} under `option` — token palette, fonts, a solid hairline
42
+ * grid and the UIx tooltip — and re-applies it when the page theme changes. `'none'` renders `option` as is.
43
+ */
44
+ theme?: 'uix' | 'none';
45
+ }
46
+ interface ChartMetricProps extends HTMLAttributes<HTMLDivElement> {
47
+ value: ReactNode;
48
+ label?: ReactNode;
49
+ delta?: ReactNode;
50
+ deltaTone?: 'neutral' | 'positive' | 'negative' | 'warning';
51
+ }
52
+ declare function ChartMetric({ value, label, delta, deltaTone, className, ...props }: ChartMetricProps): react.JSX.Element;
53
+ interface ChartLegendProps extends HTMLAttributes<HTMLUListElement> {
54
+ children?: ReactNode;
55
+ }
56
+ declare function ChartLegend({ children, className, ...props }: ChartLegendProps): react.JSX.Element;
57
+ interface ChartLegendItemProps extends HTMLAttributes<HTMLLIElement> {
58
+ label: ReactNode;
59
+ color?: string;
60
+ swatch?: 'block' | 'line' | 'dash';
61
+ }
62
+ declare function ChartLegendItem({ label, color, swatch, className, style, ...props }: ChartLegendItemProps): react.JSX.Element;
63
+
64
+ /** Where tokens are read from: an element (its computed style), or a reader for tests and non-DOM use. */
65
+ type ChartTokenSource = Element | ((token: string) => string);
66
+ /** The analytic chart roles: reference lines, threshold zones, forecast bands, events, partial periods. */
67
+ interface UixChartTokens {
68
+ palette: string[];
69
+ neutral: string;
70
+ grid: string;
71
+ axis: string;
72
+ reference: string;
73
+ zoneWarning: string;
74
+ zoneDanger: string;
75
+ forecastBand: string;
76
+ event: string;
77
+ partial: string;
78
+ comparison: string;
79
+ surface: string;
80
+ text: string;
81
+ textMuted: string;
82
+ border: string;
83
+ fontSans: string;
84
+ fontMono: string;
85
+ }
86
+ /** Resolve the chart tokens once (current theme). */
87
+ declare function uixChartTokens(source?: ChartTokenSource): UixChartTokens;
88
+ /**
89
+ * The base option every UIx chart merges under the consumer's option (the consumer wins).
90
+ * Axis defaults apply to every x/y axis, whether the consumer passes one axis or an array.
91
+ */
92
+ declare function uixChartTheme(source?: ChartTokenSource): EChartsOption;
93
+ /** A vertical area fill that fades the series colour (28 % → 6 % → 0) toward the baseline. */
94
+ declare function uixChartAreaGradient(color: string): {
95
+ type: "linear";
96
+ x: number;
97
+ y: number;
98
+ x2: number;
99
+ y2: number;
100
+ colorStops: {
101
+ offset: number;
102
+ color: string;
103
+ }[];
104
+ };
105
+ /**
106
+ * Merge the theme under a consumer option: plain objects merge deeply, everything else (arrays,
107
+ * series, data, functions) is the consumer's. Array-valued components (`xAxis: [...]`, `title: [...]`)
108
+ * take the theme entry per element.
109
+ */
110
+ declare function mergeChartTheme(theme: EChartsOption, option: EChartsOption): EChartsOption;
111
+
112
+ export { type ChartProps as C, DEFAULT_CHART_LABELS as D, type UixChartTokens as U, type ChartLabels as a, ChartLegend as b, ChartLegendItem as c, type ChartLegendItemProps as d, type ChartLegendProps as e, ChartMetric as f, type ChartMetricProps as g, type ChartTableRow as h, type ChartTokenSource as i, uixChartPalette as j, uixChartTheme as k, uixChartTokens as l, mergeChartTheme as m, uixChartAreaGradient as u };
@@ -0,0 +1,51 @@
1
+ import { EChartsOption } from 'echarts';
2
+
3
+ /** Where tokens are read from: an element (its computed style), or a reader for tests and non-DOM use. */
4
+ type ChartTokenSource = Element | ((token: string) => string);
5
+ /** The analytic chart roles: reference lines, threshold zones, forecast bands, events, partial periods. */
6
+ interface UixChartTokens {
7
+ palette: string[];
8
+ neutral: string;
9
+ grid: string;
10
+ axis: string;
11
+ reference: string;
12
+ zoneWarning: string;
13
+ zoneDanger: string;
14
+ forecastBand: string;
15
+ event: string;
16
+ partial: string;
17
+ comparison: string;
18
+ surface: string;
19
+ text: string;
20
+ textMuted: string;
21
+ border: string;
22
+ fontSans: string;
23
+ fontMono: string;
24
+ }
25
+ /** Resolve the chart tokens once (current theme). */
26
+ declare function uixChartTokens(source?: ChartTokenSource): UixChartTokens;
27
+ /**
28
+ * The base option every UIx chart merges under the consumer's option (the consumer wins).
29
+ * Axis defaults apply to every x/y axis, whether the consumer passes one axis or an array.
30
+ */
31
+ declare function uixChartTheme(source?: ChartTokenSource): EChartsOption;
32
+ /** A vertical area fill that fades the series colour (28 % → 6 % → 0) toward the baseline. */
33
+ declare function uixChartAreaGradient(color: string): {
34
+ type: "linear";
35
+ x: number;
36
+ y: number;
37
+ x2: number;
38
+ y2: number;
39
+ colorStops: {
40
+ offset: number;
41
+ color: string;
42
+ }[];
43
+ };
44
+ /**
45
+ * Merge the theme under a consumer option: plain objects merge deeply, everything else (arrays,
46
+ * series, data, functions) is the consumer's. Array-valued components (`xAxis: [...]`, `title: [...]`)
47
+ * take the theme entry per element.
48
+ */
49
+ declare function mergeChartTheme(theme: EChartsOption, option: EChartsOption): EChartsOption;
50
+
51
+ export { type ChartTokenSource, type UixChartTokens, mergeChartTheme, uixChartAreaGradient, uixChartTheme, uixChartTokens };