@tensor_1/react 2.31.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.
- package/README.md +350 -0
- package/dist/attachment-labels.d.ts +16 -0
- package/dist/attachment-labels.js +9 -0
- package/dist/calendar-model.d.ts +141 -1
- package/dist/calendar-model.js +200 -11
- package/dist/chart-preset.cjs +127 -7
- package/dist/chart-preset.d.cts +2 -2
- package/dist/chart-preset.d.ts +1 -0
- package/dist/chart-preset.js +6 -1
- package/dist/chart-theme-Cl0IrkKQ.d.cts +112 -0
- package/dist/chart-theme.d.ts +51 -0
- package/dist/chart-theme.js +99 -0
- package/dist/chart.cjs +127 -7
- package/dist/chart.d.cts +2 -2
- package/dist/chart.d.ts +1 -0
- package/dist/chart.js +6 -2
- package/dist/components/Alert.d.ts +17 -1
- package/dist/components/Alert.js +9 -4
- package/dist/components/AlertDismiss.d.ts +14 -0
- package/dist/components/AlertDismiss.js +11 -0
- package/dist/components/Attachment.d.ts +15 -12
- package/dist/components/Attachment.js +17 -17
- package/dist/components/AttachmentParts.d.ts +24 -0
- package/dist/components/AttachmentParts.js +20 -0
- package/dist/components/Chart.d.ts +1 -0
- package/dist/components/Chart.js +6 -1
- package/dist/components/ChartCore.d.ts +6 -1
- package/dist/components/ChartCore.js +23 -5
- package/dist/components/Chip.d.ts +17 -2
- package/dist/components/Chip.js +35 -11
- package/dist/components/ChipRemove.d.ts +17 -0
- package/dist/components/ChipRemove.js +13 -0
- package/dist/components/CollapsibleParts.d.ts +29 -0
- package/dist/components/CollapsibleParts.js +20 -0
- package/dist/components/CollapsibleSection.d.ts +30 -3
- package/dist/components/CollapsibleSection.js +7 -11
- package/dist/components/CollapsibleSectionState.d.ts +1 -1
- package/dist/components/CollapsibleSectionState.js +54 -27
- package/dist/components/DashboardGrid.d.ts +60 -0
- package/dist/components/DashboardGrid.js +40 -0
- package/dist/components/DateRangePicker.d.ts +7 -1
- package/dist/components/DateRangePicker.js +5 -1
- package/dist/components/DescriptionList.d.ts +12 -1
- package/dist/components/DescriptionList.js +5 -5
- package/dist/components/Dialogs.d.ts +24 -3
- package/dist/components/Dialogs.js +74 -16
- package/dist/components/FileUpload.d.ts +10 -2
- package/dist/components/FileUpload.js +10 -4
- package/dist/components/FilterEditor.d.ts +4 -0
- package/dist/components/FilterEditor.js +13 -2
- package/dist/components/Heartbeat.d.ts +31 -0
- package/dist/components/Heartbeat.js +28 -0
- package/dist/components/Menu.d.ts +53 -5
- package/dist/components/Menu.js +104 -4
- package/dist/components/Meter.d.ts +7 -3
- package/dist/components/Meter.js +2 -1
- package/dist/components/Popover.d.ts +21 -2
- package/dist/components/Popover.js +94 -17
- package/dist/components/Prose.d.ts +6 -2
- package/dist/components/Prose.js +1 -1
- package/dist/components/RuleBuilder.d.ts +52 -4
- package/dist/components/RuleBuilder.js +109 -24
- package/dist/components/SchedulingCalendar.d.ts +142 -11
- package/dist/components/SchedulingCalendar.js +234 -57
- package/dist/components/SchedulingTimeline.d.ts +1 -0
- package/dist/components/Segmented.d.ts +17 -3
- package/dist/components/Segmented.js +59 -5
- package/dist/components/Select.d.ts +66 -2
- package/dist/components/Select.js +800 -10
- package/dist/components/Spinner.d.ts +2 -1
- package/dist/components/Spinner.js +1 -1
- package/dist/components/StatusPill.d.ts +8 -2
- package/dist/components/StatusPill.js +2 -2
- package/dist/components/Steps.d.ts +28 -4
- package/dist/components/Steps.js +46 -16
- package/dist/components/TableControls.js +4 -3
- package/dist/components/Tabs.d.ts +7 -2
- package/dist/components/Tabs.js +14 -1
- package/dist/components/TextDiff.d.ts +49 -0
- package/dist/components/TextDiff.js +124 -0
- package/dist/{emoji-image-6mPZ15Zy.d.cts → emoji-image-DjCKpdwE.d.cts} +1 -1
- package/dist/emoji.cjs +169 -27
- package/dist/emoji.d.cts +3 -3
- package/dist/file-model.d.ts +22 -3
- package/dist/file-model.js +6 -4
- package/dist/filter-model.d.ts +26 -2
- package/dist/filter-model.js +13 -1
- package/dist/hooks/useAnchoredPosition.d.ts +24 -1
- package/dist/hooks/useAnchoredPosition.js +58 -8
- package/dist/hooks/useVirtualRows.d.ts +17 -2
- package/dist/hooks/useVirtualRows.js +6 -5
- package/dist/icons/Icon.d.ts +14 -14
- package/dist/index.cjs +4179 -1678
- package/dist/index.d.cts +1706 -660
- package/dist/index.d.ts +16 -9
- package/dist/index.js +53 -4
- package/dist/labels-context.d.ts +28 -0
- package/dist/{overlay-position-Cjv5E7mn.d.cts → overlay-position-2Afke51l.d.cts} +20 -0
- package/dist/overlay-position.d.ts +20 -0
- package/dist/overlay-position.js +17 -2
- package/dist/rich-text.cjs +169 -27
- package/dist/rich-text.d.cts +3 -3
- package/dist/rule-builder-model.d.ts +34 -2
- package/dist/rule-builder-model.js +48 -12
- package/dist/scheduling-calendar-model.d.ts +66 -0
- package/dist/scheduling-calendar-model.js +82 -0
- package/dist/select-model.d.ts +80 -0
- package/dist/select-model.js +109 -0
- package/dist/table-engine.d.ts +7 -0
- package/dist/table-engine.js +2 -1
- package/dist/text-diff-model.d.ts +71 -0
- package/dist/text-diff-model.js +261 -0
- package/package.json +1 -1
- package/dist/ChartCore-DzWe10bN.d.cts +0 -59
package/dist/calendar-model.js
CHANGED
|
@@ -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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
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
|
};
|
package/dist/chart-preset.cjs
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
145
|
-
chart
|
|
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
|
-
|
|
339
|
+
mergeChartTheme,
|
|
340
|
+
uixChartAreaGradient,
|
|
341
|
+
uixChartPalette,
|
|
342
|
+
uixChartTheme,
|
|
343
|
+
uixChartTokens
|
|
224
344
|
});
|
package/dist/chart-preset.d.cts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as react from 'react';
|
|
2
|
-
import { C as ChartProps } from './
|
|
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 './
|
|
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. */
|
package/dist/chart-preset.d.ts
CHANGED
|
@@ -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. */
|
package/dist/chart-preset.js
CHANGED
|
@@ -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
|
-
|
|
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 };
|