@opendata-ai/openchart-core 7.11.0 → 8.0.0-rc.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 +1154 -119
- package/dist/index.js +530 -41
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2 -1
- package/dist/styles.css.map +1 -0
- package/package.json +9 -3
- package/schema/chart.schema.json +8957 -0
- package/schema/table.schema.json +861 -0
- package/schema/vizspec.schema.json +17694 -0
- package/src/accessibility/alt-text.ts +39 -1
- package/src/accessibility/aria.ts +4 -2
- package/src/colors/__tests__/colorblind.test.ts +12 -0
- package/src/colors/colorblind.ts +11 -2
- package/src/colors/contrast.ts +11 -0
- package/src/colors/index.ts +9 -1
- package/src/colors/palettes.ts +47 -0
- package/src/helpers/__tests__/deep-merge.test.ts +54 -0
- package/src/helpers/__tests__/spec-builders.test.ts +3 -3
- package/src/helpers/deep-merge.ts +29 -0
- package/src/helpers/spec-builders.ts +7 -7
- package/src/index.ts +29 -1
- package/src/labels/collision.ts +1 -0
- package/src/layout/chrome.ts +24 -0
- package/src/layout/index.ts +1 -1
- package/src/locale/__tests__/format.test.ts +347 -11
- package/src/locale/format.ts +243 -18
- package/src/locale/index.ts +10 -1
- package/src/responsive/index.ts +2 -0
- package/src/responsive/metrics.ts +74 -9
- package/src/schema/__tests__/generated-artifacts.test.ts +42 -0
- package/src/schema/__tests__/schema.test.ts +179 -0
- package/src/styles/__tests__/reduced-motion-selectors.test.ts +28 -0
- package/src/styles/animation.css +197 -168
- package/src/styles/base.css +89 -62
- package/src/styles/chrome.css +173 -179
- package/src/styles/dark.css +38 -35
- package/src/styles/graph.css +116 -111
- package/src/styles/index.css +5 -0
- package/src/styles/keyframes.css +115 -100
- package/src/styles/legend.css +14 -12
- package/src/styles/reduced-motion.css +61 -40
- package/src/styles/series-search.css +153 -0
- package/src/styles/sparkline.css +14 -12
- package/src/styles/table-animation.css +82 -80
- package/src/styles/table.css +314 -302
- package/src/styles/token-definitions.ts +199 -0
- package/src/styles/tokens.css +132 -128
- package/src/styles/tooltip.css +109 -115
- package/src/styles/you-draw-it.css +126 -0
- package/src/types/__tests__/encoding.test.ts +86 -17
- package/src/types/__tests__/spec.test.ts +16 -12
- package/src/types/encoding.ts +69 -25
- package/src/types/events.ts +12 -0
- package/src/types/index.ts +39 -3
- package/src/types/layout.ts +414 -8
- package/src/types/schema-roots.ts +32 -0
- package/src/types/spec.ts +643 -84
- package/src/types/table.ts +3 -2
package/dist/index.js
CHANGED
|
@@ -15,8 +15,6 @@ var MARK_ENCODING_RULES = {
|
|
|
15
15
|
size: optional(),
|
|
16
16
|
opacity: optional("quantitative"),
|
|
17
17
|
tooltip: optional(),
|
|
18
|
-
href: optional(),
|
|
19
|
-
order: optional("quantitative", "ordinal"),
|
|
20
18
|
detail: optional("nominal")
|
|
21
19
|
},
|
|
22
20
|
line: {
|
|
@@ -27,8 +25,6 @@ var MARK_ENCODING_RULES = {
|
|
|
27
25
|
opacity: optional("quantitative"),
|
|
28
26
|
strokeDash: optional("nominal", "ordinal"),
|
|
29
27
|
tooltip: optional(),
|
|
30
|
-
href: optional(),
|
|
31
|
-
order: optional("quantitative", "ordinal"),
|
|
32
28
|
detail: optional("nominal")
|
|
33
29
|
},
|
|
34
30
|
area: {
|
|
@@ -39,8 +35,6 @@ var MARK_ENCODING_RULES = {
|
|
|
39
35
|
size: optional(),
|
|
40
36
|
opacity: optional("quantitative"),
|
|
41
37
|
tooltip: optional(),
|
|
42
|
-
href: optional(),
|
|
43
|
-
order: optional("quantitative", "ordinal"),
|
|
44
38
|
detail: optional("nominal")
|
|
45
39
|
},
|
|
46
40
|
point: {
|
|
@@ -48,11 +42,8 @@ var MARK_ENCODING_RULES = {
|
|
|
48
42
|
y: required("quantitative", "temporal", "nominal", "ordinal"),
|
|
49
43
|
color: optional("nominal", "ordinal", "quantitative"),
|
|
50
44
|
size: optional("quantitative"),
|
|
51
|
-
shape: optional("nominal", "ordinal"),
|
|
52
45
|
opacity: optional("quantitative"),
|
|
53
46
|
tooltip: optional(),
|
|
54
|
-
href: optional(),
|
|
55
|
-
order: optional("quantitative", "ordinal"),
|
|
56
47
|
detail: optional("nominal")
|
|
57
48
|
},
|
|
58
49
|
circle: {
|
|
@@ -62,8 +53,6 @@ var MARK_ENCODING_RULES = {
|
|
|
62
53
|
size: optional("quantitative"),
|
|
63
54
|
opacity: optional("quantitative"),
|
|
64
55
|
tooltip: optional(),
|
|
65
|
-
href: optional(),
|
|
66
|
-
order: optional("quantitative", "ordinal"),
|
|
67
56
|
detail: optional("nominal")
|
|
68
57
|
},
|
|
69
58
|
lollipop: {
|
|
@@ -73,21 +62,63 @@ var MARK_ENCODING_RULES = {
|
|
|
73
62
|
size: optional("quantitative"),
|
|
74
63
|
opacity: optional("quantitative"),
|
|
75
64
|
tooltip: optional(),
|
|
76
|
-
|
|
77
|
-
|
|
65
|
+
detail: optional("nominal")
|
|
66
|
+
},
|
|
67
|
+
beeswarm: {
|
|
68
|
+
x: optional("quantitative", "nominal", "ordinal"),
|
|
69
|
+
y: optional("quantitative", "nominal", "ordinal"),
|
|
70
|
+
color: optional("nominal", "ordinal", "quantitative"),
|
|
71
|
+
size: optional("quantitative"),
|
|
72
|
+
opacity: optional("quantitative"),
|
|
73
|
+
tooltip: optional(),
|
|
74
|
+
detail: optional("nominal")
|
|
75
|
+
},
|
|
76
|
+
// Range: x+x2 with nominal y (horizontal) or y+y2 with nominal x (vertical).
|
|
77
|
+
// The orientation-dependent x2/y2 requirement is enforced by a dedicated
|
|
78
|
+
// check in the validator; the static table can only mark them optional.
|
|
79
|
+
range: {
|
|
80
|
+
x: required("quantitative", "nominal", "ordinal"),
|
|
81
|
+
y: required("quantitative", "nominal", "ordinal"),
|
|
82
|
+
x2: optional("quantitative"),
|
|
83
|
+
y2: optional("quantitative"),
|
|
84
|
+
color: optional("nominal", "ordinal"),
|
|
85
|
+
size: optional(),
|
|
86
|
+
opacity: optional("quantitative"),
|
|
87
|
+
tooltip: optional(),
|
|
78
88
|
detail: optional("nominal")
|
|
79
89
|
},
|
|
80
90
|
arc: {
|
|
91
|
+
x: optional(),
|
|
92
|
+
y: optional("quantitative"),
|
|
93
|
+
theta: required("quantitative"),
|
|
94
|
+
color: required("nominal", "ordinal"),
|
|
95
|
+
size: optional(),
|
|
96
|
+
opacity: optional("quantitative"),
|
|
97
|
+
tooltip: optional(),
|
|
98
|
+
detail: optional("nominal")
|
|
99
|
+
},
|
|
100
|
+
waffle: {
|
|
101
|
+
x: optional(),
|
|
102
|
+
y: required("quantitative"),
|
|
103
|
+
color: required("nominal", "ordinal"),
|
|
104
|
+
size: optional(),
|
|
105
|
+
opacity: optional("quantitative"),
|
|
106
|
+
tooltip: optional(),
|
|
107
|
+
theta: optional("quantitative"),
|
|
108
|
+
detail: optional("nominal")
|
|
109
|
+
},
|
|
110
|
+
// parliament: hemicycle seat chart. Like arc/waffle, no positional axes;
|
|
111
|
+
// color is the party (required), theta the seat count (aliased to y in the
|
|
112
|
+
// sugar pass). y is accepted so the theta alias resolves before the rules
|
|
113
|
+
// check runs.
|
|
114
|
+
parliament: {
|
|
81
115
|
x: optional(),
|
|
82
116
|
y: required("quantitative"),
|
|
83
117
|
color: required("nominal", "ordinal"),
|
|
84
118
|
size: optional(),
|
|
85
119
|
opacity: optional("quantitative"),
|
|
86
120
|
tooltip: optional(),
|
|
87
|
-
href: optional(),
|
|
88
|
-
order: optional("quantitative", "ordinal"),
|
|
89
121
|
theta: optional("quantitative"),
|
|
90
|
-
radius: optional("quantitative"),
|
|
91
122
|
detail: optional("nominal")
|
|
92
123
|
},
|
|
93
124
|
text: {
|
|
@@ -98,7 +129,6 @@ var MARK_ENCODING_RULES = {
|
|
|
98
129
|
opacity: optional("quantitative"),
|
|
99
130
|
text: required(),
|
|
100
131
|
tooltip: optional(),
|
|
101
|
-
href: optional(),
|
|
102
132
|
detail: optional("nominal")
|
|
103
133
|
},
|
|
104
134
|
rule: {
|
|
@@ -111,7 +141,6 @@ var MARK_ENCODING_RULES = {
|
|
|
111
141
|
opacity: optional("quantitative"),
|
|
112
142
|
strokeDash: optional("nominal", "ordinal"),
|
|
113
143
|
tooltip: optional(),
|
|
114
|
-
href: optional(),
|
|
115
144
|
detail: optional("nominal")
|
|
116
145
|
},
|
|
117
146
|
tick: {
|
|
@@ -121,7 +150,6 @@ var MARK_ENCODING_RULES = {
|
|
|
121
150
|
size: optional(),
|
|
122
151
|
opacity: optional("quantitative"),
|
|
123
152
|
tooltip: optional(),
|
|
124
|
-
href: optional(),
|
|
125
153
|
detail: optional("nominal")
|
|
126
154
|
},
|
|
127
155
|
rect: {
|
|
@@ -133,12 +161,22 @@ var MARK_ENCODING_RULES = {
|
|
|
133
161
|
size: optional(),
|
|
134
162
|
opacity: optional("quantitative"),
|
|
135
163
|
tooltip: optional(),
|
|
136
|
-
|
|
137
|
-
|
|
164
|
+
detail: optional("nominal")
|
|
165
|
+
},
|
|
166
|
+
// calendar: x is the daily date (temporal), color the per-day value
|
|
167
|
+
// (quantitative). No y channel: the calendar computes its own
|
|
168
|
+
// weeks-x-weekdays geometry, so y is left optional here and the dedicated
|
|
169
|
+
// validator rejects it with a pointed message.
|
|
170
|
+
calendar: {
|
|
171
|
+
x: required("temporal"),
|
|
172
|
+
y: optional(),
|
|
173
|
+
color: required("quantitative"),
|
|
174
|
+
size: optional(),
|
|
175
|
+
opacity: optional("quantitative"),
|
|
176
|
+
tooltip: optional(),
|
|
138
177
|
detail: optional("nominal")
|
|
139
178
|
}
|
|
140
179
|
};
|
|
141
|
-
var CHART_ENCODING_RULES = MARK_ENCODING_RULES;
|
|
142
180
|
var GRAPH_ENCODING_RULES = {
|
|
143
181
|
nodeColor: { required: false, allowedTypes: ["nominal", "ordinal"] },
|
|
144
182
|
nodeSize: { required: false, allowedTypes: ["quantitative"] },
|
|
@@ -177,6 +215,10 @@ function isConditionalDef(def) {
|
|
|
177
215
|
if (!def) return false;
|
|
178
216
|
return "condition" in def;
|
|
179
217
|
}
|
|
218
|
+
function isValueDef(def) {
|
|
219
|
+
if (!def) return false;
|
|
220
|
+
return "value" in def && !("condition" in def) && !("field" in def);
|
|
221
|
+
}
|
|
180
222
|
var MARK_TYPES = /* @__PURE__ */ new Set([
|
|
181
223
|
"bar",
|
|
182
224
|
"line",
|
|
@@ -188,9 +230,16 @@ var MARK_TYPES = /* @__PURE__ */ new Set([
|
|
|
188
230
|
"rule",
|
|
189
231
|
"tick",
|
|
190
232
|
"rect",
|
|
191
|
-
"lollipop"
|
|
233
|
+
"lollipop",
|
|
234
|
+
"beeswarm",
|
|
235
|
+
"range",
|
|
236
|
+
"waffle",
|
|
237
|
+
"calendar",
|
|
238
|
+
"parliament"
|
|
192
239
|
]);
|
|
193
|
-
|
|
240
|
+
function isAxislessMark(markType) {
|
|
241
|
+
return markType === "arc" || markType === "waffle" || markType === "calendar" || markType === "parliament";
|
|
242
|
+
}
|
|
194
243
|
function resolveMarkType(mark) {
|
|
195
244
|
return typeof mark === "string" ? mark : mark.type;
|
|
196
245
|
}
|
|
@@ -218,6 +267,9 @@ function isTileMapSpec(spec) {
|
|
|
218
267
|
function isBarListSpec(spec) {
|
|
219
268
|
return "type" in spec && spec.type === "barlist";
|
|
220
269
|
}
|
|
270
|
+
function isMapSpec(spec) {
|
|
271
|
+
return "type" in spec && spec.type === "map";
|
|
272
|
+
}
|
|
221
273
|
function isTextAnnotation(annotation) {
|
|
222
274
|
return annotation.type === "text";
|
|
223
275
|
}
|
|
@@ -225,7 +277,8 @@ function isRangeAnnotation(annotation) {
|
|
|
225
277
|
return annotation.type === "range";
|
|
226
278
|
}
|
|
227
279
|
function isRefLineAnnotation(annotation) {
|
|
228
|
-
|
|
280
|
+
const type = annotation.type;
|
|
281
|
+
return type === "refline" || type === "rule";
|
|
229
282
|
}
|
|
230
283
|
var MARK_DISPLAY_NAMES = {
|
|
231
284
|
bar: "Bar chart",
|
|
@@ -239,7 +292,12 @@ var MARK_DISPLAY_NAMES = {
|
|
|
239
292
|
rule: "Rule chart",
|
|
240
293
|
tick: "Tick plot",
|
|
241
294
|
rect: "Heatmap",
|
|
242
|
-
lollipop: "Lollipop chart"
|
|
295
|
+
lollipop: "Lollipop chart",
|
|
296
|
+
beeswarm: "Beeswarm chart",
|
|
297
|
+
range: "Range plot",
|
|
298
|
+
waffle: "Waffle chart",
|
|
299
|
+
calendar: "Calendar heatmap",
|
|
300
|
+
parliament: "Parliament chart"
|
|
243
301
|
};
|
|
244
302
|
|
|
245
303
|
// ../../node_modules/.bun/d3-color@3.1.0/node_modules/d3-color/src/define.js
|
|
@@ -606,10 +664,16 @@ var TRITAN_MATRIX = [
|
|
|
606
664
|
[0, 0.433, 0.567],
|
|
607
665
|
[0, 0.475, 0.525]
|
|
608
666
|
];
|
|
667
|
+
var ACHROMAT_MATRIX = [
|
|
668
|
+
[0.2126, 0.7152, 0.0722],
|
|
669
|
+
[0.2126, 0.7152, 0.0722],
|
|
670
|
+
[0.2126, 0.7152, 0.0722]
|
|
671
|
+
];
|
|
609
672
|
var MATRICES = {
|
|
610
673
|
protanopia: PROTAN_MATRIX,
|
|
611
674
|
deuteranopia: DEUTAN_MATRIX,
|
|
612
|
-
tritanopia: TRITAN_MATRIX
|
|
675
|
+
tritanopia: TRITAN_MATRIX,
|
|
676
|
+
achromatopsia: ACHROMAT_MATRIX
|
|
613
677
|
};
|
|
614
678
|
function linearize(v) {
|
|
615
679
|
const s = v / 255;
|
|
@@ -654,6 +718,10 @@ function relativeLuminance(color2) {
|
|
|
654
718
|
const linear = srgb.map((v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4);
|
|
655
719
|
return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
|
|
656
720
|
}
|
|
721
|
+
function isOpaqueColor(color2) {
|
|
722
|
+
const c = rgb(color2);
|
|
723
|
+
return c != null && !Number.isNaN(c.r) && c.opacity === 1;
|
|
724
|
+
}
|
|
657
725
|
function contrastRatio(fg, bg) {
|
|
658
726
|
const l1 = relativeLuminance(fg);
|
|
659
727
|
const l2 = relativeLuminance(bg);
|
|
@@ -812,6 +880,30 @@ var DIVERGING_PALETTES = {
|
|
|
812
880
|
redBlue: [...DIVERGING_RED_BLUE.stops],
|
|
813
881
|
brownTeal: [...DIVERGING_BROWN_TEAL.stops]
|
|
814
882
|
};
|
|
883
|
+
var VL_SCHEME_ALIASES = {
|
|
884
|
+
blues: "blue",
|
|
885
|
+
greens: "green",
|
|
886
|
+
oranges: "orange",
|
|
887
|
+
purples: "purple",
|
|
888
|
+
teals: "teal",
|
|
889
|
+
redblue: "redBlue",
|
|
890
|
+
brownteal: "brownTeal",
|
|
891
|
+
// ColorBrewer BrBG, which brownTeal mirrors
|
|
892
|
+
brownbluegreen: "brownTeal",
|
|
893
|
+
category10: "categorical",
|
|
894
|
+
tableau10: "categorical"
|
|
895
|
+
};
|
|
896
|
+
function resolveSchemeName(name) {
|
|
897
|
+
const canonical = SEQUENTIAL_PALETTES[name] || DIVERGING_PALETTES[name] ? name : VL_SCHEME_ALIASES[name.toLowerCase()] ?? name.toLowerCase();
|
|
898
|
+
if (canonical === "categorical") return [...CATEGORICAL_PALETTE];
|
|
899
|
+
return SEQUENTIAL_PALETTES[canonical] ?? DIVERGING_PALETTES[canonical];
|
|
900
|
+
}
|
|
901
|
+
var SUPPORTED_SCHEME_NAMES = [
|
|
902
|
+
...Object.keys(SEQUENTIAL_PALETTES),
|
|
903
|
+
...Object.keys(DIVERGING_PALETTES),
|
|
904
|
+
"categorical",
|
|
905
|
+
...Object.keys(VL_SCHEME_ALIASES)
|
|
906
|
+
];
|
|
815
907
|
|
|
816
908
|
// src/layout/text-measure.ts
|
|
817
909
|
var CHAR_WIDTHS_400 = {
|
|
@@ -1232,6 +1324,7 @@ var X_AXIS_TITLE_BAND = 22;
|
|
|
1232
1324
|
var X_AXIS_TITLE_BAND_ROTATED = 20;
|
|
1233
1325
|
var X_AXIS_ROTATED_EXTENT_CAP = 120;
|
|
1234
1326
|
var TICK_LINE_HEIGHT_FACTOR = 1.2;
|
|
1327
|
+
var AXIS_TO_LABEL_GAP = 3;
|
|
1235
1328
|
function computeXAxisExtentFromLabels(input) {
|
|
1236
1329
|
const measure = input.measure ?? estimateTextWidth;
|
|
1237
1330
|
const baseHeight = input.xAxisHeight ?? X_AXIS_BAND_HEIGHT;
|
|
@@ -1243,7 +1336,6 @@ function computeXAxisExtentFromLabels(input) {
|
|
|
1243
1336
|
if (w > maxLabelWidth) maxLabelWidth = w;
|
|
1244
1337
|
}
|
|
1245
1338
|
const lineHeight = input.tickFontSize * TICK_LINE_HEIGHT_FACTOR;
|
|
1246
|
-
const AXIS_TO_LABEL_GAP = 3;
|
|
1247
1339
|
const rotatedHeight = Math.min(
|
|
1248
1340
|
maxLabelWidth * Math.sin(angleRad) + lineHeight * Math.cos(angleRad) + AXIS_TO_LABEL_GAP,
|
|
1249
1341
|
X_AXIS_ROTATED_EXTENT_CAP
|
|
@@ -1252,6 +1344,32 @@ function computeXAxisExtentFromLabels(input) {
|
|
|
1252
1344
|
}
|
|
1253
1345
|
return input.hasTitle ? baseHeight + X_AXIS_TITLE_BAND : baseHeight;
|
|
1254
1346
|
}
|
|
1347
|
+
function maxRotatedLabelWidth(tickAngle, tickFontSize) {
|
|
1348
|
+
const angleRad = Math.abs(tickAngle) * (Math.PI / 180);
|
|
1349
|
+
const sin = Math.sin(angleRad);
|
|
1350
|
+
if (sin <= 1e-3) return Number.POSITIVE_INFINITY;
|
|
1351
|
+
const lineHeight = tickFontSize * TICK_LINE_HEIGHT_FACTOR;
|
|
1352
|
+
const usable = X_AXIS_ROTATED_EXTENT_CAP - lineHeight * Math.cos(angleRad) - AXIS_TO_LABEL_GAP;
|
|
1353
|
+
return Math.max(0, usable / sin);
|
|
1354
|
+
}
|
|
1355
|
+
function truncateRotatedLabel(label, tickAngle, tickFontSize, tickFontWeight, measure = estimateTextWidth) {
|
|
1356
|
+
const budget = maxRotatedLabelWidth(tickAngle, tickFontSize);
|
|
1357
|
+
if (!Number.isFinite(budget)) return label;
|
|
1358
|
+
if (measure(label, tickFontSize, tickFontWeight) <= budget) return label;
|
|
1359
|
+
const ELLIPSIS = "\u2026";
|
|
1360
|
+
let lo = 0;
|
|
1361
|
+
let hi = label.length;
|
|
1362
|
+
while (lo < hi) {
|
|
1363
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
1364
|
+
const candidate = label.slice(0, mid) + ELLIPSIS;
|
|
1365
|
+
if (measure(candidate, tickFontSize, tickFontWeight) <= budget) {
|
|
1366
|
+
lo = mid;
|
|
1367
|
+
} else {
|
|
1368
|
+
hi = mid - 1;
|
|
1369
|
+
}
|
|
1370
|
+
}
|
|
1371
|
+
return lo > 0 ? label.slice(0, lo).trimEnd() + ELLIPSIS : ELLIPSIS;
|
|
1372
|
+
}
|
|
1255
1373
|
|
|
1256
1374
|
// src/theme/defaults.ts
|
|
1257
1375
|
var DEFAULT_THEME = {
|
|
@@ -1790,6 +1908,12 @@ function estimateLineCount(text, style, maxWidth, measureText) {
|
|
|
1790
1908
|
}
|
|
1791
1909
|
return lines;
|
|
1792
1910
|
}
|
|
1911
|
+
var FOOTNOTE_LINE_HEIGHT = 1.3;
|
|
1912
|
+
var FOOTNOTE_BAND_GAP = 4;
|
|
1913
|
+
function footnoteBandHeight(count, theme) {
|
|
1914
|
+
if (count <= 0) return 0;
|
|
1915
|
+
return count * theme.fonts.sizes.small * FOOTNOTE_LINE_HEIGHT + FOOTNOTE_BAND_GAP;
|
|
1916
|
+
}
|
|
1793
1917
|
function computeChrome(chrome, theme, width, measureText, chromeMode = "full", padding, watermark = true, bottomLegendHeight = 0) {
|
|
1794
1918
|
if (!chrome || chromeMode === "hidden") {
|
|
1795
1919
|
return { topHeight: 0, bottomHeight: 0 };
|
|
@@ -2118,7 +2242,8 @@ function resolveCollisions(labels, strategies = OFFSET_STRATEGIES) {
|
|
|
2118
2242
|
from: { x: bestX, y: bestY },
|
|
2119
2243
|
to: { x: label.anchorX, y: label.anchorY },
|
|
2120
2244
|
stroke: label.style.fill,
|
|
2121
|
-
style: "straight"
|
|
2245
|
+
style: "straight",
|
|
2246
|
+
arrow: false
|
|
2122
2247
|
} : void 0
|
|
2123
2248
|
});
|
|
2124
2249
|
} else {
|
|
@@ -3145,30 +3270,65 @@ function formatNumber(value, _locale) {
|
|
|
3145
3270
|
if (Number.isInteger(value)) {
|
|
3146
3271
|
return format(",")(value);
|
|
3147
3272
|
}
|
|
3273
|
+
if (Math.abs(value) < 5e-3) {
|
|
3274
|
+
return format(".2~r")(value);
|
|
3275
|
+
}
|
|
3148
3276
|
return format(",.2f")(value);
|
|
3149
3277
|
}
|
|
3150
|
-
var
|
|
3278
|
+
var UNIT_TABLE = [
|
|
3151
3279
|
{ threshold: 1e12, suffix: "T", divisor: 1e12 },
|
|
3152
3280
|
{ threshold: 1e9, suffix: "B", divisor: 1e9 },
|
|
3153
3281
|
{ threshold: 1e6, suffix: "M", divisor: 1e6 },
|
|
3154
|
-
{ threshold: 1e3, suffix: "
|
|
3282
|
+
{ threshold: 1e3, suffix: "k", divisor: 1e3 }
|
|
3155
3283
|
];
|
|
3284
|
+
function unitFor(abs) {
|
|
3285
|
+
for (const entry of UNIT_TABLE) {
|
|
3286
|
+
if (abs >= entry.threshold) return entry;
|
|
3287
|
+
}
|
|
3288
|
+
return { suffix: "", divisor: 1 };
|
|
3289
|
+
}
|
|
3290
|
+
function fractionDigits(x) {
|
|
3291
|
+
const a = Math.abs(x);
|
|
3292
|
+
for (let p = 0; p <= 3; p++) {
|
|
3293
|
+
const scaled = a * 10 ** p;
|
|
3294
|
+
if (Math.abs(scaled - Math.round(scaled)) < 1e-9) return p;
|
|
3295
|
+
}
|
|
3296
|
+
return 4;
|
|
3297
|
+
}
|
|
3156
3298
|
function abbreviateNumber(value) {
|
|
3157
3299
|
if (!Number.isFinite(value)) return String(value);
|
|
3158
3300
|
const absValue = Math.abs(value);
|
|
3159
3301
|
const sign = value < 0 ? "-" : "";
|
|
3160
|
-
for (
|
|
3302
|
+
for (let i = 0; i < UNIT_TABLE.length; i++) {
|
|
3303
|
+
const { threshold, suffix, divisor } = UNIT_TABLE[i];
|
|
3161
3304
|
if (absValue >= threshold) {
|
|
3162
|
-
const
|
|
3163
|
-
|
|
3164
|
-
|
|
3305
|
+
const mantissa = format(".1~f")(absValue / divisor);
|
|
3306
|
+
if (mantissa === "1000" && i > 0) {
|
|
3307
|
+
return `${sign}1${UNIT_TABLE[i - 1].suffix}`;
|
|
3308
|
+
}
|
|
3309
|
+
return `${sign}${mantissa}${suffix}`;
|
|
3165
3310
|
}
|
|
3166
3311
|
}
|
|
3167
3312
|
return formatNumber(value);
|
|
3168
3313
|
}
|
|
3314
|
+
function formatOrdinal(value) {
|
|
3315
|
+
if (!Number.isFinite(value)) return String(value);
|
|
3316
|
+
const n = Math.round(value);
|
|
3317
|
+
const abs = Math.abs(n);
|
|
3318
|
+
const rem100 = abs % 100;
|
|
3319
|
+
const rem10 = abs % 10;
|
|
3320
|
+
let suffix;
|
|
3321
|
+
if (rem100 >= 11 && rem100 <= 13) suffix = "th";
|
|
3322
|
+
else if (rem10 === 1) suffix = "st";
|
|
3323
|
+
else if (rem10 === 2) suffix = "nd";
|
|
3324
|
+
else if (rem10 === 3) suffix = "rd";
|
|
3325
|
+
else suffix = "th";
|
|
3326
|
+
return `${n}${suffix}`;
|
|
3327
|
+
}
|
|
3169
3328
|
var D3_FORMAT_SUFFIX_RE = /^(.*~?[efgsrdxXobcnp%])(.+)$/;
|
|
3170
3329
|
function buildD3Formatter(formatStr) {
|
|
3171
3330
|
if (!formatStr) return null;
|
|
3331
|
+
if (formatStr === "ordinal") return formatOrdinal;
|
|
3172
3332
|
try {
|
|
3173
3333
|
const fmt = format(formatStr);
|
|
3174
3334
|
if (formatStr.includes("s")) {
|
|
@@ -3188,6 +3348,111 @@ function buildD3Formatter(formatStr) {
|
|
|
3188
3348
|
}
|
|
3189
3349
|
return null;
|
|
3190
3350
|
}
|
|
3351
|
+
function formatPercent(value, options) {
|
|
3352
|
+
const fraction = options?.fraction ?? true;
|
|
3353
|
+
if (fraction) {
|
|
3354
|
+
return format(".1~%")(value);
|
|
3355
|
+
}
|
|
3356
|
+
return `${format(",.1~f")(value)}%`;
|
|
3357
|
+
}
|
|
3358
|
+
function formatCurrency(value, options) {
|
|
3359
|
+
const compact = options?.compact ?? false;
|
|
3360
|
+
const abs = Math.abs(value);
|
|
3361
|
+
const sign = value < 0 ? "-" : "";
|
|
3362
|
+
if (compact) {
|
|
3363
|
+
if (abs >= 1e3) {
|
|
3364
|
+
return `${sign}$${abbreviateNumber(abs)}`;
|
|
3365
|
+
}
|
|
3366
|
+
return `${sign}$${formatNumber(abs)}`;
|
|
3367
|
+
}
|
|
3368
|
+
if (Number.isInteger(value)) {
|
|
3369
|
+
return sign + format("$,")(abs);
|
|
3370
|
+
}
|
|
3371
|
+
return sign + format("$,.2f")(abs);
|
|
3372
|
+
}
|
|
3373
|
+
function computeFieldFormatContext(values, surface) {
|
|
3374
|
+
let min = Infinity;
|
|
3375
|
+
let max = -Infinity;
|
|
3376
|
+
let allIntegers = true;
|
|
3377
|
+
let hasFinite = false;
|
|
3378
|
+
for (const raw of values) {
|
|
3379
|
+
const v = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
|
|
3380
|
+
if (!Number.isFinite(v)) continue;
|
|
3381
|
+
hasFinite = true;
|
|
3382
|
+
if (v < min) min = v;
|
|
3383
|
+
if (v > max) max = v;
|
|
3384
|
+
if (allIntegers && !Number.isInteger(v)) allIntegers = false;
|
|
3385
|
+
}
|
|
3386
|
+
const ctx = {};
|
|
3387
|
+
if (hasFinite) {
|
|
3388
|
+
ctx.extent = [min, max];
|
|
3389
|
+
ctx.allIntegers = allIntegers;
|
|
3390
|
+
}
|
|
3391
|
+
if (surface) ctx.surface = surface;
|
|
3392
|
+
return ctx;
|
|
3393
|
+
}
|
|
3394
|
+
function isYearContext(ctx) {
|
|
3395
|
+
if (!ctx?.extent || !ctx.allIntegers) return false;
|
|
3396
|
+
const [min, max] = ctx.extent;
|
|
3397
|
+
return min >= 1500 && max <= 2500;
|
|
3398
|
+
}
|
|
3399
|
+
function resolveNumberFormatter(formatStr, ctx) {
|
|
3400
|
+
if (!formatStr) return null;
|
|
3401
|
+
if (formatStr === "ordinal") return formatOrdinal;
|
|
3402
|
+
if (formatStr === "percent") {
|
|
3403
|
+
const fraction = ctx?.extent ? Math.max(Math.abs(ctx.extent[0]), Math.abs(ctx.extent[1])) <= 1 : true;
|
|
3404
|
+
return (v) => formatPercent(v, { fraction });
|
|
3405
|
+
}
|
|
3406
|
+
if (formatStr === "currency") {
|
|
3407
|
+
const isTable = ctx?.surface === "table";
|
|
3408
|
+
if (!isTable && ctx?.step != null && (ctx.stepReference ?? 0) >= 1e3) {
|
|
3409
|
+
const stepFmt = buildCompactStepFormatter(ctx.step);
|
|
3410
|
+
return (v) => {
|
|
3411
|
+
const sign = v < 0 ? "-" : "";
|
|
3412
|
+
return `${sign}$${stepFmt(Math.abs(v))}`;
|
|
3413
|
+
};
|
|
3414
|
+
}
|
|
3415
|
+
return (v) => formatCurrency(v, { compact: !isTable });
|
|
3416
|
+
}
|
|
3417
|
+
return buildD3Formatter(formatStr);
|
|
3418
|
+
}
|
|
3419
|
+
function defaultNumberFormatter(ctx) {
|
|
3420
|
+
if (isYearContext(ctx)) {
|
|
3421
|
+
return (v) => String(Math.round(v));
|
|
3422
|
+
}
|
|
3423
|
+
if (ctx?.surface === "table") {
|
|
3424
|
+
return formatNumber;
|
|
3425
|
+
}
|
|
3426
|
+
if (ctx?.step != null && (ctx.stepReference ?? maxAbs(ctx.extent)) >= 1e3) {
|
|
3427
|
+
return buildCompactStepFormatter(ctx.step);
|
|
3428
|
+
}
|
|
3429
|
+
return (v) => {
|
|
3430
|
+
if (!Number.isFinite(v)) return String(v);
|
|
3431
|
+
if (ctx?.extent === void 0 && ctx?.allIntegers === void 0) {
|
|
3432
|
+
if (Number.isInteger(v) && v >= 1500 && v <= 2500) return String(v);
|
|
3433
|
+
}
|
|
3434
|
+
return Math.abs(v) >= 1e3 ? abbreviateNumber(v) : formatNumber(v);
|
|
3435
|
+
};
|
|
3436
|
+
}
|
|
3437
|
+
function maxAbs(extent) {
|
|
3438
|
+
if (!extent) return 0;
|
|
3439
|
+
return Math.max(Math.abs(extent[0]), Math.abs(extent[1]));
|
|
3440
|
+
}
|
|
3441
|
+
function buildCompactStepFormatter(step) {
|
|
3442
|
+
return (v) => {
|
|
3443
|
+
if (v === 0) return "0";
|
|
3444
|
+
if (!Number.isFinite(v)) return String(v);
|
|
3445
|
+
const abs = Math.abs(v);
|
|
3446
|
+
if (abs < 1e3) return formatNumber(v);
|
|
3447
|
+
const { suffix, divisor } = unitFor(abs);
|
|
3448
|
+
const p = fractionDigits(step / divisor);
|
|
3449
|
+
if (p > 2) {
|
|
3450
|
+
return Number.isInteger(v) ? format(",")(v) : format(",.2f")(v);
|
|
3451
|
+
}
|
|
3452
|
+
const sign = v < 0 ? "-" : "";
|
|
3453
|
+
return sign + format(`.${p}~f`)(abs / divisor) + suffix;
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3191
3456
|
var GRANULARITY_FORMATS = {
|
|
3192
3457
|
year: "%Y",
|
|
3193
3458
|
quarter: "",
|
|
@@ -3262,7 +3527,34 @@ function generateAltText(spec, data) {
|
|
|
3262
3527
|
const titleText = typeof title === "string" ? title : title.text;
|
|
3263
3528
|
parts.push(`showing ${titleText}`);
|
|
3264
3529
|
}
|
|
3265
|
-
if (
|
|
3530
|
+
if (markType === "waffle") {
|
|
3531
|
+
const units = markDef.units ?? 100;
|
|
3532
|
+
parts.push(`dividing ${units} units`);
|
|
3533
|
+
}
|
|
3534
|
+
if (markType === "parliament") {
|
|
3535
|
+
const valueField = spec.encoding.theta?.field ?? spec.encoding.y?.field;
|
|
3536
|
+
if (valueField) {
|
|
3537
|
+
const totalSeats = data.reduce((sum, d) => {
|
|
3538
|
+
const v = Number(d[valueField]);
|
|
3539
|
+
return sum + (Number.isFinite(v) && v > 0 ? v : 0);
|
|
3540
|
+
}, 0);
|
|
3541
|
+
if (totalSeats > 0) {
|
|
3542
|
+
const majority = Math.floor(totalSeats / 2) + 1;
|
|
3543
|
+
parts.push(`with ${totalSeats} seats, ${majority} needed for a majority`);
|
|
3544
|
+
}
|
|
3545
|
+
}
|
|
3546
|
+
}
|
|
3547
|
+
if (markType === "beeswarm") {
|
|
3548
|
+
const xIsValue = spec.encoding.x?.type === "quantitative";
|
|
3549
|
+
const valueField = xIsValue ? spec.encoding.x?.field : spec.encoding.y?.field;
|
|
3550
|
+
const laneField = xIsValue ? spec.encoding.y?.field : spec.encoding.x?.field;
|
|
3551
|
+
if (valueField) {
|
|
3552
|
+
parts.push(
|
|
3553
|
+
`plotting the distribution of ${valueField}${laneField ? ` by ${laneField}` : ""}`
|
|
3554
|
+
);
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
if (spec.encoding.x && markType !== "beeswarm" && data.length > 0) {
|
|
3266
3558
|
const field = spec.encoding.x.field;
|
|
3267
3559
|
const values = data.map((d) => d[field]).filter((v) => v != null);
|
|
3268
3560
|
if (values.length > 0) {
|
|
@@ -3347,11 +3639,12 @@ function generateAriaLabels(marks) {
|
|
|
3347
3639
|
}
|
|
3348
3640
|
return labels;
|
|
3349
3641
|
}
|
|
3642
|
+
var ariaNumberFormatter = defaultNumberFormatter();
|
|
3350
3643
|
function formatValue(value) {
|
|
3351
3644
|
if (value == null) return "N/A";
|
|
3352
3645
|
if (value instanceof Date) return value.toISOString().slice(0, 10);
|
|
3353
3646
|
if (typeof value === "number") {
|
|
3354
|
-
return
|
|
3647
|
+
return ariaNumberFormatter(value);
|
|
3355
3648
|
}
|
|
3356
3649
|
return String(value);
|
|
3357
3650
|
}
|
|
@@ -3431,7 +3724,7 @@ function pieChart(data, category, value, options) {
|
|
|
3431
3724
|
const categoryChannel = resolveField(category, data);
|
|
3432
3725
|
const valueChannel = resolveField(value, data);
|
|
3433
3726
|
const encoding = {
|
|
3434
|
-
|
|
3727
|
+
theta: valueChannel,
|
|
3435
3728
|
color: categoryChannel
|
|
3436
3729
|
};
|
|
3437
3730
|
if (options?.size && data) {
|
|
@@ -3449,7 +3742,7 @@ function donutChart(data, category, value, options) {
|
|
|
3449
3742
|
const categoryChannel = resolveField(category, data);
|
|
3450
3743
|
const valueChannel = resolveField(value, data);
|
|
3451
3744
|
const encoding = {
|
|
3452
|
-
|
|
3745
|
+
theta: valueChannel,
|
|
3453
3746
|
color: categoryChannel
|
|
3454
3747
|
};
|
|
3455
3748
|
if (options?.size && data) {
|
|
@@ -3514,6 +3807,182 @@ function tileMap(data, options) {
|
|
|
3514
3807
|
...options?.valueFormat && { valueFormat: options.valueFormat }
|
|
3515
3808
|
};
|
|
3516
3809
|
}
|
|
3810
|
+
|
|
3811
|
+
// src/helpers/deep-merge.ts
|
|
3812
|
+
function deepMergeSpec(target, source) {
|
|
3813
|
+
if (source === void 0) return target;
|
|
3814
|
+
if (source === null) return source;
|
|
3815
|
+
if (typeof source !== "object" || Array.isArray(source) || typeof target !== "object" || target === null || Array.isArray(target)) {
|
|
3816
|
+
return source;
|
|
3817
|
+
}
|
|
3818
|
+
const result = { ...target };
|
|
3819
|
+
for (const key of Object.keys(source)) {
|
|
3820
|
+
result[key] = deepMergeSpec(target[key], source[key]);
|
|
3821
|
+
}
|
|
3822
|
+
return result;
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
// src/styles/token-definitions.ts
|
|
3826
|
+
var CSS_TOKEN_ROOT_SELECTORS = [
|
|
3827
|
+
".oc-root",
|
|
3828
|
+
".oc-chart-root",
|
|
3829
|
+
".oc-table-wrapper",
|
|
3830
|
+
".oc-table-root",
|
|
3831
|
+
".oc-graph-wrapper",
|
|
3832
|
+
".oc-graph-root",
|
|
3833
|
+
".oc-sankey-root",
|
|
3834
|
+
".oc-tilemap-root",
|
|
3835
|
+
".oc-barlist-root",
|
|
3836
|
+
".oc-map-root"
|
|
3837
|
+
];
|
|
3838
|
+
var CSS_TOKENS = [
|
|
3839
|
+
{
|
|
3840
|
+
name: "--oc-font-family",
|
|
3841
|
+
light: '\n "Inter Variable", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
3842
|
+
},
|
|
3843
|
+
{
|
|
3844
|
+
name: "--oc-font-mono",
|
|
3845
|
+
light: '"JetBrains Mono", "Fira Code", "Cascadia Code", monospace'
|
|
3846
|
+
},
|
|
3847
|
+
{
|
|
3848
|
+
section: "Animation easing presets via CSS linear()",
|
|
3849
|
+
name: "--oc-ease-smooth",
|
|
3850
|
+
light: "linear(\n 0,\n 0.157,\n 0.438,\n 0.64,\n 0.766,\n 0.85,\n 0.906,\n 0.941,\n 0.964,\n 0.978,\n 0.988,\n 0.994,\n 0.998,\n 1\n )"
|
|
3851
|
+
},
|
|
3852
|
+
{
|
|
3853
|
+
name: "--oc-ease-snappy",
|
|
3854
|
+
light: "linear(\n 0,\n 0.012,\n 0.048,\n 0.108,\n 0.194,\n 0.302,\n 0.426,\n 0.559,\n 0.69,\n 0.808,\n 0.905,\n 0.973,\n 1.013,\n 1.028,\n 1.023,\n 1.006,\n 0.984,\n 0.966,\n 0.957,\n 0.957,\n 0.964,\n 0.975,\n 0.986,\n 0.995,\n 1,\n 1.003,\n 1.002,\n 1,\n 0.998,\n 0.998,\n 0.999,\n 1\n )",
|
|
3855
|
+
consumers: "EASE_VAR_MAP in vanilla renderers"
|
|
3856
|
+
},
|
|
3857
|
+
{ section: "Animation timing defaults", name: "--oc-animation-duration", light: "500ms" },
|
|
3858
|
+
{ name: "--oc-animation-stagger", light: "80ms" },
|
|
3859
|
+
{ name: "--oc-annotation-delay", light: "200ms" },
|
|
3860
|
+
{ section: "Typography scale (editorial design system)", name: "--oc-title-size", light: "26px" },
|
|
3861
|
+
{ name: "--oc-title-weight", light: "590" },
|
|
3862
|
+
{ name: "--oc-title-tracking", light: "-0.022em" },
|
|
3863
|
+
{ name: "--oc-subtitle-size", light: "14px" },
|
|
3864
|
+
{ name: "--oc-subtitle-weight", light: "450" },
|
|
3865
|
+
{ name: "--oc-source-size", light: "11px" },
|
|
3866
|
+
{ name: "--oc-source-weight", light: "450" },
|
|
3867
|
+
{ name: "--oc-body-size", light: "13px" },
|
|
3868
|
+
{ name: "--oc-eyebrow-size", light: "11px" },
|
|
3869
|
+
{ name: "--oc-eyebrow-weight", light: "550" },
|
|
3870
|
+
{ name: "--oc-eyebrow-tracking", light: "0.08em" },
|
|
3871
|
+
{ section: "Surfaces (light mode defaults)", name: "--oc-bg", light: "#ffffff", dark: "#09090b" },
|
|
3872
|
+
{ name: "--oc-card", light: "#ffffff", dark: "#111113" },
|
|
3873
|
+
{
|
|
3874
|
+
name: "--oc-secondary",
|
|
3875
|
+
light: "#f4f4f5",
|
|
3876
|
+
dark: "#27272a",
|
|
3877
|
+
comment: "zinc-100, raised surface"
|
|
3878
|
+
},
|
|
3879
|
+
{
|
|
3880
|
+
section: `Text levels. Names invert across modes: in light mode "muted" sits at
|
|
3881
|
+
* a lighter zinc step than "subtle" because both are picked relative to
|
|
3882
|
+
* the active background, not from a fixed lightness ladder. The intent
|
|
3883
|
+
* is "muted = first step away from primary text"; "subtle = next step
|
|
3884
|
+
* down"; etc.
|
|
3885
|
+
*
|
|
3886
|
+
* Light mode: text=zinc-950, secondary=zinc-700, muted=zinc-500,
|
|
3887
|
+
* subtle=zinc-400, faint=zinc-300
|
|
3888
|
+
* Dark mode (dark.css): inverts the surface tokens but keeps the same
|
|
3889
|
+
* muted -> subtle -> faint progression away from primary.`,
|
|
3890
|
+
name: "--oc-text",
|
|
3891
|
+
light: "#09090b",
|
|
3892
|
+
dark: "#f7f8f8"
|
|
3893
|
+
},
|
|
3894
|
+
{ name: "--oc-text-secondary", light: "#3f3f46", dark: "#d0d6e0" },
|
|
3895
|
+
{ name: "--oc-text-muted", light: "#71717a", dark: "#a1a1aa" },
|
|
3896
|
+
{ name: "--oc-text-faint", light: "#d4d4d8", dark: "#52525b" },
|
|
3897
|
+
{
|
|
3898
|
+
section: "Lines",
|
|
3899
|
+
name: "--oc-gridline",
|
|
3900
|
+
light: "rgba(0, 0, 0, 0.1)",
|
|
3901
|
+
dark: "rgba(255, 255, 255, 0.05)"
|
|
3902
|
+
},
|
|
3903
|
+
{
|
|
3904
|
+
name: "--oc-axis",
|
|
3905
|
+
light: "rgba(0, 0, 0, 0.1)",
|
|
3906
|
+
dark: "rgba(255, 255, 255, 0.1)"
|
|
3907
|
+
},
|
|
3908
|
+
{
|
|
3909
|
+
name: "--oc-border",
|
|
3910
|
+
light: "rgba(0, 0, 0, 0.08)",
|
|
3911
|
+
dark: "rgba(255, 255, 255, 0.1)"
|
|
3912
|
+
},
|
|
3913
|
+
{ name: "--oc-border-radius", light: "2px" },
|
|
3914
|
+
{
|
|
3915
|
+
section: "Brand and semantic",
|
|
3916
|
+
name: "--oc-accent",
|
|
3917
|
+
light: "#06b6d4",
|
|
3918
|
+
dark: "#06b6d4"
|
|
3919
|
+
},
|
|
3920
|
+
{
|
|
3921
|
+
name: "--oc-accent-strong",
|
|
3922
|
+
light: "#0891b2",
|
|
3923
|
+
dark: "#06b6d4",
|
|
3924
|
+
comment: "darker cyan for line strokes on light bg",
|
|
3925
|
+
consumers: "stamped via adaptForLightLineStroke"
|
|
3926
|
+
},
|
|
3927
|
+
{ name: "--oc-positive", light: "#10b981", dark: "#34d399" },
|
|
3928
|
+
{ name: "--oc-negative", light: "#e11d48", dark: "#fb7185" },
|
|
3929
|
+
{ name: "--oc-focus", light: "#3b82f6", dark: "#60a5fa" },
|
|
3930
|
+
{
|
|
3931
|
+
name: "--oc-focus-ring",
|
|
3932
|
+
light: "rgba(59, 130, 246, 0.1)",
|
|
3933
|
+
comment: "static, intentionally NOT derived from --oc-focus and NOT flipped in dark mode"
|
|
3934
|
+
},
|
|
3935
|
+
{
|
|
3936
|
+
name: "--oc-focus-ring-strong",
|
|
3937
|
+
light: "rgba(59, 130, 246, 0.25)"
|
|
3938
|
+
},
|
|
3939
|
+
{
|
|
3940
|
+
name: "--oc-editable-hover",
|
|
3941
|
+
light: "rgba(79, 70, 229, 0.35)",
|
|
3942
|
+
comment: "edit-mode hover outline, indigo one-off"
|
|
3943
|
+
},
|
|
3944
|
+
{
|
|
3945
|
+
section: "Spacing scale (4px base) \u2014 only --oc-space-2/4 are consumed (JS-stamped)",
|
|
3946
|
+
name: "--oc-space-2",
|
|
3947
|
+
light: "8px",
|
|
3948
|
+
consumers: "stamped at mount from theme.spacing (theme-tokens.ts); component CSS must NOT consume these"
|
|
3949
|
+
},
|
|
3950
|
+
{
|
|
3951
|
+
name: "--oc-space-4",
|
|
3952
|
+
light: "16px",
|
|
3953
|
+
consumers: "stamped at mount from theme.spacing (theme-tokens.ts); component CSS must NOT consume these"
|
|
3954
|
+
},
|
|
3955
|
+
{
|
|
3956
|
+
section: "Interactive states",
|
|
3957
|
+
name: "--oc-hover-bg",
|
|
3958
|
+
light: "rgba(0, 0, 0, 0.025)",
|
|
3959
|
+
dark: "rgba(255, 255, 255, 0.05)"
|
|
3960
|
+
},
|
|
3961
|
+
{
|
|
3962
|
+
name: "--oc-tooltip-bg",
|
|
3963
|
+
light: "rgba(255, 255, 255, 0.88)",
|
|
3964
|
+
dark: "rgba(17, 17, 19, 0.92)"
|
|
3965
|
+
},
|
|
3966
|
+
{
|
|
3967
|
+
name: "--oc-tooltip-border",
|
|
3968
|
+
light: "rgba(0, 0, 0, 0.08)",
|
|
3969
|
+
dark: "rgba(255, 255, 255, 0.08)"
|
|
3970
|
+
},
|
|
3971
|
+
{
|
|
3972
|
+
name: "--oc-tooltip-shadow",
|
|
3973
|
+
light: "0 2px 8px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.12)",
|
|
3974
|
+
dark: "0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4)"
|
|
3975
|
+
},
|
|
3976
|
+
{ name: "--oc-tooltip-text", light: "#09090b", dark: "#f7f8f8" },
|
|
3977
|
+
{ name: "--oc-legend-text", light: "#3f3f46", dark: "#d0d6e0" }
|
|
3978
|
+
];
|
|
3979
|
+
var TOKEN_MAP = new Map(CSS_TOKENS.map((t) => [t.name, t]));
|
|
3980
|
+
function cssTokenDefault(name, mode) {
|
|
3981
|
+
const token = TOKEN_MAP.get(name);
|
|
3982
|
+
if (!token) throw new Error(`Unknown CSS token: ${name}`);
|
|
3983
|
+
if (mode === "dark" && token.dark !== void 0) return token.dark;
|
|
3984
|
+
return token.light;
|
|
3985
|
+
}
|
|
3517
3986
|
export {
|
|
3518
3987
|
ACHROMATIC_RAMP,
|
|
3519
3988
|
AXIS_TITLE_GAP,
|
|
@@ -3526,12 +3995,13 @@ export {
|
|
|
3526
3995
|
BREAKPOINT_COMPACT_MAX,
|
|
3527
3996
|
BREAKPOINT_MEDIUM_MAX,
|
|
3528
3997
|
CATEGORICAL_PALETTE,
|
|
3529
|
-
CHART_ENCODING_RULES,
|
|
3530
|
-
CHART_TYPES,
|
|
3531
3998
|
COMPACT_WIDTH,
|
|
3999
|
+
CSS_TOKENS,
|
|
4000
|
+
CSS_TOKEN_ROOT_SELECTORS,
|
|
3532
4001
|
DEFAULT_THEME,
|
|
3533
4002
|
DIVERGING_PALETTES,
|
|
3534
4003
|
EXTENDED_OFFSET_STRATEGIES,
|
|
4004
|
+
FOOTNOTE_LINE_HEIGHT,
|
|
3535
4005
|
GRAPH_ENCODING_RULES,
|
|
3536
4006
|
HEIGHT_CRAMPED_MAX,
|
|
3537
4007
|
HEIGHT_SHORT_MAX,
|
|
@@ -3550,6 +4020,7 @@ export {
|
|
|
3550
4020
|
NARROW_VIEWPORT_MAX,
|
|
3551
4021
|
OFFSET_STRATEGIES,
|
|
3552
4022
|
SEQUENTIAL_PALETTES,
|
|
4023
|
+
SUPPORTED_SCHEME_NAMES,
|
|
3553
4024
|
TICK_LABEL_OFFSET,
|
|
3554
4025
|
TICK_LINE_HEIGHT_FACTOR,
|
|
3555
4026
|
TOP_PAD_EXTRA_NARROW,
|
|
@@ -3565,15 +4036,20 @@ export {
|
|
|
3565
4036
|
areaChart,
|
|
3566
4037
|
axisTitleOffset,
|
|
3567
4038
|
barChart,
|
|
4039
|
+
buildCompactStepFormatter,
|
|
3568
4040
|
buildD3Formatter,
|
|
3569
4041
|
buildTemporalFormatter,
|
|
3570
4042
|
checkPaletteDistinguishability,
|
|
3571
4043
|
columnChart,
|
|
3572
4044
|
computeChrome,
|
|
4045
|
+
computeFieldFormatContext,
|
|
3573
4046
|
computeLabelBounds,
|
|
3574
4047
|
computeXAxisExtentFromLabels,
|
|
3575
4048
|
contrastRatio,
|
|
4049
|
+
cssTokenDefault,
|
|
3576
4050
|
dataTable,
|
|
4051
|
+
deepMergeSpec,
|
|
4052
|
+
defaultNumberFormatter,
|
|
3577
4053
|
detectCollision,
|
|
3578
4054
|
donutChart,
|
|
3579
4055
|
dotChart,
|
|
@@ -3582,8 +4058,12 @@ export {
|
|
|
3582
4058
|
essay,
|
|
3583
4059
|
estimateTextWidth,
|
|
3584
4060
|
findAccessibleColor,
|
|
4061
|
+
footnoteBandHeight,
|
|
4062
|
+
formatCurrency,
|
|
3585
4063
|
formatDate,
|
|
3586
4064
|
formatNumber,
|
|
4065
|
+
formatOrdinal,
|
|
4066
|
+
formatPercent,
|
|
3587
4067
|
generateAltText,
|
|
3588
4068
|
generateAriaLabels,
|
|
3589
4069
|
generateDataTable,
|
|
@@ -3594,6 +4074,7 @@ export {
|
|
|
3594
4074
|
getRepresentativeColor,
|
|
3595
4075
|
heuristicMeasure,
|
|
3596
4076
|
inferFieldType,
|
|
4077
|
+
isAxislessMark,
|
|
3597
4078
|
isBarListSpec,
|
|
3598
4079
|
isChartSpec,
|
|
3599
4080
|
isConditionalDef,
|
|
@@ -3601,13 +4082,18 @@ export {
|
|
|
3601
4082
|
isGradientDef,
|
|
3602
4083
|
isGraphSpec,
|
|
3603
4084
|
isLayerSpec,
|
|
4085
|
+
isMapSpec,
|
|
4086
|
+
isOpaqueColor,
|
|
3604
4087
|
isRangeAnnotation,
|
|
3605
4088
|
isRefLineAnnotation,
|
|
3606
4089
|
isSankeySpec,
|
|
3607
4090
|
isTableSpec,
|
|
3608
4091
|
isTextAnnotation,
|
|
3609
4092
|
isTileMapSpec,
|
|
4093
|
+
isValueDef,
|
|
4094
|
+
isYearContext,
|
|
3610
4095
|
lineChart,
|
|
4096
|
+
maxRotatedLabelWidth,
|
|
3611
4097
|
meetsAA,
|
|
3612
4098
|
overlapArea,
|
|
3613
4099
|
pickLabelColor,
|
|
@@ -3616,11 +4102,14 @@ export {
|
|
|
3616
4102
|
resolveMarkDef,
|
|
3617
4103
|
resolveMarkType,
|
|
3618
4104
|
resolveMeasurer,
|
|
4105
|
+
resolveNumberFormatter,
|
|
4106
|
+
resolveSchemeName,
|
|
3619
4107
|
resolveTheme,
|
|
3620
4108
|
scatterChart,
|
|
3621
4109
|
simulateColorBlindness,
|
|
3622
4110
|
textAscent,
|
|
3623
4111
|
tileMap,
|
|
4112
|
+
truncateRotatedLabel,
|
|
3624
4113
|
wire,
|
|
3625
4114
|
wrapText
|
|
3626
4115
|
};
|