@opendata-ai/openchart-svelte 6.4.1 → 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/Chart.svelte CHANGED
@@ -176,6 +176,6 @@ export function deselect(): void {
176
176
 
177
177
  <div
178
178
  bind:this={containerEl}
179
- class={className ? `viz-chart-root ${className}` : 'viz-chart-root'}
179
+ class={className ? `oc-chart-root ${className}` : 'oc-chart-root'}
180
180
  {style}
181
181
  ></div>
@@ -127,6 +127,6 @@ $effect(() => {
127
127
 
128
128
  <div
129
129
  bind:this={containerEl}
130
- class={className ? `viz-table-root ${className}` : 'viz-table-root'}
130
+ class={className ? `oc-table-root ${className}` : 'oc-table-root'}
131
131
  {style}
132
132
  ></div>
package/dist/Graph.svelte CHANGED
@@ -114,6 +114,6 @@ export function getSelectedNodes(): string[] {
114
114
 
115
115
  <div
116
116
  bind:this={containerEl}
117
- class={className ? `viz-graph-root ${className}` : 'viz-graph-root'}
117
+ class={className ? `oc-graph-root ${className}` : 'oc-graph-root'}
118
118
  {style}
119
119
  ></div>
@@ -59,25 +59,25 @@ describe('<Chart />', () => {
59
59
  const { container } = await renderChart({ spec: lineSpec });
60
60
  const svg = container.querySelector('svg');
61
61
  expect(svg).not.toBeNull();
62
- expect(svg?.getAttribute('class')).toBe('viz-chart');
62
+ expect(svg?.getAttribute('class')).toBe('oc-chart');
63
63
  });
64
64
  it('renders chrome text elements', async () => {
65
65
  const { container } = await renderChart({ spec: lineSpec });
66
- const title = container.querySelector('.viz-title');
66
+ const title = container.querySelector('.oc-title');
67
67
  expect(title).not.toBeNull();
68
68
  expect(title?.textContent).toBe('GDP Growth');
69
- const subtitle = container.querySelector('.viz-subtitle');
69
+ const subtitle = container.querySelector('.oc-subtitle');
70
70
  expect(subtitle?.textContent).toBe('US vs UK over time');
71
- const source = container.querySelector('.viz-source');
71
+ const source = container.querySelector('.oc-source');
72
72
  expect(source?.textContent).toBe('World Bank');
73
73
  });
74
74
  it('spec changes trigger re-render', async () => {
75
75
  const { container, rerender } = await renderChart({ spec: lineSpec });
76
- const titleBefore = container.querySelector('.viz-title');
76
+ const titleBefore = container.querySelector('.oc-title');
77
77
  expect(titleBefore?.textContent).toBe('GDP Growth');
78
78
  await rerender({ spec: barSpec });
79
79
  await waitFor(() => {
80
- expect(container.querySelector('.viz-title')?.textContent).toBe('Updated Title');
80
+ expect(container.querySelector('.oc-title')?.textContent).toBe('Updated Title');
81
81
  });
82
82
  });
83
83
  it('unmounting cleans up chart instance', async () => {
@@ -64,11 +64,11 @@ describe('<DataTable />', () => {
64
64
  });
65
65
  it('spec changes trigger re-render', async () => {
66
66
  const { container, rerender } = await renderTable({ spec: tableSpec });
67
- const titleBefore = container.querySelector('.viz-table-title');
67
+ const titleBefore = container.querySelector('.oc-table-title');
68
68
  expect(titleBefore?.textContent).toBe('People Table');
69
69
  await rerender({ spec: updatedSpec });
70
70
  await waitFor(() => {
71
- expect(container.querySelector('.viz-table-title')?.textContent).toBe('Updated Table');
71
+ expect(container.querySelector('.oc-table-title')?.textContent).toBe('Updated Table');
72
72
  });
73
73
  const headersAfter = container.querySelectorAll('thead th');
74
74
  expect(headersAfter.length).toBe(2);
@@ -61,19 +61,19 @@ describe('<Graph />', () => {
61
61
  });
62
62
  it('renders chrome text elements', async () => {
63
63
  const { container } = await renderGraph({ spec: basicSpec });
64
- const title = container.querySelector('.viz-title');
64
+ const title = container.querySelector('.oc-title');
65
65
  expect(title).not.toBeNull();
66
66
  expect(title?.textContent).toBe('Test Graph');
67
- const subtitle = container.querySelector('.viz-subtitle');
67
+ const subtitle = container.querySelector('.oc-subtitle');
68
68
  expect(subtitle?.textContent).toBe('A simple test graph');
69
69
  });
70
70
  it('spec changes trigger re-render', async () => {
71
71
  const { container, rerender } = await renderGraph({ spec: basicSpec });
72
- const titleBefore = container.querySelector('.viz-title');
72
+ const titleBefore = container.querySelector('.oc-title');
73
73
  expect(titleBefore?.textContent).toBe('Test Graph');
74
74
  await rerender({ spec: updatedSpec });
75
75
  await waitFor(() => {
76
- expect(container.querySelector('.viz-title')?.textContent).toBe('Updated Graph');
76
+ expect(container.querySelector('.oc-title')?.textContent).toBe('Updated Graph');
77
77
  });
78
78
  });
79
79
  it('unmounting cleans up graph instance', async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAGzE,+DAA+D;AAC/D,eAAO,MAAM,SAAS,eAAsB,CAAC;AAC7C,mEAAmE;AACnE,eAAO,MAAM,aAAa,eAA0B,CAAC;AAErD,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI,CAEtE;AAED,gEAAgE;AAChE,wBAAgB,WAAW,IAAI,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,CAEzE;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAEzE;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,IAAI,CAAC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,SAAS,CAEzE"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAGzE,+DAA+D;AAC/D,eAAO,MAAM,SAAS,eAAqB,CAAC;AAC5C,mEAAmE;AACnE,eAAO,MAAM,aAAa,eAAyB,CAAC;AAEpD,uDAAuD;AACvD,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,WAAW,GAAG,SAAS,GAAG,IAAI,CAEtE;AAED,gEAAgE;AAChE,wBAAgB,WAAW,IAAI,CAAC,MAAM,WAAW,GAAG,SAAS,CAAC,GAAG,SAAS,CAEzE;AAED,2DAA2D;AAC3D,wBAAgB,cAAc,CAAC,QAAQ,EAAE,MAAM,QAAQ,GAAG,SAAS,GAAG,IAAI,CAEzE;AAED,+EAA+E;AAC/E,wBAAgB,cAAc,IAAI,CAAC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,SAAS,CAEzE"}
package/dist/context.js CHANGED
@@ -7,9 +7,9 @@
7
7
  */
8
8
  import { getContext, setContext } from 'svelte';
9
9
  /** @internal Context key for theme (exported for test use). */
10
- export const THEME_KEY = Symbol('viz-theme');
10
+ export const THEME_KEY = Symbol('oc-theme');
11
11
  /** @internal Context key for dark mode (exported for test use). */
12
- export const DARK_MODE_KEY = Symbol('viz-dark-mode');
12
+ export const DARK_MODE_KEY = Symbol('oc-dark-mode');
13
13
  /** Set the theme context for descendant components. */
14
14
  export function setVizTheme(theme) {
15
15
  setContext(THEME_KEY, theme);
package/dist/styles.css CHANGED
@@ -1,764 +1 @@
1
- /**
2
- * @opendata-ai/core styles
3
- *
4
- * Plain CSS with viz- prefix for all class names.
5
- * CSS custom properties for theme overrides.
6
- * Dark mode via .viz-dark class on the container.
7
- */
8
-
9
- /* For optimal typography, load Inter: https://fonts.google.com/specimen/Inter */
10
-
11
- /* ---------------------------------------------------------------------------
12
- * Custom properties (light mode defaults)
13
- * --------------------------------------------------------------------------- */
14
-
15
- .viz-root,
16
- .viz-chart-root,
17
- .viz-table-wrapper,
18
- .viz-table-root,
19
- .viz-graph-wrapper,
20
- .viz-graph-root {
21
- --viz-font-family: Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
22
- --viz-font-mono: "JetBrains Mono", "Fira Code", "Cascadia Code", monospace;
23
- --viz-title-size: 22px;
24
- --viz-title-weight: 700;
25
- --viz-title-tracking: -0.02em;
26
- --viz-subtitle-size: 14px;
27
- --viz-subtitle-weight: 400;
28
- --viz-source-size: 12px;
29
- --viz-source-weight: 400;
30
- --viz-body-size: 13px;
31
- --viz-bg: #ffffff;
32
- --viz-text: #1d1d1d;
33
- --viz-text-secondary: #5c5c5c;
34
- --viz-text-muted: #999999;
35
- --viz-gridline: #e8e8e8;
36
- --viz-axis: #888888;
37
- --viz-border: #e2e2e2;
38
- --viz-border-radius: 4px;
39
- --viz-focus: #3b82f6;
40
- --viz-hover-bg: rgba(0, 0, 0, 0.025);
41
- --viz-tooltip-bg: rgba(255, 255, 255, 0.88);
42
- --viz-tooltip-border: rgba(0, 0, 0, 0.08);
43
- --viz-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.08), 0 0 1px rgba(0, 0, 0, 0.12);
44
- --viz-tooltip-text: #1d1d1d;
45
- --viz-legend-text: #555555;
46
- }
47
-
48
- /* ---------------------------------------------------------------------------
49
- * Dark mode overrides
50
- * --------------------------------------------------------------------------- */
51
-
52
- .viz-dark {
53
- --viz-bg: #1a1a2e;
54
- --viz-text: #e0e0e0;
55
- --viz-text-secondary: #b0b0b0;
56
- --viz-text-muted: #808080;
57
- --viz-gridline: #333355;
58
- --viz-axis: #999999;
59
- --viz-border: #444466;
60
- --viz-focus: #60a5fa;
61
- --viz-hover-bg: rgba(255, 255, 255, 0.05);
62
- --viz-tooltip-bg: rgba(30, 30, 50, 0.85);
63
- --viz-tooltip-border: rgba(255, 255, 255, 0.08);
64
- --viz-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.3), 0 0 1px rgba(0, 0, 0, 0.4);
65
- --viz-tooltip-text: #e0e0e0;
66
- --viz-legend-text: #b0b0b0;
67
- }
68
-
69
- /* ---------------------------------------------------------------------------
70
- * Chrome (title, subtitle, source, footer)
71
- * --------------------------------------------------------------------------- */
72
-
73
- .viz-chrome {
74
- font-family: var(--viz-font-family);
75
- }
76
-
77
- .viz-title {
78
- font-size: var(--viz-title-size);
79
- font-weight: var(--viz-title-weight);
80
- letter-spacing: var(--viz-title-tracking);
81
- fill: var(--viz-text);
82
- }
83
-
84
- .viz-subtitle {
85
- font-size: var(--viz-subtitle-size);
86
- font-weight: var(--viz-subtitle-weight);
87
- fill: var(--viz-text-secondary);
88
- }
89
-
90
- .viz-source,
91
- .viz-byline,
92
- .viz-footer {
93
- font-size: var(--viz-source-size);
94
- font-weight: var(--viz-source-weight);
95
- fill: var(--viz-text-muted);
96
- }
97
-
98
- /* ---------------------------------------------------------------------------
99
- * Table footer chrome
100
- * --------------------------------------------------------------------------- */
101
-
102
- .viz-chrome-footer {
103
- padding-top: 16px;
104
- }
105
-
106
- /* ---------------------------------------------------------------------------
107
- * Tooltip
108
- * --------------------------------------------------------------------------- */
109
-
110
- .viz-tooltip {
111
- position: absolute;
112
- display: none;
113
- pointer-events: none;
114
- z-index: 1000;
115
- background: var(--viz-tooltip-bg);
116
- backdrop-filter: blur(12px);
117
- border: 1px solid var(--viz-tooltip-border);
118
- border-radius: 8px;
119
- box-shadow: var(--viz-tooltip-shadow);
120
- color: var(--viz-tooltip-text);
121
- font-family: var(--viz-font-family);
122
- font-size: 12px;
123
- padding: 0;
124
- max-width: 260px;
125
- min-width: 140px;
126
- line-height: 1.4;
127
- animation: viz-tooltip-in 120ms ease-out;
128
- }
129
-
130
- @keyframes viz-tooltip-in {
131
- from {
132
- opacity: 0;
133
- transform: translateY(2px);
134
- }
135
- to {
136
- opacity: 1;
137
- transform: translateY(0);
138
- }
139
- }
140
-
141
- .viz-tooltip-header {
142
- display: flex;
143
- align-items: center;
144
- gap: 6px;
145
- padding: 8px 12px 6px;
146
- }
147
-
148
- .viz-tooltip-dot {
149
- width: 8px;
150
- height: 8px;
151
- border-radius: 50%;
152
- flex-shrink: 0;
153
- }
154
-
155
- .viz-tooltip-title {
156
- font-weight: 600;
157
- font-size: 12px;
158
- letter-spacing: -0.01em;
159
- color: var(--viz-tooltip-text);
160
- white-space: nowrap;
161
- overflow: hidden;
162
- text-overflow: ellipsis;
163
- }
164
-
165
- .viz-tooltip-body {
166
- padding: 4px 12px 8px;
167
- border-top: 1px solid var(--viz-tooltip-border);
168
- }
169
-
170
- /* Only add separator when header is present */
171
- .viz-tooltip-header + .viz-tooltip-body {
172
- padding-top: 6px;
173
- }
174
-
175
- /* No separator when body is the only child */
176
- .viz-tooltip-body:first-child {
177
- border-top: none;
178
- padding-top: 8px;
179
- }
180
-
181
- .viz-tooltip-row {
182
- display: flex;
183
- align-items: baseline;
184
- justify-content: space-between;
185
- gap: 12px;
186
- padding: 1px 0;
187
- }
188
-
189
- .viz-tooltip-label {
190
- color: var(--viz-text-muted);
191
- font-size: 11px;
192
- white-space: nowrap;
193
- flex-shrink: 0;
194
- }
195
-
196
- .viz-tooltip-value {
197
- font-weight: 500;
198
- font-size: 11px;
199
- font-variant-numeric: tabular-nums;
200
- text-align: right;
201
- overflow: hidden;
202
- text-overflow: ellipsis;
203
- white-space: nowrap;
204
- }
205
-
206
- /* ---------------------------------------------------------------------------
207
- * Legend
208
- * --------------------------------------------------------------------------- */
209
-
210
- .viz-legend {
211
- font-family: var(--viz-font-family);
212
- font-size: var(--viz-body-size);
213
- }
214
-
215
- .viz-legend-entry {
216
- cursor: default;
217
- }
218
-
219
- .viz-legend text {
220
- fill: var(--viz-legend-text);
221
- }
222
-
223
- /* ---------------------------------------------------------------------------
224
- * React wrapper roots
225
- * --------------------------------------------------------------------------- */
226
-
227
- .viz-chart-root {
228
- width: 100%;
229
- }
230
-
231
- .viz-table-root,
232
- .viz-graph-root {
233
- width: 100%;
234
- height: 100%;
235
- }
236
-
237
- .viz-table-root {
238
- overflow: auto;
239
- }
240
-
241
- /* ---------------------------------------------------------------------------
242
- * Chart container
243
- * --------------------------------------------------------------------------- */
244
-
245
- .viz-chart {
246
- font-family: var(--viz-font-family);
247
- display: block;
248
- width: 100%;
249
- }
250
-
251
- /* ---------------------------------------------------------------------------
252
- * Screen reader only utility
253
- * --------------------------------------------------------------------------- */
254
-
255
- .viz-sr-only {
256
- position: absolute;
257
- width: 1px;
258
- height: 1px;
259
- padding: 0;
260
- margin: -1px;
261
- overflow: hidden;
262
- clip-path: inset(50%);
263
- white-space: nowrap;
264
- border-width: 0;
265
- }
266
-
267
- /* ---------------------------------------------------------------------------
268
- * Table base
269
- * --------------------------------------------------------------------------- */
270
-
271
- .viz-table-wrapper {
272
- font-family: var(--viz-font-family);
273
- color: var(--viz-text);
274
- background: var(--viz-bg);
275
- }
276
-
277
- .viz-table-wrapper > .viz-chrome {
278
- margin-bottom: 16px;
279
- }
280
-
281
- .viz-table-title {
282
- margin-bottom: 4px;
283
- font-size: var(--viz-title-computed-size, var(--viz-title-size));
284
- font-weight: var(--viz-title-computed-weight, var(--viz-title-weight));
285
- color: var(--viz-title-computed-color, var(--viz-text));
286
- }
287
-
288
- .viz-table-subtitle {
289
- margin-bottom: 8px;
290
- font-size: var(--viz-subtitle-computed-size, var(--viz-subtitle-size));
291
- font-weight: var(--viz-subtitle-computed-weight, var(--viz-subtitle-weight));
292
- color: var(--viz-subtitle-computed-color, var(--viz-text-secondary));
293
- }
294
-
295
- .viz-table-source {
296
- font-size: var(--viz-source-computed-size, var(--viz-source-size));
297
- color: var(--viz-source-computed-color, var(--viz-text-muted));
298
- }
299
-
300
- .viz-table-footer-text {
301
- font-size: var(--viz-footer-computed-size, var(--viz-source-size));
302
- color: var(--viz-footer-computed-color, var(--viz-text-muted));
303
- }
304
-
305
- .viz-table-scroll {
306
- overflow-x: auto;
307
- }
308
-
309
- .viz-table-wrapper table {
310
- width: 100%;
311
- border-collapse: collapse;
312
- }
313
-
314
- .viz-table-wrapper th,
315
- .viz-table-wrapper td {
316
- padding: 10px 16px;
317
- text-align: left;
318
- border-bottom: 1px solid var(--viz-border);
319
- }
320
-
321
- .viz-table-wrapper th {
322
- font-weight: 600;
323
- font-size: 12px;
324
- text-transform: uppercase;
325
- letter-spacing: 0.05em;
326
- color: var(--viz-text-secondary);
327
- white-space: nowrap;
328
- }
329
-
330
- .viz-table-wrapper thead {
331
- position: sticky;
332
- top: 0;
333
- z-index: 2;
334
- background: var(--viz-bg);
335
- }
336
-
337
- .viz-table-wrapper thead th {
338
- border-bottom-width: 2px;
339
- }
340
-
341
- .viz-table-wrapper td {
342
- font-size: 14px;
343
- font-variant-numeric: tabular-nums;
344
- }
345
-
346
- /* ---------------------------------------------------------------------------
347
- * Sticky first column
348
- * --------------------------------------------------------------------------- */
349
-
350
- .viz-table--sticky th:first-child,
351
- .viz-table--sticky td:first-child {
352
- position: sticky;
353
- left: 0;
354
- z-index: 1;
355
- background: var(--viz-bg);
356
- }
357
-
358
- /* ---------------------------------------------------------------------------
359
- * Sort controls
360
- * --------------------------------------------------------------------------- */
361
-
362
- .viz-table-sort-btn {
363
- background: none;
364
- border: none;
365
- cursor: pointer;
366
- padding: 2px;
367
- margin-left: 6px;
368
- display: inline-flex;
369
- flex-direction: column;
370
- align-items: center;
371
- vertical-align: middle;
372
- gap: 2px;
373
- }
374
-
375
- .viz-table-sort-btn::before,
376
- .viz-table-sort-btn::after {
377
- content: "";
378
- display: block;
379
- width: 0;
380
- height: 0;
381
- border-left: 5px solid transparent;
382
- border-right: 5px solid transparent;
383
- transition:
384
- opacity 0.15s,
385
- border-color 0.15s;
386
- }
387
-
388
- .viz-table-sort-btn::before {
389
- border-bottom: 4.5px solid var(--viz-text-secondary);
390
- opacity: 0.45;
391
- }
392
-
393
- .viz-table-sort-btn::after {
394
- border-top: 4.5px solid var(--viz-text-secondary);
395
- opacity: 0.45;
396
- }
397
-
398
- .viz-table-sort-btn:hover::before,
399
- .viz-table-sort-btn:hover::after {
400
- opacity: 0.75;
401
- }
402
-
403
- th[aria-sort="ascending"] .viz-table-sort-btn::before {
404
- opacity: 1;
405
- border-bottom-color: var(--viz-text);
406
- }
407
-
408
- th[aria-sort="ascending"] .viz-table-sort-btn::after {
409
- opacity: 0.15;
410
- }
411
-
412
- th[aria-sort="descending"] .viz-table-sort-btn::after {
413
- opacity: 1;
414
- border-top-color: var(--viz-text);
415
- }
416
-
417
- th[aria-sort="descending"] .viz-table-sort-btn::before {
418
- opacity: 0.15;
419
- }
420
-
421
- /* ---------------------------------------------------------------------------
422
- * Search
423
- * --------------------------------------------------------------------------- */
424
-
425
- .viz-table-search {
426
- padding: 8px 0;
427
- }
428
-
429
- .viz-table-search input {
430
- width: 100%;
431
- padding: 8px 12px;
432
- border: 1px solid var(--viz-border);
433
- border-radius: 6px;
434
- font-size: 13px;
435
- font-family: inherit;
436
- background: var(--viz-bg);
437
- color: var(--viz-text);
438
- box-sizing: border-box;
439
- transition: border-color 0.15s;
440
- }
441
-
442
- .viz-table-search input::placeholder {
443
- color: var(--viz-text-muted);
444
- font-size: 13px;
445
- }
446
-
447
- .viz-table-search input:focus {
448
- outline: none;
449
- border-color: var(--viz-focus);
450
- box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
451
- }
452
-
453
- /* ---------------------------------------------------------------------------
454
- * Pagination
455
- * --------------------------------------------------------------------------- */
456
-
457
- .viz-table-pagination {
458
- display: flex;
459
- align-items: center;
460
- justify-content: space-between;
461
- padding: 12px 0 4px;
462
- font-size: 13px;
463
- color: var(--viz-text-secondary);
464
- }
465
-
466
- .viz-table-pagination-info {
467
- font-variant-numeric: tabular-nums;
468
- }
469
-
470
- .viz-table-pagination-btns {
471
- display: flex;
472
- gap: 8px;
473
- }
474
-
475
- .viz-table-pagination button {
476
- padding: 6px 14px;
477
- border: 1px solid var(--viz-border);
478
- border-radius: 6px;
479
- background: var(--viz-bg);
480
- color: var(--viz-text);
481
- cursor: pointer;
482
- font-size: 13px;
483
- font-family: inherit;
484
- transition:
485
- background 0.15s,
486
- border-color 0.15s;
487
- }
488
-
489
- .viz-table-pagination button:disabled {
490
- opacity: 0.35;
491
- cursor: not-allowed;
492
- }
493
-
494
- .viz-table-pagination button:hover:not(:disabled) {
495
- background: var(--viz-hover-bg);
496
- border-color: var(--viz-axis);
497
- }
498
-
499
- .viz-table-pagination button:focus-visible {
500
- outline: 2px solid var(--viz-focus);
501
- outline-offset: 1px;
502
- }
503
-
504
- /* ---------------------------------------------------------------------------
505
- * Bar cells
506
- * --------------------------------------------------------------------------- */
507
-
508
- .viz-table-bar {
509
- position: relative;
510
- }
511
-
512
- .viz-table-bar-fill {
513
- position: absolute;
514
- top: 6px;
515
- left: 0;
516
- bottom: 6px;
517
- border-radius: 2px;
518
- opacity: 0.15;
519
- pointer-events: none;
520
- }
521
-
522
- .viz-table-bar-value {
523
- position: relative;
524
- z-index: 1;
525
- }
526
-
527
- /* ---------------------------------------------------------------------------
528
- * Sparkline cells
529
- * --------------------------------------------------------------------------- */
530
-
531
- .viz-table-sparkline {
532
- display: block;
533
- width: 100%;
534
- position: relative;
535
- }
536
-
537
- .viz-table-sparkline svg {
538
- display: block;
539
- width: 100%;
540
- overflow: visible;
541
- }
542
-
543
- .viz-table-sparkline-dot {
544
- position: absolute;
545
- border-radius: 50%;
546
- width: 5px;
547
- height: 5px;
548
- }
549
-
550
- .viz-table-sparkline-labels {
551
- display: flex;
552
- justify-content: space-between;
553
- font-size: 11px;
554
- line-height: 1;
555
- }
556
-
557
- /* ---------------------------------------------------------------------------
558
- * Image cells
559
- * --------------------------------------------------------------------------- */
560
-
561
- .viz-table-image {
562
- display: inline-block;
563
- vertical-align: middle;
564
- }
565
-
566
- .viz-table-image img {
567
- object-fit: cover;
568
- }
569
-
570
- .viz-table-image-rounded img {
571
- border-radius: 50%;
572
- }
573
-
574
- /* ---------------------------------------------------------------------------
575
- * Flag cells
576
- * --------------------------------------------------------------------------- */
577
-
578
- .viz-table-flag {
579
- font-size: 1.2em;
580
- }
581
-
582
- /* ---------------------------------------------------------------------------
583
- * Compact mode
584
- * --------------------------------------------------------------------------- */
585
-
586
- .viz-table--compact th,
587
- .viz-table--compact td {
588
- padding: 4px 8px;
589
- font-size: 13px;
590
- }
591
-
592
- .viz-table--compact th {
593
- font-size: 11px;
594
- }
595
-
596
- /* ---------------------------------------------------------------------------
597
- * Row hover (when onRowClick is set)
598
- * --------------------------------------------------------------------------- */
599
-
600
- .viz-table--clickable tbody tr {
601
- cursor: pointer;
602
- }
603
-
604
- .viz-table--clickable tbody tr:hover {
605
- background: var(--viz-hover-bg);
606
- }
607
-
608
- /* ---------------------------------------------------------------------------
609
- * Table header keyboard focus
610
- * --------------------------------------------------------------------------- */
611
-
612
- .viz-table-wrapper th:focus {
613
- outline: 2px solid var(--viz-focus);
614
- outline-offset: -2px;
615
- }
616
-
617
- /* ---------------------------------------------------------------------------
618
- * Keyboard cell focus indicator
619
- * --------------------------------------------------------------------------- */
620
-
621
- .viz-table-cell-focus {
622
- outline: 2px solid var(--viz-focus);
623
- outline-offset: -2px;
624
- }
625
-
626
- /* ---------------------------------------------------------------------------
627
- * Table body focus (for keyboard navigation entry)
628
- * --------------------------------------------------------------------------- */
629
-
630
- .viz-table-wrapper tbody:focus {
631
- outline: none;
632
- }
633
-
634
- /* ---------------------------------------------------------------------------
635
- * Empty state
636
- * --------------------------------------------------------------------------- */
637
-
638
- .viz-table-empty {
639
- padding: 32px 16px;
640
- text-align: center;
641
- color: var(--viz-text-secondary);
642
- font-size: 14px;
643
- font-style: italic;
644
- }
645
-
646
- /* ---------------------------------------------------------------------------
647
- * Reduced motion
648
- * --------------------------------------------------------------------------- */
649
-
650
- @media (prefers-reduced-motion: reduce) {
651
- .viz-table-sort-btn::before,
652
- .viz-table-sort-btn::after,
653
- .viz-table-search input,
654
- .viz-table-pagination button {
655
- transition: none;
656
- }
657
- }
658
-
659
- /* ---------------------------------------------------------------------------
660
- * Graph
661
- * --------------------------------------------------------------------------- */
662
-
663
- .viz-graph-wrapper {
664
- position: relative;
665
- overflow: hidden;
666
- background: var(--viz-bg);
667
- font-family: var(--viz-font-family);
668
- width: 100%;
669
- height: 100%;
670
- }
671
-
672
- .viz-graph-canvas {
673
- display: block;
674
- cursor: grab;
675
- }
676
-
677
- .viz-graph-canvas--dragging {
678
- cursor: grabbing;
679
- }
680
-
681
- .viz-graph-chrome {
682
- padding: 16px 16px 8px;
683
- }
684
-
685
- .viz-graph-chrome .viz-title {
686
- font-size: var(--viz-title-size);
687
- font-weight: var(--viz-title-weight);
688
- letter-spacing: var(--viz-title-tracking);
689
- color: var(--viz-text);
690
- margin: 0 0 4px;
691
- }
692
-
693
- .viz-graph-chrome .viz-subtitle {
694
- font-size: var(--viz-subtitle-size);
695
- color: var(--viz-text-secondary);
696
- margin: 0;
697
- }
698
-
699
- .viz-graph-legend {
700
- position: absolute;
701
- top: 8px;
702
- right: 8px;
703
- background: var(--viz-bg);
704
- border: 1px solid var(--viz-border);
705
- border-radius: var(--viz-border-radius);
706
- padding: 8px 12px;
707
- font-size: 12px;
708
- color: var(--viz-text-secondary);
709
- max-height: 200px;
710
- overflow-y: auto;
711
- }
712
-
713
- .viz-graph-legend-item {
714
- display: flex;
715
- align-items: center;
716
- gap: 6px;
717
- padding: 2px 0;
718
- }
719
-
720
- .viz-graph-legend-swatch {
721
- width: 10px;
722
- height: 10px;
723
- border-radius: 50%;
724
- flex-shrink: 0;
725
- }
726
-
727
- .viz-graph-search {
728
- position: absolute;
729
- top: 8px;
730
- left: 8px;
731
- }
732
-
733
- .viz-graph-search input {
734
- font-family: var(--viz-font-family);
735
- font-size: var(--viz-body-size);
736
- padding: 6px 10px;
737
- border: 1px solid var(--viz-border);
738
- border-radius: var(--viz-border-radius);
739
- background: var(--viz-bg);
740
- color: var(--viz-text);
741
- outline: none;
742
- }
743
-
744
- .viz-graph-search input:focus {
745
- border-color: var(--viz-focus);
746
- box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.25);
747
- }
748
-
749
- /* Dark mode graph overrides (darker bg for canvas-based rendering) */
750
- .viz-dark .viz-graph-wrapper,
751
- .viz-graph-wrapper.viz-dark {
752
- --viz-bg: #0d1117;
753
- }
754
-
755
- .viz-dark .viz-graph-legend,
756
- .viz-dark.viz-graph-wrapper .viz-graph-legend {
757
- background: rgba(13, 17, 23, 0.85);
758
- border-color: rgba(255, 255, 255, 0.1);
759
- }
760
-
761
- .viz-dark .viz-graph-search input {
762
- background: rgba(13, 17, 23, 0.85);
763
- border-color: rgba(255, 255, 255, 0.1);
764
- }
1
+ .oc-root,.oc-chart-root,.oc-table-wrapper,.oc-table-root,.oc-graph-wrapper,.oc-graph-root{--oc-font-family:Inter, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;--oc-font-mono:"JetBrains Mono", "Fira Code", "Cascadia Code", monospace;--oc-ease-smooth:linear(0, .157, .438, .64, .766, .85, .906, .941, .964, .978, .988, .994, .998, 1);--oc-ease-snappy:linear(0, .012, .048, .108, .194, .302, .426, .559, .69, .808, .905, .973, 1.013, 1.028, 1.023, 1.006, .984, .966, .957, .957, .964, .975, .986, .995, 1, 1.003, 1.002, 1, .998, .998, .999, 1);--oc-animation-duration:.5s;--oc-animation-stagger:80ms;--oc-annotation-delay:.2s;--oc-title-size:22px;--oc-title-weight:700;--oc-title-tracking:-.02em;--oc-subtitle-size:14px;--oc-subtitle-weight:400;--oc-source-size:12px;--oc-source-weight:400;--oc-body-size:13px;--oc-bg:#fff;--oc-text:#1d1d1d;--oc-text-secondary:#5c5c5c;--oc-text-muted:#999;--oc-gridline:#e8e8e8;--oc-axis:#888;--oc-border:#e2e2e2;--oc-border-radius:4px;--oc-focus:#3b82f6;--oc-hover-bg:rgba(0,0,0,.024);--oc-tooltip-bg:rgba(255,255,255,.88);--oc-tooltip-border:rgba(0,0,0,.08);--oc-tooltip-shadow:0 2px 8px rgba(0,0,0,.08), 0 0 1px rgba(0,0,0,.12);--oc-tooltip-text:#1d1d1d;--oc-legend-text:#555}.oc-dark{--oc-bg:#1a1a2e;--oc-text:#e0e0e0;--oc-text-secondary:#b0b0b0;--oc-text-muted:gray;--oc-gridline:#335;--oc-axis:#999;--oc-border:#446;--oc-focus:#60a5fa;--oc-hover-bg:rgba(255,255,255,.05);--oc-tooltip-bg:rgba(30,30,50,.85);--oc-tooltip-border:rgba(255,255,255,.08);--oc-tooltip-shadow:0 2px 8px rgba(0,0,0,.3), 0 0 1px rgba(0,0,0,.4);--oc-tooltip-text:#e0e0e0;--oc-legend-text:#b0b0b0}.oc-chart-root{width:100%}.oc-table-root,.oc-graph-root{width:100%;height:100%}.oc-table-root{overflow:auto}.oc-chart{font-family:var(--oc-font-family);width:100%;display:block}.oc-sr-only{clip-path:inset(50%);white-space:nowrap;border-width:0;width:1px;height:1px;margin:-1px;padding:0;position:absolute;overflow:hidden}.oc-editable-hover{outline-offset:2px;border-radius:2px;outline:1.5px solid rgba(79,70,229,.35)}.oc-chrome{font-family:var(--oc-font-family)}.oc-title{font-size:var(--oc-title-size);font-weight:var(--oc-title-weight);letter-spacing:var(--oc-title-tracking);fill:var(--oc-text)}.oc-subtitle{font-size:var(--oc-subtitle-size);font-weight:var(--oc-subtitle-weight);fill:var(--oc-text-secondary)}.oc-source,.oc-byline,.oc-footer{font-size:var(--oc-source-size);font-weight:var(--oc-source-weight);fill:var(--oc-text-muted)}.oc-chrome-footer{padding-top:16px}.oc-tooltip{pointer-events:none;z-index:1000;background:var(--oc-tooltip-bg);-webkit-backdrop-filter:blur(12px);backdrop-filter:blur(12px);border:1px solid var(--oc-tooltip-border);box-shadow:var(--oc-tooltip-shadow);color:var(--oc-tooltip-text);font-family:var(--oc-font-family);border-radius:8px;min-width:140px;max-width:260px;padding:0;font-size:12px;line-height:1.4;animation:.12s ease-out oc-tooltip-in;display:none;position:absolute}.oc-tooltip .oc-tooltip-header{align-items:center;gap:6px;padding:8px 12px 6px;display:flex}.oc-tooltip .oc-tooltip-dot{border-radius:50%;flex-shrink:0;width:8px;height:8px}.oc-tooltip .oc-tooltip-title{letter-spacing:-.01em;color:var(--oc-tooltip-text);white-space:nowrap;text-overflow:ellipsis;font-size:12px;font-weight:600;overflow:hidden}.oc-tooltip .oc-tooltip-body{border-top:1px solid var(--oc-tooltip-border);padding:4px 12px 8px}.oc-tooltip .oc-tooltip-header+.oc-tooltip-body{padding-top:6px}.oc-tooltip .oc-tooltip-body:first-child{border-top:none;padding-top:8px}.oc-tooltip .oc-tooltip-row{justify-content:space-between;align-items:baseline;gap:12px;padding:1px 0;display:flex}.oc-tooltip .oc-tooltip-label{color:var(--oc-text-muted);white-space:nowrap;flex-shrink:0;font-size:11px}.oc-tooltip .oc-tooltip-value{font-variant-numeric:tabular-nums;text-align:right;text-overflow:ellipsis;white-space:nowrap;font-size:11px;font-weight:500;overflow:hidden}.oc-legend{font-family:var(--oc-font-family);font-size:var(--oc-body-size)}.oc-legend-entry{cursor:default}.oc-legend text{fill:var(--oc-legend-text)}.oc-table-wrapper{font-family:var(--oc-font-family);color:var(--oc-text);background:var(--oc-bg)}.oc-table-wrapper>.oc-chrome{margin-bottom:16px}.oc-table-wrapper table{border-collapse:collapse;width:100%}.oc-table-wrapper th{text-align:left;border-bottom:1px solid var(--oc-border);padding:10px 16px}.oc-table-wrapper td{text-align:left;border-bottom:1px solid var(--oc-border);padding:10px 16px}.oc-table-wrapper th{text-transform:uppercase;letter-spacing:.05em;color:var(--oc-text-secondary);white-space:nowrap;font-size:12px;font-weight:600}.oc-table-wrapper thead{z-index:2;background:var(--oc-bg);position:sticky;top:0}.oc-table-wrapper thead th{border-bottom-width:2px}.oc-table-wrapper td{font-variant-numeric:tabular-nums;font-size:14px}.oc-table-wrapper th:focus{outline:2px solid var(--oc-focus);outline-offset:-2px}.oc-table-wrapper tbody:focus{outline:none}.oc-table-title{font-size:var(--oc-title-computed-size,var(--oc-title-size));font-weight:var(--oc-title-computed-weight,var(--oc-title-weight));color:var(--oc-title-computed-color,var(--oc-text));margin-bottom:4px}.oc-table-subtitle{font-size:var(--oc-subtitle-computed-size,var(--oc-subtitle-size));font-weight:var(--oc-subtitle-computed-weight,var(--oc-subtitle-weight));color:var(--oc-subtitle-computed-color,var(--oc-text-secondary));margin-bottom:8px}.oc-table-source{font-size:var(--oc-source-computed-size,var(--oc-source-size));color:var(--oc-source-computed-color,var(--oc-text-muted))}.oc-table-footer-text{font-size:var(--oc-footer-computed-size,var(--oc-source-size));color:var(--oc-footer-computed-color,var(--oc-text-muted))}.oc-table-scroll{overflow-x:auto}.oc-table--sticky th:first-child{z-index:1;background:var(--oc-bg);position:sticky;left:0}.oc-table--sticky td:first-child{z-index:1;background:var(--oc-bg);position:sticky;left:0}.oc-table-sort-btn{cursor:pointer;vertical-align:middle;background:0 0;border:none;flex-direction:column;align-items:center;gap:2px;margin-left:6px;padding:2px;display:inline-flex}.oc-table-sort-btn:before{content:"";border-left:5px solid transparent;border-right:5px solid transparent;width:0;height:0;transition:opacity .15s,border-color .15s;display:block}.oc-table-sort-btn:after{content:"";border-left:5px solid transparent;border-right:5px solid transparent;width:0;height:0;transition:opacity .15s,border-color .15s;display:block}.oc-table-sort-btn:before{border-bottom:4.5px solid var(--oc-text-secondary);opacity:.45}.oc-table-sort-btn:after{border-top:4.5px solid var(--oc-text-secondary);opacity:.45}.oc-table-sort-btn:hover:before{opacity:.75}.oc-table-sort-btn:hover:after{opacity:.75}th[aria-sort=ascending] .oc-table-sort-btn:before{opacity:1;border-bottom-color:var(--oc-text)}th[aria-sort=ascending] .oc-table-sort-btn:after{opacity:.15}th[aria-sort=descending] .oc-table-sort-btn:after{opacity:1;border-top-color:var(--oc-text)}th[aria-sort=descending] .oc-table-sort-btn:before{opacity:.15}.oc-table-search{padding:8px 0}.oc-table-search input{border:1px solid var(--oc-border);background:var(--oc-bg);width:100%;color:var(--oc-text);box-sizing:border-box;border-radius:6px;padding:8px 12px;font-family:inherit;font-size:13px;transition:border-color .15s}.oc-table-search input::-ms-input-placeholder{color:var(--oc-text-muted);font-size:13px}.oc-table-search input::placeholder{color:var(--oc-text-muted);font-size:13px}.oc-table-search input:focus{border-color:var(--oc-focus);outline:none;box-shadow:0 0 0 3px rgba(59,130,246,.1)}.oc-table-pagination{color:var(--oc-text-secondary);justify-content:space-between;align-items:center;padding:12px 0 4px;font-size:13px;display:flex}.oc-table-pagination button{border:1px solid var(--oc-border);background:var(--oc-bg);color:var(--oc-text);cursor:pointer;border-radius:6px;padding:6px 14px;font-family:inherit;font-size:13px;transition:background .15s,border-color .15s}.oc-table-pagination button:disabled{opacity:.35;cursor:not-allowed}.oc-table-pagination button:hover:not(:disabled){background:var(--oc-hover-bg);border-color:var(--oc-axis)}.oc-table-pagination button:focus-visible{outline:2px solid var(--oc-focus);outline-offset:1px}.oc-table-pagination-info{font-variant-numeric:tabular-nums}.oc-table-pagination-btns{gap:8px;display:flex}.oc-table-bar{position:relative}.oc-table-bar-fill{opacity:.15;pointer-events:none;border-radius:2px;position:absolute;top:6px;bottom:6px;left:0}.oc-table-bar-value{z-index:1;position:relative}.oc-table-sparkline{width:100%;display:block;position:relative}.oc-table-sparkline svg{width:100%;display:block;overflow:visible}.oc-table-sparkline-dot{border-radius:50%;width:5px;height:5px;position:absolute}.oc-table-sparkline-labels{justify-content:space-between;font-size:11px;line-height:1;display:flex}.oc-table-image{vertical-align:middle;display:inline-block}.oc-table-image img{object-fit:cover}.oc-table-image-rounded img{border-radius:50%}.oc-table-flag{font-size:1.2em}.oc-table--compact th{padding:4px 8px;font-size:13px}.oc-table--compact td{padding:4px 8px;font-size:13px}.oc-table--compact th{font-size:11px}.oc-table--clickable tbody tr{cursor:pointer}.oc-table--clickable tbody tr:hover{background:var(--oc-hover-bg)}.oc-table-cell-focus{outline:2px solid var(--oc-focus);outline-offset:-2px}.oc-table-empty{text-align:center;color:var(--oc-text-secondary);padding:32px 16px;font-size:14px;font-style:italic}.oc-table-wrapper.oc-animate>.oc-chrome{animation:oc-enter-fade calc(var(--oc-animation-duration) * .6) var(--oc-animation-ease,var(--oc-ease-smooth)) both}.oc-table-wrapper.oc-animate thead{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .4) var(--oc-animation-ease,var(--oc-ease-smooth)) both}.oc-table-wrapper.oc-animate tbody tr{animation:oc-table-enter-row var(--oc-animation-duration) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0))}.oc-table-wrapper.oc-animate tbody td{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .5) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0))}.oc-table-wrapper.oc-animate td.oc-table-heatmap{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .7) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0) + var(--oc-animation-duration) * .3)}.oc-table-wrapper.oc-animate td.oc-table-category{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .7) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0) + var(--oc-animation-duration) * .3)}.oc-table-wrapper.oc-animate .oc-table-bar-fill{animation:oc-table-enter-bar-fill calc(var(--oc-animation-duration) * .8) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0) + var(--oc-animation-duration) * .3)}.oc-table-wrapper.oc-animate .oc-table-sparkline>svg{animation:oc-enter-line calc(var(--oc-animation-duration) * .8) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0) + var(--oc-animation-duration) * .4)}.oc-table-wrapper.oc-animate .oc-table-sparkline-dot{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .3) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0) + var(--oc-animation-duration) * .8)}.oc-table-wrapper.oc-animate .oc-table-sparkline-labels{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .3) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-row-index,0) + var(--oc-animation-duration) * .8)}.oc-table-wrapper.oc-animate .oc-table-search{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .5) var(--oc-animation-ease,var(--oc-ease-smooth)) both}.oc-table-wrapper.oc-animate .oc-table-pagination{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .5) var(--oc-animation-ease,var(--oc-ease-smooth)) both}.oc-graph-wrapper{background:var(--oc-bg);font-family:var(--oc-font-family);width:100%;height:100%;position:relative;overflow:hidden}.oc-graph-canvas{cursor:grab;display:block}.oc-graph-canvas--dragging{cursor:grabbing}.oc-graph-chrome{padding:16px 16px 8px}.oc-graph-chrome .oc-title{font-size:var(--oc-title-size);font-weight:var(--oc-title-weight);letter-spacing:var(--oc-title-tracking);color:var(--oc-text);margin:0 0 4px}.oc-graph-chrome .oc-subtitle{font-size:var(--oc-subtitle-size);color:var(--oc-text-secondary);margin:0}.oc-graph-legend{background:var(--oc-bg);border:1px solid var(--oc-border);border-radius:var(--oc-border-radius);color:var(--oc-text-secondary);max-height:200px;padding:8px 12px;font-size:12px;position:absolute;top:8px;right:8px;overflow-y:auto}.oc-graph-legend-item{align-items:center;gap:6px;padding:2px 0;display:flex}.oc-graph-legend-swatch{border-radius:50%;flex-shrink:0;width:10px;height:10px}.oc-graph-search{position:absolute;top:8px;left:8px}.oc-graph-search input{font-family:var(--oc-font-family);font-size:var(--oc-body-size);border:1px solid var(--oc-border);border-radius:var(--oc-border-radius);background:var(--oc-bg);color:var(--oc-text);outline:none;padding:6px 10px}.oc-graph-search input:focus{border-color:var(--oc-focus);box-shadow:0 0 0 2px rgba(59,130,246,.25)}.oc-dark .oc-graph-wrapper,.oc-graph-wrapper.oc-dark{--oc-bg:#0d1117}.oc-dark .oc-graph-legend,.oc-dark.oc-graph-wrapper .oc-graph-legend,.oc-dark .oc-graph-search input{background:rgba(13,17,23,.85);border-color:rgba(255,255,255,.1)}@keyframes oc-enter-bar{0%{clip-path:inset(100% 0 0);opacity:0}75%{opacity:1}to{clip-path:inset(0);opacity:1}}@keyframes oc-enter-bar-h{0%{clip-path:inset(0 100% 0 0);opacity:0}75%{opacity:1}to{clip-path:inset(0);opacity:1}}@keyframes oc-enter-line{0%{clip-path:inset(0 100% 0 0);opacity:0}15%{opacity:1}to{clip-path:inset(0);opacity:1}}@keyframes oc-enter-point{0%{opacity:0;transform:scale(.3)}to{opacity:1;transform:scale(1)}}@keyframes oc-enter-fade-only{0%{opacity:0}to{opacity:1}}@keyframes oc-enter-fade{0%{opacity:0;transform:translateY(4px)}to{opacity:1;transform:translateY(0)}}@keyframes oc-table-enter-row{0%{transform:translateY(6px)}to{transform:translateY(0)}}@keyframes oc-table-enter-bar-fill{0%{clip-path:inset(0 100% 0 0)}to{clip-path:inset(0)}}@keyframes oc-tooltip-in{0%{opacity:0;transform:translateY(2px)}to{opacity:1;transform:translateY(0)}}.oc-animate .oc-mark-rect rect{animation:oc-enter-bar var(--oc-animation-duration) var(--oc-ease-smooth) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-bar rect{animation:oc-enter-bar var(--oc-animation-duration) var(--oc-ease-smooth) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-rect[data-orient=horizontal] rect{animation-name:oc-enter-bar-h}.oc-animate .oc-mark-bar[data-orient=horizontal] rect{animation-name:oc-enter-bar-h}.oc-animate .oc-mark-rect[data-stack-pos] rect{animation-duration:var(--oc-stack-segment-duration,.15s);animation-timing-function:linear;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0) + var(--oc-stack-pos,0) * var(--oc-stack-segment-duration,.15s))}.oc-animate .oc-mark-line{animation:oc-enter-line var(--oc-animation-duration) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-area{animation:oc-enter-line var(--oc-animation-duration) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-arc{animation:oc-enter-fade-only var(--oc-animation-duration) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate circle.oc-mark-point{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .4) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate circle.oc-mark-circle{animation:oc-enter-fade-only calc(var(--oc-animation-duration) * .4) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-line~circle.oc-mark-point{animation-delay:calc(var(--oc-animation-duration) * .35 + var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-area~circle.oc-mark-point{animation-delay:calc(var(--oc-animation-duration) * .35 + var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-text text{animation:oc-enter-fade calc(var(--oc-animation-duration) * .6) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-rule line{animation:oc-enter-fade calc(var(--oc-animation-duration) * .5) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-tick line{animation:oc-enter-fade calc(var(--oc-animation-duration) * .5) var(--oc-animation-ease,var(--oc-ease-smooth)) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0))}.oc-animate .oc-mark-label{animation:oc-enter-fade .3s var(--oc-ease-smooth) both;animation-delay:calc(var(--oc-animation-stagger) * var(--oc-mark-index,0) + var(--oc-animation-duration) * .7)}.oc-animate .oc-annotation{animation:oc-enter-fade .4s var(--oc-ease-smooth) both;animation-delay:calc(var(--oc-animation-duration) + var(--oc-annotation-delay,.2s))}@media (prefers-reduced-motion:reduce){.oc-table-sort-btn:before,.oc-table-sort-btn:after,.oc-table-search input,.oc-table-pagination button{transition:none}.oc-animate .oc-mark-rect rect,.oc-animate .oc-mark-bar rect,.oc-animate .oc-mark-arc,.oc-animate .oc-mark-line,.oc-animate .oc-mark-area,.oc-animate circle.oc-mark-point,.oc-animate circle.oc-mark-circle,.oc-animate .oc-mark-text text,.oc-animate .oc-mark-rule line,.oc-animate .oc-mark-tick line,.oc-animate .oc-mark-label,.oc-animate .oc-annotation,.oc-table-wrapper.oc-animate>.oc-chrome,.oc-table-wrapper.oc-animate thead,.oc-table-wrapper.oc-animate tbody tr,.oc-table-wrapper.oc-animate tbody td,.oc-table-wrapper.oc-animate td.oc-table-heatmap,.oc-table-wrapper.oc-animate td.oc-table-category,.oc-table-wrapper.oc-animate .oc-table-bar-fill,.oc-table-wrapper.oc-animate .oc-table-sparkline>svg,.oc-table-wrapper.oc-animate .oc-table-sparkline-dot,.oc-table-wrapper.oc-animate .oc-table-sparkline-labels,.oc-table-wrapper.oc-animate .oc-table-search,.oc-table-wrapper.oc-animate .oc-table-pagination{animation:none}}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@opendata-ai/openchart-svelte",
3
- "version": "6.4.1",
3
+ "version": "6.5.0",
4
4
  "description": "Svelte components for openchart: <Chart />, <DataTable />, <Graph />, <VizThemeProvider />",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Riley Hilliard",
@@ -51,9 +51,9 @@
51
51
  "typecheck": "svelte-check --tsconfig ./tsconfig.json"
52
52
  },
53
53
  "dependencies": {
54
- "@opendata-ai/openchart-core": "6.4.1",
55
- "@opendata-ai/openchart-engine": "6.4.1",
56
- "@opendata-ai/openchart-vanilla": "6.4.1"
54
+ "@opendata-ai/openchart-core": "6.5.0",
55
+ "@opendata-ai/openchart-engine": "6.5.0",
56
+ "@opendata-ai/openchart-vanilla": "6.5.0"
57
57
  },
58
58
  "peerDependencies": {
59
59
  "svelte": ">=5.0.0"
package/src/Chart.svelte CHANGED
@@ -176,6 +176,6 @@ export function deselect(): void {
176
176
 
177
177
  <div
178
178
  bind:this={containerEl}
179
- class={className ? `viz-chart-root ${className}` : 'viz-chart-root'}
179
+ class={className ? `oc-chart-root ${className}` : 'oc-chart-root'}
180
180
  {style}
181
181
  ></div>
@@ -127,6 +127,6 @@ $effect(() => {
127
127
 
128
128
  <div
129
129
  bind:this={containerEl}
130
- class={className ? `viz-table-root ${className}` : 'viz-table-root'}
130
+ class={className ? `oc-table-root ${className}` : 'oc-table-root'}
131
131
  {style}
132
132
  ></div>
package/src/Graph.svelte CHANGED
@@ -114,6 +114,6 @@ export function getSelectedNodes(): string[] {
114
114
 
115
115
  <div
116
116
  bind:this={containerEl}
117
- class={className ? `viz-graph-root ${className}` : 'viz-graph-root'}
117
+ class={className ? `oc-graph-root ${className}` : 'oc-graph-root'}
118
118
  {style}
119
119
  ></div>
@@ -68,32 +68,32 @@ describe('<Chart />', () => {
68
68
  const { container } = await renderChart({ spec: lineSpec });
69
69
  const svg = container.querySelector('svg');
70
70
  expect(svg).not.toBeNull();
71
- expect(svg?.getAttribute('class')).toBe('viz-chart');
71
+ expect(svg?.getAttribute('class')).toBe('oc-chart');
72
72
  });
73
73
 
74
74
  it('renders chrome text elements', async () => {
75
75
  const { container } = await renderChart({ spec: lineSpec });
76
76
 
77
- const title = container.querySelector('.viz-title');
77
+ const title = container.querySelector('.oc-title');
78
78
  expect(title).not.toBeNull();
79
79
  expect(title?.textContent).toBe('GDP Growth');
80
80
 
81
- const subtitle = container.querySelector('.viz-subtitle');
81
+ const subtitle = container.querySelector('.oc-subtitle');
82
82
  expect(subtitle?.textContent).toBe('US vs UK over time');
83
83
 
84
- const source = container.querySelector('.viz-source');
84
+ const source = container.querySelector('.oc-source');
85
85
  expect(source?.textContent).toBe('World Bank');
86
86
  });
87
87
 
88
88
  it('spec changes trigger re-render', async () => {
89
89
  const { container, rerender } = await renderChart({ spec: lineSpec });
90
90
 
91
- const titleBefore = container.querySelector('.viz-title');
91
+ const titleBefore = container.querySelector('.oc-title');
92
92
  expect(titleBefore?.textContent).toBe('GDP Growth');
93
93
 
94
94
  await rerender({ spec: barSpec });
95
95
  await waitFor(() => {
96
- expect(container.querySelector('.viz-title')?.textContent).toBe('Updated Title');
96
+ expect(container.querySelector('.oc-title')?.textContent).toBe('Updated Title');
97
97
  });
98
98
  });
99
99
 
@@ -77,12 +77,12 @@ describe('<DataTable />', () => {
77
77
  it('spec changes trigger re-render', async () => {
78
78
  const { container, rerender } = await renderTable({ spec: tableSpec });
79
79
 
80
- const titleBefore = container.querySelector('.viz-table-title');
80
+ const titleBefore = container.querySelector('.oc-table-title');
81
81
  expect(titleBefore?.textContent).toBe('People Table');
82
82
 
83
83
  await rerender({ spec: updatedSpec });
84
84
  await waitFor(() => {
85
- expect(container.querySelector('.viz-table-title')?.textContent).toBe('Updated Table');
85
+ expect(container.querySelector('.oc-table-title')?.textContent).toBe('Updated Table');
86
86
  });
87
87
 
88
88
  const headersAfter = container.querySelectorAll('thead th');
@@ -73,23 +73,23 @@ describe('<Graph />', () => {
73
73
  it('renders chrome text elements', async () => {
74
74
  const { container } = await renderGraph({ spec: basicSpec });
75
75
 
76
- const title = container.querySelector('.viz-title');
76
+ const title = container.querySelector('.oc-title');
77
77
  expect(title).not.toBeNull();
78
78
  expect(title?.textContent).toBe('Test Graph');
79
79
 
80
- const subtitle = container.querySelector('.viz-subtitle');
80
+ const subtitle = container.querySelector('.oc-subtitle');
81
81
  expect(subtitle?.textContent).toBe('A simple test graph');
82
82
  });
83
83
 
84
84
  it('spec changes trigger re-render', async () => {
85
85
  const { container, rerender } = await renderGraph({ spec: basicSpec });
86
86
 
87
- const titleBefore = container.querySelector('.viz-title');
87
+ const titleBefore = container.querySelector('.oc-title');
88
88
  expect(titleBefore?.textContent).toBe('Test Graph');
89
89
 
90
90
  await rerender({ spec: updatedSpec });
91
91
  await waitFor(() => {
92
- expect(container.querySelector('.viz-title')?.textContent).toBe('Updated Graph');
92
+ expect(container.querySelector('.oc-title')?.textContent).toBe('Updated Graph');
93
93
  });
94
94
  });
95
95
 
package/src/context.ts CHANGED
@@ -10,9 +10,9 @@ import type { DarkMode, ThemeConfig } from '@opendata-ai/openchart-core';
10
10
  import { getContext, setContext } from 'svelte';
11
11
 
12
12
  /** @internal Context key for theme (exported for test use). */
13
- export const THEME_KEY = Symbol('viz-theme');
13
+ export const THEME_KEY = Symbol('oc-theme');
14
14
  /** @internal Context key for dark mode (exported for test use). */
15
- export const DARK_MODE_KEY = Symbol('viz-dark-mode');
15
+ export const DARK_MODE_KEY = Symbol('oc-dark-mode');
16
16
 
17
17
  /** Set the theme context for descendant components. */
18
18
  export function setVizTheme(theme: () => ThemeConfig | undefined): void {