@opendata-ai/openchart-vanilla 6.4.1 → 6.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -2561,7 +2561,7 @@ import { computePosition, flip, offset, shift } from "@floating-ui/dom";
2561
2561
  var TOOLTIP_OFFSET = 12;
2562
2562
  function createTooltipManager(container) {
2563
2563
  const tooltip = document.createElement("div");
2564
- tooltip.className = "viz-tooltip";
2564
+ tooltip.className = "oc-tooltip";
2565
2565
  tooltip.setAttribute("role", "tooltip");
2566
2566
  container.style.position = container.style.position || "relative";
2567
2567
  container.appendChild(tooltip);
@@ -2580,19 +2580,19 @@ function createTooltipManager(container) {
2580
2580
  let html = "";
2581
2581
  if (content.title) {
2582
2582
  const titleColor = content.fields.find((f) => f.color)?.color;
2583
- html += '<div class="viz-tooltip-header">';
2583
+ html += '<div class="oc-tooltip-header">';
2584
2584
  if (titleColor) {
2585
- html += `<span class="viz-tooltip-dot" style="background:${esc(titleColor)}"></span>`;
2585
+ html += `<span class="oc-tooltip-dot" style="background:${esc(titleColor)}"></span>`;
2586
2586
  }
2587
- html += `<span class="viz-tooltip-title">${esc(content.title)}</span>`;
2587
+ html += `<span class="oc-tooltip-title">${esc(content.title)}</span>`;
2588
2588
  html += "</div>";
2589
2589
  }
2590
2590
  if (content.fields.length > 0) {
2591
- html += '<div class="viz-tooltip-body">';
2591
+ html += '<div class="oc-tooltip-body">';
2592
2592
  for (const field of content.fields) {
2593
- html += '<div class="viz-tooltip-row">';
2594
- html += `<span class="viz-tooltip-label">${esc(field.label)}</span>`;
2595
- html += `<span class="viz-tooltip-value">${esc(field.value)}</span>`;
2593
+ html += '<div class="oc-tooltip-row">';
2594
+ html += `<span class="oc-tooltip-label">${esc(field.label)}</span>`;
2595
+ html += `<span class="oc-tooltip-value">${esc(field.value)}</span>`;
2596
2596
  html += "</div>";
2597
2597
  }
2598
2598
  html += "</div>";
@@ -2771,27 +2771,27 @@ function createGraph(container, spec, options) {
2771
2771
  const { width, height } = getContainerDimensions();
2772
2772
  const isDark = resolveDarkMode(options?.darkMode);
2773
2773
  wrapper = document.createElement("div");
2774
- wrapper.className = isDark ? "viz-graph-wrapper viz-dark" : "viz-graph-wrapper";
2774
+ wrapper.className = isDark ? "oc-graph-wrapper oc-dark" : "oc-graph-wrapper";
2775
2775
  if (isDark) {
2776
- container.classList.add("viz-dark");
2776
+ container.classList.add("oc-dark");
2777
2777
  } else {
2778
- container.classList.remove("viz-dark");
2778
+ container.classList.remove("oc-dark");
2779
2779
  }
2780
2780
  const resolvedTheme = compilation.theme;
2781
2781
  if (resolvedTheme) {
2782
2782
  const s = wrapper.style;
2783
- s.setProperty("--viz-bg", resolvedTheme.colors.background);
2784
- s.setProperty("--viz-text", resolvedTheme.colors.text);
2785
- s.setProperty("--viz-text-secondary", resolvedTheme.colors.axis ?? resolvedTheme.colors.text);
2786
- s.setProperty("--viz-font-family", resolvedTheme.fonts.family);
2783
+ s.setProperty("--oc-bg", resolvedTheme.colors.background);
2784
+ s.setProperty("--oc-text", resolvedTheme.colors.text);
2785
+ s.setProperty("--oc-text-secondary", resolvedTheme.colors.axis ?? resolvedTheme.colors.text);
2786
+ s.setProperty("--oc-font-family", resolvedTheme.fonts.family);
2787
2787
  s.fontFamily = resolvedTheme.fonts.family;
2788
2788
  }
2789
2789
  chromeEl = document.createElement("div");
2790
- chromeEl.className = "viz-graph-chrome";
2790
+ chromeEl.className = "oc-graph-chrome";
2791
2791
  renderChrome2();
2792
2792
  wrapper.appendChild(chromeEl);
2793
2793
  canvas = document.createElement("canvas");
2794
- canvas.className = "viz-graph-canvas";
2794
+ canvas.className = "oc-graph-canvas";
2795
2795
  canvas.setAttribute("role", "img");
2796
2796
  if (compilation.a11y?.altText) {
2797
2797
  canvas.setAttribute("aria-label", compilation.a11y.altText);
@@ -2799,7 +2799,7 @@ function createGraph(container, spec, options) {
2799
2799
  wrapper.appendChild(canvas);
2800
2800
  if (options?.legend !== false) {
2801
2801
  legendEl = document.createElement("div");
2802
- legendEl.className = "viz-graph-legend";
2802
+ legendEl.className = "oc-graph-legend";
2803
2803
  renderLegend2();
2804
2804
  wrapper.appendChild(legendEl);
2805
2805
  }
@@ -2813,10 +2813,10 @@ function createGraph(container, spec, options) {
2813
2813
  if (!chromeEl) return;
2814
2814
  let html = "";
2815
2815
  if (compilation.chrome.title) {
2816
- html += `<h2 class="viz-title">${escapeHtml(compilation.chrome.title.text)}</h2>`;
2816
+ html += `<h2 class="oc-title">${escapeHtml(compilation.chrome.title.text)}</h2>`;
2817
2817
  }
2818
2818
  if (compilation.chrome.subtitle) {
2819
- html += `<p class="viz-subtitle">${escapeHtml(compilation.chrome.subtitle.text)}</p>`;
2819
+ html += `<p class="oc-subtitle">${escapeHtml(compilation.chrome.subtitle.text)}</p>`;
2820
2820
  }
2821
2821
  chromeEl.innerHTML = html;
2822
2822
  if (!html) {
@@ -2835,8 +2835,8 @@ function createGraph(container, spec, options) {
2835
2835
  legendEl.style.display = "";
2836
2836
  let html = "";
2837
2837
  for (const entry of entries) {
2838
- html += '<div class="viz-graph-legend-item">';
2839
- html += `<span class="viz-graph-legend-swatch" style="background:${escapeHtml(entry.color)}"></span>`;
2838
+ html += '<div class="oc-graph-legend-item">';
2839
+ html += `<span class="oc-graph-legend-swatch" style="background:${escapeHtml(entry.color)}"></span>`;
2840
2840
  html += `<span>${escapeHtml(entry.label)}</span>`;
2841
2841
  html += "</div>";
2842
2842
  }
@@ -3017,14 +3017,14 @@ function createGraph(container, spec, options) {
3017
3017
  const x3 = node?.x ?? 0;
3018
3018
  const y3 = node?.y ?? 0;
3019
3019
  simulation?.pinNode(nodeId, x3, y3);
3020
- canvas?.classList.add("viz-graph-canvas--dragging");
3020
+ canvas?.classList.add("oc-graph-canvas--dragging");
3021
3021
  },
3022
3022
  onNodeDrag(nodeId, x3, y3) {
3023
3023
  simulation?.dragNode(nodeId, x3, y3);
3024
3024
  },
3025
3025
  onNodeDragEnd(nodeId) {
3026
3026
  simulation?.unpinNode(nodeId);
3027
- canvas?.classList.remove("viz-graph-canvas--dragging");
3027
+ canvas?.classList.remove("oc-graph-canvas--dragging");
3028
3028
  },
3029
3029
  onDoubleClick(nodeId) {
3030
3030
  options?.onNodeDoubleClick?.(nodeDataById(nodeId));
@@ -3199,7 +3199,7 @@ function createGraph(container, spec, options) {
3199
3199
  chromeEl = null;
3200
3200
  legendEl = null;
3201
3201
  renderer = null;
3202
- container.classList.remove("viz-dark");
3202
+ container.classList.remove("oc-dark");
3203
3203
  }
3204
3204
  try {
3205
3205
  compilation = compile();
@@ -3258,9 +3258,59 @@ function escapeHtml(str) {
3258
3258
  import { elementRef, isLayerSpec } from "@opendata-ai/openchart-core";
3259
3259
  import { compileChart, compileLayer } from "@opendata-ai/openchart-engine";
3260
3260
 
3261
+ // src/animation.ts
3262
+ function cancelAnimations(svg) {
3263
+ if (svg) {
3264
+ svg.classList.remove("oc-animate");
3265
+ }
3266
+ }
3267
+ function setupAnimationCleanup(svg) {
3268
+ const style = svg.style;
3269
+ const duration = parseFloat(style.getPropertyValue("--oc-animation-duration")) || 600;
3270
+ const stagger = parseFloat(style.getPropertyValue("--oc-animation-stagger")) || 0;
3271
+ const annotationDelay = parseFloat(style.getPropertyValue("--oc-annotation-delay")) || 200;
3272
+ const animatedElements = svg.querySelectorAll("[data-animation-index]").length;
3273
+ const totalStagger = stagger * Math.max(0, animatedElements - 1);
3274
+ const totalTime = totalStagger + duration + annotationDelay + 500;
3275
+ const timer2 = setTimeout(() => {
3276
+ svg.classList.remove("oc-animate");
3277
+ }, totalTime);
3278
+ return () => {
3279
+ clearTimeout(timer2);
3280
+ cancelAnimations(svg);
3281
+ };
3282
+ }
3283
+ function setupTableAnimationCleanup(wrapper) {
3284
+ const style = wrapper.style;
3285
+ const duration = parseFloat(style.getPropertyValue("--oc-animation-duration")) || 500;
3286
+ const stagger = parseFloat(style.getPropertyValue("--oc-animation-stagger")) || 0;
3287
+ const rows = wrapper.querySelectorAll("tbody tr").length;
3288
+ const totalStagger = stagger * Math.max(0, rows - 1);
3289
+ const totalTime = totalStagger + duration + 300;
3290
+ const timer2 = setTimeout(() => {
3291
+ wrapper.classList.remove("oc-animate");
3292
+ }, totalTime);
3293
+ return () => {
3294
+ clearTimeout(timer2);
3295
+ wrapper.classList.remove("oc-animate");
3296
+ };
3297
+ }
3298
+
3261
3299
  // src/svg-renderer.ts
3262
3300
  import { BRAND_FONT_SIZE as BRAND_FONT_SIZE2, BRAND_MIN_WIDTH as BRAND_MIN_WIDTH2, estimateTextWidth } from "@opendata-ai/openchart-core";
3301
+ import { clampStaggerDelay } from "@opendata-ai/openchart-engine";
3263
3302
  var SVG_NS = "http://www.w3.org/2000/svg";
3303
+ var currentAnimation;
3304
+ function stampAnimationAttrs(el, mark, fallbackIndex) {
3305
+ if (!currentAnimation?.enabled) return;
3306
+ const idx = mark.animationIndex ?? fallbackIndex;
3307
+ el.setAttribute("data-animation-index", String(idx));
3308
+ el.style.setProperty("--oc-mark-index", String(idx));
3309
+ }
3310
+ var EASE_VAR_MAP = {
3311
+ smooth: "var(--oc-ease-smooth)",
3312
+ snappy: "var(--oc-ease-snappy)"
3313
+ };
3264
3314
  function computeXAxisExtent(layout) {
3265
3315
  const xAxis = layout.axes.x;
3266
3316
  if (!xAxis) return 0;
@@ -3363,13 +3413,13 @@ function renderChromeElement(parent, element, className, chromeKey) {
3363
3413
  }
3364
3414
  function renderChrome(parent, layout) {
3365
3415
  const g = createSVGElement("g");
3366
- g.setAttribute("class", "viz-chrome");
3416
+ g.setAttribute("class", "oc-chrome");
3367
3417
  const { chrome } = layout;
3368
3418
  if (chrome.title) {
3369
- renderChromeElement(g, chrome.title, "viz-title", "title");
3419
+ renderChromeElement(g, chrome.title, "oc-title", "title");
3370
3420
  }
3371
3421
  if (chrome.subtitle) {
3372
- renderChromeElement(g, chrome.subtitle, "viz-subtitle", "subtitle");
3422
+ renderChromeElement(g, chrome.subtitle, "oc-subtitle", "subtitle");
3373
3423
  }
3374
3424
  const xAxisExtent = computeXAxisExtent(layout);
3375
3425
  const bottomOffset = layout.area.y + layout.area.height + xAxisExtent;
@@ -3377,7 +3427,7 @@ function renderChrome(parent, layout) {
3377
3427
  renderChromeElement(
3378
3428
  g,
3379
3429
  { ...chrome.source, y: bottomOffset + chrome.source.y },
3380
- "viz-source",
3430
+ "oc-source",
3381
3431
  "source"
3382
3432
  );
3383
3433
  }
@@ -3385,7 +3435,7 @@ function renderChrome(parent, layout) {
3385
3435
  renderChromeElement(
3386
3436
  g,
3387
3437
  { ...chrome.byline, y: bottomOffset + chrome.byline.y },
3388
- "viz-byline",
3438
+ "oc-byline",
3389
3439
  "byline"
3390
3440
  );
3391
3441
  }
@@ -3393,7 +3443,7 @@ function renderChrome(parent, layout) {
3393
3443
  renderChromeElement(
3394
3444
  g,
3395
3445
  { ...chrome.footer, y: bottomOffset + chrome.footer.y },
3396
- "viz-footer",
3446
+ "oc-footer",
3397
3447
  "footer"
3398
3448
  );
3399
3449
  }
@@ -3401,11 +3451,11 @@ function renderChrome(parent, layout) {
3401
3451
  }
3402
3452
  function renderAxis(parent, axis, orientation, layout) {
3403
3453
  const g = createSVGElement("g");
3404
- g.setAttribute("class", `viz-axis viz-axis-${orientation}`);
3454
+ g.setAttribute("class", `oc-axis oc-axis-${orientation}`);
3405
3455
  const { area } = layout;
3406
3456
  if (orientation === "x") {
3407
3457
  const line = createSVGElement("line");
3408
- line.setAttribute("class", "viz-axis-line");
3458
+ line.setAttribute("class", "oc-axis-line");
3409
3459
  setAttrs(line, {
3410
3460
  x1: axis.start.x,
3411
3461
  y1: axis.start.y,
@@ -3419,7 +3469,7 @@ function renderAxis(parent, axis, orientation, layout) {
3419
3469
  for (const tick of axis.ticks) {
3420
3470
  if (orientation === "x") {
3421
3471
  const label = createSVGElement("text");
3422
- label.setAttribute("class", "viz-axis-tick");
3472
+ label.setAttribute("class", "oc-axis-tick");
3423
3473
  if (axis.tickAngle && Math.abs(axis.tickAngle) > 10) {
3424
3474
  const labelX = tick.position;
3425
3475
  const labelY = area.y + area.height + 6;
@@ -3442,7 +3492,7 @@ function renderAxis(parent, axis, orientation, layout) {
3442
3492
  g.appendChild(label);
3443
3493
  } else {
3444
3494
  const label = createSVGElement("text");
3445
- label.setAttribute("class", "viz-axis-tick");
3495
+ label.setAttribute("class", "oc-axis-tick");
3446
3496
  setAttrs(label, {
3447
3497
  x: area.x - 6,
3448
3498
  y: tick.position,
@@ -3456,7 +3506,7 @@ function renderAxis(parent, axis, orientation, layout) {
3456
3506
  }
3457
3507
  for (const gridline of axis.gridlines) {
3458
3508
  const gl = createSVGElement("line");
3459
- gl.setAttribute("class", "viz-gridline");
3509
+ gl.setAttribute("class", "oc-gridline");
3460
3510
  if (orientation === "y") {
3461
3511
  setAttrs(gl, {
3462
3512
  x1: area.x,
@@ -3482,7 +3532,7 @@ function renderAxis(parent, axis, orientation, layout) {
3482
3532
  }
3483
3533
  if (axis.label && axis.labelStyle) {
3484
3534
  const axisLabel = createSVGElement("text");
3485
- axisLabel.setAttribute("class", "viz-axis-title");
3535
+ axisLabel.setAttribute("class", "oc-axis-title");
3486
3536
  applyTextStyle(axisLabel, axis.labelStyle);
3487
3537
  axisLabel.textContent = axis.label;
3488
3538
  if (orientation === "x") {
@@ -3533,7 +3583,8 @@ function registerMarkRenderer(type, renderer) {
3533
3583
  function renderLineMark(mark, index2) {
3534
3584
  const g = createSVGElement("g");
3535
3585
  g.setAttribute("data-mark-id", `line-${mark.seriesKey ?? index2}`);
3536
- g.setAttribute("class", "viz-mark viz-mark-line");
3586
+ g.setAttribute("class", "oc-mark oc-mark-line");
3587
+ stampAnimationAttrs(g, mark, index2);
3537
3588
  if (mark.points.length > 1) {
3538
3589
  const path = createSVGElement("path");
3539
3590
  const d = mark.path ?? mark.points.map((p, i) => `${i === 0 ? "M" : "L"}${p.x},${p.y}`).join(" ");
@@ -3553,7 +3604,7 @@ function renderLineMark(mark, index2) {
3553
3604
  }
3554
3605
  if (mark.label?.visible) {
3555
3606
  const label = createSVGElement("text");
3556
- label.setAttribute("class", "viz-mark-label");
3607
+ label.setAttribute("class", "oc-mark-label");
3557
3608
  if (mark.seriesKey) {
3558
3609
  label.setAttribute("data-series", mark.seriesKey);
3559
3610
  }
@@ -3563,7 +3614,7 @@ function renderLineMark(mark, index2) {
3563
3614
  g.appendChild(label);
3564
3615
  if (mark.label.connector) {
3565
3616
  const connector = createSVGElement("line");
3566
- connector.setAttribute("class", "viz-mark-connector");
3617
+ connector.setAttribute("class", "oc-mark-connector");
3567
3618
  setAttrs(connector, {
3568
3619
  x1: mark.label.connector.from.x,
3569
3620
  y1: mark.label.connector.from.y,
@@ -3581,7 +3632,8 @@ function renderLineMark(mark, index2) {
3581
3632
  function renderAreaMark(mark, index2) {
3582
3633
  const g = createSVGElement("g");
3583
3634
  g.setAttribute("data-mark-id", `area-${mark.seriesKey ?? index2}`);
3584
- g.setAttribute("class", "viz-mark viz-mark-area");
3635
+ g.setAttribute("class", "oc-mark oc-mark-area");
3636
+ stampAnimationAttrs(g, mark, index2);
3585
3637
  if (mark.path) {
3586
3638
  const fill = createSVGElement("path");
3587
3639
  setAttrs(fill, {
@@ -3593,6 +3645,7 @@ function renderAreaMark(mark, index2) {
3593
3645
  g.appendChild(fill);
3594
3646
  if (mark.stroke && mark.topPath) {
3595
3647
  const strokePath = createSVGElement("path");
3648
+ strokePath.setAttribute("class", "oc-area-top");
3596
3649
  setAttrs(strokePath, {
3597
3650
  d: mark.topPath,
3598
3651
  fill: "none",
@@ -3607,7 +3660,11 @@ function renderAreaMark(mark, index2) {
3607
3660
  function renderRectMark(mark, index2) {
3608
3661
  const g = createSVGElement("g");
3609
3662
  g.setAttribute("data-mark-id", `rect-${index2}`);
3610
- g.setAttribute("class", "viz-mark viz-mark-rect");
3663
+ g.setAttribute("class", "oc-mark oc-mark-rect");
3664
+ stampAnimationAttrs(g, mark, index2);
3665
+ if (currentAnimation?.enabled && mark.orient === "horizontal") {
3666
+ g.setAttribute("data-orient", "horizontal");
3667
+ }
3611
3668
  const rect = createSVGElement("rect");
3612
3669
  setAttrs(rect, {
3613
3670
  x: mark.x,
@@ -3628,7 +3685,7 @@ function renderRectMark(mark, index2) {
3628
3685
  g.appendChild(rect);
3629
3686
  if (mark.label?.visible) {
3630
3687
  const label = createSVGElement("text");
3631
- label.setAttribute("class", "viz-mark-label");
3688
+ label.setAttribute("class", "oc-mark-label");
3632
3689
  setAttrs(label, { x: mark.label.x, y: mark.label.y });
3633
3690
  applyTextStyle(label, mark.label.style);
3634
3691
  label.textContent = mark.label.text;
@@ -3639,8 +3696,9 @@ function renderRectMark(mark, index2) {
3639
3696
  function renderArcMark(mark, index2) {
3640
3697
  const g = createSVGElement("g");
3641
3698
  g.setAttribute("data-mark-id", `arc-${index2}`);
3642
- g.setAttribute("class", "viz-mark viz-mark-arc");
3699
+ g.setAttribute("class", "oc-mark oc-mark-arc");
3643
3700
  g.setAttribute("transform", `translate(${mark.center.x},${mark.center.y})`);
3701
+ stampAnimationAttrs(g, mark, index2);
3644
3702
  const path = createSVGElement("path");
3645
3703
  setAttrs(path, {
3646
3704
  d: mark.path,
@@ -3651,7 +3709,7 @@ function renderArcMark(mark, index2) {
3651
3709
  g.appendChild(path);
3652
3710
  if (mark.label?.visible) {
3653
3711
  const label = createSVGElement("text");
3654
- label.setAttribute("class", "viz-mark-label");
3712
+ label.setAttribute("class", "oc-mark-label");
3655
3713
  setAttrs(label, {
3656
3714
  x: mark.label.x - mark.center.x,
3657
3715
  y: mark.label.y - mark.center.y
@@ -3665,7 +3723,8 @@ function renderArcMark(mark, index2) {
3665
3723
  function renderPointMark(mark, index2) {
3666
3724
  const circle = createSVGElement("circle");
3667
3725
  circle.setAttribute("data-mark-id", `point-${index2}`);
3668
- circle.setAttribute("class", "viz-mark viz-mark-point");
3726
+ circle.setAttribute("class", "oc-mark oc-mark-point");
3727
+ stampAnimationAttrs(circle, mark, index2);
3669
3728
  setAttrs(circle, {
3670
3729
  cx: mark.cx,
3671
3730
  cy: mark.cy,
@@ -3682,7 +3741,8 @@ function renderPointMark(mark, index2) {
3682
3741
  function renderTextMark(mark, index2) {
3683
3742
  const text = createSVGElement("text");
3684
3743
  text.setAttribute("data-mark-id", `textMark-${index2}`);
3685
- text.setAttribute("class", "viz-mark viz-mark-text");
3744
+ text.setAttribute("class", "oc-mark oc-mark-text");
3745
+ stampAnimationAttrs(text, mark, index2);
3686
3746
  setAttrs(text, {
3687
3747
  x: mark.x,
3688
3748
  y: mark.y,
@@ -3705,7 +3765,8 @@ function renderTextMark(mark, index2) {
3705
3765
  function renderRuleMark(mark, index2) {
3706
3766
  const line = createSVGElement("line");
3707
3767
  line.setAttribute("data-mark-id", `rule-${index2}`);
3708
- line.setAttribute("class", "viz-mark viz-mark-rule");
3768
+ line.setAttribute("class", "oc-mark oc-mark-rule");
3769
+ stampAnimationAttrs(line, mark, index2);
3709
3770
  setAttrs(line, {
3710
3771
  x1: mark.x1,
3711
3772
  y1: mark.y1,
@@ -3725,7 +3786,8 @@ function renderRuleMark(mark, index2) {
3725
3786
  function renderTickMark(mark, index2) {
3726
3787
  const line = createSVGElement("line");
3727
3788
  line.setAttribute("data-mark-id", `tick-${index2}`);
3728
- line.setAttribute("class", "viz-mark viz-mark-tick");
3789
+ line.setAttribute("class", "oc-mark oc-mark-tick");
3790
+ stampAnimationAttrs(line, mark, index2);
3729
3791
  const half = mark.length / 2;
3730
3792
  if (mark.orient === "vertical") {
3731
3793
  setAttrs(line, {
@@ -3774,28 +3836,37 @@ function getMarkSeries(mark) {
3774
3836
  }
3775
3837
  function renderMarks(parent, layout) {
3776
3838
  const g = createSVGElement("g");
3777
- g.setAttribute("class", "viz-marks");
3839
+ g.setAttribute("class", "oc-marks");
3778
3840
  for (let i = 0; i < layout.marks.length; i++) {
3779
3841
  const mark = layout.marks[i];
3780
3842
  const renderer = markRenderers[mark.type];
3781
- if (renderer) {
3782
- const el = renderer(mark, i);
3783
- if (mark.aria?.label) {
3784
- el.setAttribute("aria-label", mark.aria.label);
3785
- }
3786
- const series = getMarkSeries(mark);
3787
- if (series) {
3788
- el.setAttribute("data-series", series);
3843
+ if (!renderer) continue;
3844
+ const el = renderer(mark, i);
3845
+ if (mark.aria?.label) {
3846
+ el.setAttribute("aria-label", mark.aria.label);
3847
+ }
3848
+ const series = getMarkSeries(mark);
3849
+ if (series) {
3850
+ el.setAttribute("data-series", series);
3851
+ }
3852
+ if (currentAnimation?.enabled && mark.type === "rect") {
3853
+ const rect = mark;
3854
+ if (rect.stackGroup && rect.stackPos !== void 0) {
3855
+ el.setAttribute("data-stack-pos", String(rect.stackPos));
3856
+ el.style.setProperty(
3857
+ "--oc-stack-pos",
3858
+ String(rect.stackPos)
3859
+ );
3789
3860
  }
3790
- g.appendChild(el);
3791
3861
  }
3862
+ g.appendChild(el);
3792
3863
  }
3793
3864
  parent.appendChild(g);
3794
3865
  }
3795
3866
  function renderAnnotations(parent, layout) {
3796
3867
  if (layout.annotations.length === 0) return;
3797
3868
  const g = createSVGElement("g");
3798
- g.setAttribute("class", "viz-annotations");
3869
+ g.setAttribute("class", "oc-annotations");
3799
3870
  for (let i = 0; i < layout.annotations.length; i++) {
3800
3871
  renderAnnotation(g, layout.annotations[i], i);
3801
3872
  }
@@ -3821,7 +3892,7 @@ function renderCurvedArrow(parent, from, to, stroke) {
3821
3892
  const baseX = to.x - ux * arrowLen;
3822
3893
  const baseY = tipY - uy * arrowLen;
3823
3894
  const path = createSVGElement("path");
3824
- path.setAttribute("class", "viz-annotation-connector");
3895
+ path.setAttribute("class", "oc-annotation-connector");
3825
3896
  setAttrs(path, {
3826
3897
  d: `M ${from.x} ${from.y} C ${cp1x} ${cp1y}, ${cp2x} ${cp2y}, ${baseX} ${baseY}`,
3827
3898
  fill: "none",
@@ -3832,7 +3903,7 @@ function renderCurvedArrow(parent, from, to, stroke) {
3832
3903
  const px = -uy;
3833
3904
  const py = ux;
3834
3905
  const arrow = createSVGElement("polygon");
3835
- arrow.setAttribute("class", "viz-annotation-connector");
3906
+ arrow.setAttribute("class", "oc-annotation-connector");
3836
3907
  setAttrs(arrow, {
3837
3908
  points: [
3838
3909
  `${to.x},${tipY}`,
@@ -3845,14 +3916,14 @@ function renderCurvedArrow(parent, from, to, stroke) {
3845
3916
  }
3846
3917
  function renderAnnotation(parent, annotation, index2) {
3847
3918
  const g = createSVGElement("g");
3848
- g.setAttribute("class", `viz-annotation viz-annotation-${annotation.type}`);
3919
+ g.setAttribute("class", `oc-annotation oc-annotation-${annotation.type}`);
3849
3920
  g.setAttribute("data-annotation-index", String(index2));
3850
3921
  if (annotation.id) {
3851
3922
  g.setAttribute("data-annotation-id", annotation.id);
3852
3923
  }
3853
3924
  if (annotation.rect) {
3854
3925
  const rect = createSVGElement("rect");
3855
- rect.setAttribute("class", "viz-annotation-range");
3926
+ rect.setAttribute("class", "oc-annotation-range");
3856
3927
  setAttrs(rect, {
3857
3928
  x: annotation.rect.x,
3858
3929
  y: annotation.rect.y,
@@ -3867,7 +3938,7 @@ function renderAnnotation(parent, annotation, index2) {
3867
3938
  }
3868
3939
  if (annotation.line) {
3869
3940
  const line = createSVGElement("line");
3870
- line.setAttribute("class", "viz-annotation-line");
3941
+ line.setAttribute("class", "oc-annotation-line");
3871
3942
  setAttrs(line, {
3872
3943
  x1: annotation.line.start.x,
3873
3944
  y1: annotation.line.start.y,
@@ -3898,7 +3969,7 @@ function renderAnnotation(parent, annotation, index2) {
3898
3969
  const tipY = pointsDown ? midY + caretSize / 2 : midY - caretSize / 2;
3899
3970
  const baseY = pointsDown ? tipY - caretSize : tipY + caretSize;
3900
3971
  const path = createSVGElement("path");
3901
- path.setAttribute("class", "viz-annotation-connector");
3972
+ path.setAttribute("class", "oc-annotation-connector");
3902
3973
  setAttrs(path, {
3903
3974
  d: `M${tipX - caretSize},${baseY} L${tipX},${tipY} L${tipX + caretSize},${baseY}`,
3904
3975
  fill: "none",
@@ -3913,7 +3984,7 @@ function renderAnnotation(parent, annotation, index2) {
3913
3984
  renderCurvedArrow(g, c2.from, c2.to, c2.stroke);
3914
3985
  } else {
3915
3986
  const connector = createSVGElement("line");
3916
- connector.setAttribute("class", "viz-annotation-connector");
3987
+ connector.setAttribute("class", "oc-annotation-connector");
3917
3988
  setAttrs(connector, {
3918
3989
  x1: c2.from.x,
3919
3990
  y1: c2.from.y,
@@ -3927,7 +3998,7 @@ function renderAnnotation(parent, annotation, index2) {
3927
3998
  }
3928
3999
  }
3929
4000
  const text = createSVGElement("text");
3930
- text.setAttribute("class", "viz-annotation-label");
4001
+ text.setAttribute("class", "oc-annotation-label");
3931
4002
  setAttrs(text, { x: annotation.label.x, y: annotation.label.y });
3932
4003
  applyTextStyle(text, annotation.label.style);
3933
4004
  const lines = annotation.label.text.split("\n");
@@ -3952,7 +4023,7 @@ function renderAnnotation(parent, annotation, index2) {
3952
4023
  const pad = 3;
3953
4024
  const bgX = isMultiLine ? annotation.label.x - maxLineWidth / 2 - pad : annotation.label.x - pad;
3954
4025
  const bgRect = createSVGElement("rect");
3955
- bgRect.setAttribute("class", "viz-annotation-bg");
4026
+ bgRect.setAttribute("class", "oc-annotation-bg");
3956
4027
  setAttrs(bgRect, {
3957
4028
  x: bgX,
3958
4029
  y: annotation.label.y - fontSize + (lineHeight - fontSize) / 2 - pad,
@@ -3970,7 +4041,7 @@ function renderAnnotation(parent, annotation, index2) {
3970
4041
  function renderLegend(parent, legend) {
3971
4042
  if (legend.entries.length === 0) return;
3972
4043
  const g = createSVGElement("g");
3973
- g.setAttribute("class", "viz-legend");
4044
+ g.setAttribute("class", "oc-legend");
3974
4045
  g.setAttribute("role", "list");
3975
4046
  g.setAttribute("aria-label", "Chart legend");
3976
4047
  const isHorizontal = legend.position === "top" || legend.position === "bottom";
@@ -3991,7 +4062,7 @@ function renderLegend(parent, legend) {
3991
4062
  }
3992
4063
  }
3993
4064
  const entryG = createSVGElement("g");
3994
- entryG.setAttribute("class", "viz-legend-entry");
4065
+ entryG.setAttribute("class", "oc-legend-entry");
3995
4066
  entryG.setAttribute("role", "listitem");
3996
4067
  entryG.setAttribute("data-legend-index", String(i));
3997
4068
  entryG.setAttribute("data-legend-label", entry.label);
@@ -4091,7 +4162,7 @@ function renderBrand(parent, layout) {
4091
4162
  a2.setAttributeNS(XLINK_NS, "xlink:href", BRAND_URL);
4092
4163
  a2.setAttribute("target", "_blank");
4093
4164
  a2.setAttribute("rel", "noopener");
4094
- a2.setAttribute("class", "viz-chrome-ref");
4165
+ a2.setAttribute("class", "oc-chrome-ref");
4095
4166
  const text = createSVGElement("text");
4096
4167
  setAttrs(text, {
4097
4168
  x: rightEdge,
@@ -4114,8 +4185,10 @@ function renderBrand(parent, layout) {
4114
4185
  a2.appendChild(text);
4115
4186
  parent.appendChild(a2);
4116
4187
  }
4117
- function renderChartSVG(layout, container) {
4188
+ function renderChartSVG(layout, container, opts) {
4118
4189
  const { width, height } = layout.dimensions;
4190
+ const animation = layout.animation;
4191
+ currentAnimation = animation;
4119
4192
  const svg = createSVGElement("svg");
4120
4193
  setAttrs(svg, {
4121
4194
  viewBox: `0 0 ${width} ${height}`,
@@ -4130,7 +4203,30 @@ function renderChartSVG(layout, container) {
4130
4203
  svg.style.height = `${height}px`;
4131
4204
  svg.setAttribute("role", layout.a11y.role);
4132
4205
  svg.setAttribute("aria-label", layout.a11y.altText);
4133
- svg.setAttribute("class", "viz-chart");
4206
+ const classes = opts?.animate ? "oc-chart oc-animate" : "oc-chart";
4207
+ svg.setAttribute("class", classes);
4208
+ if (animation?.enabled) {
4209
+ const markCount = layout.marks.length;
4210
+ const stagger = clampStaggerDelay(animation.staggerDelay, markCount);
4211
+ svg.style.setProperty("--oc-animation-duration", `${animation.duration}ms`);
4212
+ svg.style.setProperty("--oc-animation-stagger", `${stagger}ms`);
4213
+ svg.style.setProperty("--oc-annotation-delay", `${animation.annotationDelay}ms`);
4214
+ const easeVar = EASE_VAR_MAP[animation.ease] || EASE_VAR_MAP.smooth;
4215
+ svg.style.setProperty("--oc-animation-ease", easeVar);
4216
+ let maxSegments = 0;
4217
+ for (const m2 of layout.marks) {
4218
+ if (m2.type === "rect") {
4219
+ const pos = m2.stackPos;
4220
+ if (pos !== void 0 && pos + 1 > maxSegments) {
4221
+ maxSegments = pos + 1;
4222
+ }
4223
+ }
4224
+ }
4225
+ if (maxSegments > 0) {
4226
+ const segDuration = Math.round(animation.duration / maxSegments);
4227
+ svg.style.setProperty("--oc-stack-segment-duration", `${segDuration}ms`);
4228
+ }
4229
+ }
4134
4230
  const bg = createSVGElement("rect");
4135
4231
  setAttrs(bg, {
4136
4232
  x: 0,
@@ -4140,7 +4236,7 @@ function renderChartSVG(layout, container) {
4140
4236
  fill: layout.theme.colors.background
4141
4237
  });
4142
4238
  svg.appendChild(bg);
4143
- const clipId = `viz-clip-${Math.random().toString(36).slice(2, 8)}`;
4239
+ const clipId = `oc-clip-${Math.random().toString(36).slice(2, 8)}`;
4144
4240
  const defs = createSVGElement("defs");
4145
4241
  const clipPath = createSVGElement("clipPath");
4146
4242
  clipPath.setAttribute("id", clipId);
@@ -4171,7 +4267,7 @@ function renderChartSVG(layout, container) {
4171
4267
  height: layout.area.height,
4172
4268
  fill: "transparent"
4173
4269
  });
4174
- overlay.setAttribute("class", "viz-voronoi-overlay");
4270
+ overlay.setAttribute("class", "oc-voronoi-overlay");
4175
4271
  overlay.setAttribute("data-voronoi-overlay", "true");
4176
4272
  clippedGroup.appendChild(overlay);
4177
4273
  }
@@ -4180,6 +4276,7 @@ function renderChartSVG(layout, container) {
4180
4276
  renderLegend(svg, layout.legend);
4181
4277
  renderChrome(svg, layout);
4182
4278
  renderBrand(svg, layout);
4279
+ currentAnimation = void 0;
4183
4280
  container.appendChild(svg);
4184
4281
  return svg;
4185
4282
  }
@@ -4587,7 +4684,7 @@ function wireChartEvents(svg, layout, specAnnotations, handlers) {
4587
4684
  }
4588
4685
  }
4589
4686
  if (handlers.onAnnotationClick) {
4590
- const annotationElements = svg.querySelectorAll(".viz-annotation");
4687
+ const annotationElements = svg.querySelectorAll(".oc-annotation");
4591
4688
  for (let i = 0; i < annotationElements.length; i++) {
4592
4689
  const el = annotationElements[i];
4593
4690
  const specAnnotation = specAnnotations[i];
@@ -4750,7 +4847,7 @@ function createDragHandler(config) {
4750
4847
  };
4751
4848
  }
4752
4849
  function wireAnnotationDrag(svg, specAnnotations, onAnnotationEdit, onEdit, setDragging) {
4753
- const annotationElements = svg.querySelectorAll(".viz-annotation-text");
4850
+ const annotationElements = svg.querySelectorAll(".oc-annotation-text");
4754
4851
  const cleanups = [];
4755
4852
  for (const el of annotationElements) {
4756
4853
  const indexStr = el.getAttribute("data-annotation-index");
@@ -4761,11 +4858,11 @@ function wireAnnotationDrag(svg, specAnnotations, onAnnotationEdit, onEdit, setD
4761
4858
  const textAnnotation = specAnnotation;
4762
4859
  const annotationG = el;
4763
4860
  annotationG.style.cursor = "grab";
4764
- const connectorLine = annotationG.querySelector("line.viz-annotation-connector");
4861
+ const connectorLine = annotationG.querySelector("line.oc-annotation-connector");
4765
4862
  const origX2 = connectorLine ? Number(connectorLine.getAttribute("x2")) : 0;
4766
4863
  const origY2 = connectorLine ? Number(connectorLine.getAttribute("y2")) : 0;
4767
- const curvedPath = annotationG.querySelector("path.viz-annotation-connector");
4768
- const arrowhead = annotationG.querySelector("polygon.viz-annotation-connector");
4864
+ const curvedPath = annotationG.querySelector("path.oc-annotation-connector");
4865
+ const arrowhead = annotationG.querySelector("polygon.oc-annotation-connector");
4769
4866
  const hasCurvedConnector = curvedPath !== null;
4770
4867
  const origDx = textAnnotation.offset?.dx ?? 0;
4771
4868
  const origDy = textAnnotation.offset?.dy ?? 0;
@@ -4815,7 +4912,7 @@ function wireAnnotationDrag(svg, specAnnotations, onAnnotationEdit, onEdit, setD
4815
4912
  function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
4816
4913
  const SVG_NS2 = "http://www.w3.org/2000/svg";
4817
4914
  const cleanups = [];
4818
- const annotationGroups = svg.querySelectorAll(".viz-annotation-text");
4915
+ const annotationGroups = svg.querySelectorAll(".oc-annotation-text");
4819
4916
  for (const el of annotationGroups) {
4820
4917
  const annotationG = el;
4821
4918
  const indexStr = annotationG.getAttribute("data-annotation-index");
@@ -4824,8 +4921,8 @@ function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
4824
4921
  const specAnnotation = specAnnotations[index2];
4825
4922
  if (!specAnnotation || specAnnotation.type !== "text") continue;
4826
4923
  const textAnnotation = specAnnotation;
4827
- const connectorLine = annotationG.querySelector("line.viz-annotation-connector");
4828
- const curvedPath = annotationG.querySelector("path.viz-annotation-connector");
4924
+ const connectorLine = annotationG.querySelector("line.oc-annotation-connector");
4925
+ const curvedPath = annotationG.querySelector("path.oc-annotation-connector");
4829
4926
  if (!connectorLine && !curvedPath) continue;
4830
4927
  let fromX, fromY, toX, toY;
4831
4928
  if (connectorLine) {
@@ -4838,7 +4935,7 @@ function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
4838
4935
  const mMatch = pathD.match(/M\s*([\d.e+-]+)\s+([\d.e+-]+)/);
4839
4936
  fromX = mMatch ? Number(mMatch[1]) : 0;
4840
4937
  fromY = mMatch ? Number(mMatch[2]) : 0;
4841
- const arrowhead = annotationG.querySelector("polygon.viz-annotation-connector");
4938
+ const arrowhead = annotationG.querySelector("polygon.oc-annotation-connector");
4842
4939
  const points = arrowhead?.getAttribute("points") ?? "";
4843
4940
  const firstPoint = points.split(" ")[0] ?? "0,0";
4844
4941
  const [px, py] = firstPoint.split(",");
@@ -4853,7 +4950,7 @@ function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
4853
4950
  for (const ep of endpoints) {
4854
4951
  if (!Number.isFinite(ep.cx) || !Number.isFinite(ep.cy)) continue;
4855
4952
  const handleEl = document.createElementNS(SVG_NS2, "circle");
4856
- handleEl.setAttribute("class", "viz-connector-handle");
4953
+ handleEl.setAttribute("class", "oc-connector-handle");
4857
4954
  handleEl.setAttribute("data-endpoint", ep.name);
4858
4955
  handleEl.setAttribute("cx", String(ep.cx));
4859
4956
  handleEl.setAttribute("cy", String(ep.cy));
@@ -4947,13 +5044,13 @@ function wireConnectorEndpointDrag(svg, specAnnotations, onEdit, setDragging) {
4947
5044
  function wireAnnotationLabelDrag(svg, specAnnotations, onEdit, setDragging) {
4948
5045
  const cleanups = [];
4949
5046
  const selectors = [
4950
- ".viz-annotation-range .viz-annotation-label",
4951
- ".viz-annotation-refline .viz-annotation-label"
5047
+ ".oc-annotation-range .oc-annotation-label",
5048
+ ".oc-annotation-refline .oc-annotation-label"
4952
5049
  ];
4953
5050
  for (const selector of selectors) {
4954
5051
  const labels = svg.querySelectorAll(selector);
4955
5052
  for (const label of labels) {
4956
- const annotationG = label.closest(".viz-annotation");
5053
+ const annotationG = label.closest(".oc-annotation");
4957
5054
  if (!annotationG) continue;
4958
5055
  const indexStr = annotationG.getAttribute("data-annotation-index");
4959
5056
  if (indexStr === null) continue;
@@ -5002,7 +5099,7 @@ function wireAnnotationLabelDrag(svg, specAnnotations, onEdit, setDragging) {
5002
5099
  };
5003
5100
  }
5004
5101
  function wireChromeDrag(svg, spec, onEdit, setDragging) {
5005
- const chromeTexts = svg.querySelectorAll(".viz-chrome text[data-chrome-key]");
5102
+ const chromeTexts = svg.querySelectorAll(".oc-chrome text[data-chrome-key]");
5006
5103
  const cleanups = [];
5007
5104
  const chromeConfig = "chrome" in spec ? spec.chrome : void 0;
5008
5105
  for (const el of chromeTexts) {
@@ -5042,7 +5139,7 @@ function wireChromeDrag(svg, spec, onEdit, setDragging) {
5042
5139
  };
5043
5140
  }
5044
5141
  function wireLegendDrag(svg, spec, onEdit, setDragging) {
5045
- const legendG = svg.querySelector(".viz-legend");
5142
+ const legendG = svg.querySelector(".oc-legend");
5046
5143
  if (!legendG) return () => {
5047
5144
  };
5048
5145
  const cleanups = [];
@@ -5072,7 +5169,7 @@ function wireLegendDrag(svg, spec, onEdit, setDragging) {
5072
5169
  };
5073
5170
  }
5074
5171
  function wireSeriesLabelDrag(svg, spec, onEdit, setDragging) {
5075
- const labels = svg.querySelectorAll(".viz-mark-label");
5172
+ const labels = svg.querySelectorAll(".oc-mark-label");
5076
5173
  const cleanups = [];
5077
5174
  const labelsConfig = "labels" in spec ? spec.labels : void 0;
5078
5175
  for (const label of labels) {
@@ -5131,7 +5228,7 @@ function wireLegendInteraction(svg, _layout, onLegendToggle, onEdit) {
5131
5228
  onLegendToggle?.(label, false);
5132
5229
  onEdit?.({ type: "legend-toggle", series: label, hidden: true });
5133
5230
  }
5134
- const marks = svg.querySelectorAll(".viz-mark");
5231
+ const marks = svg.querySelectorAll(".oc-mark");
5135
5232
  for (const mark of marks) {
5136
5233
  const seriesName = mark.getAttribute("data-series");
5137
5234
  if (!seriesName) continue;
@@ -5166,13 +5263,13 @@ function wireKeyboardNav(svg, container, tooltipDescriptors, tooltipManager, lay
5166
5263
  let focusIndex = -1;
5167
5264
  function highlightMark(index2) {
5168
5265
  if (focusIndex >= 0 && focusIndex < markElements.length) {
5169
- markElements[focusIndex].classList.remove("viz-mark-focused");
5266
+ markElements[focusIndex].classList.remove("oc-mark-focused");
5170
5267
  markElements[focusIndex].removeAttribute("aria-selected");
5171
5268
  }
5172
5269
  focusIndex = index2;
5173
5270
  if (focusIndex >= 0 && focusIndex < markElements.length) {
5174
5271
  const el = markElements[focusIndex];
5175
- el.classList.add("viz-mark-focused");
5272
+ el.classList.add("oc-mark-focused");
5176
5273
  el.setAttribute("aria-selected", "true");
5177
5274
  }
5178
5275
  }
@@ -5239,7 +5336,7 @@ function createScreenReaderTable(layout, container) {
5239
5336
  const data = layout.a11y.dataTableFallback;
5240
5337
  if (!data || data.length === 0) return null;
5241
5338
  const table = document.createElement("table");
5242
- table.className = "viz-sr-only";
5339
+ table.className = "oc-sr-only";
5243
5340
  table.style.position = "absolute";
5244
5341
  table.style.width = "1px";
5245
5342
  table.style.height = "1px";
@@ -5282,7 +5379,7 @@ function createScreenReaderTable(layout, container) {
5282
5379
  return table;
5283
5380
  }
5284
5381
  var EDITABLE_HOVER_CSS = `
5285
- .viz-editable-hover {
5382
+ .oc-editable-hover {
5286
5383
  outline: 1.5px solid rgba(79, 70, 229, 0.35);
5287
5384
  outline-offset: 2px;
5288
5385
  border-radius: 2px;
@@ -5310,9 +5407,9 @@ function findElementByRef(svg, ref) {
5310
5407
  case "chrome":
5311
5408
  return svg.querySelector(`[data-chrome-key="${ref.key}"]`);
5312
5409
  case "series-label":
5313
- return svg.querySelector(`.viz-mark-label[data-series="${ref.series}"]`);
5410
+ return svg.querySelector(`.oc-mark-label[data-series="${ref.series}"]`);
5314
5411
  case "legend":
5315
- return svg.querySelector(".viz-legend");
5412
+ return svg.querySelector(".oc-legend");
5316
5413
  case "legend-entry":
5317
5414
  return svg.querySelector(`[data-legend-index="${ref.index}"]`);
5318
5415
  }
@@ -5329,7 +5426,7 @@ function buildElementRef(element, _specAnnotations) {
5329
5426
  const key = chromeEl.getAttribute("data-chrome-key");
5330
5427
  if (key) return elementRef.chrome(key);
5331
5428
  }
5332
- const seriesLabelEl = element.closest(".viz-mark-label[data-series]");
5429
+ const seriesLabelEl = element.closest(".oc-mark-label[data-series]");
5333
5430
  if (seriesLabelEl) {
5334
5431
  const series = seriesLabelEl.getAttribute("data-series");
5335
5432
  if (series) return elementRef.seriesLabel(series);
@@ -5340,7 +5437,7 @@ function buildElementRef(element, _specAnnotations) {
5340
5437
  const series = legendEntryEl.getAttribute("data-legend-label") ?? "";
5341
5438
  return elementRef.legendEntry(series, index2);
5342
5439
  }
5343
- const legendEl = element.closest(".viz-legend");
5440
+ const legendEl = element.closest(".oc-legend");
5344
5441
  if (legendEl) return elementRef.legend();
5345
5442
  return null;
5346
5443
  }
@@ -5427,7 +5524,7 @@ function renderSelectionOverlay(svg, ref, layout) {
5427
5524
  const padding = 4;
5428
5525
  const accentColor = layout.theme.colors.categorical?.[0] ?? "#4f46e5";
5429
5526
  const g = document.createElementNS("http://www.w3.org/2000/svg", "g");
5430
- g.setAttribute("class", "viz-selection-overlay");
5527
+ g.setAttribute("class", "oc-selection-overlay");
5431
5528
  const rect = document.createElementNS("http://www.w3.org/2000/svg", "rect");
5432
5529
  rect.setAttribute("x", String(bbox.x - padding));
5433
5530
  rect.setAttribute("y", String(bbox.y - padding));
@@ -5462,6 +5559,8 @@ function createChart(container, spec, options) {
5462
5559
  let isDragging = false;
5463
5560
  let pendingRender = false;
5464
5561
  let resizeTimer = null;
5562
+ let isFirstRender = true;
5563
+ let cleanupAnimations = null;
5465
5564
  let selectedElement = options?.selectedElement ?? null;
5466
5565
  let overlayElement = null;
5467
5566
  let isTextEditingActive = false;
@@ -5577,16 +5676,16 @@ function createChart(container, spec, options) {
5577
5676
  cleanups.push(() => svg.removeEventListener("click", handleClick));
5578
5677
  const handleMouseEnter = (e) => {
5579
5678
  const target = e.target.closest(
5580
- "[data-annotation-index], [data-chrome-key], .viz-mark-label[data-series], .viz-legend, [data-legend-index]"
5679
+ "[data-annotation-index], [data-chrome-key], .oc-mark-label[data-series], .oc-legend, [data-legend-index]"
5581
5680
  );
5582
5681
  if (target) {
5583
- target.classList.add("viz-editable-hover");
5682
+ target.classList.add("oc-editable-hover");
5584
5683
  }
5585
5684
  };
5586
5685
  const handleMouseLeave = (e) => {
5587
- const target = e.target.closest(".viz-editable-hover");
5686
+ const target = e.target.closest(".oc-editable-hover");
5588
5687
  if (target) {
5589
- target.classList.remove("viz-editable-hover");
5688
+ target.classList.remove("oc-editable-hover");
5590
5689
  }
5591
5690
  };
5592
5691
  svg.addEventListener("mouseenter", handleMouseEnter, true);
@@ -5686,6 +5785,11 @@ function createChart(container, spec, options) {
5686
5785
  pendingRender = true;
5687
5786
  return;
5688
5787
  }
5788
+ if (cleanupAnimations) {
5789
+ cleanupAnimations();
5790
+ cleanupAnimations = null;
5791
+ }
5792
+ cancelAnimations(svgElement);
5689
5793
  if (cleanupTooltipEvents) {
5690
5794
  cleanupTooltipEvents();
5691
5795
  cleanupTooltipEvents = null;
@@ -5739,7 +5843,8 @@ function createChart(container, spec, options) {
5739
5843
  srTable = null;
5740
5844
  }
5741
5845
  currentLayout = compile();
5742
- svgElement = renderChartSVG(currentLayout, container);
5846
+ const shouldAnimate = isFirstRender && !!currentLayout.animation?.enabled;
5847
+ svgElement = renderChartSVG(currentLayout, container, { animate: shouldAnimate });
5743
5848
  tooltipManager = createTooltipManager(container);
5744
5849
  cleanupTooltipEvents = wireTooltipEvents(
5745
5850
  svgElement,
@@ -5814,12 +5919,18 @@ function createChart(container, spec, options) {
5814
5919
  }
5815
5920
  }
5816
5921
  srTable = createScreenReaderTable(currentLayout, container);
5817
- container.classList.add("viz-root");
5922
+ container.classList.add("oc-root");
5818
5923
  const isDark = resolveDarkMode2(options?.darkMode);
5819
5924
  if (isDark) {
5820
- container.classList.add("viz-dark");
5925
+ container.classList.add("oc-dark");
5821
5926
  } else {
5822
- container.classList.remove("viz-dark");
5927
+ container.classList.remove("oc-dark");
5928
+ }
5929
+ if (shouldAnimate && svgElement) {
5930
+ cleanupAnimations = setupAnimationCleanup(svgElement);
5931
+ }
5932
+ if (isFirstRender) {
5933
+ isFirstRender = false;
5823
5934
  }
5824
5935
  }
5825
5936
  function update(newSpec, updateOpts) {
@@ -5832,6 +5943,7 @@ function createChart(container, spec, options) {
5832
5943
  }
5833
5944
  function resize() {
5834
5945
  if (destroyed) return;
5946
+ if (cleanupAnimations) return;
5835
5947
  render();
5836
5948
  }
5837
5949
  function doExport(format, exportOptions) {
@@ -5858,6 +5970,11 @@ function createChart(container, spec, options) {
5858
5970
  function destroy() {
5859
5971
  if (destroyed) return;
5860
5972
  destroyed = true;
5973
+ if (cleanupAnimations) {
5974
+ cleanupAnimations();
5975
+ cleanupAnimations = null;
5976
+ }
5977
+ cancelAnimations(svgElement);
5861
5978
  if (resizeTimer !== null) {
5862
5979
  clearTimeout(resizeTimer);
5863
5980
  resizeTimer = null;
@@ -5921,8 +6038,8 @@ function createChart(container, spec, options) {
5921
6038
  srTable.parentNode.removeChild(srTable);
5922
6039
  srTable = null;
5923
6040
  }
5924
- container.classList.remove("viz-dark");
5925
- container.classList.remove("viz-root");
6041
+ container.classList.remove("oc-dark");
6042
+ container.classList.remove("oc-root");
5926
6043
  }
5927
6044
  render();
5928
6045
  if (options?.responsive !== false) {
@@ -6059,28 +6176,30 @@ function renderTextCell(cell) {
6059
6176
  }
6060
6177
  function renderHeatmapCell(cell) {
6061
6178
  const td = document.createElement("td");
6179
+ td.className = "oc-table-heatmap";
6062
6180
  td.textContent = cell.formattedValue;
6063
6181
  applyCellStyle(td, cell);
6064
6182
  return td;
6065
6183
  }
6066
6184
  function renderCategoryCell(cell) {
6067
6185
  const td = document.createElement("td");
6186
+ td.className = "oc-table-category";
6068
6187
  td.textContent = cell.formattedValue;
6069
6188
  applyCellStyle(td, cell);
6070
6189
  return td;
6071
6190
  }
6072
6191
  function renderBarCell(cell) {
6073
6192
  const td = document.createElement("td");
6074
- td.className = "viz-table-bar";
6193
+ td.className = "oc-table-bar";
6075
6194
  applyCellStyle(td, cell);
6076
6195
  const fill = document.createElement("div");
6077
- fill.className = "viz-table-bar-fill";
6196
+ fill.className = "oc-table-bar-fill";
6078
6197
  fill.style.width = `${Math.round(cell.barWidth * 100)}%`;
6079
6198
  fill.style.left = `${Math.round(cell.barOffset * 100)}%`;
6080
6199
  fill.style.background = cell.barColor;
6081
6200
  td.appendChild(fill);
6082
6201
  const valueSpan = document.createElement("span");
6083
- valueSpan.className = "viz-table-bar-value";
6202
+ valueSpan.className = "oc-table-bar-value";
6084
6203
  valueSpan.textContent = cell.formattedValue;
6085
6204
  td.appendChild(valueSpan);
6086
6205
  return td;
@@ -6107,7 +6226,7 @@ function renderSparklineCell(cell) {
6107
6226
  td.setAttribute("aria-label", trendDescription);
6108
6227
  }
6109
6228
  const wrapper = document.createElement("span");
6110
- wrapper.className = "viz-table-sparkline";
6229
+ wrapper.className = "oc-table-sparkline";
6111
6230
  const svgNS = "http://www.w3.org/2000/svg";
6112
6231
  if (sparklineData.type === "line") {
6113
6232
  const svgH = 28;
@@ -6139,19 +6258,19 @@ function renderSparklineCell(cell) {
6139
6258
  const lastY = yPositions[yPositions.length - 1];
6140
6259
  const dotSize = 5;
6141
6260
  const startDot = document.createElement("span");
6142
- startDot.className = "viz-table-sparkline-dot";
6261
+ startDot.className = "oc-table-sparkline-dot";
6143
6262
  startDot.style.left = "0";
6144
6263
  startDot.style.top = `${firstY - dotSize / 2}px`;
6145
6264
  startDot.style.background = sparklineData.color;
6146
6265
  wrapper.appendChild(startDot);
6147
6266
  const endDot = document.createElement("span");
6148
- endDot.className = "viz-table-sparkline-dot";
6267
+ endDot.className = "oc-table-sparkline-dot";
6149
6268
  endDot.style.right = "0";
6150
6269
  endDot.style.top = `${lastY - dotSize / 2}px`;
6151
6270
  endDot.style.background = sparklineData.color;
6152
6271
  wrapper.appendChild(endDot);
6153
6272
  const labelsRow = document.createElement("span");
6154
- labelsRow.className = "viz-table-sparkline-labels";
6273
+ labelsRow.className = "oc-table-sparkline-labels";
6155
6274
  labelsRow.style.color = sparklineData.color;
6156
6275
  const startLabel = document.createElement("span");
6157
6276
  startLabel.textContent = formatSparklineValue(sparklineData.startValue);
@@ -6228,7 +6347,7 @@ function renderImageCell(cell) {
6228
6347
  const td = document.createElement("td");
6229
6348
  applyCellStyle(td, cell);
6230
6349
  const wrapper = document.createElement("span");
6231
- wrapper.className = `viz-table-image${cell.rounded ? " viz-table-image-rounded" : ""}`;
6350
+ wrapper.className = `oc-table-image${cell.rounded ? " oc-table-image-rounded" : ""}`;
6232
6351
  const img = document.createElement("img");
6233
6352
  img.src = cell.src;
6234
6353
  img.alt = cell.formattedValue || "";
@@ -6243,7 +6362,7 @@ function renderFlagCell(cell) {
6243
6362
  const td = document.createElement("td");
6244
6363
  applyCellStyle(td, cell);
6245
6364
  const span = document.createElement("span");
6246
- span.className = "viz-table-flag";
6365
+ span.className = "oc-table-flag";
6247
6366
  span.setAttribute("role", "img");
6248
6367
  if (cell.countryCode && cell.countryCode.length === 2) {
6249
6368
  const countryName = getCountryName(cell.countryCode);
@@ -6308,9 +6427,9 @@ function attachKeyboardNav(options) {
6308
6427
  return getCellsInRow(rows[0]).length;
6309
6428
  }
6310
6429
  function clearFocusHighlight() {
6311
- const prev = wrapper.querySelector(".viz-table-cell-focus");
6430
+ const prev = wrapper.querySelector(".oc-table-cell-focus");
6312
6431
  if (prev) {
6313
- prev.classList.remove("viz-table-cell-focus");
6432
+ prev.classList.remove("oc-table-cell-focus");
6314
6433
  prev.removeAttribute("id");
6315
6434
  }
6316
6435
  }
@@ -6327,9 +6446,9 @@ function attachKeyboardNav(options) {
6327
6446
  const cells = getCellsInRow(tr);
6328
6447
  const cell = cells[col];
6329
6448
  if (!cell) return;
6330
- const cellId = `viz-cell-${row}-${col}`;
6449
+ const cellId = `oc-cell-${row}-${col}`;
6331
6450
  cell.id = cellId;
6332
- cell.classList.add("viz-table-cell-focus");
6451
+ cell.classList.add("oc-table-cell-focus");
6333
6452
  cell.setAttribute("data-row", String(row));
6334
6453
  cell.setAttribute("data-col", String(col));
6335
6454
  if (tbody) {
@@ -6430,7 +6549,7 @@ function attachKeyboardNav(options) {
6430
6549
  }
6431
6550
  }
6432
6551
  }
6433
- const searchInput = wrapper.querySelector(".viz-table-search input");
6552
+ const searchInput = wrapper.querySelector(".oc-table-search input");
6434
6553
  function handleSearchKeydown(e) {
6435
6554
  if (e.key === "Escape") {
6436
6555
  e.preventDefault();
@@ -6470,22 +6589,27 @@ import { compileTable } from "@opendata-ai/openchart-engine";
6470
6589
 
6471
6590
  // src/table-renderer.ts
6472
6591
  import { BRAND_FONT_SIZE as BRAND_FONT_SIZE3 } from "@opendata-ai/openchart-core";
6592
+ import { clampStaggerDelay as clampStaggerDelay2 } from "@opendata-ai/openchart-engine";
6593
+ var EASE_VAR_MAP2 = {
6594
+ smooth: "var(--oc-ease-smooth)",
6595
+ snappy: "var(--oc-ease-snappy)"
6596
+ };
6473
6597
  var BRAND_URL2 = "https://tryopendata.ai";
6474
6598
  function renderChromeBlock(layout, position) {
6475
6599
  const chrome = layout.chrome;
6476
6600
  if (position === "header") {
6477
6601
  if (!chrome.title && !chrome.subtitle) return null;
6478
6602
  const div2 = document.createElement("div");
6479
- div2.className = "viz-chrome";
6603
+ div2.className = "oc-chrome";
6480
6604
  if (chrome.title) {
6481
6605
  const h = document.createElement("div");
6482
- h.className = "viz-table-title";
6606
+ h.className = "oc-table-title";
6483
6607
  h.textContent = chrome.title.text;
6484
6608
  div2.appendChild(h);
6485
6609
  }
6486
6610
  if (chrome.subtitle) {
6487
6611
  const sub = document.createElement("div");
6488
- sub.className = "viz-table-subtitle";
6612
+ sub.className = "oc-table-subtitle";
6489
6613
  sub.textContent = chrome.subtitle.text;
6490
6614
  div2.appendChild(sub);
6491
6615
  }
@@ -6493,16 +6617,16 @@ function renderChromeBlock(layout, position) {
6493
6617
  }
6494
6618
  if (!chrome.source && !chrome.footer) return null;
6495
6619
  const div = document.createElement("div");
6496
- div.className = "viz-chrome viz-chrome-footer";
6620
+ div.className = "oc-chrome oc-chrome-footer";
6497
6621
  if (chrome.source) {
6498
6622
  const src = document.createElement("div");
6499
- src.className = "viz-table-source";
6623
+ src.className = "oc-table-source";
6500
6624
  src.textContent = chrome.source.text;
6501
6625
  div.appendChild(src);
6502
6626
  }
6503
6627
  if (chrome.footer) {
6504
6628
  const foot = document.createElement("div");
6505
- foot.className = "viz-table-footer-text";
6629
+ foot.className = "oc-table-footer-text";
6506
6630
  foot.textContent = chrome.footer.text;
6507
6631
  div.appendChild(foot);
6508
6632
  }
@@ -6528,7 +6652,7 @@ function renderThead(columns, sort) {
6528
6652
  th.appendChild(labelSpan);
6529
6653
  if (col.sortable) {
6530
6654
  const btn = document.createElement("button");
6531
- btn.className = "viz-table-sort-btn";
6655
+ btn.className = "oc-table-sort-btn";
6532
6656
  btn.setAttribute("aria-label", `Sort by ${col.label}`);
6533
6657
  btn.setAttribute("data-sort-column", col.key);
6534
6658
  btn.type = "button";
@@ -6546,6 +6670,7 @@ function renderTbody(rows, columns) {
6546
6670
  const tr = document.createElement("tr");
6547
6671
  tr.setAttribute("role", "row");
6548
6672
  tr.setAttribute("data-row-id", row.id);
6673
+ tr.style.setProperty("--oc-row-index", String(r));
6549
6674
  for (let c2 = 0; c2 < columns.length; c2++) {
6550
6675
  const cell = row.cells[c2];
6551
6676
  if (!cell) continue;
@@ -6561,7 +6686,7 @@ function renderTbody(rows, columns) {
6561
6686
  function renderSearchBar(layout) {
6562
6687
  if (!layout.search.enabled) return null;
6563
6688
  const div = document.createElement("div");
6564
- div.className = "viz-table-search";
6689
+ div.className = "oc-table-search";
6565
6690
  const input = document.createElement("input");
6566
6691
  input.type = "search";
6567
6692
  input.placeholder = layout.search.placeholder;
@@ -6574,9 +6699,9 @@ function renderPagination(layout) {
6574
6699
  if (!layout.pagination) return null;
6575
6700
  const { page, pageSize, totalRows, totalPages } = layout.pagination;
6576
6701
  const div = document.createElement("div");
6577
- div.className = "viz-table-pagination";
6702
+ div.className = "oc-table-pagination";
6578
6703
  const info = document.createElement("span");
6579
- info.className = "viz-table-pagination-info";
6704
+ info.className = "oc-table-pagination-info";
6580
6705
  if (totalRows === 0) {
6581
6706
  info.textContent = "No results";
6582
6707
  } else {
@@ -6586,7 +6711,7 @@ function renderPagination(layout) {
6586
6711
  }
6587
6712
  div.appendChild(info);
6588
6713
  const btnGroup = document.createElement("span");
6589
- btnGroup.className = "viz-table-pagination-btns";
6714
+ btnGroup.className = "oc-table-pagination-btns";
6590
6715
  const prevBtn = document.createElement("button");
6591
6716
  prevBtn.setAttribute("aria-label", "Previous page");
6592
6717
  prevBtn.setAttribute("data-page-action", "prev");
@@ -6604,49 +6729,49 @@ function renderPagination(layout) {
6604
6729
  }
6605
6730
  function renderEmptyState(message) {
6606
6731
  const div = document.createElement("div");
6607
- div.className = "viz-table-empty";
6732
+ div.className = "oc-table-empty";
6608
6733
  div.setAttribute("aria-live", "polite");
6609
6734
  div.textContent = message;
6610
6735
  return div;
6611
6736
  }
6612
- function renderTable(layout, container) {
6737
+ function renderTable(layout, container, opts) {
6613
6738
  const wrapper = document.createElement("div");
6614
- wrapper.className = "viz-table-wrapper";
6739
+ wrapper.className = "oc-table-wrapper";
6615
6740
  const { theme, chrome } = layout;
6616
6741
  if (theme) {
6617
6742
  const s = wrapper.style;
6618
- s.setProperty("--viz-bg", theme.colors.background);
6619
- s.setProperty("--viz-text", theme.colors.text);
6620
- s.setProperty("--viz-text-secondary", theme.colors.axis ?? theme.colors.text);
6621
- s.setProperty("--viz-text-muted", theme.colors.axis ?? theme.colors.text);
6622
- s.setProperty("--viz-gridline", theme.colors.gridline);
6623
- s.setProperty("--viz-border", theme.colors.gridline);
6624
- s.setProperty("--viz-font-family", theme.fonts.family);
6743
+ s.setProperty("--oc-bg", theme.colors.background);
6744
+ s.setProperty("--oc-text", theme.colors.text);
6745
+ s.setProperty("--oc-text-secondary", theme.colors.axis ?? theme.colors.text);
6746
+ s.setProperty("--oc-text-muted", theme.colors.axis ?? theme.colors.text);
6747
+ s.setProperty("--oc-gridline", theme.colors.gridline);
6748
+ s.setProperty("--oc-border", theme.colors.gridline);
6749
+ s.setProperty("--oc-font-family", theme.fonts.family);
6625
6750
  s.fontFamily = theme.fonts.family;
6626
6751
  }
6627
6752
  {
6628
6753
  const s = wrapper.style;
6629
6754
  if (chrome.title) {
6630
- s.setProperty("--viz-title-computed-size", `${chrome.title.style.fontSize}px`);
6631
- s.setProperty("--viz-title-computed-weight", String(chrome.title.style.fontWeight));
6632
- s.setProperty("--viz-title-computed-color", chrome.title.style.fill);
6755
+ s.setProperty("--oc-title-computed-size", `${chrome.title.style.fontSize}px`);
6756
+ s.setProperty("--oc-title-computed-weight", String(chrome.title.style.fontWeight));
6757
+ s.setProperty("--oc-title-computed-color", chrome.title.style.fill);
6633
6758
  }
6634
6759
  if (chrome.subtitle) {
6635
- s.setProperty("--viz-subtitle-computed-size", `${chrome.subtitle.style.fontSize}px`);
6636
- s.setProperty("--viz-subtitle-computed-weight", String(chrome.subtitle.style.fontWeight));
6637
- s.setProperty("--viz-subtitle-computed-color", chrome.subtitle.style.fill);
6760
+ s.setProperty("--oc-subtitle-computed-size", `${chrome.subtitle.style.fontSize}px`);
6761
+ s.setProperty("--oc-subtitle-computed-weight", String(chrome.subtitle.style.fontWeight));
6762
+ s.setProperty("--oc-subtitle-computed-color", chrome.subtitle.style.fill);
6638
6763
  }
6639
6764
  if (chrome.source) {
6640
- s.setProperty("--viz-source-computed-size", `${chrome.source.style.fontSize}px`);
6641
- s.setProperty("--viz-source-computed-color", chrome.source.style.fill);
6765
+ s.setProperty("--oc-source-computed-size", `${chrome.source.style.fontSize}px`);
6766
+ s.setProperty("--oc-source-computed-color", chrome.source.style.fill);
6642
6767
  }
6643
6768
  if (chrome.footer) {
6644
- s.setProperty("--viz-footer-computed-size", `${chrome.footer.style.fontSize}px`);
6645
- s.setProperty("--viz-footer-computed-color", chrome.footer.style.fill);
6769
+ s.setProperty("--oc-footer-computed-size", `${chrome.footer.style.fontSize}px`);
6770
+ s.setProperty("--oc-footer-computed-color", chrome.footer.style.fill);
6646
6771
  }
6647
6772
  }
6648
6773
  if (layout.compact) {
6649
- wrapper.classList.add("viz-table--compact");
6774
+ wrapper.classList.add("oc-table--compact");
6650
6775
  }
6651
6776
  const headerChrome = renderChromeBlock(layout, "header");
6652
6777
  if (headerChrome) {
@@ -6661,15 +6786,15 @@ function renderTable(layout, container) {
6661
6786
  wrapper.appendChild(renderEmptyState(message));
6662
6787
  } else {
6663
6788
  const scroll = document.createElement("div");
6664
- scroll.className = "viz-table-scroll";
6789
+ scroll.className = "oc-table-scroll";
6665
6790
  const table = document.createElement("table");
6666
6791
  table.setAttribute("role", "grid");
6667
6792
  table.setAttribute("aria-label", layout.a11y.caption);
6668
6793
  if (layout.stickyFirstColumn) {
6669
- table.classList.add("viz-table--sticky");
6794
+ table.classList.add("oc-table--sticky");
6670
6795
  }
6671
6796
  const caption = document.createElement("caption");
6672
- caption.className = "viz-sr-only";
6797
+ caption.className = "oc-sr-only";
6673
6798
  caption.style.position = "absolute";
6674
6799
  caption.style.width = "1px";
6675
6800
  caption.style.height = "1px";
@@ -6695,7 +6820,7 @@ function renderTable(layout, container) {
6695
6820
  wrapper.appendChild(footerChrome);
6696
6821
  }
6697
6822
  const liveRegion = document.createElement("div");
6698
- liveRegion.className = "viz-table-live-region viz-sr-only";
6823
+ liveRegion.className = "oc-table-live-region oc-sr-only";
6699
6824
  liveRegion.style.position = "absolute";
6700
6825
  liveRegion.style.width = "1px";
6701
6826
  liveRegion.style.height = "1px";
@@ -6711,7 +6836,7 @@ function renderTable(layout, container) {
6711
6836
  wrapper.appendChild(liveRegion);
6712
6837
  const brandColor = theme ? theme.colors.axis : "#999999";
6713
6838
  const brand = document.createElement("div");
6714
- brand.className = "viz-table-ref";
6839
+ brand.className = "oc-table-ref";
6715
6840
  brand.style.cssText = "text-align: right; padding: 4px 8px;";
6716
6841
  const brandLink = document.createElement("a");
6717
6842
  brandLink.href = BRAND_URL2;
@@ -6721,6 +6846,16 @@ function renderTable(layout, container) {
6721
6846
  brandLink.textContent = "OpenData";
6722
6847
  brand.appendChild(brandLink);
6723
6848
  wrapper.appendChild(brand);
6849
+ if (opts?.animate && layout.animation?.enabled) {
6850
+ const anim = layout.animation;
6851
+ const rowCount = layout.rows.length;
6852
+ const stagger = clampStaggerDelay2(anim.staggerDelay, rowCount);
6853
+ const s = wrapper.style;
6854
+ s.setProperty("--oc-animation-duration", `${anim.duration}ms`);
6855
+ s.setProperty("--oc-animation-stagger", `${stagger}ms`);
6856
+ s.setProperty("--oc-animation-ease", EASE_VAR_MAP2[anim.ease] || EASE_VAR_MAP2.smooth);
6857
+ wrapper.classList.add("oc-animate");
6858
+ }
6724
6859
  container.appendChild(wrapper);
6725
6860
  return wrapper;
6726
6861
  }
@@ -6755,6 +6890,8 @@ function createTable(container, spec, options) {
6755
6890
  let wrapperElement = null;
6756
6891
  let disconnectResize = null;
6757
6892
  let cleanupKeyboard = null;
6893
+ let cleanupAnimations = null;
6894
+ let isFirstRender = true;
6758
6895
  let destroyed = false;
6759
6896
  const internalState = {
6760
6897
  sort: null,
@@ -6814,7 +6951,7 @@ function createTable(container, spec, options) {
6814
6951
  }
6815
6952
  function announce(message) {
6816
6953
  if (!wrapperElement) return;
6817
- const liveRegion = wrapperElement.querySelector(".viz-table-live-region");
6954
+ const liveRegion = wrapperElement.querySelector(".oc-table-live-region");
6818
6955
  if (liveRegion) {
6819
6956
  liveRegion.textContent = message;
6820
6957
  }
@@ -6824,14 +6961,18 @@ function createTable(container, spec, options) {
6824
6961
  const { width } = getContainerDimensions();
6825
6962
  const bp = getBreakpoint(width);
6826
6963
  if (bp === "compact" || bp === "medium") {
6827
- wrapperElement.classList.add("viz-table--compact");
6964
+ wrapperElement.classList.add("oc-table--compact");
6828
6965
  } else if (!currentLayout?.compact) {
6829
- wrapperElement.classList.remove("viz-table--compact");
6966
+ wrapperElement.classList.remove("oc-table--compact");
6830
6967
  }
6831
6968
  }
6832
6969
  function render() {
6833
6970
  if (destroyed) return;
6834
6971
  try {
6972
+ if (cleanupAnimations) {
6973
+ cleanupAnimations();
6974
+ cleanupAnimations = null;
6975
+ }
6835
6976
  if (cleanupKeyboard) {
6836
6977
  cleanupKeyboard();
6837
6978
  cleanupKeyboard = null;
@@ -6841,16 +6982,23 @@ function createTable(container, spec, options) {
6841
6982
  wrapperElement = null;
6842
6983
  }
6843
6984
  currentLayout = compile();
6844
- wrapperElement = renderTable(currentLayout, container);
6985
+ const shouldAnimate = isFirstRender && !!currentLayout.animation?.enabled;
6986
+ wrapperElement = renderTable(currentLayout, container, { animate: shouldAnimate });
6987
+ if (shouldAnimate && wrapperElement) {
6988
+ cleanupAnimations = setupTableAnimationCleanup(wrapperElement);
6989
+ }
6990
+ if (isFirstRender) {
6991
+ isFirstRender = false;
6992
+ }
6845
6993
  const isDark = resolveDarkMode3(options?.darkMode);
6846
6994
  if (isDark) {
6847
- container.classList.add("viz-dark");
6995
+ container.classList.add("oc-dark");
6848
6996
  } else {
6849
- container.classList.remove("viz-dark");
6997
+ container.classList.remove("oc-dark");
6850
6998
  }
6851
6999
  applyBreakpointClass();
6852
7000
  if (options?.onRowClick) {
6853
- wrapperElement.classList.add("viz-table--clickable");
7001
+ wrapperElement.classList.add("oc-table--clickable");
6854
7002
  }
6855
7003
  wireEvents();
6856
7004
  if (wrapperElement) {
@@ -6890,7 +7038,7 @@ function createTable(container, spec, options) {
6890
7038
  btn.addEventListener("click", handleSortClick);
6891
7039
  }
6892
7040
  const searchInput = wrapperElement.querySelector(
6893
- ".viz-table-search input"
7041
+ ".oc-table-search input"
6894
7042
  );
6895
7043
  if (searchInput) {
6896
7044
  searchInput.addEventListener("input", handleSearchInput);
@@ -6966,7 +7114,7 @@ function createTable(container, spec, options) {
6966
7114
  function rerender() {
6967
7115
  if (destroyed) return;
6968
7116
  const searchInput = wrapperElement?.querySelector(
6969
- ".viz-table-search input"
7117
+ ".oc-table-search input"
6970
7118
  );
6971
7119
  const hadFocus = searchInput && document.activeElement === searchInput;
6972
7120
  const selectionStart = searchInput?.selectionStart ?? 0;
@@ -6974,7 +7122,7 @@ function createTable(container, spec, options) {
6974
7122
  render();
6975
7123
  if (hadFocus) {
6976
7124
  const newInput = wrapperElement?.querySelector(
6977
- ".viz-table-search input"
7125
+ ".oc-table-search input"
6978
7126
  );
6979
7127
  if (newInput) {
6980
7128
  newInput.focus();
@@ -6989,6 +7137,7 @@ function createTable(container, spec, options) {
6989
7137
  }
6990
7138
  function resize() {
6991
7139
  if (destroyed) return;
7140
+ if (cleanupAnimations) return;
6992
7141
  render();
6993
7142
  }
6994
7143
  function doExport(format) {
@@ -7025,6 +7174,10 @@ function createTable(container, spec, options) {
7025
7174
  function destroy() {
7026
7175
  if (destroyed) return;
7027
7176
  destroyed = true;
7177
+ if (cleanupAnimations) {
7178
+ cleanupAnimations();
7179
+ cleanupAnimations = null;
7180
+ }
7028
7181
  if (cleanupKeyboard) {
7029
7182
  cleanupKeyboard();
7030
7183
  cleanupKeyboard = null;
@@ -7045,7 +7198,7 @@ function createTable(container, spec, options) {
7045
7198
  wrapperElement.parentNode.removeChild(wrapperElement);
7046
7199
  wrapperElement = null;
7047
7200
  }
7048
- container.classList.remove("viz-dark");
7201
+ container.classList.remove("oc-dark");
7049
7202
  }
7050
7203
  render();
7051
7204
  if (options?.responsive !== false) {