@opendata-ai/openchart-core 8.9.0 → 8.9.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +310 -197
- package/dist/index.js +245 -7
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +1 -1
- package/schema/chart.schema.json +74 -14
- package/schema/table.schema.json +42 -14
- package/schema/vizspec.schema.json +101 -42
package/dist/index.js
CHANGED
|
@@ -1,3 +1,121 @@
|
|
|
1
|
+
// src/helpers/edit-transactions.ts
|
|
2
|
+
function isContainer(value) {
|
|
3
|
+
return Array.isArray(value) || value !== null && typeof value === "object" && (Object.getPrototypeOf(value) === Object.prototype || Object.getPrototypeOf(value) === null);
|
|
4
|
+
}
|
|
5
|
+
function clone(value) {
|
|
6
|
+
if (Array.isArray(value)) return value.map(clone);
|
|
7
|
+
if (!isContainer(value)) return value;
|
|
8
|
+
return Object.fromEntries(Object.entries(value).map(([key, child]) => [key, clone(child)]));
|
|
9
|
+
}
|
|
10
|
+
function tokens(path) {
|
|
11
|
+
if (!path.startsWith("/")) throw new Error("Expected a non-root JSON Pointer beginning with /.");
|
|
12
|
+
return path.slice(1).split("/").map((token) => {
|
|
13
|
+
if (/~(?:[^01]|$)/.test(token)) throw new Error("Invalid JSON Pointer escape.");
|
|
14
|
+
const decoded = token.replace(/~1/g, "/").replace(/~0/g, "~");
|
|
15
|
+
if (["__proto__", "prototype", "constructor"].includes(decoded)) {
|
|
16
|
+
throw new Error("Unsafe property in edit path.");
|
|
17
|
+
}
|
|
18
|
+
return decoded;
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
function pointer(parts) {
|
|
22
|
+
return `/${parts.map((part) => part.replace(/~/g, "~0").replace(/\//g, "~1")).join("/")}`;
|
|
23
|
+
}
|
|
24
|
+
function keyAt(parent, token, insert = false) {
|
|
25
|
+
if (!Array.isArray(parent)) return token;
|
|
26
|
+
if (insert && token === "-") return parent.length;
|
|
27
|
+
if (!/^(0|[1-9]\d*)$/.test(token)) throw new Error("Expected an array index.");
|
|
28
|
+
const index = Number(token);
|
|
29
|
+
if (!Number.isSafeInteger(index) || index > parent.length || !insert && index === parent.length) {
|
|
30
|
+
throw new Error("Array index is out of bounds.");
|
|
31
|
+
}
|
|
32
|
+
return index;
|
|
33
|
+
}
|
|
34
|
+
function read(parent, key) {
|
|
35
|
+
return parent[key];
|
|
36
|
+
}
|
|
37
|
+
function checkExpectation(root, parts, expected) {
|
|
38
|
+
if (!expected) return;
|
|
39
|
+
let end = -1;
|
|
40
|
+
for (let i = 0; i + 1 < parts.length; i++) {
|
|
41
|
+
if (parts[i] === "annotations" && /^(0|[1-9]\d*)$/.test(parts[i + 1])) end = i + 2;
|
|
42
|
+
}
|
|
43
|
+
if (end === -1) throw new Error("Annotation precondition requires an annotation path.");
|
|
44
|
+
let target = root;
|
|
45
|
+
for (const part of parts.slice(0, end)) {
|
|
46
|
+
if (!isContainer(target)) throw new Error("Annotation target no longer exists.");
|
|
47
|
+
const key = keyAt(target, part);
|
|
48
|
+
if (!Object.hasOwn(target, key)) throw new Error("Annotation target no longer exists.");
|
|
49
|
+
target = read(target, key);
|
|
50
|
+
}
|
|
51
|
+
if (!isContainer(target) || Array.isArray(target))
|
|
52
|
+
throw new Error("Annotation target is invalid.");
|
|
53
|
+
for (const field of ["id", "type", "text"]) {
|
|
54
|
+
if (Object.hasOwn(expected, field) && target[field] !== expected[field]) {
|
|
55
|
+
throw new Error(`Annotation ${field} changed; discard the stale edit.`);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
function applyEditTransaction(spec, tx) {
|
|
60
|
+
const result = clone(spec);
|
|
61
|
+
const inverse = [];
|
|
62
|
+
for (const [opIndex, op] of tx.ops.entries()) {
|
|
63
|
+
try {
|
|
64
|
+
if (!["set", "add", "remove"].includes(op.op)) throw new Error("Unknown edit operation.");
|
|
65
|
+
if (op.op !== "remove" && !Object.hasOwn(op, "value"))
|
|
66
|
+
throw new Error("Edit value is missing.");
|
|
67
|
+
const parts = tokens(op.path);
|
|
68
|
+
checkExpectation(result, parts, op.expect);
|
|
69
|
+
let parent = result;
|
|
70
|
+
const created = [];
|
|
71
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
72
|
+
if (!isContainer(parent)) throw new Error("Cannot traverse a primitive or non-JSON value.");
|
|
73
|
+
const key2 = keyAt(parent, parts[i]);
|
|
74
|
+
if (!Object.hasOwn(parent, key2)) {
|
|
75
|
+
if (op.op !== "add" || Array.isArray(parent))
|
|
76
|
+
throw new Error("Intermediate container is missing.");
|
|
77
|
+
parent[key2] = /^(0|[1-9]\d*|-)$/.test(parts[i + 1]) ? [] : {};
|
|
78
|
+
created.push(pointer(parts.slice(0, i + 1)));
|
|
79
|
+
}
|
|
80
|
+
parent = read(parent, key2);
|
|
81
|
+
}
|
|
82
|
+
if (!isContainer(parent)) throw new Error("Edit parent is not a JSON container.");
|
|
83
|
+
const key = keyAt(parent, parts.at(-1), op.op === "add");
|
|
84
|
+
const exists = Object.hasOwn(parent, key);
|
|
85
|
+
const old = read(parent, key);
|
|
86
|
+
const path = pointer([...parts.slice(0, -1), String(key)]);
|
|
87
|
+
let undo;
|
|
88
|
+
if (op.op === "remove") {
|
|
89
|
+
if (!exists) throw new Error("Edit target no longer exists.");
|
|
90
|
+
if (Array.isArray(parent)) parent.splice(Number(key), 1);
|
|
91
|
+
else delete parent[key];
|
|
92
|
+
undo = { op: "add", path, value: old };
|
|
93
|
+
} else if (op.op === "add" && Array.isArray(parent)) {
|
|
94
|
+
parent.splice(Number(key), 0, clone(op.value));
|
|
95
|
+
undo = { op: "remove", path };
|
|
96
|
+
} else {
|
|
97
|
+
parent[key] = clone(op.value);
|
|
98
|
+
undo = exists ? { op: "set", path, value: old } : { op: "remove", path };
|
|
99
|
+
}
|
|
100
|
+
inverse.unshift(undo, ...created.reverse().map((path2) => ({ op: "remove", path: path2 })));
|
|
101
|
+
} catch (error) {
|
|
102
|
+
return {
|
|
103
|
+
ok: false,
|
|
104
|
+
error: {
|
|
105
|
+
opIndex,
|
|
106
|
+
path: op.path,
|
|
107
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
return {
|
|
113
|
+
ok: true,
|
|
114
|
+
spec: result,
|
|
115
|
+
inverse: { ...tx.revision !== void 0 ? { revision: tx.revision } : {}, ops: inverse }
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
1
119
|
// src/types/encoding.ts
|
|
2
120
|
function required(...types) {
|
|
3
121
|
return { required: true, allowedTypes: types };
|
|
@@ -521,6 +639,13 @@ var CSS_TOKENS = [
|
|
|
521
639
|
{ name: "--oc-source-size", light: "11px" },
|
|
522
640
|
{ name: "--oc-source-weight", light: "400" },
|
|
523
641
|
{ name: "--oc-body-size", light: "13px" },
|
|
642
|
+
{ name: "--oc-annotation-label", light: "#333333", dark: "#d1d5db" },
|
|
643
|
+
{ name: "--oc-annotation-muted", light: "#6b7280", dark: "#9ca3af" },
|
|
644
|
+
{ name: "--oc-annotation-leader", light: "#8f8f8f", dark: "#9aa0a6" },
|
|
645
|
+
{ name: "--oc-annotation-rule", light: "#666666", dark: "#666666" },
|
|
646
|
+
{ name: "--oc-annotation-range-fill", light: "#000000", dark: "#000000" },
|
|
647
|
+
{ name: "--oc-annotation-marker-fill", light: "#ffffff", dark: "#0a0a0a" },
|
|
648
|
+
{ name: "--oc-annotation-plate", light: "#ffffff", dark: "#0a0a0a" },
|
|
524
649
|
{ name: "--oc-eyebrow-size", light: "11px" },
|
|
525
650
|
{ name: "--oc-eyebrow-weight", light: "500" },
|
|
526
651
|
{ name: "--oc-eyebrow-tracking", light: "0.08em" },
|
|
@@ -1439,6 +1564,13 @@ var DEFAULT_THEME = {
|
|
|
1439
1564
|
axis: "#71717a",
|
|
1440
1565
|
annotationFill: "rgba(0,0,0,0.04)",
|
|
1441
1566
|
annotationText: "#71717a",
|
|
1567
|
+
annotationLabel: "#333333",
|
|
1568
|
+
annotationMuted: "#6b7280",
|
|
1569
|
+
annotationLeader: "#8f8f8f",
|
|
1570
|
+
annotationRule: "#666666",
|
|
1571
|
+
annotationRangeFill: "#000000",
|
|
1572
|
+
annotationMarkerFill: "#ffffff",
|
|
1573
|
+
annotationPlate: "#ffffff",
|
|
1442
1574
|
positive: "#15803d",
|
|
1443
1575
|
negative: "#dc2626"
|
|
1444
1576
|
},
|
|
@@ -1605,6 +1737,13 @@ function adaptTheme(theme) {
|
|
|
1605
1737
|
axis: darkAxis,
|
|
1606
1738
|
annotationFill: pairs?.["colors.annotationFill"] ? pairs["colors.annotationFill"].dark : overridden(theme.colors.annotationFill, light.annotationFill, "rgba(255,255,255,0.06)"),
|
|
1607
1739
|
annotationText: pairs?.["colors.annotationText"] ? pairs["colors.annotationText"].dark : overridden(theme.colors.annotationText, light.annotationText, darkMuted),
|
|
1740
|
+
annotationLabel: pairs?.["colors.annotationLabel"]?.dark ?? overridden(theme.colors.annotationLabel, light.annotationLabel, "#d1d5db"),
|
|
1741
|
+
annotationMuted: pairs?.["colors.annotationMuted"]?.dark ?? overridden(theme.colors.annotationMuted, light.annotationMuted, "#9ca3af"),
|
|
1742
|
+
annotationLeader: pairs?.["colors.annotationLeader"]?.dark ?? overridden(theme.colors.annotationLeader, light.annotationLeader, "#9aa0a6"),
|
|
1743
|
+
annotationRule: pairs?.["colors.annotationRule"]?.dark ?? overridden(theme.colors.annotationRule, light.annotationRule, "#666666"),
|
|
1744
|
+
annotationRangeFill: pairs?.["colors.annotationRangeFill"]?.dark ?? overridden(theme.colors.annotationRangeFill, light.annotationRangeFill, "#000000"),
|
|
1745
|
+
annotationMarkerFill: pairs?.["colors.annotationMarkerFill"]?.dark ?? overridden(theme.colors.annotationMarkerFill, light.annotationMarkerFill, "#0a0a0a"),
|
|
1746
|
+
annotationPlate: pairs?.["colors.annotationPlate"]?.dark ?? overridden(theme.colors.annotationPlate, light.annotationPlate, "#0a0a0a"),
|
|
1608
1747
|
categorical,
|
|
1609
1748
|
categoricalFill,
|
|
1610
1749
|
hairline: darkHairline,
|
|
@@ -1656,6 +1795,11 @@ function adaptForLightLineStroke(color) {
|
|
|
1656
1795
|
return c.formatHex();
|
|
1657
1796
|
}
|
|
1658
1797
|
|
|
1798
|
+
// src/theme/merge.ts
|
|
1799
|
+
function mergeThemeConfig(base, override) {
|
|
1800
|
+
return override ? { ...base, ...override } : base;
|
|
1801
|
+
}
|
|
1802
|
+
|
|
1659
1803
|
// src/theme/presets.ts
|
|
1660
1804
|
var editorial = {};
|
|
1661
1805
|
var essay = {
|
|
@@ -1826,6 +1970,20 @@ function themeConfigToPartial(config) {
|
|
|
1826
1970
|
colors.annotationFill = resolveTokenLight(config.colors.annotationFill);
|
|
1827
1971
|
if (config.colors.annotationText)
|
|
1828
1972
|
colors.annotationText = resolveTokenLight(config.colors.annotationText);
|
|
1973
|
+
if (config.colors.annotationLabel)
|
|
1974
|
+
colors.annotationLabel = resolveTokenLight(config.colors.annotationLabel);
|
|
1975
|
+
if (config.colors.annotationMuted)
|
|
1976
|
+
colors.annotationMuted = resolveTokenLight(config.colors.annotationMuted);
|
|
1977
|
+
if (config.colors.annotationLeader)
|
|
1978
|
+
colors.annotationLeader = resolveTokenLight(config.colors.annotationLeader);
|
|
1979
|
+
if (config.colors.annotationRule)
|
|
1980
|
+
colors.annotationRule = resolveTokenLight(config.colors.annotationRule);
|
|
1981
|
+
if (config.colors.annotationRangeFill)
|
|
1982
|
+
colors.annotationRangeFill = resolveTokenLight(config.colors.annotationRangeFill);
|
|
1983
|
+
if (config.colors.annotationMarkerFill)
|
|
1984
|
+
colors.annotationMarkerFill = resolveTokenLight(config.colors.annotationMarkerFill);
|
|
1985
|
+
if (config.colors.annotationPlate)
|
|
1986
|
+
colors.annotationPlate = resolveTokenLight(config.colors.annotationPlate);
|
|
1829
1987
|
if (config.colors.positive) colors.positive = resolveTokenLight(config.colors.positive);
|
|
1830
1988
|
if (config.colors.negative) colors.negative = resolveTokenLight(config.colors.negative);
|
|
1831
1989
|
}
|
|
@@ -1900,6 +2058,13 @@ function collectTokenPairs(config) {
|
|
|
1900
2058
|
"axis",
|
|
1901
2059
|
"annotationFill",
|
|
1902
2060
|
"annotationText",
|
|
2061
|
+
"annotationLabel",
|
|
2062
|
+
"annotationMuted",
|
|
2063
|
+
"annotationLeader",
|
|
2064
|
+
"annotationRule",
|
|
2065
|
+
"annotationRangeFill",
|
|
2066
|
+
"annotationMarkerFill",
|
|
2067
|
+
"annotationPlate",
|
|
1903
2068
|
"positive",
|
|
1904
2069
|
"negative"
|
|
1905
2070
|
];
|
|
@@ -2000,6 +2165,22 @@ function resolveTheme(userTheme, base = DEFAULT_THEME) {
|
|
|
2000
2165
|
const dark = isDarkBackground(merged.colors.background);
|
|
2001
2166
|
if (dark) {
|
|
2002
2167
|
merged = adaptChromeForDarkBg(merged, merged.colors.text);
|
|
2168
|
+
const authoredColors = userTheme?.colors && !Array.isArray(userTheme.colors) ? userTheme.colors : {};
|
|
2169
|
+
for (const key of [
|
|
2170
|
+
"annotationLabel",
|
|
2171
|
+
"annotationMuted",
|
|
2172
|
+
"annotationLeader",
|
|
2173
|
+
"annotationRule",
|
|
2174
|
+
"annotationRangeFill",
|
|
2175
|
+
"annotationMarkerFill",
|
|
2176
|
+
"annotationPlate"
|
|
2177
|
+
]) {
|
|
2178
|
+
if (authoredColors[key] === void 0)
|
|
2179
|
+
merged.colors[key] = cssTokenDefault(
|
|
2180
|
+
`--oc-${key.replace(/[A-Z]/g, (c) => `-${c.toLowerCase()}`)}`,
|
|
2181
|
+
"dark"
|
|
2182
|
+
);
|
|
2183
|
+
}
|
|
2003
2184
|
}
|
|
2004
2185
|
return {
|
|
2005
2186
|
...merged,
|
|
@@ -2084,9 +2265,20 @@ function estimateLineCount(text, style, maxWidth, measureText, maxLines) {
|
|
|
2084
2265
|
}
|
|
2085
2266
|
var FOOTNOTE_LINE_HEIGHT = 1.3;
|
|
2086
2267
|
var FOOTNOTE_BAND_GAP = 4;
|
|
2087
|
-
function
|
|
2088
|
-
if (
|
|
2089
|
-
|
|
2268
|
+
function computeNoteBandHeight(input, theme) {
|
|
2269
|
+
if (typeof input !== "number" && input.noteBandHeight !== void 0) return input.noteBandHeight;
|
|
2270
|
+
const count = typeof input === "number" ? input : (input.footnotes?.reduce((sum, note) => sum + (note.lines?.length ?? 1), 0) ?? 0) + (input.seriesSummary?.reduce((sum, entry) => sum + entry.lines.length, 0) ?? 0);
|
|
2271
|
+
return count <= 0 ? 0 : count * theme.fonts.sizes.small * FOOTNOTE_LINE_HEIGHT + FOOTNOTE_BAND_GAP;
|
|
2272
|
+
}
|
|
2273
|
+
var warnedFootnoteBandHeight = false;
|
|
2274
|
+
function footnoteBandHeight(input, theme) {
|
|
2275
|
+
if (!warnedFootnoteBandHeight) {
|
|
2276
|
+
warnedFootnoteBandHeight = true;
|
|
2277
|
+
console.warn(
|
|
2278
|
+
"[openchart] footnoteBandHeight is deprecated; read layout.chrome.noteBandHeight."
|
|
2279
|
+
);
|
|
2280
|
+
}
|
|
2281
|
+
return computeNoteBandHeight(input, theme);
|
|
2090
2282
|
}
|
|
2091
2283
|
function computeChrome(chrome, theme, width, measureText, chromeMode = "full", padding, watermark = true, bottomLegendHeight = 0, crampedTitle = false) {
|
|
2092
2284
|
if (!chrome || chromeMode === "hidden") {
|
|
@@ -2600,6 +2792,10 @@ function buildD3Formatter(formatStr) {
|
|
|
2600
2792
|
}
|
|
2601
2793
|
function formatPercent(value, options) {
|
|
2602
2794
|
const fraction = options?.fraction ?? true;
|
|
2795
|
+
const percent = fraction ? value * 100 : value;
|
|
2796
|
+
if (Number.isFinite(percent) && percent !== 0 && Math.abs(percent) < 0.1) {
|
|
2797
|
+
return percent < 0 ? `>${FORMAT_PERCENT_RAW(-0.1)}%` : `<${FORMAT_PERCENT_RAW(0.1)}%`;
|
|
2798
|
+
}
|
|
2603
2799
|
if (fraction) {
|
|
2604
2800
|
return FORMAT_PERCENT_FRACTION(value);
|
|
2605
2801
|
}
|
|
@@ -2935,6 +3131,19 @@ function formatValue(value) {
|
|
|
2935
3131
|
}
|
|
2936
3132
|
|
|
2937
3133
|
// src/helpers/spec-builders.ts
|
|
3134
|
+
var warnedBuilderOptions = /* @__PURE__ */ new Set();
|
|
3135
|
+
function warnBuilderOption(key, message) {
|
|
3136
|
+
if (warnedBuilderOptions.has(key)) return;
|
|
3137
|
+
warnedBuilderOptions.add(key);
|
|
3138
|
+
console.warn(`[openchart] ${message}`);
|
|
3139
|
+
}
|
|
3140
|
+
function warnDarkMode(options) {
|
|
3141
|
+
if (options?.darkMode !== void 0)
|
|
3142
|
+
warnBuilderOption(
|
|
3143
|
+
"darkMode",
|
|
3144
|
+
"Builder darkMode is deprecated and has no effect; use the mount option."
|
|
3145
|
+
);
|
|
3146
|
+
}
|
|
2938
3147
|
var ISO_DATE_RE = /^\d{4}(-\d{2}(-\d{2}(T\d{2}(:\d{2}(:\d{2})?)?)?)?)?$/;
|
|
2939
3148
|
function inferFieldType(data, field) {
|
|
2940
3149
|
const sampleSize = Math.min(data.length, 20);
|
|
@@ -2979,12 +3188,12 @@ function buildEncoding(channels, options, data) {
|
|
|
2979
3188
|
return encoding;
|
|
2980
3189
|
}
|
|
2981
3190
|
function buildChartSpec(mark, data, encoding, options) {
|
|
3191
|
+
warnDarkMode(options);
|
|
2982
3192
|
const spec = { mark, data, encoding };
|
|
2983
3193
|
if (options?.chrome) spec.chrome = options.chrome;
|
|
2984
3194
|
if (options?.annotations) spec.annotations = options.annotations;
|
|
2985
3195
|
if (options?.responsive !== void 0) spec.responsive = options.responsive;
|
|
2986
3196
|
if (options?.theme) spec.theme = options.theme;
|
|
2987
|
-
if (options?.darkMode) spec.darkMode = options.darkMode;
|
|
2988
3197
|
return spec;
|
|
2989
3198
|
}
|
|
2990
3199
|
function lineChart(data, x, y, options) {
|
|
@@ -3048,6 +3257,9 @@ function scatterChart(data, x, y, options) {
|
|
|
3048
3257
|
return buildChartSpec("point", data, encoding, options);
|
|
3049
3258
|
}
|
|
3050
3259
|
function dataTable(data, options) {
|
|
3260
|
+
warnDarkMode(options);
|
|
3261
|
+
if (options?.compact !== void 0)
|
|
3262
|
+
warnBuilderOption("compact", "dataTable compact is deprecated; use density.");
|
|
3051
3263
|
let columns = options?.columns;
|
|
3052
3264
|
if (!columns && data.length > 0) {
|
|
3053
3265
|
columns = Object.keys(data[0]).map((key) => {
|
|
@@ -3068,15 +3280,16 @@ function dataTable(data, options) {
|
|
|
3068
3280
|
if (options?.rowKey) spec.rowKey = options.rowKey;
|
|
3069
3281
|
if (options?.chrome) spec.chrome = options.chrome;
|
|
3070
3282
|
if (options?.theme) spec.theme = options.theme;
|
|
3071
|
-
if (options?.darkMode) spec.darkMode = options.darkMode;
|
|
3072
3283
|
if (options?.search !== void 0) spec.search = options.search;
|
|
3073
3284
|
if (options?.pagination !== void 0) spec.pagination = options.pagination;
|
|
3074
3285
|
if (options?.stickyFirstColumn !== void 0) spec.stickyFirstColumn = options.stickyFirstColumn;
|
|
3075
|
-
if (options?.
|
|
3286
|
+
if (options?.density !== void 0) spec.density = options.density;
|
|
3287
|
+
else if (options?.compact !== void 0) spec.density = options.compact ? "condensed" : "regular";
|
|
3076
3288
|
if (options?.responsive !== void 0) spec.responsive = options.responsive;
|
|
3077
3289
|
return spec;
|
|
3078
3290
|
}
|
|
3079
3291
|
function tileMap(data, options) {
|
|
3292
|
+
warnDarkMode(options);
|
|
3080
3293
|
return {
|
|
3081
3294
|
type: "tilemap",
|
|
3082
3295
|
data,
|
|
@@ -3086,7 +3299,6 @@ function tileMap(data, options) {
|
|
|
3086
3299
|
...options?.chrome && { chrome: options.chrome },
|
|
3087
3300
|
...options?.legend && { legend: options.legend },
|
|
3088
3301
|
...options?.theme && { theme: options.theme },
|
|
3089
|
-
...options?.darkMode && { darkMode: options.darkMode },
|
|
3090
3302
|
...options?.watermark !== void 0 && { watermark: options.watermark },
|
|
3091
3303
|
...options?.animation && { animation: options.animation },
|
|
3092
3304
|
...options?.valueFormat && { valueFormat: options.valueFormat }
|
|
@@ -3107,6 +3319,28 @@ function deepMergeSpec(target, source) {
|
|
|
3107
3319
|
return result;
|
|
3108
3320
|
}
|
|
3109
3321
|
|
|
3322
|
+
// src/helpers/annotation-source.ts
|
|
3323
|
+
var object = (value) => value !== null && typeof value === "object" && !Array.isArray(value) ? value : void 0;
|
|
3324
|
+
function annotationSource(spec) {
|
|
3325
|
+
const root = object(spec);
|
|
3326
|
+
if (Array.isArray(root?.annotations))
|
|
3327
|
+
return { annotations: root.annotations, path: "/annotations" };
|
|
3328
|
+
function firstLeaf(node, path) {
|
|
3329
|
+
if (Array.isArray(node?.layer)) {
|
|
3330
|
+
for (const [index, child] of node.layer.entries()) {
|
|
3331
|
+
const result = firstLeaf(object(child), `${path}/layer/${index}`);
|
|
3332
|
+
if (result) return result;
|
|
3333
|
+
}
|
|
3334
|
+
} else if (node && "mark" in node) {
|
|
3335
|
+
return {
|
|
3336
|
+
annotations: Array.isArray(node.annotations) ? node.annotations : [],
|
|
3337
|
+
path: `${path}/annotations`
|
|
3338
|
+
};
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
return firstLeaf(root, "") ?? { annotations: [], path: "/annotations" };
|
|
3342
|
+
}
|
|
3343
|
+
|
|
3110
3344
|
// src/motion/sample.ts
|
|
3111
3345
|
var MOTION_REST_THRESHOLD = 1e-3;
|
|
3112
3346
|
var MAX_SPRING_DURATION = 1200;
|
|
@@ -3243,6 +3477,8 @@ export {
|
|
|
3243
3477
|
adaptColorForDarkMode,
|
|
3244
3478
|
adaptForLightLineStroke,
|
|
3245
3479
|
adaptTheme,
|
|
3480
|
+
annotationSource,
|
|
3481
|
+
applyEditTransaction,
|
|
3246
3482
|
areaChart,
|
|
3247
3483
|
axisTitleOffset,
|
|
3248
3484
|
barChart,
|
|
@@ -3256,6 +3492,7 @@ export {
|
|
|
3256
3492
|
computeChrome,
|
|
3257
3493
|
computeFieldFormatContext,
|
|
3258
3494
|
computeLabelBounds,
|
|
3495
|
+
computeNoteBandHeight,
|
|
3259
3496
|
computeXAxisExtentFromLabels,
|
|
3260
3497
|
contrastRatio,
|
|
3261
3498
|
cssTokenDefault,
|
|
@@ -3309,6 +3546,7 @@ export {
|
|
|
3309
3546
|
lineChart,
|
|
3310
3547
|
maxRotatedLabelWidth,
|
|
3311
3548
|
meetsAA,
|
|
3549
|
+
mergeThemeConfig,
|
|
3312
3550
|
motionCSS,
|
|
3313
3551
|
overlapArea,
|
|
3314
3552
|
pickLabelColor,
|