@opendata-ai/openchart-core 7.11.0 → 8.0.0-rc.2
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 +533 -42
- 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 +77 -10
- 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,14 +1336,41 @@ 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
|
|
1250
1342
|
);
|
|
1251
1343
|
return input.hasTitle ? rotatedHeight + X_AXIS_TITLE_BAND_ROTATED : rotatedHeight;
|
|
1252
1344
|
}
|
|
1253
|
-
|
|
1345
|
+
const tickExtent = 4 + input.tickFontSize + Math.max(11, Math.ceil(input.tickFontSize * 0.7));
|
|
1346
|
+
const flatHeight = Math.max(baseHeight, tickExtent);
|
|
1347
|
+
return input.hasTitle ? flatHeight + X_AXIS_TITLE_BAND : flatHeight;
|
|
1348
|
+
}
|
|
1349
|
+
function maxRotatedLabelWidth(tickAngle, tickFontSize) {
|
|
1350
|
+
const angleRad = Math.abs(tickAngle) * (Math.PI / 180);
|
|
1351
|
+
const sin = Math.sin(angleRad);
|
|
1352
|
+
if (sin <= 1e-3) return Number.POSITIVE_INFINITY;
|
|
1353
|
+
const lineHeight = tickFontSize * TICK_LINE_HEIGHT_FACTOR;
|
|
1354
|
+
const usable = X_AXIS_ROTATED_EXTENT_CAP - lineHeight * Math.cos(angleRad) - AXIS_TO_LABEL_GAP;
|
|
1355
|
+
return Math.max(0, usable / sin);
|
|
1356
|
+
}
|
|
1357
|
+
function truncateRotatedLabel(label, tickAngle, tickFontSize, tickFontWeight, measure = estimateTextWidth) {
|
|
1358
|
+
const budget = maxRotatedLabelWidth(tickAngle, tickFontSize);
|
|
1359
|
+
if (!Number.isFinite(budget)) return label;
|
|
1360
|
+
if (measure(label, tickFontSize, tickFontWeight) <= budget) return label;
|
|
1361
|
+
const ELLIPSIS = "\u2026";
|
|
1362
|
+
let lo = 0;
|
|
1363
|
+
let hi = label.length;
|
|
1364
|
+
while (lo < hi) {
|
|
1365
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
1366
|
+
const candidate = label.slice(0, mid) + ELLIPSIS;
|
|
1367
|
+
if (measure(candidate, tickFontSize, tickFontWeight) <= budget) {
|
|
1368
|
+
lo = mid;
|
|
1369
|
+
} else {
|
|
1370
|
+
hi = mid - 1;
|
|
1371
|
+
}
|
|
1372
|
+
}
|
|
1373
|
+
return lo > 0 ? label.slice(0, lo).trimEnd() + ELLIPSIS : ELLIPSIS;
|
|
1254
1374
|
}
|
|
1255
1375
|
|
|
1256
1376
|
// src/theme/defaults.ts
|
|
@@ -1790,6 +1910,12 @@ function estimateLineCount(text, style, maxWidth, measureText) {
|
|
|
1790
1910
|
}
|
|
1791
1911
|
return lines;
|
|
1792
1912
|
}
|
|
1913
|
+
var FOOTNOTE_LINE_HEIGHT = 1.3;
|
|
1914
|
+
var FOOTNOTE_BAND_GAP = 4;
|
|
1915
|
+
function footnoteBandHeight(count, theme) {
|
|
1916
|
+
if (count <= 0) return 0;
|
|
1917
|
+
return count * theme.fonts.sizes.small * FOOTNOTE_LINE_HEIGHT + FOOTNOTE_BAND_GAP;
|
|
1918
|
+
}
|
|
1793
1919
|
function computeChrome(chrome, theme, width, measureText, chromeMode = "full", padding, watermark = true, bottomLegendHeight = 0) {
|
|
1794
1920
|
if (!chrome || chromeMode === "hidden") {
|
|
1795
1921
|
return { topHeight: 0, bottomHeight: 0 };
|
|
@@ -2118,7 +2244,8 @@ function resolveCollisions(labels, strategies = OFFSET_STRATEGIES) {
|
|
|
2118
2244
|
from: { x: bestX, y: bestY },
|
|
2119
2245
|
to: { x: label.anchorX, y: label.anchorY },
|
|
2120
2246
|
stroke: label.style.fill,
|
|
2121
|
-
style: "straight"
|
|
2247
|
+
style: "straight",
|
|
2248
|
+
arrow: false
|
|
2122
2249
|
} : void 0
|
|
2123
2250
|
});
|
|
2124
2251
|
} else {
|
|
@@ -3145,30 +3272,65 @@ function formatNumber(value, _locale) {
|
|
|
3145
3272
|
if (Number.isInteger(value)) {
|
|
3146
3273
|
return format(",")(value);
|
|
3147
3274
|
}
|
|
3275
|
+
if (Math.abs(value) < 5e-3) {
|
|
3276
|
+
return format(".2~r")(value);
|
|
3277
|
+
}
|
|
3148
3278
|
return format(",.2f")(value);
|
|
3149
3279
|
}
|
|
3150
|
-
var
|
|
3280
|
+
var UNIT_TABLE = [
|
|
3151
3281
|
{ threshold: 1e12, suffix: "T", divisor: 1e12 },
|
|
3152
3282
|
{ threshold: 1e9, suffix: "B", divisor: 1e9 },
|
|
3153
3283
|
{ threshold: 1e6, suffix: "M", divisor: 1e6 },
|
|
3154
|
-
{ threshold: 1e3, suffix: "
|
|
3284
|
+
{ threshold: 1e3, suffix: "k", divisor: 1e3 }
|
|
3155
3285
|
];
|
|
3286
|
+
function unitFor(abs) {
|
|
3287
|
+
for (const entry of UNIT_TABLE) {
|
|
3288
|
+
if (abs >= entry.threshold) return entry;
|
|
3289
|
+
}
|
|
3290
|
+
return { suffix: "", divisor: 1 };
|
|
3291
|
+
}
|
|
3292
|
+
function fractionDigits(x) {
|
|
3293
|
+
const a = Math.abs(x);
|
|
3294
|
+
for (let p = 0; p <= 3; p++) {
|
|
3295
|
+
const scaled = a * 10 ** p;
|
|
3296
|
+
if (Math.abs(scaled - Math.round(scaled)) < 1e-9) return p;
|
|
3297
|
+
}
|
|
3298
|
+
return 4;
|
|
3299
|
+
}
|
|
3156
3300
|
function abbreviateNumber(value) {
|
|
3157
3301
|
if (!Number.isFinite(value)) return String(value);
|
|
3158
3302
|
const absValue = Math.abs(value);
|
|
3159
3303
|
const sign = value < 0 ? "-" : "";
|
|
3160
|
-
for (
|
|
3304
|
+
for (let i = 0; i < UNIT_TABLE.length; i++) {
|
|
3305
|
+
const { threshold, suffix, divisor } = UNIT_TABLE[i];
|
|
3161
3306
|
if (absValue >= threshold) {
|
|
3162
|
-
const
|
|
3163
|
-
|
|
3164
|
-
|
|
3307
|
+
const mantissa = format(".1~f")(absValue / divisor);
|
|
3308
|
+
if (mantissa === "1000" && i > 0) {
|
|
3309
|
+
return `${sign}1${UNIT_TABLE[i - 1].suffix}`;
|
|
3310
|
+
}
|
|
3311
|
+
return `${sign}${mantissa}${suffix}`;
|
|
3165
3312
|
}
|
|
3166
3313
|
}
|
|
3167
3314
|
return formatNumber(value);
|
|
3168
3315
|
}
|
|
3316
|
+
function formatOrdinal(value) {
|
|
3317
|
+
if (!Number.isFinite(value)) return String(value);
|
|
3318
|
+
const n = Math.round(value);
|
|
3319
|
+
const abs = Math.abs(n);
|
|
3320
|
+
const rem100 = abs % 100;
|
|
3321
|
+
const rem10 = abs % 10;
|
|
3322
|
+
let suffix;
|
|
3323
|
+
if (rem100 >= 11 && rem100 <= 13) suffix = "th";
|
|
3324
|
+
else if (rem10 === 1) suffix = "st";
|
|
3325
|
+
else if (rem10 === 2) suffix = "nd";
|
|
3326
|
+
else if (rem10 === 3) suffix = "rd";
|
|
3327
|
+
else suffix = "th";
|
|
3328
|
+
return `${n}${suffix}`;
|
|
3329
|
+
}
|
|
3169
3330
|
var D3_FORMAT_SUFFIX_RE = /^(.*~?[efgsrdxXobcnp%])(.+)$/;
|
|
3170
3331
|
function buildD3Formatter(formatStr) {
|
|
3171
3332
|
if (!formatStr) return null;
|
|
3333
|
+
if (formatStr === "ordinal") return formatOrdinal;
|
|
3172
3334
|
try {
|
|
3173
3335
|
const fmt = format(formatStr);
|
|
3174
3336
|
if (formatStr.includes("s")) {
|
|
@@ -3188,6 +3350,111 @@ function buildD3Formatter(formatStr) {
|
|
|
3188
3350
|
}
|
|
3189
3351
|
return null;
|
|
3190
3352
|
}
|
|
3353
|
+
function formatPercent(value, options) {
|
|
3354
|
+
const fraction = options?.fraction ?? true;
|
|
3355
|
+
if (fraction) {
|
|
3356
|
+
return format(".1~%")(value);
|
|
3357
|
+
}
|
|
3358
|
+
return `${format(",.1~f")(value)}%`;
|
|
3359
|
+
}
|
|
3360
|
+
function formatCurrency(value, options) {
|
|
3361
|
+
const compact = options?.compact ?? false;
|
|
3362
|
+
const abs = Math.abs(value);
|
|
3363
|
+
const sign = value < 0 ? "-" : "";
|
|
3364
|
+
if (compact) {
|
|
3365
|
+
if (abs >= 1e3) {
|
|
3366
|
+
return `${sign}$${abbreviateNumber(abs)}`;
|
|
3367
|
+
}
|
|
3368
|
+
return `${sign}$${formatNumber(abs)}`;
|
|
3369
|
+
}
|
|
3370
|
+
if (Number.isInteger(value)) {
|
|
3371
|
+
return sign + format("$,")(abs);
|
|
3372
|
+
}
|
|
3373
|
+
return sign + format("$,.2f")(abs);
|
|
3374
|
+
}
|
|
3375
|
+
function computeFieldFormatContext(values, surface) {
|
|
3376
|
+
let min = Infinity;
|
|
3377
|
+
let max = -Infinity;
|
|
3378
|
+
let allIntegers = true;
|
|
3379
|
+
let hasFinite = false;
|
|
3380
|
+
for (const raw of values) {
|
|
3381
|
+
const v = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
|
|
3382
|
+
if (!Number.isFinite(v)) continue;
|
|
3383
|
+
hasFinite = true;
|
|
3384
|
+
if (v < min) min = v;
|
|
3385
|
+
if (v > max) max = v;
|
|
3386
|
+
if (allIntegers && !Number.isInteger(v)) allIntegers = false;
|
|
3387
|
+
}
|
|
3388
|
+
const ctx = {};
|
|
3389
|
+
if (hasFinite) {
|
|
3390
|
+
ctx.extent = [min, max];
|
|
3391
|
+
ctx.allIntegers = allIntegers;
|
|
3392
|
+
}
|
|
3393
|
+
if (surface) ctx.surface = surface;
|
|
3394
|
+
return ctx;
|
|
3395
|
+
}
|
|
3396
|
+
function isYearContext(ctx) {
|
|
3397
|
+
if (!ctx?.extent || !ctx.allIntegers) return false;
|
|
3398
|
+
const [min, max] = ctx.extent;
|
|
3399
|
+
return min >= 1500 && max <= 2500;
|
|
3400
|
+
}
|
|
3401
|
+
function resolveNumberFormatter(formatStr, ctx) {
|
|
3402
|
+
if (!formatStr) return null;
|
|
3403
|
+
if (formatStr === "ordinal") return formatOrdinal;
|
|
3404
|
+
if (formatStr === "percent") {
|
|
3405
|
+
const fraction = ctx?.extent ? Math.max(Math.abs(ctx.extent[0]), Math.abs(ctx.extent[1])) <= 1 : true;
|
|
3406
|
+
return (v) => formatPercent(v, { fraction });
|
|
3407
|
+
}
|
|
3408
|
+
if (formatStr === "currency") {
|
|
3409
|
+
const isTable = ctx?.surface === "table";
|
|
3410
|
+
if (!isTable && ctx?.step != null && (ctx.stepReference ?? 0) >= 1e3) {
|
|
3411
|
+
const stepFmt = buildCompactStepFormatter(ctx.step);
|
|
3412
|
+
return (v) => {
|
|
3413
|
+
const sign = v < 0 ? "-" : "";
|
|
3414
|
+
return `${sign}$${stepFmt(Math.abs(v))}`;
|
|
3415
|
+
};
|
|
3416
|
+
}
|
|
3417
|
+
return (v) => formatCurrency(v, { compact: !isTable });
|
|
3418
|
+
}
|
|
3419
|
+
return buildD3Formatter(formatStr);
|
|
3420
|
+
}
|
|
3421
|
+
function defaultNumberFormatter(ctx) {
|
|
3422
|
+
if (isYearContext(ctx)) {
|
|
3423
|
+
return (v) => String(Math.round(v));
|
|
3424
|
+
}
|
|
3425
|
+
if (ctx?.surface === "table") {
|
|
3426
|
+
return formatNumber;
|
|
3427
|
+
}
|
|
3428
|
+
if (ctx?.step != null && (ctx.stepReference ?? maxAbs(ctx.extent)) >= 1e3) {
|
|
3429
|
+
return buildCompactStepFormatter(ctx.step);
|
|
3430
|
+
}
|
|
3431
|
+
return (v) => {
|
|
3432
|
+
if (!Number.isFinite(v)) return String(v);
|
|
3433
|
+
if (ctx?.extent === void 0 && ctx?.allIntegers === void 0) {
|
|
3434
|
+
if (Number.isInteger(v) && v >= 1500 && v <= 2500) return String(v);
|
|
3435
|
+
}
|
|
3436
|
+
return Math.abs(v) >= 1e3 ? abbreviateNumber(v) : formatNumber(v);
|
|
3437
|
+
};
|
|
3438
|
+
}
|
|
3439
|
+
function maxAbs(extent) {
|
|
3440
|
+
if (!extent) return 0;
|
|
3441
|
+
return Math.max(Math.abs(extent[0]), Math.abs(extent[1]));
|
|
3442
|
+
}
|
|
3443
|
+
function buildCompactStepFormatter(step) {
|
|
3444
|
+
return (v) => {
|
|
3445
|
+
if (v === 0) return "0";
|
|
3446
|
+
if (!Number.isFinite(v)) return String(v);
|
|
3447
|
+
const abs = Math.abs(v);
|
|
3448
|
+
if (abs < 1e3) return formatNumber(v);
|
|
3449
|
+
const { suffix, divisor } = unitFor(abs);
|
|
3450
|
+
const p = fractionDigits(step / divisor);
|
|
3451
|
+
if (p > 2) {
|
|
3452
|
+
return Number.isInteger(v) ? format(",")(v) : format(",.2f")(v);
|
|
3453
|
+
}
|
|
3454
|
+
const sign = v < 0 ? "-" : "";
|
|
3455
|
+
return sign + format(`.${p}~f`)(abs / divisor) + suffix;
|
|
3456
|
+
};
|
|
3457
|
+
}
|
|
3191
3458
|
var GRANULARITY_FORMATS = {
|
|
3192
3459
|
year: "%Y",
|
|
3193
3460
|
quarter: "",
|
|
@@ -3262,7 +3529,34 @@ function generateAltText(spec, data) {
|
|
|
3262
3529
|
const titleText = typeof title === "string" ? title : title.text;
|
|
3263
3530
|
parts.push(`showing ${titleText}`);
|
|
3264
3531
|
}
|
|
3265
|
-
if (
|
|
3532
|
+
if (markType === "waffle") {
|
|
3533
|
+
const units = markDef.units ?? 100;
|
|
3534
|
+
parts.push(`dividing ${units} units`);
|
|
3535
|
+
}
|
|
3536
|
+
if (markType === "parliament") {
|
|
3537
|
+
const valueField = spec.encoding.theta?.field ?? spec.encoding.y?.field;
|
|
3538
|
+
if (valueField) {
|
|
3539
|
+
const totalSeats = data.reduce((sum, d) => {
|
|
3540
|
+
const v = Number(d[valueField]);
|
|
3541
|
+
return sum + (Number.isFinite(v) && v > 0 ? v : 0);
|
|
3542
|
+
}, 0);
|
|
3543
|
+
if (totalSeats > 0) {
|
|
3544
|
+
const majority = Math.floor(totalSeats / 2) + 1;
|
|
3545
|
+
parts.push(`with ${totalSeats} seats, ${majority} needed for a majority`);
|
|
3546
|
+
}
|
|
3547
|
+
}
|
|
3548
|
+
}
|
|
3549
|
+
if (markType === "beeswarm") {
|
|
3550
|
+
const xIsValue = spec.encoding.x?.type === "quantitative";
|
|
3551
|
+
const valueField = xIsValue ? spec.encoding.x?.field : spec.encoding.y?.field;
|
|
3552
|
+
const laneField = xIsValue ? spec.encoding.y?.field : spec.encoding.x?.field;
|
|
3553
|
+
if (valueField) {
|
|
3554
|
+
parts.push(
|
|
3555
|
+
`plotting the distribution of ${valueField}${laneField ? ` by ${laneField}` : ""}`
|
|
3556
|
+
);
|
|
3557
|
+
}
|
|
3558
|
+
}
|
|
3559
|
+
if (spec.encoding.x && markType !== "beeswarm" && data.length > 0) {
|
|
3266
3560
|
const field = spec.encoding.x.field;
|
|
3267
3561
|
const values = data.map((d) => d[field]).filter((v) => v != null);
|
|
3268
3562
|
if (values.length > 0) {
|
|
@@ -3347,11 +3641,12 @@ function generateAriaLabels(marks) {
|
|
|
3347
3641
|
}
|
|
3348
3642
|
return labels;
|
|
3349
3643
|
}
|
|
3644
|
+
var ariaNumberFormatter = defaultNumberFormatter();
|
|
3350
3645
|
function formatValue(value) {
|
|
3351
3646
|
if (value == null) return "N/A";
|
|
3352
3647
|
if (value instanceof Date) return value.toISOString().slice(0, 10);
|
|
3353
3648
|
if (typeof value === "number") {
|
|
3354
|
-
return
|
|
3649
|
+
return ariaNumberFormatter(value);
|
|
3355
3650
|
}
|
|
3356
3651
|
return String(value);
|
|
3357
3652
|
}
|
|
@@ -3431,7 +3726,7 @@ function pieChart(data, category, value, options) {
|
|
|
3431
3726
|
const categoryChannel = resolveField(category, data);
|
|
3432
3727
|
const valueChannel = resolveField(value, data);
|
|
3433
3728
|
const encoding = {
|
|
3434
|
-
|
|
3729
|
+
theta: valueChannel,
|
|
3435
3730
|
color: categoryChannel
|
|
3436
3731
|
};
|
|
3437
3732
|
if (options?.size && data) {
|
|
@@ -3449,7 +3744,7 @@ function donutChart(data, category, value, options) {
|
|
|
3449
3744
|
const categoryChannel = resolveField(category, data);
|
|
3450
3745
|
const valueChannel = resolveField(value, data);
|
|
3451
3746
|
const encoding = {
|
|
3452
|
-
|
|
3747
|
+
theta: valueChannel,
|
|
3453
3748
|
color: categoryChannel
|
|
3454
3749
|
};
|
|
3455
3750
|
if (options?.size && data) {
|
|
@@ -3514,6 +3809,182 @@ function tileMap(data, options) {
|
|
|
3514
3809
|
...options?.valueFormat && { valueFormat: options.valueFormat }
|
|
3515
3810
|
};
|
|
3516
3811
|
}
|
|
3812
|
+
|
|
3813
|
+
// src/helpers/deep-merge.ts
|
|
3814
|
+
function deepMergeSpec(target, source) {
|
|
3815
|
+
if (source === void 0) return target;
|
|
3816
|
+
if (source === null) return source;
|
|
3817
|
+
if (typeof source !== "object" || Array.isArray(source) || typeof target !== "object" || target === null || Array.isArray(target)) {
|
|
3818
|
+
return source;
|
|
3819
|
+
}
|
|
3820
|
+
const result = { ...target };
|
|
3821
|
+
for (const key of Object.keys(source)) {
|
|
3822
|
+
result[key] = deepMergeSpec(target[key], source[key]);
|
|
3823
|
+
}
|
|
3824
|
+
return result;
|
|
3825
|
+
}
|
|
3826
|
+
|
|
3827
|
+
// src/styles/token-definitions.ts
|
|
3828
|
+
var CSS_TOKEN_ROOT_SELECTORS = [
|
|
3829
|
+
".oc-root",
|
|
3830
|
+
".oc-chart-root",
|
|
3831
|
+
".oc-table-wrapper",
|
|
3832
|
+
".oc-table-root",
|
|
3833
|
+
".oc-graph-wrapper",
|
|
3834
|
+
".oc-graph-root",
|
|
3835
|
+
".oc-sankey-root",
|
|
3836
|
+
".oc-tilemap-root",
|
|
3837
|
+
".oc-barlist-root",
|
|
3838
|
+
".oc-map-root"
|
|
3839
|
+
];
|
|
3840
|
+
var CSS_TOKENS = [
|
|
3841
|
+
{
|
|
3842
|
+
name: "--oc-font-family",
|
|
3843
|
+
light: '\n "Inter Variable", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
3844
|
+
},
|
|
3845
|
+
{
|
|
3846
|
+
name: "--oc-font-mono",
|
|
3847
|
+
light: '"JetBrains Mono", "Fira Code", "Cascadia Code", monospace'
|
|
3848
|
+
},
|
|
3849
|
+
{
|
|
3850
|
+
section: "Animation easing presets via CSS linear()",
|
|
3851
|
+
name: "--oc-ease-smooth",
|
|
3852
|
+
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 )"
|
|
3853
|
+
},
|
|
3854
|
+
{
|
|
3855
|
+
name: "--oc-ease-snappy",
|
|
3856
|
+
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 )",
|
|
3857
|
+
consumers: "EASE_VAR_MAP in vanilla renderers"
|
|
3858
|
+
},
|
|
3859
|
+
{ section: "Animation timing defaults", name: "--oc-animation-duration", light: "500ms" },
|
|
3860
|
+
{ name: "--oc-animation-stagger", light: "80ms" },
|
|
3861
|
+
{ name: "--oc-annotation-delay", light: "200ms" },
|
|
3862
|
+
{ section: "Typography scale (editorial design system)", name: "--oc-title-size", light: "26px" },
|
|
3863
|
+
{ name: "--oc-title-weight", light: "590" },
|
|
3864
|
+
{ name: "--oc-title-tracking", light: "-0.022em" },
|
|
3865
|
+
{ name: "--oc-subtitle-size", light: "14px" },
|
|
3866
|
+
{ name: "--oc-subtitle-weight", light: "450" },
|
|
3867
|
+
{ name: "--oc-source-size", light: "11px" },
|
|
3868
|
+
{ name: "--oc-source-weight", light: "450" },
|
|
3869
|
+
{ name: "--oc-body-size", light: "13px" },
|
|
3870
|
+
{ name: "--oc-eyebrow-size", light: "11px" },
|
|
3871
|
+
{ name: "--oc-eyebrow-weight", light: "550" },
|
|
3872
|
+
{ name: "--oc-eyebrow-tracking", light: "0.08em" },
|
|
3873
|
+
{ section: "Surfaces (light mode defaults)", name: "--oc-bg", light: "#ffffff", dark: "#09090b" },
|
|
3874
|
+
{ name: "--oc-card", light: "#ffffff", dark: "#111113" },
|
|
3875
|
+
{
|
|
3876
|
+
name: "--oc-secondary",
|
|
3877
|
+
light: "#f4f4f5",
|
|
3878
|
+
dark: "#27272a",
|
|
3879
|
+
comment: "zinc-100, raised surface"
|
|
3880
|
+
},
|
|
3881
|
+
{
|
|
3882
|
+
section: `Text levels. Names invert across modes: in light mode "muted" sits at
|
|
3883
|
+
* a lighter zinc step than "subtle" because both are picked relative to
|
|
3884
|
+
* the active background, not from a fixed lightness ladder. The intent
|
|
3885
|
+
* is "muted = first step away from primary text"; "subtle = next step
|
|
3886
|
+
* down"; etc.
|
|
3887
|
+
*
|
|
3888
|
+
* Light mode: text=zinc-950, secondary=zinc-700, muted=zinc-500,
|
|
3889
|
+
* subtle=zinc-400, faint=zinc-300
|
|
3890
|
+
* Dark mode (dark.css): inverts the surface tokens but keeps the same
|
|
3891
|
+
* muted -> subtle -> faint progression away from primary.`,
|
|
3892
|
+
name: "--oc-text",
|
|
3893
|
+
light: "#09090b",
|
|
3894
|
+
dark: "#f7f8f8"
|
|
3895
|
+
},
|
|
3896
|
+
{ name: "--oc-text-secondary", light: "#3f3f46", dark: "#d0d6e0" },
|
|
3897
|
+
{ name: "--oc-text-muted", light: "#71717a", dark: "#a1a1aa" },
|
|
3898
|
+
{ name: "--oc-text-faint", light: "#d4d4d8", dark: "#52525b" },
|
|
3899
|
+
{
|
|
3900
|
+
section: "Lines",
|
|
3901
|
+
name: "--oc-gridline",
|
|
3902
|
+
light: "rgba(0, 0, 0, 0.1)",
|
|
3903
|
+
dark: "rgba(255, 255, 255, 0.05)"
|
|
3904
|
+
},
|
|
3905
|
+
{
|
|
3906
|
+
name: "--oc-axis",
|
|
3907
|
+
light: "rgba(0, 0, 0, 0.1)",
|
|
3908
|
+
dark: "rgba(255, 255, 255, 0.1)"
|
|
3909
|
+
},
|
|
3910
|
+
{
|
|
3911
|
+
name: "--oc-border",
|
|
3912
|
+
light: "rgba(0, 0, 0, 0.08)",
|
|
3913
|
+
dark: "rgba(255, 255, 255, 0.1)"
|
|
3914
|
+
},
|
|
3915
|
+
{ name: "--oc-border-radius", light: "2px" },
|
|
3916
|
+
{
|
|
3917
|
+
section: "Brand and semantic",
|
|
3918
|
+
name: "--oc-accent",
|
|
3919
|
+
light: "#06b6d4",
|
|
3920
|
+
dark: "#06b6d4"
|
|
3921
|
+
},
|
|
3922
|
+
{
|
|
3923
|
+
name: "--oc-accent-strong",
|
|
3924
|
+
light: "#0891b2",
|
|
3925
|
+
dark: "#06b6d4",
|
|
3926
|
+
comment: "darker cyan for line strokes on light bg",
|
|
3927
|
+
consumers: "stamped via adaptForLightLineStroke"
|
|
3928
|
+
},
|
|
3929
|
+
{ name: "--oc-positive", light: "#10b981", dark: "#34d399" },
|
|
3930
|
+
{ name: "--oc-negative", light: "#e11d48", dark: "#fb7185" },
|
|
3931
|
+
{ name: "--oc-focus", light: "#3b82f6", dark: "#60a5fa" },
|
|
3932
|
+
{
|
|
3933
|
+
name: "--oc-focus-ring",
|
|
3934
|
+
light: "rgba(59, 130, 246, 0.1)",
|
|
3935
|
+
comment: "static, intentionally NOT derived from --oc-focus and NOT flipped in dark mode"
|
|
3936
|
+
},
|
|
3937
|
+
{
|
|
3938
|
+
name: "--oc-focus-ring-strong",
|
|
3939
|
+
light: "rgba(59, 130, 246, 0.25)"
|
|
3940
|
+
},
|
|
3941
|
+
{
|
|
3942
|
+
name: "--oc-editable-hover",
|
|
3943
|
+
light: "rgba(79, 70, 229, 0.35)",
|
|
3944
|
+
comment: "edit-mode hover outline, indigo one-off"
|
|
3945
|
+
},
|
|
3946
|
+
{
|
|
3947
|
+
section: "Spacing scale (4px base) \u2014 only --oc-space-2/4 are consumed (JS-stamped)",
|
|
3948
|
+
name: "--oc-space-2",
|
|
3949
|
+
light: "8px",
|
|
3950
|
+
consumers: "stamped at mount from theme.spacing (theme-tokens.ts); component CSS must NOT consume these"
|
|
3951
|
+
},
|
|
3952
|
+
{
|
|
3953
|
+
name: "--oc-space-4",
|
|
3954
|
+
light: "16px",
|
|
3955
|
+
consumers: "stamped at mount from theme.spacing (theme-tokens.ts); component CSS must NOT consume these"
|
|
3956
|
+
},
|
|
3957
|
+
{
|
|
3958
|
+
section: "Interactive states",
|
|
3959
|
+
name: "--oc-hover-bg",
|
|
3960
|
+
light: "rgba(0, 0, 0, 0.025)",
|
|
3961
|
+
dark: "rgba(255, 255, 255, 0.05)"
|
|
3962
|
+
},
|
|
3963
|
+
{
|
|
3964
|
+
name: "--oc-tooltip-bg",
|
|
3965
|
+
light: "rgba(255, 255, 255, 0.88)",
|
|
3966
|
+
dark: "rgba(17, 17, 19, 0.92)"
|
|
3967
|
+
},
|
|
3968
|
+
{
|
|
3969
|
+
name: "--oc-tooltip-border",
|
|
3970
|
+
light: "rgba(0, 0, 0, 0.08)",
|
|
3971
|
+
dark: "rgba(255, 255, 255, 0.08)"
|
|
3972
|
+
},
|
|
3973
|
+
{
|
|
3974
|
+
name: "--oc-tooltip-shadow",
|
|
3975
|
+
light: "0 2px 8px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.12)",
|
|
3976
|
+
dark: "0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4)"
|
|
3977
|
+
},
|
|
3978
|
+
{ name: "--oc-tooltip-text", light: "#09090b", dark: "#f7f8f8" },
|
|
3979
|
+
{ name: "--oc-legend-text", light: "#3f3f46", dark: "#d0d6e0" }
|
|
3980
|
+
];
|
|
3981
|
+
var TOKEN_MAP = new Map(CSS_TOKENS.map((t) => [t.name, t]));
|
|
3982
|
+
function cssTokenDefault(name, mode) {
|
|
3983
|
+
const token = TOKEN_MAP.get(name);
|
|
3984
|
+
if (!token) throw new Error(`Unknown CSS token: ${name}`);
|
|
3985
|
+
if (mode === "dark" && token.dark !== void 0) return token.dark;
|
|
3986
|
+
return token.light;
|
|
3987
|
+
}
|
|
3517
3988
|
export {
|
|
3518
3989
|
ACHROMATIC_RAMP,
|
|
3519
3990
|
AXIS_TITLE_GAP,
|
|
@@ -3526,12 +3997,13 @@ export {
|
|
|
3526
3997
|
BREAKPOINT_COMPACT_MAX,
|
|
3527
3998
|
BREAKPOINT_MEDIUM_MAX,
|
|
3528
3999
|
CATEGORICAL_PALETTE,
|
|
3529
|
-
CHART_ENCODING_RULES,
|
|
3530
|
-
CHART_TYPES,
|
|
3531
4000
|
COMPACT_WIDTH,
|
|
4001
|
+
CSS_TOKENS,
|
|
4002
|
+
CSS_TOKEN_ROOT_SELECTORS,
|
|
3532
4003
|
DEFAULT_THEME,
|
|
3533
4004
|
DIVERGING_PALETTES,
|
|
3534
4005
|
EXTENDED_OFFSET_STRATEGIES,
|
|
4006
|
+
FOOTNOTE_LINE_HEIGHT,
|
|
3535
4007
|
GRAPH_ENCODING_RULES,
|
|
3536
4008
|
HEIGHT_CRAMPED_MAX,
|
|
3537
4009
|
HEIGHT_SHORT_MAX,
|
|
@@ -3550,6 +4022,7 @@ export {
|
|
|
3550
4022
|
NARROW_VIEWPORT_MAX,
|
|
3551
4023
|
OFFSET_STRATEGIES,
|
|
3552
4024
|
SEQUENTIAL_PALETTES,
|
|
4025
|
+
SUPPORTED_SCHEME_NAMES,
|
|
3553
4026
|
TICK_LABEL_OFFSET,
|
|
3554
4027
|
TICK_LINE_HEIGHT_FACTOR,
|
|
3555
4028
|
TOP_PAD_EXTRA_NARROW,
|
|
@@ -3565,15 +4038,20 @@ export {
|
|
|
3565
4038
|
areaChart,
|
|
3566
4039
|
axisTitleOffset,
|
|
3567
4040
|
barChart,
|
|
4041
|
+
buildCompactStepFormatter,
|
|
3568
4042
|
buildD3Formatter,
|
|
3569
4043
|
buildTemporalFormatter,
|
|
3570
4044
|
checkPaletteDistinguishability,
|
|
3571
4045
|
columnChart,
|
|
3572
4046
|
computeChrome,
|
|
4047
|
+
computeFieldFormatContext,
|
|
3573
4048
|
computeLabelBounds,
|
|
3574
4049
|
computeXAxisExtentFromLabels,
|
|
3575
4050
|
contrastRatio,
|
|
4051
|
+
cssTokenDefault,
|
|
3576
4052
|
dataTable,
|
|
4053
|
+
deepMergeSpec,
|
|
4054
|
+
defaultNumberFormatter,
|
|
3577
4055
|
detectCollision,
|
|
3578
4056
|
donutChart,
|
|
3579
4057
|
dotChart,
|
|
@@ -3582,8 +4060,12 @@ export {
|
|
|
3582
4060
|
essay,
|
|
3583
4061
|
estimateTextWidth,
|
|
3584
4062
|
findAccessibleColor,
|
|
4063
|
+
footnoteBandHeight,
|
|
4064
|
+
formatCurrency,
|
|
3585
4065
|
formatDate,
|
|
3586
4066
|
formatNumber,
|
|
4067
|
+
formatOrdinal,
|
|
4068
|
+
formatPercent,
|
|
3587
4069
|
generateAltText,
|
|
3588
4070
|
generateAriaLabels,
|
|
3589
4071
|
generateDataTable,
|
|
@@ -3594,6 +4076,7 @@ export {
|
|
|
3594
4076
|
getRepresentativeColor,
|
|
3595
4077
|
heuristicMeasure,
|
|
3596
4078
|
inferFieldType,
|
|
4079
|
+
isAxislessMark,
|
|
3597
4080
|
isBarListSpec,
|
|
3598
4081
|
isChartSpec,
|
|
3599
4082
|
isConditionalDef,
|
|
@@ -3601,13 +4084,18 @@ export {
|
|
|
3601
4084
|
isGradientDef,
|
|
3602
4085
|
isGraphSpec,
|
|
3603
4086
|
isLayerSpec,
|
|
4087
|
+
isMapSpec,
|
|
4088
|
+
isOpaqueColor,
|
|
3604
4089
|
isRangeAnnotation,
|
|
3605
4090
|
isRefLineAnnotation,
|
|
3606
4091
|
isSankeySpec,
|
|
3607
4092
|
isTableSpec,
|
|
3608
4093
|
isTextAnnotation,
|
|
3609
4094
|
isTileMapSpec,
|
|
4095
|
+
isValueDef,
|
|
4096
|
+
isYearContext,
|
|
3610
4097
|
lineChart,
|
|
4098
|
+
maxRotatedLabelWidth,
|
|
3611
4099
|
meetsAA,
|
|
3612
4100
|
overlapArea,
|
|
3613
4101
|
pickLabelColor,
|
|
@@ -3616,11 +4104,14 @@ export {
|
|
|
3616
4104
|
resolveMarkDef,
|
|
3617
4105
|
resolveMarkType,
|
|
3618
4106
|
resolveMeasurer,
|
|
4107
|
+
resolveNumberFormatter,
|
|
4108
|
+
resolveSchemeName,
|
|
3619
4109
|
resolveTheme,
|
|
3620
4110
|
scatterChart,
|
|
3621
4111
|
simulateColorBlindness,
|
|
3622
4112
|
textAscent,
|
|
3623
4113
|
tileMap,
|
|
4114
|
+
truncateRotatedLabel,
|
|
3624
4115
|
wire,
|
|
3625
4116
|
wrapText
|
|
3626
4117
|
};
|