@opendata-ai/openchart-core 7.11.0 → 8.0.0-rc.10
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 +1348 -132
- package/dist/index.js +556 -48
- 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 +9086 -0
- package/schema/table.schema.json +861 -0
- package/schema/vizspec.schema.json +17922 -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/breakpoints.ts +7 -2
- 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 +211 -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 +130 -99
- 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 +107 -13
- package/src/types/index.ts +42 -3
- package/src/types/layout.ts +484 -11
- package/src/types/schema-roots.ts +32 -0
- package/src/types/spec.ts +718 -87
- 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"] },
|
|
@@ -149,14 +187,31 @@ var GRAPH_ENCODING_RULES = {
|
|
|
149
187
|
|
|
150
188
|
// src/types/events.ts
|
|
151
189
|
var elementRef = {
|
|
152
|
-
annotation: (index, id) => ({
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
190
|
+
annotation: (index, id, path) => ({
|
|
191
|
+
type: "annotation",
|
|
192
|
+
index,
|
|
193
|
+
...id !== void 0 ? { id } : {},
|
|
194
|
+
...path !== void 0 ? { path } : {}
|
|
195
|
+
}),
|
|
196
|
+
chrome: (key, path) => ({
|
|
197
|
+
type: "chrome",
|
|
198
|
+
key,
|
|
199
|
+
...path !== void 0 ? { path } : {}
|
|
200
|
+
}),
|
|
201
|
+
seriesLabel: (series, path) => ({
|
|
202
|
+
type: "series-label",
|
|
203
|
+
series,
|
|
204
|
+
...path !== void 0 ? { path } : {}
|
|
205
|
+
}),
|
|
206
|
+
legend: (path) => ({
|
|
207
|
+
type: "legend",
|
|
208
|
+
...path !== void 0 ? { path } : {}
|
|
209
|
+
}),
|
|
210
|
+
legendEntry: (series, index, path) => ({
|
|
157
211
|
type: "legend-entry",
|
|
158
212
|
series,
|
|
159
|
-
index
|
|
213
|
+
index,
|
|
214
|
+
...path !== void 0 ? { path } : {}
|
|
160
215
|
})
|
|
161
216
|
};
|
|
162
217
|
|
|
@@ -177,6 +232,10 @@ function isConditionalDef(def) {
|
|
|
177
232
|
if (!def) return false;
|
|
178
233
|
return "condition" in def;
|
|
179
234
|
}
|
|
235
|
+
function isValueDef(def) {
|
|
236
|
+
if (!def) return false;
|
|
237
|
+
return "value" in def && !("condition" in def) && !("field" in def);
|
|
238
|
+
}
|
|
180
239
|
var MARK_TYPES = /* @__PURE__ */ new Set([
|
|
181
240
|
"bar",
|
|
182
241
|
"line",
|
|
@@ -188,9 +247,16 @@ var MARK_TYPES = /* @__PURE__ */ new Set([
|
|
|
188
247
|
"rule",
|
|
189
248
|
"tick",
|
|
190
249
|
"rect",
|
|
191
|
-
"lollipop"
|
|
250
|
+
"lollipop",
|
|
251
|
+
"beeswarm",
|
|
252
|
+
"range",
|
|
253
|
+
"waffle",
|
|
254
|
+
"calendar",
|
|
255
|
+
"parliament"
|
|
192
256
|
]);
|
|
193
|
-
|
|
257
|
+
function isAxislessMark(markType) {
|
|
258
|
+
return markType === "arc" || markType === "waffle" || markType === "calendar" || markType === "parliament";
|
|
259
|
+
}
|
|
194
260
|
function resolveMarkType(mark) {
|
|
195
261
|
return typeof mark === "string" ? mark : mark.type;
|
|
196
262
|
}
|
|
@@ -218,6 +284,9 @@ function isTileMapSpec(spec) {
|
|
|
218
284
|
function isBarListSpec(spec) {
|
|
219
285
|
return "type" in spec && spec.type === "barlist";
|
|
220
286
|
}
|
|
287
|
+
function isMapSpec(spec) {
|
|
288
|
+
return "type" in spec && spec.type === "map";
|
|
289
|
+
}
|
|
221
290
|
function isTextAnnotation(annotation) {
|
|
222
291
|
return annotation.type === "text";
|
|
223
292
|
}
|
|
@@ -225,7 +294,8 @@ function isRangeAnnotation(annotation) {
|
|
|
225
294
|
return annotation.type === "range";
|
|
226
295
|
}
|
|
227
296
|
function isRefLineAnnotation(annotation) {
|
|
228
|
-
|
|
297
|
+
const type = annotation.type;
|
|
298
|
+
return type === "refline" || type === "rule";
|
|
229
299
|
}
|
|
230
300
|
var MARK_DISPLAY_NAMES = {
|
|
231
301
|
bar: "Bar chart",
|
|
@@ -239,7 +309,12 @@ var MARK_DISPLAY_NAMES = {
|
|
|
239
309
|
rule: "Rule chart",
|
|
240
310
|
tick: "Tick plot",
|
|
241
311
|
rect: "Heatmap",
|
|
242
|
-
lollipop: "Lollipop chart"
|
|
312
|
+
lollipop: "Lollipop chart",
|
|
313
|
+
beeswarm: "Beeswarm chart",
|
|
314
|
+
range: "Range plot",
|
|
315
|
+
waffle: "Waffle chart",
|
|
316
|
+
calendar: "Calendar heatmap",
|
|
317
|
+
parliament: "Parliament chart"
|
|
243
318
|
};
|
|
244
319
|
|
|
245
320
|
// ../../node_modules/.bun/d3-color@3.1.0/node_modules/d3-color/src/define.js
|
|
@@ -606,10 +681,16 @@ var TRITAN_MATRIX = [
|
|
|
606
681
|
[0, 0.433, 0.567],
|
|
607
682
|
[0, 0.475, 0.525]
|
|
608
683
|
];
|
|
684
|
+
var ACHROMAT_MATRIX = [
|
|
685
|
+
[0.2126, 0.7152, 0.0722],
|
|
686
|
+
[0.2126, 0.7152, 0.0722],
|
|
687
|
+
[0.2126, 0.7152, 0.0722]
|
|
688
|
+
];
|
|
609
689
|
var MATRICES = {
|
|
610
690
|
protanopia: PROTAN_MATRIX,
|
|
611
691
|
deuteranopia: DEUTAN_MATRIX,
|
|
612
|
-
tritanopia: TRITAN_MATRIX
|
|
692
|
+
tritanopia: TRITAN_MATRIX,
|
|
693
|
+
achromatopsia: ACHROMAT_MATRIX
|
|
613
694
|
};
|
|
614
695
|
function linearize(v) {
|
|
615
696
|
const s = v / 255;
|
|
@@ -654,6 +735,10 @@ function relativeLuminance(color2) {
|
|
|
654
735
|
const linear = srgb.map((v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4);
|
|
655
736
|
return 0.2126 * linear[0] + 0.7152 * linear[1] + 0.0722 * linear[2];
|
|
656
737
|
}
|
|
738
|
+
function isOpaqueColor(color2) {
|
|
739
|
+
const c = rgb(color2);
|
|
740
|
+
return c != null && !Number.isNaN(c.r) && c.opacity === 1;
|
|
741
|
+
}
|
|
657
742
|
function contrastRatio(fg, bg) {
|
|
658
743
|
const l1 = relativeLuminance(fg);
|
|
659
744
|
const l2 = relativeLuminance(bg);
|
|
@@ -812,6 +897,30 @@ var DIVERGING_PALETTES = {
|
|
|
812
897
|
redBlue: [...DIVERGING_RED_BLUE.stops],
|
|
813
898
|
brownTeal: [...DIVERGING_BROWN_TEAL.stops]
|
|
814
899
|
};
|
|
900
|
+
var VL_SCHEME_ALIASES = {
|
|
901
|
+
blues: "blue",
|
|
902
|
+
greens: "green",
|
|
903
|
+
oranges: "orange",
|
|
904
|
+
purples: "purple",
|
|
905
|
+
teals: "teal",
|
|
906
|
+
redblue: "redBlue",
|
|
907
|
+
brownteal: "brownTeal",
|
|
908
|
+
// ColorBrewer BrBG, which brownTeal mirrors
|
|
909
|
+
brownbluegreen: "brownTeal",
|
|
910
|
+
category10: "categorical",
|
|
911
|
+
tableau10: "categorical"
|
|
912
|
+
};
|
|
913
|
+
function resolveSchemeName(name) {
|
|
914
|
+
const canonical = SEQUENTIAL_PALETTES[name] || DIVERGING_PALETTES[name] ? name : VL_SCHEME_ALIASES[name.toLowerCase()] ?? name.toLowerCase();
|
|
915
|
+
if (canonical === "categorical") return [...CATEGORICAL_PALETTE];
|
|
916
|
+
return SEQUENTIAL_PALETTES[canonical] ?? DIVERGING_PALETTES[canonical];
|
|
917
|
+
}
|
|
918
|
+
var SUPPORTED_SCHEME_NAMES = [
|
|
919
|
+
...Object.keys(SEQUENTIAL_PALETTES),
|
|
920
|
+
...Object.keys(DIVERGING_PALETTES),
|
|
921
|
+
"categorical",
|
|
922
|
+
...Object.keys(VL_SCHEME_ALIASES)
|
|
923
|
+
];
|
|
815
924
|
|
|
816
925
|
// src/layout/text-measure.ts
|
|
817
926
|
var CHAR_WIDTHS_400 = {
|
|
@@ -1232,6 +1341,7 @@ var X_AXIS_TITLE_BAND = 22;
|
|
|
1232
1341
|
var X_AXIS_TITLE_BAND_ROTATED = 20;
|
|
1233
1342
|
var X_AXIS_ROTATED_EXTENT_CAP = 120;
|
|
1234
1343
|
var TICK_LINE_HEIGHT_FACTOR = 1.2;
|
|
1344
|
+
var AXIS_TO_LABEL_GAP = 3;
|
|
1235
1345
|
function computeXAxisExtentFromLabels(input) {
|
|
1236
1346
|
const measure = input.measure ?? estimateTextWidth;
|
|
1237
1347
|
const baseHeight = input.xAxisHeight ?? X_AXIS_BAND_HEIGHT;
|
|
@@ -1243,14 +1353,41 @@ function computeXAxisExtentFromLabels(input) {
|
|
|
1243
1353
|
if (w > maxLabelWidth) maxLabelWidth = w;
|
|
1244
1354
|
}
|
|
1245
1355
|
const lineHeight = input.tickFontSize * TICK_LINE_HEIGHT_FACTOR;
|
|
1246
|
-
const AXIS_TO_LABEL_GAP = 3;
|
|
1247
1356
|
const rotatedHeight = Math.min(
|
|
1248
1357
|
maxLabelWidth * Math.sin(angleRad) + lineHeight * Math.cos(angleRad) + AXIS_TO_LABEL_GAP,
|
|
1249
1358
|
X_AXIS_ROTATED_EXTENT_CAP
|
|
1250
1359
|
);
|
|
1251
1360
|
return input.hasTitle ? rotatedHeight + X_AXIS_TITLE_BAND_ROTATED : rotatedHeight;
|
|
1252
1361
|
}
|
|
1253
|
-
|
|
1362
|
+
const tickExtent = 4 + input.tickFontSize + Math.max(11, Math.ceil(input.tickFontSize * 0.7));
|
|
1363
|
+
const flatHeight = Math.max(baseHeight, tickExtent);
|
|
1364
|
+
return input.hasTitle ? flatHeight + X_AXIS_TITLE_BAND : flatHeight;
|
|
1365
|
+
}
|
|
1366
|
+
function maxRotatedLabelWidth(tickAngle, tickFontSize) {
|
|
1367
|
+
const angleRad = Math.abs(tickAngle) * (Math.PI / 180);
|
|
1368
|
+
const sin = Math.sin(angleRad);
|
|
1369
|
+
if (sin <= 1e-3) return Number.POSITIVE_INFINITY;
|
|
1370
|
+
const lineHeight = tickFontSize * TICK_LINE_HEIGHT_FACTOR;
|
|
1371
|
+
const usable = X_AXIS_ROTATED_EXTENT_CAP - lineHeight * Math.cos(angleRad) - AXIS_TO_LABEL_GAP;
|
|
1372
|
+
return Math.max(0, usable / sin);
|
|
1373
|
+
}
|
|
1374
|
+
function truncateRotatedLabel(label, tickAngle, tickFontSize, tickFontWeight, measure = estimateTextWidth) {
|
|
1375
|
+
const budget = maxRotatedLabelWidth(tickAngle, tickFontSize);
|
|
1376
|
+
if (!Number.isFinite(budget)) return label;
|
|
1377
|
+
if (measure(label, tickFontSize, tickFontWeight) <= budget) return label;
|
|
1378
|
+
const ELLIPSIS = "\u2026";
|
|
1379
|
+
let lo = 0;
|
|
1380
|
+
let hi = label.length;
|
|
1381
|
+
while (lo < hi) {
|
|
1382
|
+
const mid = Math.ceil((lo + hi) / 2);
|
|
1383
|
+
const candidate = label.slice(0, mid) + ELLIPSIS;
|
|
1384
|
+
if (measure(candidate, tickFontSize, tickFontWeight) <= budget) {
|
|
1385
|
+
lo = mid;
|
|
1386
|
+
} else {
|
|
1387
|
+
hi = mid - 1;
|
|
1388
|
+
}
|
|
1389
|
+
}
|
|
1390
|
+
return lo > 0 ? label.slice(0, lo).trimEnd() + ELLIPSIS : ELLIPSIS;
|
|
1254
1391
|
}
|
|
1255
1392
|
|
|
1256
1393
|
// src/theme/defaults.ts
|
|
@@ -1790,6 +1927,12 @@ function estimateLineCount(text, style, maxWidth, measureText) {
|
|
|
1790
1927
|
}
|
|
1791
1928
|
return lines;
|
|
1792
1929
|
}
|
|
1930
|
+
var FOOTNOTE_LINE_HEIGHT = 1.3;
|
|
1931
|
+
var FOOTNOTE_BAND_GAP = 4;
|
|
1932
|
+
function footnoteBandHeight(count, theme) {
|
|
1933
|
+
if (count <= 0) return 0;
|
|
1934
|
+
return count * theme.fonts.sizes.small * FOOTNOTE_LINE_HEIGHT + FOOTNOTE_BAND_GAP;
|
|
1935
|
+
}
|
|
1793
1936
|
function computeChrome(chrome, theme, width, measureText, chromeMode = "full", padding, watermark = true, bottomLegendHeight = 0) {
|
|
1794
1937
|
if (!chrome || chromeMode === "hidden") {
|
|
1795
1938
|
return { topHeight: 0, bottomHeight: 0 };
|
|
@@ -2118,7 +2261,8 @@ function resolveCollisions(labels, strategies = OFFSET_STRATEGIES) {
|
|
|
2118
2261
|
from: { x: bestX, y: bestY },
|
|
2119
2262
|
to: { x: label.anchorX, y: label.anchorY },
|
|
2120
2263
|
stroke: label.style.fill,
|
|
2121
|
-
style: "straight"
|
|
2264
|
+
style: "straight",
|
|
2265
|
+
arrow: false
|
|
2122
2266
|
} : void 0
|
|
2123
2267
|
});
|
|
2124
2268
|
} else {
|
|
@@ -3145,30 +3289,65 @@ function formatNumber(value, _locale) {
|
|
|
3145
3289
|
if (Number.isInteger(value)) {
|
|
3146
3290
|
return format(",")(value);
|
|
3147
3291
|
}
|
|
3292
|
+
if (Math.abs(value) < 5e-3) {
|
|
3293
|
+
return format(".2~r")(value);
|
|
3294
|
+
}
|
|
3148
3295
|
return format(",.2f")(value);
|
|
3149
3296
|
}
|
|
3150
|
-
var
|
|
3297
|
+
var UNIT_TABLE = [
|
|
3151
3298
|
{ threshold: 1e12, suffix: "T", divisor: 1e12 },
|
|
3152
3299
|
{ threshold: 1e9, suffix: "B", divisor: 1e9 },
|
|
3153
3300
|
{ threshold: 1e6, suffix: "M", divisor: 1e6 },
|
|
3154
|
-
{ threshold: 1e3, suffix: "
|
|
3301
|
+
{ threshold: 1e3, suffix: "k", divisor: 1e3 }
|
|
3155
3302
|
];
|
|
3303
|
+
function unitFor(abs) {
|
|
3304
|
+
for (const entry of UNIT_TABLE) {
|
|
3305
|
+
if (abs >= entry.threshold) return entry;
|
|
3306
|
+
}
|
|
3307
|
+
return { suffix: "", divisor: 1 };
|
|
3308
|
+
}
|
|
3309
|
+
function fractionDigits(x) {
|
|
3310
|
+
const a = Math.abs(x);
|
|
3311
|
+
for (let p = 0; p <= 3; p++) {
|
|
3312
|
+
const scaled = a * 10 ** p;
|
|
3313
|
+
if (Math.abs(scaled - Math.round(scaled)) < 1e-9) return p;
|
|
3314
|
+
}
|
|
3315
|
+
return 4;
|
|
3316
|
+
}
|
|
3156
3317
|
function abbreviateNumber(value) {
|
|
3157
3318
|
if (!Number.isFinite(value)) return String(value);
|
|
3158
3319
|
const absValue = Math.abs(value);
|
|
3159
3320
|
const sign = value < 0 ? "-" : "";
|
|
3160
|
-
for (
|
|
3321
|
+
for (let i = 0; i < UNIT_TABLE.length; i++) {
|
|
3322
|
+
const { threshold, suffix, divisor } = UNIT_TABLE[i];
|
|
3161
3323
|
if (absValue >= threshold) {
|
|
3162
|
-
const
|
|
3163
|
-
|
|
3164
|
-
|
|
3324
|
+
const mantissa = format(".1~f")(absValue / divisor);
|
|
3325
|
+
if (mantissa === "1000" && i > 0) {
|
|
3326
|
+
return `${sign}1${UNIT_TABLE[i - 1].suffix}`;
|
|
3327
|
+
}
|
|
3328
|
+
return `${sign}${mantissa}${suffix}`;
|
|
3165
3329
|
}
|
|
3166
3330
|
}
|
|
3167
3331
|
return formatNumber(value);
|
|
3168
3332
|
}
|
|
3333
|
+
function formatOrdinal(value) {
|
|
3334
|
+
if (!Number.isFinite(value)) return String(value);
|
|
3335
|
+
const n = Math.round(value);
|
|
3336
|
+
const abs = Math.abs(n);
|
|
3337
|
+
const rem100 = abs % 100;
|
|
3338
|
+
const rem10 = abs % 10;
|
|
3339
|
+
let suffix;
|
|
3340
|
+
if (rem100 >= 11 && rem100 <= 13) suffix = "th";
|
|
3341
|
+
else if (rem10 === 1) suffix = "st";
|
|
3342
|
+
else if (rem10 === 2) suffix = "nd";
|
|
3343
|
+
else if (rem10 === 3) suffix = "rd";
|
|
3344
|
+
else suffix = "th";
|
|
3345
|
+
return `${n}${suffix}`;
|
|
3346
|
+
}
|
|
3169
3347
|
var D3_FORMAT_SUFFIX_RE = /^(.*~?[efgsrdxXobcnp%])(.+)$/;
|
|
3170
3348
|
function buildD3Formatter(formatStr) {
|
|
3171
3349
|
if (!formatStr) return null;
|
|
3350
|
+
if (formatStr === "ordinal") return formatOrdinal;
|
|
3172
3351
|
try {
|
|
3173
3352
|
const fmt = format(formatStr);
|
|
3174
3353
|
if (formatStr.includes("s")) {
|
|
@@ -3188,6 +3367,111 @@ function buildD3Formatter(formatStr) {
|
|
|
3188
3367
|
}
|
|
3189
3368
|
return null;
|
|
3190
3369
|
}
|
|
3370
|
+
function formatPercent(value, options) {
|
|
3371
|
+
const fraction = options?.fraction ?? true;
|
|
3372
|
+
if (fraction) {
|
|
3373
|
+
return format(".1~%")(value);
|
|
3374
|
+
}
|
|
3375
|
+
return `${format(",.1~f")(value)}%`;
|
|
3376
|
+
}
|
|
3377
|
+
function formatCurrency(value, options) {
|
|
3378
|
+
const compact = options?.compact ?? false;
|
|
3379
|
+
const abs = Math.abs(value);
|
|
3380
|
+
const sign = value < 0 ? "-" : "";
|
|
3381
|
+
if (compact) {
|
|
3382
|
+
if (abs >= 1e3) {
|
|
3383
|
+
return `${sign}$${abbreviateNumber(abs)}`;
|
|
3384
|
+
}
|
|
3385
|
+
return `${sign}$${formatNumber(abs)}`;
|
|
3386
|
+
}
|
|
3387
|
+
if (Number.isInteger(value)) {
|
|
3388
|
+
return sign + format("$,")(abs);
|
|
3389
|
+
}
|
|
3390
|
+
return sign + format("$,.2f")(abs);
|
|
3391
|
+
}
|
|
3392
|
+
function computeFieldFormatContext(values, surface) {
|
|
3393
|
+
let min = Infinity;
|
|
3394
|
+
let max = -Infinity;
|
|
3395
|
+
let allIntegers = true;
|
|
3396
|
+
let hasFinite = false;
|
|
3397
|
+
for (const raw of values) {
|
|
3398
|
+
const v = typeof raw === "number" ? raw : typeof raw === "string" ? Number(raw) : NaN;
|
|
3399
|
+
if (!Number.isFinite(v)) continue;
|
|
3400
|
+
hasFinite = true;
|
|
3401
|
+
if (v < min) min = v;
|
|
3402
|
+
if (v > max) max = v;
|
|
3403
|
+
if (allIntegers && !Number.isInteger(v)) allIntegers = false;
|
|
3404
|
+
}
|
|
3405
|
+
const ctx = {};
|
|
3406
|
+
if (hasFinite) {
|
|
3407
|
+
ctx.extent = [min, max];
|
|
3408
|
+
ctx.allIntegers = allIntegers;
|
|
3409
|
+
}
|
|
3410
|
+
if (surface) ctx.surface = surface;
|
|
3411
|
+
return ctx;
|
|
3412
|
+
}
|
|
3413
|
+
function isYearContext(ctx) {
|
|
3414
|
+
if (!ctx?.extent || !ctx.allIntegers) return false;
|
|
3415
|
+
const [min, max] = ctx.extent;
|
|
3416
|
+
return min >= 1500 && max <= 2500;
|
|
3417
|
+
}
|
|
3418
|
+
function resolveNumberFormatter(formatStr, ctx) {
|
|
3419
|
+
if (!formatStr) return null;
|
|
3420
|
+
if (formatStr === "ordinal") return formatOrdinal;
|
|
3421
|
+
if (formatStr === "percent") {
|
|
3422
|
+
const fraction = ctx?.extent ? Math.max(Math.abs(ctx.extent[0]), Math.abs(ctx.extent[1])) <= 1 : true;
|
|
3423
|
+
return (v) => formatPercent(v, { fraction });
|
|
3424
|
+
}
|
|
3425
|
+
if (formatStr === "currency") {
|
|
3426
|
+
const isTable = ctx?.surface === "table";
|
|
3427
|
+
if (!isTable && ctx?.step != null && (ctx.stepReference ?? 0) >= 1e3) {
|
|
3428
|
+
const stepFmt = buildCompactStepFormatter(ctx.step);
|
|
3429
|
+
return (v) => {
|
|
3430
|
+
const sign = v < 0 ? "-" : "";
|
|
3431
|
+
return `${sign}$${stepFmt(Math.abs(v))}`;
|
|
3432
|
+
};
|
|
3433
|
+
}
|
|
3434
|
+
return (v) => formatCurrency(v, { compact: !isTable });
|
|
3435
|
+
}
|
|
3436
|
+
return buildD3Formatter(formatStr);
|
|
3437
|
+
}
|
|
3438
|
+
function defaultNumberFormatter(ctx) {
|
|
3439
|
+
if (isYearContext(ctx)) {
|
|
3440
|
+
return (v) => String(Math.round(v));
|
|
3441
|
+
}
|
|
3442
|
+
if (ctx?.surface === "table") {
|
|
3443
|
+
return formatNumber;
|
|
3444
|
+
}
|
|
3445
|
+
if (ctx?.step != null && (ctx.stepReference ?? maxAbs(ctx.extent)) >= 1e3) {
|
|
3446
|
+
return buildCompactStepFormatter(ctx.step);
|
|
3447
|
+
}
|
|
3448
|
+
return (v) => {
|
|
3449
|
+
if (!Number.isFinite(v)) return String(v);
|
|
3450
|
+
if (ctx?.extent === void 0 && ctx?.allIntegers === void 0) {
|
|
3451
|
+
if (Number.isInteger(v) && v >= 1500 && v <= 2500) return String(v);
|
|
3452
|
+
}
|
|
3453
|
+
return Math.abs(v) >= 1e3 ? abbreviateNumber(v) : formatNumber(v);
|
|
3454
|
+
};
|
|
3455
|
+
}
|
|
3456
|
+
function maxAbs(extent) {
|
|
3457
|
+
if (!extent) return 0;
|
|
3458
|
+
return Math.max(Math.abs(extent[0]), Math.abs(extent[1]));
|
|
3459
|
+
}
|
|
3460
|
+
function buildCompactStepFormatter(step) {
|
|
3461
|
+
return (v) => {
|
|
3462
|
+
if (v === 0) return "0";
|
|
3463
|
+
if (!Number.isFinite(v)) return String(v);
|
|
3464
|
+
const abs = Math.abs(v);
|
|
3465
|
+
if (abs < 1e3) return formatNumber(v);
|
|
3466
|
+
const { suffix, divisor } = unitFor(abs);
|
|
3467
|
+
const p = fractionDigits(step / divisor);
|
|
3468
|
+
if (p > 2) {
|
|
3469
|
+
return Number.isInteger(v) ? format(",")(v) : format(",.2f")(v);
|
|
3470
|
+
}
|
|
3471
|
+
const sign = v < 0 ? "-" : "";
|
|
3472
|
+
return sign + format(`.${p}~f`)(abs / divisor) + suffix;
|
|
3473
|
+
};
|
|
3474
|
+
}
|
|
3191
3475
|
var GRANULARITY_FORMATS = {
|
|
3192
3476
|
year: "%Y",
|
|
3193
3477
|
quarter: "",
|
|
@@ -3262,7 +3546,34 @@ function generateAltText(spec, data) {
|
|
|
3262
3546
|
const titleText = typeof title === "string" ? title : title.text;
|
|
3263
3547
|
parts.push(`showing ${titleText}`);
|
|
3264
3548
|
}
|
|
3265
|
-
if (
|
|
3549
|
+
if (markType === "waffle") {
|
|
3550
|
+
const units = markDef.units ?? 100;
|
|
3551
|
+
parts.push(`dividing ${units} units`);
|
|
3552
|
+
}
|
|
3553
|
+
if (markType === "parliament") {
|
|
3554
|
+
const valueField = spec.encoding.theta?.field ?? spec.encoding.y?.field;
|
|
3555
|
+
if (valueField) {
|
|
3556
|
+
const totalSeats = data.reduce((sum, d) => {
|
|
3557
|
+
const v = Number(d[valueField]);
|
|
3558
|
+
return sum + (Number.isFinite(v) && v > 0 ? v : 0);
|
|
3559
|
+
}, 0);
|
|
3560
|
+
if (totalSeats > 0) {
|
|
3561
|
+
const majority = Math.floor(totalSeats / 2) + 1;
|
|
3562
|
+
parts.push(`with ${totalSeats} seats, ${majority} needed for a majority`);
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
}
|
|
3566
|
+
if (markType === "beeswarm") {
|
|
3567
|
+
const xIsValue = spec.encoding.x?.type === "quantitative";
|
|
3568
|
+
const valueField = xIsValue ? spec.encoding.x?.field : spec.encoding.y?.field;
|
|
3569
|
+
const laneField = xIsValue ? spec.encoding.y?.field : spec.encoding.x?.field;
|
|
3570
|
+
if (valueField) {
|
|
3571
|
+
parts.push(
|
|
3572
|
+
`plotting the distribution of ${valueField}${laneField ? ` by ${laneField}` : ""}`
|
|
3573
|
+
);
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
if (spec.encoding.x && markType !== "beeswarm" && data.length > 0) {
|
|
3266
3577
|
const field = spec.encoding.x.field;
|
|
3267
3578
|
const values = data.map((d) => d[field]).filter((v) => v != null);
|
|
3268
3579
|
if (values.length > 0) {
|
|
@@ -3347,11 +3658,12 @@ function generateAriaLabels(marks) {
|
|
|
3347
3658
|
}
|
|
3348
3659
|
return labels;
|
|
3349
3660
|
}
|
|
3661
|
+
var ariaNumberFormatter = defaultNumberFormatter();
|
|
3350
3662
|
function formatValue(value) {
|
|
3351
3663
|
if (value == null) return "N/A";
|
|
3352
3664
|
if (value instanceof Date) return value.toISOString().slice(0, 10);
|
|
3353
3665
|
if (typeof value === "number") {
|
|
3354
|
-
return
|
|
3666
|
+
return ariaNumberFormatter(value);
|
|
3355
3667
|
}
|
|
3356
3668
|
return String(value);
|
|
3357
3669
|
}
|
|
@@ -3431,7 +3743,7 @@ function pieChart(data, category, value, options) {
|
|
|
3431
3743
|
const categoryChannel = resolveField(category, data);
|
|
3432
3744
|
const valueChannel = resolveField(value, data);
|
|
3433
3745
|
const encoding = {
|
|
3434
|
-
|
|
3746
|
+
theta: valueChannel,
|
|
3435
3747
|
color: categoryChannel
|
|
3436
3748
|
};
|
|
3437
3749
|
if (options?.size && data) {
|
|
@@ -3449,7 +3761,7 @@ function donutChart(data, category, value, options) {
|
|
|
3449
3761
|
const categoryChannel = resolveField(category, data);
|
|
3450
3762
|
const valueChannel = resolveField(value, data);
|
|
3451
3763
|
const encoding = {
|
|
3452
|
-
|
|
3764
|
+
theta: valueChannel,
|
|
3453
3765
|
color: categoryChannel
|
|
3454
3766
|
};
|
|
3455
3767
|
if (options?.size && data) {
|
|
@@ -3514,6 +3826,182 @@ function tileMap(data, options) {
|
|
|
3514
3826
|
...options?.valueFormat && { valueFormat: options.valueFormat }
|
|
3515
3827
|
};
|
|
3516
3828
|
}
|
|
3829
|
+
|
|
3830
|
+
// src/helpers/deep-merge.ts
|
|
3831
|
+
function deepMergeSpec(target, source) {
|
|
3832
|
+
if (source === void 0) return target;
|
|
3833
|
+
if (source === null) return source;
|
|
3834
|
+
if (typeof source !== "object" || Array.isArray(source) || typeof target !== "object" || target === null || Array.isArray(target)) {
|
|
3835
|
+
return source;
|
|
3836
|
+
}
|
|
3837
|
+
const result = { ...target };
|
|
3838
|
+
for (const key of Object.keys(source)) {
|
|
3839
|
+
result[key] = deepMergeSpec(target[key], source[key]);
|
|
3840
|
+
}
|
|
3841
|
+
return result;
|
|
3842
|
+
}
|
|
3843
|
+
|
|
3844
|
+
// src/styles/token-definitions.ts
|
|
3845
|
+
var CSS_TOKEN_ROOT_SELECTORS = [
|
|
3846
|
+
".oc-root",
|
|
3847
|
+
".oc-chart-root",
|
|
3848
|
+
".oc-table-wrapper",
|
|
3849
|
+
".oc-table-root",
|
|
3850
|
+
".oc-graph-wrapper",
|
|
3851
|
+
".oc-graph-root",
|
|
3852
|
+
".oc-sankey-root",
|
|
3853
|
+
".oc-tilemap-root",
|
|
3854
|
+
".oc-barlist-root",
|
|
3855
|
+
".oc-map-root"
|
|
3856
|
+
];
|
|
3857
|
+
var CSS_TOKENS = [
|
|
3858
|
+
{
|
|
3859
|
+
name: "--oc-font-family",
|
|
3860
|
+
light: '\n "Inter Variable", Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif'
|
|
3861
|
+
},
|
|
3862
|
+
{
|
|
3863
|
+
name: "--oc-font-mono",
|
|
3864
|
+
light: '"JetBrains Mono", "Fira Code", "Cascadia Code", monospace'
|
|
3865
|
+
},
|
|
3866
|
+
{
|
|
3867
|
+
section: "Animation easing presets via CSS linear()",
|
|
3868
|
+
name: "--oc-ease-smooth",
|
|
3869
|
+
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 )"
|
|
3870
|
+
},
|
|
3871
|
+
{
|
|
3872
|
+
name: "--oc-ease-snappy",
|
|
3873
|
+
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 )",
|
|
3874
|
+
consumers: "EASE_VAR_MAP in vanilla renderers"
|
|
3875
|
+
},
|
|
3876
|
+
{ section: "Animation timing defaults", name: "--oc-animation-duration", light: "500ms" },
|
|
3877
|
+
{ name: "--oc-animation-stagger", light: "80ms" },
|
|
3878
|
+
{ name: "--oc-annotation-delay", light: "200ms" },
|
|
3879
|
+
{ section: "Typography scale (editorial design system)", name: "--oc-title-size", light: "26px" },
|
|
3880
|
+
{ name: "--oc-title-weight", light: "590" },
|
|
3881
|
+
{ name: "--oc-title-tracking", light: "-0.022em" },
|
|
3882
|
+
{ name: "--oc-subtitle-size", light: "14px" },
|
|
3883
|
+
{ name: "--oc-subtitle-weight", light: "450" },
|
|
3884
|
+
{ name: "--oc-source-size", light: "11px" },
|
|
3885
|
+
{ name: "--oc-source-weight", light: "450" },
|
|
3886
|
+
{ name: "--oc-body-size", light: "13px" },
|
|
3887
|
+
{ name: "--oc-eyebrow-size", light: "11px" },
|
|
3888
|
+
{ name: "--oc-eyebrow-weight", light: "550" },
|
|
3889
|
+
{ name: "--oc-eyebrow-tracking", light: "0.08em" },
|
|
3890
|
+
{ section: "Surfaces (light mode defaults)", name: "--oc-bg", light: "#ffffff", dark: "#09090b" },
|
|
3891
|
+
{ name: "--oc-card", light: "#ffffff", dark: "#111113" },
|
|
3892
|
+
{
|
|
3893
|
+
name: "--oc-secondary",
|
|
3894
|
+
light: "#f4f4f5",
|
|
3895
|
+
dark: "#27272a",
|
|
3896
|
+
comment: "zinc-100, raised surface"
|
|
3897
|
+
},
|
|
3898
|
+
{
|
|
3899
|
+
section: `Text levels. Names invert across modes: in light mode "muted" sits at
|
|
3900
|
+
* a lighter zinc step than "subtle" because both are picked relative to
|
|
3901
|
+
* the active background, not from a fixed lightness ladder. The intent
|
|
3902
|
+
* is "muted = first step away from primary text"; "subtle = next step
|
|
3903
|
+
* down"; etc.
|
|
3904
|
+
*
|
|
3905
|
+
* Light mode: text=zinc-950, secondary=zinc-700, muted=zinc-500,
|
|
3906
|
+
* subtle=zinc-400, faint=zinc-300
|
|
3907
|
+
* Dark mode (dark.css): inverts the surface tokens but keeps the same
|
|
3908
|
+
* muted -> subtle -> faint progression away from primary.`,
|
|
3909
|
+
name: "--oc-text",
|
|
3910
|
+
light: "#09090b",
|
|
3911
|
+
dark: "#f7f8f8"
|
|
3912
|
+
},
|
|
3913
|
+
{ name: "--oc-text-secondary", light: "#3f3f46", dark: "#d0d6e0" },
|
|
3914
|
+
{ name: "--oc-text-muted", light: "#71717a", dark: "#a1a1aa" },
|
|
3915
|
+
{ name: "--oc-text-faint", light: "#d4d4d8", dark: "#52525b" },
|
|
3916
|
+
{
|
|
3917
|
+
section: "Lines",
|
|
3918
|
+
name: "--oc-gridline",
|
|
3919
|
+
light: "rgba(0, 0, 0, 0.1)",
|
|
3920
|
+
dark: "rgba(255, 255, 255, 0.05)"
|
|
3921
|
+
},
|
|
3922
|
+
{
|
|
3923
|
+
name: "--oc-axis",
|
|
3924
|
+
light: "rgba(0, 0, 0, 0.1)",
|
|
3925
|
+
dark: "rgba(255, 255, 255, 0.1)"
|
|
3926
|
+
},
|
|
3927
|
+
{
|
|
3928
|
+
name: "--oc-border",
|
|
3929
|
+
light: "rgba(0, 0, 0, 0.08)",
|
|
3930
|
+
dark: "rgba(255, 255, 255, 0.1)"
|
|
3931
|
+
},
|
|
3932
|
+
{ name: "--oc-border-radius", light: "2px" },
|
|
3933
|
+
{
|
|
3934
|
+
section: "Brand and semantic",
|
|
3935
|
+
name: "--oc-accent",
|
|
3936
|
+
light: "#06b6d4",
|
|
3937
|
+
dark: "#06b6d4"
|
|
3938
|
+
},
|
|
3939
|
+
{
|
|
3940
|
+
name: "--oc-accent-strong",
|
|
3941
|
+
light: "#0891b2",
|
|
3942
|
+
dark: "#06b6d4",
|
|
3943
|
+
comment: "darker cyan for line strokes on light bg",
|
|
3944
|
+
consumers: "stamped via adaptForLightLineStroke"
|
|
3945
|
+
},
|
|
3946
|
+
{ name: "--oc-positive", light: "#10b981", dark: "#34d399" },
|
|
3947
|
+
{ name: "--oc-negative", light: "#e11d48", dark: "#fb7185" },
|
|
3948
|
+
{ name: "--oc-focus", light: "#3b82f6", dark: "#60a5fa" },
|
|
3949
|
+
{
|
|
3950
|
+
name: "--oc-focus-ring",
|
|
3951
|
+
light: "rgba(59, 130, 246, 0.1)",
|
|
3952
|
+
comment: "static, intentionally NOT derived from --oc-focus and NOT flipped in dark mode"
|
|
3953
|
+
},
|
|
3954
|
+
{
|
|
3955
|
+
name: "--oc-focus-ring-strong",
|
|
3956
|
+
light: "rgba(59, 130, 246, 0.25)"
|
|
3957
|
+
},
|
|
3958
|
+
{
|
|
3959
|
+
name: "--oc-editable-hover",
|
|
3960
|
+
light: "rgba(79, 70, 229, 0.35)",
|
|
3961
|
+
comment: "edit-mode hover outline, indigo one-off"
|
|
3962
|
+
},
|
|
3963
|
+
{
|
|
3964
|
+
section: "Spacing scale (4px base) \u2014 only --oc-space-2/4 are consumed (JS-stamped)",
|
|
3965
|
+
name: "--oc-space-2",
|
|
3966
|
+
light: "8px",
|
|
3967
|
+
consumers: "stamped at mount from theme.spacing (theme-tokens.ts); component CSS must NOT consume these"
|
|
3968
|
+
},
|
|
3969
|
+
{
|
|
3970
|
+
name: "--oc-space-4",
|
|
3971
|
+
light: "16px",
|
|
3972
|
+
consumers: "stamped at mount from theme.spacing (theme-tokens.ts); component CSS must NOT consume these"
|
|
3973
|
+
},
|
|
3974
|
+
{
|
|
3975
|
+
section: "Interactive states",
|
|
3976
|
+
name: "--oc-hover-bg",
|
|
3977
|
+
light: "rgba(0, 0, 0, 0.025)",
|
|
3978
|
+
dark: "rgba(255, 255, 255, 0.05)"
|
|
3979
|
+
},
|
|
3980
|
+
{
|
|
3981
|
+
name: "--oc-tooltip-bg",
|
|
3982
|
+
light: "rgba(255, 255, 255, 0.88)",
|
|
3983
|
+
dark: "rgba(17, 17, 19, 0.92)"
|
|
3984
|
+
},
|
|
3985
|
+
{
|
|
3986
|
+
name: "--oc-tooltip-border",
|
|
3987
|
+
light: "rgba(0, 0, 0, 0.08)",
|
|
3988
|
+
dark: "rgba(255, 255, 255, 0.08)"
|
|
3989
|
+
},
|
|
3990
|
+
{
|
|
3991
|
+
name: "--oc-tooltip-shadow",
|
|
3992
|
+
light: "0 2px 8px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.12)",
|
|
3993
|
+
dark: "0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4)"
|
|
3994
|
+
},
|
|
3995
|
+
{ name: "--oc-tooltip-text", light: "#09090b", dark: "#f7f8f8" },
|
|
3996
|
+
{ name: "--oc-legend-text", light: "#3f3f46", dark: "#d0d6e0" }
|
|
3997
|
+
];
|
|
3998
|
+
var TOKEN_MAP = new Map(CSS_TOKENS.map((t) => [t.name, t]));
|
|
3999
|
+
function cssTokenDefault(name, mode) {
|
|
4000
|
+
const token = TOKEN_MAP.get(name);
|
|
4001
|
+
if (!token) throw new Error(`Unknown CSS token: ${name}`);
|
|
4002
|
+
if (mode === "dark" && token.dark !== void 0) return token.dark;
|
|
4003
|
+
return token.light;
|
|
4004
|
+
}
|
|
3517
4005
|
export {
|
|
3518
4006
|
ACHROMATIC_RAMP,
|
|
3519
4007
|
AXIS_TITLE_GAP,
|
|
@@ -3526,12 +4014,13 @@ export {
|
|
|
3526
4014
|
BREAKPOINT_COMPACT_MAX,
|
|
3527
4015
|
BREAKPOINT_MEDIUM_MAX,
|
|
3528
4016
|
CATEGORICAL_PALETTE,
|
|
3529
|
-
CHART_ENCODING_RULES,
|
|
3530
|
-
CHART_TYPES,
|
|
3531
4017
|
COMPACT_WIDTH,
|
|
4018
|
+
CSS_TOKENS,
|
|
4019
|
+
CSS_TOKEN_ROOT_SELECTORS,
|
|
3532
4020
|
DEFAULT_THEME,
|
|
3533
4021
|
DIVERGING_PALETTES,
|
|
3534
4022
|
EXTENDED_OFFSET_STRATEGIES,
|
|
4023
|
+
FOOTNOTE_LINE_HEIGHT,
|
|
3535
4024
|
GRAPH_ENCODING_RULES,
|
|
3536
4025
|
HEIGHT_CRAMPED_MAX,
|
|
3537
4026
|
HEIGHT_SHORT_MAX,
|
|
@@ -3550,6 +4039,7 @@ export {
|
|
|
3550
4039
|
NARROW_VIEWPORT_MAX,
|
|
3551
4040
|
OFFSET_STRATEGIES,
|
|
3552
4041
|
SEQUENTIAL_PALETTES,
|
|
4042
|
+
SUPPORTED_SCHEME_NAMES,
|
|
3553
4043
|
TICK_LABEL_OFFSET,
|
|
3554
4044
|
TICK_LINE_HEIGHT_FACTOR,
|
|
3555
4045
|
TOP_PAD_EXTRA_NARROW,
|
|
@@ -3565,15 +4055,20 @@ export {
|
|
|
3565
4055
|
areaChart,
|
|
3566
4056
|
axisTitleOffset,
|
|
3567
4057
|
barChart,
|
|
4058
|
+
buildCompactStepFormatter,
|
|
3568
4059
|
buildD3Formatter,
|
|
3569
4060
|
buildTemporalFormatter,
|
|
3570
4061
|
checkPaletteDistinguishability,
|
|
3571
4062
|
columnChart,
|
|
3572
4063
|
computeChrome,
|
|
4064
|
+
computeFieldFormatContext,
|
|
3573
4065
|
computeLabelBounds,
|
|
3574
4066
|
computeXAxisExtentFromLabels,
|
|
3575
4067
|
contrastRatio,
|
|
4068
|
+
cssTokenDefault,
|
|
3576
4069
|
dataTable,
|
|
4070
|
+
deepMergeSpec,
|
|
4071
|
+
defaultNumberFormatter,
|
|
3577
4072
|
detectCollision,
|
|
3578
4073
|
donutChart,
|
|
3579
4074
|
dotChart,
|
|
@@ -3582,8 +4077,12 @@ export {
|
|
|
3582
4077
|
essay,
|
|
3583
4078
|
estimateTextWidth,
|
|
3584
4079
|
findAccessibleColor,
|
|
4080
|
+
footnoteBandHeight,
|
|
4081
|
+
formatCurrency,
|
|
3585
4082
|
formatDate,
|
|
3586
4083
|
formatNumber,
|
|
4084
|
+
formatOrdinal,
|
|
4085
|
+
formatPercent,
|
|
3587
4086
|
generateAltText,
|
|
3588
4087
|
generateAriaLabels,
|
|
3589
4088
|
generateDataTable,
|
|
@@ -3594,6 +4093,7 @@ export {
|
|
|
3594
4093
|
getRepresentativeColor,
|
|
3595
4094
|
heuristicMeasure,
|
|
3596
4095
|
inferFieldType,
|
|
4096
|
+
isAxislessMark,
|
|
3597
4097
|
isBarListSpec,
|
|
3598
4098
|
isChartSpec,
|
|
3599
4099
|
isConditionalDef,
|
|
@@ -3601,13 +4101,18 @@ export {
|
|
|
3601
4101
|
isGradientDef,
|
|
3602
4102
|
isGraphSpec,
|
|
3603
4103
|
isLayerSpec,
|
|
4104
|
+
isMapSpec,
|
|
4105
|
+
isOpaqueColor,
|
|
3604
4106
|
isRangeAnnotation,
|
|
3605
4107
|
isRefLineAnnotation,
|
|
3606
4108
|
isSankeySpec,
|
|
3607
4109
|
isTableSpec,
|
|
3608
4110
|
isTextAnnotation,
|
|
3609
4111
|
isTileMapSpec,
|
|
4112
|
+
isValueDef,
|
|
4113
|
+
isYearContext,
|
|
3610
4114
|
lineChart,
|
|
4115
|
+
maxRotatedLabelWidth,
|
|
3611
4116
|
meetsAA,
|
|
3612
4117
|
overlapArea,
|
|
3613
4118
|
pickLabelColor,
|
|
@@ -3616,11 +4121,14 @@ export {
|
|
|
3616
4121
|
resolveMarkDef,
|
|
3617
4122
|
resolveMarkType,
|
|
3618
4123
|
resolveMeasurer,
|
|
4124
|
+
resolveNumberFormatter,
|
|
4125
|
+
resolveSchemeName,
|
|
3619
4126
|
resolveTheme,
|
|
3620
4127
|
scatterChart,
|
|
3621
4128
|
simulateColorBlindness,
|
|
3622
4129
|
textAscent,
|
|
3623
4130
|
tileMap,
|
|
4131
|
+
truncateRotatedLabel,
|
|
3624
4132
|
wire,
|
|
3625
4133
|
wrapText
|
|
3626
4134
|
};
|