@opendata-ai/openchart-core 6.3.0 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +155 -3
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1 -764
- package/package.json +3 -2
- package/src/styles/animation.css +117 -0
- package/src/styles/base.css +53 -0
- package/src/styles/chrome.css +36 -0
- package/src/styles/dark.css +20 -0
- package/src/styles/graph.css +106 -0
- package/src/styles/index.css +22 -0
- package/src/styles/keyframes.css +120 -0
- package/src/styles/legend.css +16 -0
- package/src/styles/reduced-motion.css +44 -0
- package/src/styles/table-animation.css +91 -0
- package/src/styles/table.css +380 -0
- package/src/styles/tokens.css +93 -0
- package/src/styles/tooltip.css +88 -0
- package/src/types/events.ts +43 -3
- package/src/types/index.ts +8 -0
- package/src/types/layout.ts +48 -0
- package/src/types/spec.ts +71 -0
- package/src/styles/viz.css +0 -764
|
@@ -0,0 +1,380 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
* Table base
|
|
3
|
+
* --------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
.oc-table-wrapper {
|
|
6
|
+
font-family: var(--oc-font-family);
|
|
7
|
+
color: var(--oc-text);
|
|
8
|
+
background: var(--oc-bg);
|
|
9
|
+
|
|
10
|
+
& > .oc-chrome {
|
|
11
|
+
margin-bottom: 16px;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
& table {
|
|
15
|
+
width: 100%;
|
|
16
|
+
border-collapse: collapse;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
& th,
|
|
20
|
+
& td {
|
|
21
|
+
padding: 10px 16px;
|
|
22
|
+
text-align: left;
|
|
23
|
+
border-bottom: 1px solid var(--oc-border);
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
& th {
|
|
27
|
+
font-weight: 600;
|
|
28
|
+
font-size: 12px;
|
|
29
|
+
text-transform: uppercase;
|
|
30
|
+
letter-spacing: 0.05em;
|
|
31
|
+
color: var(--oc-text-secondary);
|
|
32
|
+
white-space: nowrap;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
& thead {
|
|
36
|
+
position: sticky;
|
|
37
|
+
top: 0;
|
|
38
|
+
z-index: 2;
|
|
39
|
+
background: var(--oc-bg);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
& thead th {
|
|
43
|
+
border-bottom-width: 2px;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
& td {
|
|
47
|
+
font-size: 14px;
|
|
48
|
+
font-variant-numeric: tabular-nums;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
& th:focus {
|
|
52
|
+
outline: 2px solid var(--oc-focus);
|
|
53
|
+
outline-offset: -2px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
& tbody:focus {
|
|
57
|
+
outline: none;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
.oc-table-title {
|
|
62
|
+
margin-bottom: 4px;
|
|
63
|
+
font-size: var(--oc-title-computed-size, var(--oc-title-size));
|
|
64
|
+
font-weight: var(--oc-title-computed-weight, var(--oc-title-weight));
|
|
65
|
+
color: var(--oc-title-computed-color, var(--oc-text));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.oc-table-subtitle {
|
|
69
|
+
margin-bottom: 8px;
|
|
70
|
+
font-size: var(--oc-subtitle-computed-size, var(--oc-subtitle-size));
|
|
71
|
+
font-weight: var(--oc-subtitle-computed-weight, var(--oc-subtitle-weight));
|
|
72
|
+
color: var(--oc-subtitle-computed-color, var(--oc-text-secondary));
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.oc-table-source {
|
|
76
|
+
font-size: var(--oc-source-computed-size, var(--oc-source-size));
|
|
77
|
+
color: var(--oc-source-computed-color, var(--oc-text-muted));
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.oc-table-footer-text {
|
|
81
|
+
font-size: var(--oc-footer-computed-size, var(--oc-source-size));
|
|
82
|
+
color: var(--oc-footer-computed-color, var(--oc-text-muted));
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
.oc-table-scroll {
|
|
86
|
+
overflow-x: auto;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/* ---------------------------------------------------------------------------
|
|
90
|
+
* Sticky first column
|
|
91
|
+
* --------------------------------------------------------------------------- */
|
|
92
|
+
|
|
93
|
+
.oc-table--sticky {
|
|
94
|
+
& th:first-child,
|
|
95
|
+
& td:first-child {
|
|
96
|
+
position: sticky;
|
|
97
|
+
left: 0;
|
|
98
|
+
z-index: 1;
|
|
99
|
+
background: var(--oc-bg);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/* ---------------------------------------------------------------------------
|
|
104
|
+
* Sort controls
|
|
105
|
+
* --------------------------------------------------------------------------- */
|
|
106
|
+
|
|
107
|
+
.oc-table-sort-btn {
|
|
108
|
+
background: none;
|
|
109
|
+
border: none;
|
|
110
|
+
cursor: pointer;
|
|
111
|
+
padding: 2px;
|
|
112
|
+
margin-left: 6px;
|
|
113
|
+
display: inline-flex;
|
|
114
|
+
flex-direction: column;
|
|
115
|
+
align-items: center;
|
|
116
|
+
vertical-align: middle;
|
|
117
|
+
gap: 2px;
|
|
118
|
+
|
|
119
|
+
&::before,
|
|
120
|
+
&::after {
|
|
121
|
+
content: "";
|
|
122
|
+
display: block;
|
|
123
|
+
width: 0;
|
|
124
|
+
height: 0;
|
|
125
|
+
border-left: 5px solid transparent;
|
|
126
|
+
border-right: 5px solid transparent;
|
|
127
|
+
transition:
|
|
128
|
+
opacity 0.15s,
|
|
129
|
+
border-color 0.15s;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
&::before {
|
|
133
|
+
border-bottom: 4.5px solid var(--oc-text-secondary);
|
|
134
|
+
opacity: 0.45;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
&::after {
|
|
138
|
+
border-top: 4.5px solid var(--oc-text-secondary);
|
|
139
|
+
opacity: 0.45;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
&:hover::before,
|
|
143
|
+
&:hover::after {
|
|
144
|
+
opacity: 0.75;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
th[aria-sort="ascending"] .oc-table-sort-btn {
|
|
149
|
+
&::before {
|
|
150
|
+
opacity: 1;
|
|
151
|
+
border-bottom-color: var(--oc-text);
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
&::after {
|
|
155
|
+
opacity: 0.15;
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
th[aria-sort="descending"] .oc-table-sort-btn {
|
|
160
|
+
&::after {
|
|
161
|
+
opacity: 1;
|
|
162
|
+
border-top-color: var(--oc-text);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
&::before {
|
|
166
|
+
opacity: 0.15;
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/* ---------------------------------------------------------------------------
|
|
171
|
+
* Search
|
|
172
|
+
* --------------------------------------------------------------------------- */
|
|
173
|
+
|
|
174
|
+
.oc-table-search {
|
|
175
|
+
padding: 8px 0;
|
|
176
|
+
|
|
177
|
+
& input {
|
|
178
|
+
width: 100%;
|
|
179
|
+
padding: 8px 12px;
|
|
180
|
+
border: 1px solid var(--oc-border);
|
|
181
|
+
border-radius: 6px;
|
|
182
|
+
font-size: 13px;
|
|
183
|
+
font-family: inherit;
|
|
184
|
+
background: var(--oc-bg);
|
|
185
|
+
color: var(--oc-text);
|
|
186
|
+
box-sizing: border-box;
|
|
187
|
+
transition: border-color 0.15s;
|
|
188
|
+
|
|
189
|
+
&::placeholder {
|
|
190
|
+
color: var(--oc-text-muted);
|
|
191
|
+
font-size: 13px;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
&:focus {
|
|
195
|
+
outline: none;
|
|
196
|
+
border-color: var(--oc-focus);
|
|
197
|
+
box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/* ---------------------------------------------------------------------------
|
|
203
|
+
* Pagination
|
|
204
|
+
* --------------------------------------------------------------------------- */
|
|
205
|
+
|
|
206
|
+
.oc-table-pagination {
|
|
207
|
+
display: flex;
|
|
208
|
+
align-items: center;
|
|
209
|
+
justify-content: space-between;
|
|
210
|
+
padding: 12px 0 4px;
|
|
211
|
+
font-size: 13px;
|
|
212
|
+
color: var(--oc-text-secondary);
|
|
213
|
+
|
|
214
|
+
& button {
|
|
215
|
+
padding: 6px 14px;
|
|
216
|
+
border: 1px solid var(--oc-border);
|
|
217
|
+
border-radius: 6px;
|
|
218
|
+
background: var(--oc-bg);
|
|
219
|
+
color: var(--oc-text);
|
|
220
|
+
cursor: pointer;
|
|
221
|
+
font-size: 13px;
|
|
222
|
+
font-family: inherit;
|
|
223
|
+
transition:
|
|
224
|
+
background 0.15s,
|
|
225
|
+
border-color 0.15s;
|
|
226
|
+
|
|
227
|
+
&:disabled {
|
|
228
|
+
opacity: 0.35;
|
|
229
|
+
cursor: not-allowed;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
&:hover:not(:disabled) {
|
|
233
|
+
background: var(--oc-hover-bg);
|
|
234
|
+
border-color: var(--oc-axis);
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
&:focus-visible {
|
|
238
|
+
outline: 2px solid var(--oc-focus);
|
|
239
|
+
outline-offset: 1px;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.oc-table-pagination-info {
|
|
245
|
+
font-variant-numeric: tabular-nums;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.oc-table-pagination-btns {
|
|
249
|
+
display: flex;
|
|
250
|
+
gap: 8px;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/* ---------------------------------------------------------------------------
|
|
254
|
+
* Bar cells
|
|
255
|
+
* --------------------------------------------------------------------------- */
|
|
256
|
+
|
|
257
|
+
.oc-table-bar {
|
|
258
|
+
position: relative;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
.oc-table-bar-fill {
|
|
262
|
+
position: absolute;
|
|
263
|
+
top: 6px;
|
|
264
|
+
left: 0;
|
|
265
|
+
bottom: 6px;
|
|
266
|
+
border-radius: 2px;
|
|
267
|
+
opacity: 0.15;
|
|
268
|
+
pointer-events: none;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
.oc-table-bar-value {
|
|
272
|
+
position: relative;
|
|
273
|
+
z-index: 1;
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
/* ---------------------------------------------------------------------------
|
|
277
|
+
* Sparkline cells
|
|
278
|
+
* --------------------------------------------------------------------------- */
|
|
279
|
+
|
|
280
|
+
.oc-table-sparkline {
|
|
281
|
+
display: block;
|
|
282
|
+
width: 100%;
|
|
283
|
+
position: relative;
|
|
284
|
+
|
|
285
|
+
& svg {
|
|
286
|
+
display: block;
|
|
287
|
+
width: 100%;
|
|
288
|
+
overflow: visible;
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
.oc-table-sparkline-dot {
|
|
293
|
+
position: absolute;
|
|
294
|
+
border-radius: 50%;
|
|
295
|
+
width: 5px;
|
|
296
|
+
height: 5px;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
.oc-table-sparkline-labels {
|
|
300
|
+
display: flex;
|
|
301
|
+
justify-content: space-between;
|
|
302
|
+
font-size: 11px;
|
|
303
|
+
line-height: 1;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/* ---------------------------------------------------------------------------
|
|
307
|
+
* Image cells
|
|
308
|
+
* --------------------------------------------------------------------------- */
|
|
309
|
+
|
|
310
|
+
.oc-table-image {
|
|
311
|
+
display: inline-block;
|
|
312
|
+
vertical-align: middle;
|
|
313
|
+
|
|
314
|
+
& img {
|
|
315
|
+
object-fit: cover;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
.oc-table-image-rounded img {
|
|
320
|
+
border-radius: 50%;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/* ---------------------------------------------------------------------------
|
|
324
|
+
* Flag cells
|
|
325
|
+
* --------------------------------------------------------------------------- */
|
|
326
|
+
|
|
327
|
+
.oc-table-flag {
|
|
328
|
+
font-size: 1.2em;
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
/* ---------------------------------------------------------------------------
|
|
332
|
+
* Compact mode
|
|
333
|
+
* --------------------------------------------------------------------------- */
|
|
334
|
+
|
|
335
|
+
.oc-table--compact {
|
|
336
|
+
& th,
|
|
337
|
+
& td {
|
|
338
|
+
padding: 4px 8px;
|
|
339
|
+
font-size: 13px;
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
& th {
|
|
343
|
+
font-size: 11px;
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
/* ---------------------------------------------------------------------------
|
|
348
|
+
* Row hover (when onRowClick is set)
|
|
349
|
+
* --------------------------------------------------------------------------- */
|
|
350
|
+
|
|
351
|
+
.oc-table--clickable tbody {
|
|
352
|
+
& tr {
|
|
353
|
+
cursor: pointer;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
& tr:hover {
|
|
357
|
+
background: var(--oc-hover-bg);
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/* ---------------------------------------------------------------------------
|
|
362
|
+
* Keyboard cell focus indicator
|
|
363
|
+
* --------------------------------------------------------------------------- */
|
|
364
|
+
|
|
365
|
+
.oc-table-cell-focus {
|
|
366
|
+
outline: 2px solid var(--oc-focus);
|
|
367
|
+
outline-offset: -2px;
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
/* ---------------------------------------------------------------------------
|
|
371
|
+
* Empty state
|
|
372
|
+
* --------------------------------------------------------------------------- */
|
|
373
|
+
|
|
374
|
+
.oc-table-empty {
|
|
375
|
+
padding: 32px 16px;
|
|
376
|
+
text-align: center;
|
|
377
|
+
color: var(--oc-text-secondary);
|
|
378
|
+
font-size: 14px;
|
|
379
|
+
font-style: italic;
|
|
380
|
+
}
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
* Custom properties (light mode defaults)
|
|
3
|
+
* --------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
.oc-root,
|
|
6
|
+
.oc-chart-root,
|
|
7
|
+
.oc-table-wrapper,
|
|
8
|
+
.oc-table-root,
|
|
9
|
+
.oc-graph-wrapper,
|
|
10
|
+
.oc-graph-root {
|
|
11
|
+
--oc-font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
|
12
|
+
--oc-font-mono: "JetBrains Mono", "Fira Code", "Cascadia Code", monospace;
|
|
13
|
+
|
|
14
|
+
/* Animation easing presets via CSS linear() */
|
|
15
|
+
--oc-ease-smooth: linear(
|
|
16
|
+
0,
|
|
17
|
+
0.157,
|
|
18
|
+
0.438,
|
|
19
|
+
0.64,
|
|
20
|
+
0.766,
|
|
21
|
+
0.85,
|
|
22
|
+
0.906,
|
|
23
|
+
0.941,
|
|
24
|
+
0.964,
|
|
25
|
+
0.978,
|
|
26
|
+
0.988,
|
|
27
|
+
0.994,
|
|
28
|
+
0.998,
|
|
29
|
+
1
|
|
30
|
+
);
|
|
31
|
+
--oc-ease-snappy: linear(
|
|
32
|
+
0,
|
|
33
|
+
0.012,
|
|
34
|
+
0.048,
|
|
35
|
+
0.108,
|
|
36
|
+
0.194,
|
|
37
|
+
0.302,
|
|
38
|
+
0.426,
|
|
39
|
+
0.559,
|
|
40
|
+
0.69,
|
|
41
|
+
0.808,
|
|
42
|
+
0.905,
|
|
43
|
+
0.973,
|
|
44
|
+
1.013,
|
|
45
|
+
1.028,
|
|
46
|
+
1.023,
|
|
47
|
+
1.006,
|
|
48
|
+
0.984,
|
|
49
|
+
0.966,
|
|
50
|
+
0.957,
|
|
51
|
+
0.957,
|
|
52
|
+
0.964,
|
|
53
|
+
0.975,
|
|
54
|
+
0.986,
|
|
55
|
+
0.995,
|
|
56
|
+
1,
|
|
57
|
+
1.003,
|
|
58
|
+
1.002,
|
|
59
|
+
1,
|
|
60
|
+
0.998,
|
|
61
|
+
0.998,
|
|
62
|
+
0.999,
|
|
63
|
+
1
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
/* Animation timing defaults */
|
|
67
|
+
--oc-animation-duration: 500ms;
|
|
68
|
+
--oc-animation-stagger: 80ms;
|
|
69
|
+
--oc-annotation-delay: 200ms;
|
|
70
|
+
--oc-title-size: 22px;
|
|
71
|
+
--oc-title-weight: 700;
|
|
72
|
+
--oc-title-tracking: -0.02em;
|
|
73
|
+
--oc-subtitle-size: 14px;
|
|
74
|
+
--oc-subtitle-weight: 400;
|
|
75
|
+
--oc-source-size: 12px;
|
|
76
|
+
--oc-source-weight: 400;
|
|
77
|
+
--oc-body-size: 13px;
|
|
78
|
+
--oc-bg: #ffffff;
|
|
79
|
+
--oc-text: #1d1d1d;
|
|
80
|
+
--oc-text-secondary: #5c5c5c;
|
|
81
|
+
--oc-text-muted: #999999;
|
|
82
|
+
--oc-gridline: #e8e8e8;
|
|
83
|
+
--oc-axis: #888888;
|
|
84
|
+
--oc-border: #e2e2e2;
|
|
85
|
+
--oc-border-radius: 4px;
|
|
86
|
+
--oc-focus: #3b82f6;
|
|
87
|
+
--oc-hover-bg: rgba(0, 0, 0, 0.025);
|
|
88
|
+
--oc-tooltip-bg: rgba(255, 255, 255, 0.88);
|
|
89
|
+
--oc-tooltip-border: rgba(0, 0, 0, 0.08);
|
|
90
|
+
--oc-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.12);
|
|
91
|
+
--oc-tooltip-text: #1d1d1d;
|
|
92
|
+
--oc-legend-text: #555555;
|
|
93
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
* Tooltip
|
|
3
|
+
* --------------------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
.oc-tooltip {
|
|
6
|
+
position: absolute;
|
|
7
|
+
display: none;
|
|
8
|
+
pointer-events: none;
|
|
9
|
+
z-index: 1000;
|
|
10
|
+
background: var(--oc-tooltip-bg);
|
|
11
|
+
backdrop-filter: blur(12px);
|
|
12
|
+
border: 1px solid var(--oc-tooltip-border);
|
|
13
|
+
border-radius: 8px;
|
|
14
|
+
box-shadow: var(--oc-tooltip-shadow);
|
|
15
|
+
color: var(--oc-tooltip-text);
|
|
16
|
+
font-family: var(--oc-font-family);
|
|
17
|
+
font-size: 12px;
|
|
18
|
+
padding: 0;
|
|
19
|
+
max-width: 260px;
|
|
20
|
+
min-width: 140px;
|
|
21
|
+
line-height: 1.4;
|
|
22
|
+
animation: oc-tooltip-in 120ms ease-out;
|
|
23
|
+
|
|
24
|
+
& .oc-tooltip-header {
|
|
25
|
+
display: flex;
|
|
26
|
+
align-items: center;
|
|
27
|
+
gap: 6px;
|
|
28
|
+
padding: 8px 12px 6px;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
& .oc-tooltip-dot {
|
|
32
|
+
width: 8px;
|
|
33
|
+
height: 8px;
|
|
34
|
+
border-radius: 50%;
|
|
35
|
+
flex-shrink: 0;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
& .oc-tooltip-title {
|
|
39
|
+
font-weight: 600;
|
|
40
|
+
font-size: 12px;
|
|
41
|
+
letter-spacing: -0.01em;
|
|
42
|
+
color: var(--oc-tooltip-text);
|
|
43
|
+
white-space: nowrap;
|
|
44
|
+
overflow: hidden;
|
|
45
|
+
text-overflow: ellipsis;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
& .oc-tooltip-body {
|
|
49
|
+
padding: 4px 12px 8px;
|
|
50
|
+
border-top: 1px solid var(--oc-tooltip-border);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
/* Only add separator when header is present */
|
|
54
|
+
& .oc-tooltip-header + .oc-tooltip-body {
|
|
55
|
+
padding-top: 6px;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/* No separator when body is the only child */
|
|
59
|
+
& .oc-tooltip-body:first-child {
|
|
60
|
+
border-top: none;
|
|
61
|
+
padding-top: 8px;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
& .oc-tooltip-row {
|
|
65
|
+
display: flex;
|
|
66
|
+
align-items: baseline;
|
|
67
|
+
justify-content: space-between;
|
|
68
|
+
gap: 12px;
|
|
69
|
+
padding: 1px 0;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
& .oc-tooltip-label {
|
|
73
|
+
color: var(--oc-text-muted);
|
|
74
|
+
font-size: 11px;
|
|
75
|
+
white-space: nowrap;
|
|
76
|
+
flex-shrink: 0;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
& .oc-tooltip-value {
|
|
80
|
+
font-weight: 500;
|
|
81
|
+
font-size: 11px;
|
|
82
|
+
font-variant-numeric: tabular-nums;
|
|
83
|
+
text-align: right;
|
|
84
|
+
overflow: hidden;
|
|
85
|
+
text-overflow: ellipsis;
|
|
86
|
+
white-space: nowrap;
|
|
87
|
+
}
|
|
88
|
+
}
|
package/src/types/events.ts
CHANGED
|
@@ -25,13 +25,45 @@ import type {
|
|
|
25
25
|
/** Identifies a specific chrome text element (title, subtitle, source, byline, footer). */
|
|
26
26
|
export type ChromeKey = 'title' | 'subtitle' | 'source' | 'byline' | 'footer';
|
|
27
27
|
|
|
28
|
+
// ---------------------------------------------------------------------------
|
|
29
|
+
// Element references (identity for selection/edit callbacks)
|
|
30
|
+
// ---------------------------------------------------------------------------
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Reference to an editable chart element.
|
|
34
|
+
* Carries enough info to find the element in both the spec and the DOM.
|
|
35
|
+
* The `annotation` variant uses two-tier identity: `id` (when the consumer provides one)
|
|
36
|
+
* and `index` (always available, position in the spec's annotations array).
|
|
37
|
+
*/
|
|
38
|
+
export type ElementRef =
|
|
39
|
+
| { type: 'annotation'; index: number; id?: string }
|
|
40
|
+
| { type: 'chrome'; key: ChromeKey }
|
|
41
|
+
| { type: 'series-label'; series: string }
|
|
42
|
+
| { type: 'legend' }
|
|
43
|
+
| { type: 'legend-entry'; series: string; index: number };
|
|
44
|
+
|
|
45
|
+
/** Helper constructors for ergonomic ElementRef creation. */
|
|
46
|
+
export const elementRef = {
|
|
47
|
+
annotation: (index: number, id?: string): ElementRef => ({ type: 'annotation', index, id }),
|
|
48
|
+
chrome: (key: ChromeKey): ElementRef => ({ type: 'chrome', key }),
|
|
49
|
+
seriesLabel: (series: string): ElementRef => ({ type: 'series-label', series }),
|
|
50
|
+
legend: (): ElementRef => ({ type: 'legend' }),
|
|
51
|
+
legendEntry: (series: string, index: number): ElementRef => ({
|
|
52
|
+
type: 'legend-entry',
|
|
53
|
+
series,
|
|
54
|
+
index,
|
|
55
|
+
}),
|
|
56
|
+
} as const;
|
|
57
|
+
|
|
28
58
|
// ---------------------------------------------------------------------------
|
|
29
59
|
// Element edit events
|
|
30
60
|
// ---------------------------------------------------------------------------
|
|
31
61
|
|
|
32
62
|
/**
|
|
33
63
|
* Discriminated union of all element edit events.
|
|
34
|
-
* Fired by the `onEdit` callback when any editable chart element is
|
|
64
|
+
* Fired by the `onEdit` callback when any editable chart element is modified.
|
|
65
|
+
* Covers repositioning (drag), deletion (Delete key), and text editing (double-click).
|
|
66
|
+
* Selection events (onSelect/onDeselect) are separate callbacks, not part of this union.
|
|
35
67
|
*/
|
|
36
68
|
export type ElementEdit =
|
|
37
69
|
| { type: 'annotation'; annotation: TextAnnotation; offset: AnnotationOffset }
|
|
@@ -46,7 +78,9 @@ export type ElementEdit =
|
|
|
46
78
|
| { type: 'chrome'; key: ChromeKey; text: string; offset: AnnotationOffset }
|
|
47
79
|
| { type: 'series-label'; series: string; offset: AnnotationOffset }
|
|
48
80
|
| { type: 'legend'; offset: AnnotationOffset }
|
|
49
|
-
| { type: 'legend-toggle'; series: string; hidden: boolean }
|
|
81
|
+
| { type: 'legend-toggle'; series: string; hidden: boolean }
|
|
82
|
+
| { type: 'delete'; element: ElementRef }
|
|
83
|
+
| { type: 'text-edit'; element: ElementRef; oldText: string; newText: string };
|
|
50
84
|
|
|
51
85
|
// ---------------------------------------------------------------------------
|
|
52
86
|
// Mark events
|
|
@@ -92,6 +126,12 @@ export interface ChartEventHandlers {
|
|
|
92
126
|
onAnnotationClick?: (annotation: Annotation, event: MouseEvent) => void;
|
|
93
127
|
/** Called when a text annotation label is dragged to a new position. */
|
|
94
128
|
onAnnotationEdit?: (annotation: TextAnnotation, updatedOffset: AnnotationOffset) => void;
|
|
95
|
-
/** Unified edit callback. Fires for any
|
|
129
|
+
/** Unified edit callback. Fires for any spec-modifying edit (repositioning, deletion, text editing). */
|
|
96
130
|
onEdit?: (edit: ElementEdit) => void;
|
|
131
|
+
/** Fired when an element is selected via click or programmatic select(). */
|
|
132
|
+
onSelect?: (element: ElementRef) => void;
|
|
133
|
+
/** Fired when the current element is deselected (click empty, Escape, or new selection replaces old). */
|
|
134
|
+
onDeselect?: (element: ElementRef) => void;
|
|
135
|
+
/** Fired when inline text editing commits. Also flows through onEdit as a 'text-edit' event. */
|
|
136
|
+
onTextEdit?: (element: ElementRef, oldText: string, newText: string) => void;
|
|
97
137
|
}
|
package/src/types/index.ts
CHANGED
|
@@ -21,8 +21,10 @@ export type {
|
|
|
21
21
|
ChartEventHandlers,
|
|
22
22
|
ChromeKey,
|
|
23
23
|
ElementEdit,
|
|
24
|
+
ElementRef,
|
|
24
25
|
MarkEvent,
|
|
25
26
|
} from './events';
|
|
27
|
+
export { elementRef } from './events';
|
|
26
28
|
// Layout types (engine output)
|
|
27
29
|
export type {
|
|
28
30
|
A11yMetadata,
|
|
@@ -55,6 +57,7 @@ export type {
|
|
|
55
57
|
PointMark,
|
|
56
58
|
Rect,
|
|
57
59
|
RectMark,
|
|
60
|
+
ResolvedAnimation,
|
|
58
61
|
ResolvedAnnotation,
|
|
59
62
|
ResolvedChrome,
|
|
60
63
|
ResolvedChromeElement,
|
|
@@ -78,6 +81,11 @@ export type {
|
|
|
78
81
|
// Spec types (user input)
|
|
79
82
|
export type {
|
|
80
83
|
AggregateOp,
|
|
84
|
+
AnimationConfig,
|
|
85
|
+
AnimationEase,
|
|
86
|
+
AnimationPhaseConfig,
|
|
87
|
+
AnimationSpec,
|
|
88
|
+
AnimationStagger,
|
|
81
89
|
Annotation,
|
|
82
90
|
AnnotationAnchor,
|
|
83
91
|
AnnotationOffset,
|