@opendata-ai/openchart-vanilla 8.7.0 → 8.9.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/{chunk-5O624XON.js → chunk-6TD7GWR4.js} +1141 -293
- package/dist/chunk-6TD7GWR4.js.map +1 -0
- package/dist/{chunk-DFKLAB67.js → chunk-MGFXAROR.js} +20 -8
- package/dist/chunk-MGFXAROR.js.map +1 -0
- package/dist/{chunk-I73B3DJI.js → chunk-R5TZHNTG.js} +23 -5
- package/dist/chunk-R5TZHNTG.js.map +1 -0
- package/dist/{chunk-SXTHPXG6.js → chunk-TP3GCWCO.js} +78 -7
- package/dist/chunk-TP3GCWCO.js.map +1 -0
- package/dist/{chunk-5IMVUHVC.js → chunk-YBVDBY6P.js} +17 -13
- package/dist/chunk-YBVDBY6P.js.map +1 -0
- package/dist/{chunk-EZQDCLZN.js → chunk-YHZAH6EN.js} +3 -2
- package/dist/{chunk-EZQDCLZN.js.map → chunk-YHZAH6EN.js.map} +1 -1
- package/dist/export-gif.d.ts +2 -2
- package/dist/export-gif.js +2 -2
- package/dist/graph-3d/index.js +1 -1
- package/dist/index.d.ts +34 -5
- package/dist/index.js +633 -212
- package/dist/index.js.map +1 -1
- package/dist/{mount-WiY9BIr9.d.ts → mount-FmUdKlCq.d.ts} +11 -1
- package/dist/static.js +2 -2
- package/dist/story/index.d.ts +2 -2
- package/dist/story/index.js +3 -3
- package/dist/styles.css +1 -1
- package/dist/styles.css.map +1 -1
- package/package.json +4 -4
- package/dist/chunk-5IMVUHVC.js.map +0 -1
- package/dist/chunk-5O624XON.js.map +0 -1
- package/dist/chunk-DFKLAB67.js.map +0 -1
- package/dist/chunk-I73B3DJI.js.map +0 -1
- package/dist/chunk-SXTHPXG6.js.map +0 -1
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/barlist-mount.ts","../src/barlist-renderer.ts","../src/export-sequence.ts","../src/graph/simulation-worker-url.ts","../src/renderers/table-cells.ts","../src/sankey-mount.ts","../src/sankey-renderer.ts","../src/table-keyboard.ts","../src/table-mount.ts","../src/table-renderer.ts","../src/tilemap-mount.ts"],"sourcesContent":["/**\n * BarList mount API: the main entry point for vanilla JS barlist usage.\n *\n * createBarList() takes a container, BarListSpec, and options, compiles the\n * barlist, renders it as SVG, sets up responsive resizing, tooltip interaction,\n * and returns a BarListInstance with update/resize/export/destroy.\n */\n\nimport type {\n BarListLayout,\n BarListSpec,\n CompileOptions,\n DarkMode,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport { compileBarList } from '@opendata-ai/openchart-engine';\nimport { cancelAnimations, setupAnimationCleanup } from './animation';\nimport { renderBarListSVG } from './barlist-renderer';\nimport {\n exportJPG,\n exportPNG,\n exportSVG,\n exportSVGWithFonts,\n type JPGExportOptions,\n type SVGExportOptions,\n} from './export';\nimport { createMeasureText, resolveFontFamily, scheduleFontReload } from './measure-text';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { createTooltipManager, type TooltipManager } from './tooltip';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface BarListMountOptions {\n theme?: ThemeConfig;\n darkMode?: DarkMode;\n responsive?: boolean;\n watermark?: boolean;\n tooltip?: boolean;\n onRowClick?: (row: { label: string; value: number; data: Record<string, unknown> }) => void;\n onRowHover?: (\n row: { label: string; value: number; data: Record<string, unknown> } | null,\n ) => void;\n}\n\nexport interface BarListInstance {\n update(spec: BarListSpec): void;\n resize(): void;\n export(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string>;\n destroy(): void;\n readonly layout: BarListLayout;\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\nexport function createBarList(\n container: HTMLElement,\n spec: BarListSpec,\n options?: BarListMountOptions,\n): BarListInstance {\n let currentSpec = spec;\n let currentLayout: BarListLayout;\n let destroyed = false;\n\n let svgElement: SVGSVGElement | null = null;\n let tooltipManager: TooltipManager | null = null;\n let cleanupTooltipEvents: (() => void) | null = null;\n let disconnectResize: (() => void) | null = null;\n let animationCleanup: (() => void) | null = null;\n let pendingResize = false;\n\n // Set when webfonts have loaded and a recompile is owed. The next render()\n // that recompiles flips data-oc-fonts-state to 'ready' and clears this, so\n // the attribute stays honest when resize() defers to pendingResize during\n // the entrance animation.\n let fontsReloadPending = false;\n\n // Apply the root class up front so getComputedStyle sees --oc-font-family\n // before the text measurer is built.\n container.classList.add('oc-barlist-root');\n\n // Resolve the effective font the way compile() will: compile merges\n // { ...spec.theme, ...options.theme }, so options.theme wins over the\n // spec-level theme; fall back to the container's computed font. Measuring a\n // different font than gets rendered desyncs layout metrics and the reload watcher.\n function resolveEffectiveFont(): string {\n return (\n options?.theme?.fonts?.family ??\n currentSpec.theme?.fonts?.family ??\n resolveFontFamily(container)\n );\n }\n let fontFamily = resolveEffectiveFont();\n let measureText = createMeasureText(fontFamily);\n let renderGen = 0;\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: Math.max(rect.width || 600, 100),\n height: Math.max(rect.height || 400, 100),\n };\n }\n\n function compile(): BarListLayout {\n const { width, height } = getContainerDimensions();\n const darkMode = resolveDarkMode(options?.darkMode);\n\n const compileOpts: CompileOptions = {\n width,\n height,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n measureText,\n };\n\n const layout = compileBarList(currentSpec, compileOpts);\n\n // Auto-size height to content so few-row lists don't leave empty space.\n if (layout.rows.length > 0) {\n const lastRow = layout.rows[layout.rows.length - 1];\n const contentBottom =\n lastRow.y + lastRow.height + layout.chrome.bottomHeight + layout.theme.spacing.padding;\n if (contentBottom < layout.height) {\n layout.height = contentBottom;\n layout.area.height =\n contentBottom - layout.area.y - layout.chrome.bottomHeight - layout.theme.spacing.padding;\n }\n }\n\n return layout;\n }\n\n function wireTooltipAndInteraction(svg: SVGSVGElement, layout: BarListLayout): () => void {\n const cleanups: Array<() => void> = [];\n\n const rowElements = svg.querySelectorAll('.oc-barlist-row');\n for (const el of rowElements) {\n const indexStr = el.getAttribute('data-row-index');\n if (indexStr === null) continue;\n\n const content = layout.tooltipDescriptors.get(indexStr);\n const row = layout.rows[Number(indexStr)];\n\n const handleMouseEnter = (e: Event) => {\n const mouseEvent = e as MouseEvent;\n if (content && tooltipManager && options?.tooltip !== false) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n if (row) {\n options?.onRowHover?.({\n label: row.label.text,\n value: row.value,\n data: row.data,\n });\n }\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager && options?.tooltip !== false) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n tooltipManager?.hide();\n options?.onRowHover?.(null);\n };\n\n const handleClick = () => {\n if (row) {\n options?.onRowClick?.({\n label: row.label.text,\n value: row.value,\n data: row.data,\n });\n }\n };\n\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n return () => {\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n function render(animate = false): void {\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n }\n\n if (svgElement) {\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n svgElement.remove();\n }\n\n const newSvg = renderBarListSVG(currentLayout, { animate });\n container.appendChild(newSvg);\n svgElement = newSvg;\n\n cleanupTooltipEvents = wireTooltipAndInteraction(newSvg, currentLayout);\n\n if (options?.tooltip !== false) {\n if (!tooltipManager) {\n tooltipManager = createTooltipManager(container);\n }\n }\n\n if (currentLayout.animation?.enter) {\n animationCleanup = setupAnimationCleanup(newSvg, () => {\n // Null the handle BEFORE replaying, or the deferred resize hits the\n // entrance-in-flight gate and re-defers forever (mount.ts pattern).\n animationCleanup = null;\n if (pendingResize && !destroyed) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n\n // This render recompiled with the loaded webfonts; publish 'ready' now\n // rather than right after the fonts-ready resize() (which may have deferred\n // to pendingResize during the entrance animation).\n if (fontsReloadPending) {\n fontsReloadPending = false;\n container.dataset.ocFontsState = 'ready';\n }\n }\n\n function update(newSpec: BarListSpec): void {\n currentSpec = newSpec;\n // A new spec can change theme.fonts.family; rebuild the measurer so layout\n // measures the font compile will actually render with.\n const nextFont = resolveEffectiveFont();\n if (nextFont !== fontFamily) {\n fontFamily = nextFont;\n measureText = createMeasureText(fontFamily);\n }\n currentLayout = compile();\n render();\n }\n\n function resize(): void {\n if (destroyed) return;\n if (animationCleanup) {\n pendingResize = true;\n return;\n }\n currentLayout = compile();\n render();\n }\n\n function exportChart(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options_?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string> {\n if (!svgElement) return '';\n switch (format) {\n case 'svg':\n return exportSVG(svgElement);\n case 'svg-with-fonts':\n return exportSVGWithFonts(svgElement);\n case 'png':\n return exportPNG(svgElement, options_ as JPGExportOptions);\n case 'jpg':\n return exportJPG(svgElement, options_ as JPGExportOptions);\n default:\n return '';\n }\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n if (animationCleanup) {\n cancelAnimations(svgElement);\n animationCleanup();\n animationCleanup = null;\n }\n\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n if (svgElement) {\n svgElement.remove();\n svgElement = null;\n }\n\n if (tooltipManager) {\n tooltipManager.destroy();\n tooltipManager = null;\n }\n\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n\n container.classList.remove('oc-barlist-root', 'oc-dark');\n }\n\n // Initialize\n if (resolveDarkMode(options?.darkMode)) {\n container.classList.add('oc-dark');\n }\n\n currentLayout = compile();\n render(true);\n\n // Recompile once after webfonts load so row labels aren't stuck measured\n // against fallback metrics on real devices.\n const fontsPending = scheduleFontReload(\n fontFamily,\n () => !destroyed,\n () => {\n // Mark the reload owed, then recompile. render() flips the attribute to\n // 'ready' once it actually recompiles, including the pendingResize replay\n // after the entrance animation finishes.\n fontsReloadPending = true;\n resize();\n },\n );\n container.dataset.ocFontsState = fontsPending ? 'pending' : 'ready';\n\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => resize());\n }\n\n return {\n update,\n resize,\n export: exportChart,\n destroy,\n get layout(): BarListLayout {\n return currentLayout;\n },\n };\n}\n","/**\n * BarList SVG renderer: converts a BarListLayout into SVG DOM elements.\n *\n * Creates an <svg> with rows of label + track + bar + value. Animation is\n * pure CSS, driven by data attributes and CSS custom properties.\n */\n\nimport type { BarListLayout, BarListRowMark, ResolvedAnimation } from '@opendata-ai/openchart-core';\nimport { textAscent } from '@opendata-ai/openchart-core';\nimport { stampAnimationVars } from './animation-vars';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst XLINK_NS = 'http://www.w3.org/1999/xlink';\nconst BRAND_URL = 'https://tryopendata.ai';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createSVGElement(tag: string): SVGElement {\n return document.createElementNS(SVG_NS, tag);\n}\n\nfunction setAttrs(el: SVGElement, attrs: Record<string, string | number>): void {\n for (const [key, value] of Object.entries(attrs)) {\n el.setAttribute(key, String(value));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Chrome rendering\n// ---------------------------------------------------------------------------\n\nfunction renderChrome(parent: SVGElement, layout: BarListLayout): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-chrome');\n\n const { chrome } = layout;\n const bottomOffset = layout.area.y + layout.area.height;\n\n for (const key of ['title', 'subtitle', 'source', 'byline', 'footer'] as const) {\n const el = chrome[key];\n if (!el) continue;\n\n const isBottom = key === 'source' || key === 'byline' || key === 'footer';\n const text = createSVGElement('text');\n // el.y is the TOP of the text box; convert to the alphabetic baseline\n // (WebKit mishandles dominant-baseline:hanging, see renderers/chrome.ts).\n setAttrs(text, {\n x: el.x,\n y: (isBottom ? bottomOffset + el.y : el.y) + textAscent(el.style.fontSize),\n });\n text.setAttribute('class', `oc-${key}`);\n text.setAttribute('font-family', el.style.fontFamily);\n text.setAttribute('font-size', String(el.style.fontSize));\n text.setAttribute('font-weight', String(el.style.fontWeight));\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', el.style.fill);\n text.textContent = el.text;\n g.appendChild(text);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Watermark rendering\n// ---------------------------------------------------------------------------\n\nfunction renderWatermark(parent: SVGElement, layout: BarListLayout): void {\n if (layout.width < 480) return;\n\n const { width, height, theme } = layout;\n const padding = theme.spacing.padding;\n const rightEdge = width - padding;\n const bottomEdge = height - padding;\n const fill = theme.colors.axis;\n\n const a = createSVGElement('a');\n a.setAttribute('href', BRAND_URL);\n a.setAttributeNS(XLINK_NS, 'xlink:href', BRAND_URL);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.setAttribute('class', 'oc-chrome-ref');\n\n const text = createSVGElement('text');\n setAttrs(text, {\n x: rightEdge,\n y: bottomEdge,\n 'dominant-baseline': 'alphabetic',\n 'text-anchor': 'end',\n 'font-family': theme.fonts.family,\n 'font-size': 12,\n 'fill-opacity': 0.55,\n });\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', fill);\n\n setAttrs(text, { 'font-weight': 600, 'font-size': 16 });\n text.textContent = 'OpenData';\n a.appendChild(text);\n parent.appendChild(a);\n}\n\n// ---------------------------------------------------------------------------\n// Row rendering\n// ---------------------------------------------------------------------------\n\nfunction renderRows(\n parent: SVGElement,\n rows: BarListRowMark[],\n animation?: ResolvedAnimation,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-barlist-rows');\n g.setAttribute('role', 'list');\n\n for (const row of rows) {\n const rowGroup = createSVGElement('g');\n rowGroup.setAttribute('class', 'oc-barlist-row');\n rowGroup.setAttribute('data-row-index', String(row.index));\n rowGroup.setAttribute('role', 'listitem');\n if (row.aria?.label) {\n rowGroup.setAttribute('aria-label', row.aria.label);\n }\n\n if (animation?.enter) {\n rowGroup.setAttribute('data-animation-index', String(row.animationIndex));\n const style = (rowGroup as SVGElement & ElementCSSInlineStyle).style;\n style.setProperty('--oc-mark-index', String(row.animationIndex));\n style.setProperty('--oc-row-delay', `${row.animationIndex * 40}ms`);\n }\n\n // Label text\n const labelEl = createSVGElement('text');\n setAttrs(labelEl, {\n x: row.label.x,\n y: row.label.y,\n 'dominant-baseline': 'central',\n 'text-anchor': 'start',\n 'font-family': row.label.style.fontFamily,\n 'font-size': row.label.style.fontSize,\n 'font-weight': row.label.style.fontWeight,\n });\n (labelEl as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', row.label.style.fill);\n labelEl.textContent = row.label.text;\n rowGroup.appendChild(labelEl);\n\n // Subtitle text (if present)\n if (row.subtitle?.visible) {\n const subEl = createSVGElement('text');\n setAttrs(subEl, {\n x: row.subtitle.x,\n y: row.subtitle.y,\n 'dominant-baseline': 'central',\n 'text-anchor': 'start',\n 'font-family': row.subtitle.style.fontFamily,\n 'font-size': row.subtitle.style.fontSize,\n 'font-weight': row.subtitle.style.fontWeight,\n });\n (subEl as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n row.subtitle.style.fill,\n );\n subEl.textContent = row.subtitle.text;\n rowGroup.appendChild(subEl);\n }\n\n // Track (muted background bar)\n const trackRect = createSVGElement('rect');\n setAttrs(trackRect, {\n x: row.track.x,\n y: row.track.y,\n width: row.track.width,\n height: row.track.height,\n rx: row.track.cornerRadius,\n fill: 'currentColor',\n 'fill-opacity': 0.06,\n });\n trackRect.setAttribute('class', 'oc-barlist-track');\n rowGroup.appendChild(trackRect);\n\n // Fill bar\n const barRect = createSVGElement('rect');\n setAttrs(barRect, {\n x: row.bar.x,\n y: row.bar.y,\n width: row.bar.width,\n height: row.bar.height,\n rx: row.bar.cornerRadius,\n fill: row.bar.fill,\n });\n barRect.setAttribute('class', 'oc-barlist-bar');\n rowGroup.appendChild(barRect);\n\n // Value label (right-aligned)\n const valueEl = createSVGElement('text');\n setAttrs(valueEl, {\n x: row.valueLabel.x,\n y: row.valueLabel.y,\n 'dominant-baseline': 'central',\n 'text-anchor': 'end',\n 'font-family': row.valueLabel.style.fontFamily,\n 'font-size': row.valueLabel.style.fontSize,\n 'font-weight': row.valueLabel.style.fontWeight,\n });\n (valueEl as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n row.valueLabel.style.fill,\n );\n valueEl.textContent = row.valueLabel.text;\n rowGroup.appendChild(valueEl);\n\n g.appendChild(rowGroup);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function renderBarListSVG(\n layout: BarListLayout,\n opts?: { animate?: boolean },\n): SVGSVGElement {\n const { width, height, rows, a11y, watermark, animation } = layout;\n const animate = opts?.animate && !!animation?.enter;\n\n const svg = createSVGElement('svg') as SVGSVGElement;\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n svg.setAttribute('role', 'list');\n // No explicit width attribute — CSS width:100% on .oc-barlist-root handles it.\n // Explicit pixel height via inline style avoids iOS Safari's height:100% quirk.\n svg.style.height = `${height}px`;\n if (a11y.altText) {\n svg.setAttribute('aria-label', a11y.altText);\n }\n\n const classes = animate ? 'oc-barlist oc-animate' : 'oc-barlist';\n svg.setAttribute('class', classes);\n\n if (animate && animation?.enter) {\n stampAnimationVars(svg, { duration: animation.enter.duration, stagger: 40 });\n }\n\n renderChrome(svg, layout);\n renderRows(svg, rows, animate ? animation : undefined);\n\n if (watermark) {\n renderWatermark(svg, layout);\n }\n\n return svg;\n}\n","/**\n * Multi-spec (\"keyframe\") GIF export.\n *\n * The single-chart GIF export (`exportGIF`) reproduces ONE chart's entrance\n * animation. Some charts animate a different way: a component swaps in a whole\n * new spec on a timer (e.g. a year-by-year stepper), and the on-screen chart\n * tweens between them via `chart.update()` (bars grow/shrink smoothly). The DATA\n * changes across frames, and the motion is the update transition — neither of\n * which `exportGIF` can express.\n *\n * `exportSpecSequence` reproduces that. It mounts one offscreen chart, holds the\n * first spec, then walks the rest by driving `chart.beginManualUpdate(spec)` and\n * stepping the returned transition frame-by-frame (no rAF clock), rasterizing\n * each step. Between transitions it holds the settled frame for `dwellMs`. The\n * result is the same bar tween the reader sees on screen, captured to GIF.\n *\n * `gifenc` is an optional peer dependency, loaded dynamically.\n */\n\nimport type {\n AnimationSpec,\n ChartSpec,\n LayerSpec,\n ResolvedTheme,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport {\n embedFonts,\n ensureSVGDimensions,\n exportSVG,\n getSVGBackgroundColor,\n getSVGDimensions,\n rasterizeSVGToCanvas,\n} from './export';\nimport { isModuleNotFound, resolveRepeat } from './export-gif';\nimport { paletteFromCanvas, readCanvasSRGB } from './gif-encode';\nimport { createChart } from './mount';\nimport { injectThemeStyleBlock } from './theme-style-block';\n\nexport interface SpecSequenceOptions {\n /** DPI scaling factor, matching PNG export. Defaults to 2. */\n dpi?: number;\n /** Frames per second for the tween between specs. Defaults to 25. */\n fps?: number;\n /** How long to hold each spec's settled frame, in ms. Defaults to 1200 (the common stepper cadence). */\n dwellMs?: number;\n /**\n * Loop behavior, same semantics as `exportGIF`:\n * - `false` / omitted: play once, then hold the final frame\n * - `true`: loop forever\n * - a number: loop that many times, then hold\n */\n loop?: boolean | number;\n /** Render width in CSS px. Required — pass the on-screen chart width so the export matches. */\n width: number;\n /** Render height in CSS px. Required — pass the on-screen chart height so the export matches. */\n height: number;\n /** Dark mode for the rendered charts. Defaults to 'off' (light). */\n darkMode?: 'auto' | 'force' | 'off';\n /**\n * Rendering backend for point marks; see `MountOptions.renderer`. Pass the\n * SAME value your on-screen chart mounts with so the export matches.\n */\n renderer?: 'auto' | 'svg' | 'canvas';\n /**\n * Theme overrides applied when rendering, exactly as a consumer's live wrapper\n * would apply them. Pass the SAME theme your on-screen chart uses (e.g. the\n * blog's `blogChartTheme(isDark)`), or the export won't match — its background,\n * gridlines, and chrome colors fall back to openchart's raw defaults.\n */\n theme?: ThemeConfig;\n /** Embed fonts as base64 so text matches on-screen. Defaults to true. */\n embedFonts?: boolean;\n /** Opaque background fill. Defaults to the chart's own background (white if transparent). */\n backgroundColor?: string;\n}\n\n/**\n * Force `enter:false` (each spec must render settled) while KEEPING the author's\n * own update config when they wrote one as an object. Replacing it wholesale\n * would drop fields like `update.maxMarks`, so a spec that deliberately raised\n * the tween cap above 500 marks would silently swap instead of tween on export.\n */\nexport function settleAnimation(spec: ChartSpec | LayerSpec): ChartSpec | LayerSpec {\n const authored = (spec as { animation?: AnimationSpec }).animation;\n const update =\n typeof authored === 'object' && typeof authored.update === 'object'\n ? { ...authored.update }\n : true;\n return {\n ...(spec as unknown as Record<string, unknown>),\n animation: { enter: false, update },\n } as unknown as ChartSpec | LayerSpec;\n}\n\n/**\n * Mount one live chart offscreen (used as the persistent host we step through\n * every spec). Entrance is disabled so the first spec renders settled; update\n * transitions are enabled so `beginManualUpdate` can tween between specs.\n */\nfunction mountOffscreen(\n spec: ChartSpec | LayerSpec,\n width: number,\n height: number,\n darkMode: 'auto' | 'force' | 'off',\n themeConfig: ThemeConfig | undefined,\n renderer: 'auto' | 'svg' | 'canvas' | undefined,\n): {\n instance: ReturnType<typeof createChart>;\n svg: SVGElement;\n container: HTMLElement;\n} {\n const container = document.createElement('div');\n // Offscreen but laid out, so text measurement (needs a live DOM) works.\n container.style.cssText = `position:absolute;left:-99999px;top:0;width:${width}px;height:${height}px;visibility:hidden;`;\n document.body.appendChild(container);\n\n // enter:false → first spec settled immediately; update:true → tween on\n // beginManualUpdate. responsive:false → no ResizeObserver on a detached node.\n const settledSpec = settleAnimation(spec);\n let instance: ReturnType<typeof createChart>;\n try {\n instance = createChart(container, settledSpec, {\n darkMode,\n theme: themeConfig,\n renderer,\n responsive: false,\n });\n } catch (err) {\n // A spec that fails to compile must not leak the offscreen container.\n container.remove();\n throw err;\n }\n\n const svg = container.querySelector('svg');\n if (!svg) {\n instance.destroy();\n container.remove();\n throw new Error('exportSpecSequence: chart produced no SVG');\n }\n return { instance, svg, container };\n}\n\n/**\n * Render an ordered list of specs to an animated GIF Blob. Holds the first spec,\n * then tweens to each subsequent spec (openchart's update transition, driven\n * frame-by-frame) and holds it — reproducing the on-screen bar grow/shrink.\n *\n * @param specs - Ordered specs, one per keyframe (e.g. one per year).\n * @param options - dpi, fps, dwell, loop, size (required), dark mode, theme, fonts.\n * @returns A Promise resolving to the GIF Blob.\n */\nexport async function exportSpecSequence(\n specs: Array<ChartSpec | LayerSpec>,\n options: SpecSequenceOptions,\n): Promise<Blob> {\n if (specs.length === 0) {\n throw new Error('exportSpecSequence requires at least one spec');\n }\n\n let gifenc: typeof import('gifenc');\n try {\n gifenc = await import('gifenc');\n } catch (err) {\n if (isModuleNotFound(err)) {\n throw new Error(\n \"GIF export requires the optional 'gifenc' peer dependency. Install it: npm install gifenc\",\n );\n }\n throw new Error('GIF export failed to load the gifenc encoder', {\n cause: err,\n });\n }\n const { GIFEncoder, quantize, applyPalette } = gifenc;\n\n const dpi = options.dpi ?? 2;\n const fps = options.fps ?? 25;\n const dwellMs = options.dwellMs ?? 1200;\n const frameDelay = Math.round(1000 / fps);\n const { width, height } = options;\n const darkMode = options.darkMode ?? 'off';\n const themeConfig = options.theme;\n const shouldEmbed = options.embedFonts ?? true;\n const repeat = resolveRepeat(options.loop);\n\n const { instance, svg, container } = mountOffscreen(\n specs[0],\n width,\n height,\n darkMode,\n themeConfig,\n options.renderer,\n );\n\n try {\n const w = getSVGDimensions(svg).width || width;\n const h = getSVGDimensions(svg).height || height;\n const theme = (): ResolvedTheme | undefined => {\n const layout = instance.layout;\n return layout && 'theme' in layout ? (layout.theme as ResolvedTheme) : undefined;\n };\n // The theme background is the fallback: canvas mark mode suppresses the SVG\n // background rect, so there's nothing in the markup to read it from.\n const bgColor =\n options.backgroundColor ?? getSVGBackgroundColor(svg, theme()?.colors.background);\n const fillBackground = (ctx: CanvasRenderingContext2D, cv: HTMLCanvasElement): void => {\n ctx.fillStyle = bgColor;\n ctx.fillRect(0, 0, cv.width, cv.height);\n };\n\n // `beginManualUpdate`/`render` REPLACES the live <svg> node each spec, so the\n // injected theme + @font-face blocks don't carry over. Re-inject them into\n // whatever <svg> is currently live. Fonts embed once per spec (not per frame\n // — embedding fetches font files, which across a tween would be far too slow).\n const prepareLiveSvg = async (): Promise<SVGElement> => {\n const live = container.querySelector('svg');\n if (!live) throw new Error('exportSpecSequence: live SVG vanished mid-sequence');\n injectThemeStyleBlock(live, theme());\n if (shouldEmbed) await embedFonts(live);\n return live;\n };\n\n // Rasterize the given live svg at its current (stepped) state.\n const grab = async (live: SVGElement): Promise<HTMLCanvasElement> => {\n const svgString = ensureSVGDimensions(exportSVG(live), w, h);\n return rasterizeSVGToCanvas(svgString, w, h, dpi, fillBackground);\n };\n\n // frames: each canvas with its hold duration. Hold the first spec, then for\n // each subsequent spec step its tween (frameDelay each) and hold the result.\n const frames: Array<{ canvas: HTMLCanvasElement; delayMs: number }> = [];\n let live = await prepareLiveSvg();\n frames.push({ canvas: await grab(live), delayMs: dwellMs });\n\n for (let i = 1; i < specs.length; i++) {\n // Re-apply the same settle/animation wrapper the offscreen mount used, so\n // update transitions stay enabled for each step.\n const nextSpec = settleAnimation(specs[i]);\n const handle = instance.beginManualUpdate(nextSpec);\n // render() replaced the <svg>; re-inject theme/fonts into the new one.\n live = await prepareLiveSvg();\n\n if (handle) {\n const totalMs = handle.totalMs;\n // Step across the tween at fps; capture each frame. Start one frame in\n // (t=0 is the previous held frame) and go through the final step.\n for (let t = frameDelay; t < totalMs; t += frameDelay) {\n handle.step(t);\n frames.push({ canvas: await grab(live), delayMs: frameDelay });\n }\n // Final settled frame of this spec, held for the dwell.\n handle.step(totalMs);\n handle.cancel();\n }\n frames.push({ canvas: await grab(live), delayMs: dwellMs });\n }\n\n // One global palette from the last frame — a full-color settled frame, and\n // stepper frames share a palette by construction.\n const globalPalette = paletteFromCanvas(frames[frames.length - 1].canvas, quantize);\n\n const gif = GIFEncoder();\n frames.forEach(({ canvas, delayMs }, i) => {\n const index = applyPalette(readCanvasSRGB(canvas), globalPalette);\n gif.writeFrame(index, canvas.width, canvas.height, {\n palette: globalPalette,\n delay: delayMs,\n // `repeat` writes the loop extension; only meaningful on the first frame.\n ...(i === 0 ? { repeat } : {}),\n });\n });\n\n gif.finish();\n return new Blob([gif.bytes() as BlobPart], { type: 'image/gif' });\n } finally {\n instance.destroy();\n container.remove();\n }\n}\n","/**\n * Creates a Web Worker running the force simulation.\n *\n * References the built .js file via `new URL` + `import.meta.url`.\n * The consuming app's bundler resolves the worker path at build time.\n *\n * Note: SimulationManager handles .js/.ts fallback internally. This\n * helper is exported for consumers who want to manage the worker directly.\n */\nexport function createSimulationWorker(): Worker {\n return new Worker(new URL('./simulation-worker.js', import.meta.url), { type: 'module' });\n}\n","/**\n * Table cell renderers: produce DOM elements for each cell type.\n *\n * Each renderer takes a resolved TableCell and returns an HTMLElement\n * (typically a <td>) with appropriate content, styling, and classes.\n */\n\nimport type {\n BarTableCell,\n CategoryTableCell,\n DeltaTableCell,\n FlagTableCell,\n HeatmapTableCell,\n ImageTableCell,\n SparklineData,\n SparklineTableCell,\n TableCell,\n TextTableCell,\n} from '@opendata-ai/openchart-core';\n\n// ---------------------------------------------------------------------------\n// Utility\n// ---------------------------------------------------------------------------\n\n/** Apply common cell styles (background, color, font weight, font variant). */\nfunction applyCellStyle(td: HTMLTableCellElement, cell: TableCell): void {\n if (cell.style.backgroundColor) {\n td.style.background = cell.style.backgroundColor;\n }\n if (cell.style.color) {\n td.style.color = cell.style.color;\n }\n if (cell.style.fontWeight) {\n td.style.fontWeight = String(cell.style.fontWeight);\n }\n if (cell.style.fontVariant) {\n td.style.fontVariant = cell.style.fontVariant;\n }\n if (cell.aria) {\n td.setAttribute('aria-label', cell.aria);\n }\n}\n\n/**\n * Convert a 2-char ISO 3166-1 alpha-2 country code to a flag emoji.\n * Each letter maps to a Regional Indicator Symbol (offset 0x1F1A5 from ASCII).\n */\nfunction countryToEmoji(code: string): string {\n return [...code.toUpperCase()]\n .map((c) => String.fromCodePoint(c.charCodeAt(0) + 0x1f1a5))\n .join('');\n}\n\n/**\n * Lookup map for common country names by ISO 3166-1 alpha-2 code.\n * Falls back to the raw code for unrecognized values.\n */\nconst COUNTRY_NAMES: Record<string, string> = {\n US: 'United States',\n CN: 'China',\n IN: 'India',\n ID: 'Indonesia',\n BR: 'Brazil',\n PK: 'Pakistan',\n NG: 'Nigeria',\n BD: 'Bangladesh',\n RU: 'Russia',\n MX: 'Mexico',\n JP: 'Japan',\n DE: 'Germany',\n GB: 'United Kingdom',\n FR: 'France',\n IT: 'Italy',\n CA: 'Canada',\n AU: 'Australia',\n KR: 'South Korea',\n ES: 'Spain',\n AR: 'Argentina',\n CO: 'Colombia',\n ZA: 'South Africa',\n TR: 'Turkey',\n SA: 'Saudi Arabia',\n UA: 'Ukraine',\n PL: 'Poland',\n NL: 'Netherlands',\n SE: 'Sweden',\n NO: 'Norway',\n DK: 'Denmark',\n FI: 'Finland',\n CH: 'Switzerland',\n AT: 'Austria',\n BE: 'Belgium',\n PT: 'Portugal',\n IE: 'Ireland',\n NZ: 'New Zealand',\n SG: 'Singapore',\n IL: 'Israel',\n AE: 'United Arab Emirates',\n EG: 'Egypt',\n TH: 'Thailand',\n VN: 'Vietnam',\n PH: 'Philippines',\n MY: 'Malaysia',\n CL: 'Chile',\n PE: 'Peru',\n CZ: 'Czech Republic',\n GR: 'Greece',\n HU: 'Hungary',\n RO: 'Romania',\n ET: 'Ethiopia',\n};\n\n/** Get a human-readable name for a country code. */\nfunction getCountryName(code: string): string {\n return COUNTRY_NAMES[code.toUpperCase()] || code.toUpperCase();\n}\n\n/**\n * Describe a sparkline trend for screen readers.\n * Compares first and last values to determine direction.\n */\nfunction describeSparklineTrend(data: SparklineData): string {\n if (data.type === 'line' && data.points.length >= 2) {\n const first = data.points[0].y;\n const last = data.points[data.points.length - 1].y;\n const count = data.points.length;\n if (last > first) return `Sparkline with ${count} points, trending upward`;\n if (last < first) return `Sparkline with ${count} points, trending downward`;\n return `Sparkline with ${count} points, roughly flat`;\n }\n if ((data.type === 'bar' || data.type === 'column') && data.bars.length > 0) {\n return `${data.type === 'column' ? 'Column' : 'Bar'} sparkline with ${data.bars.length} values`;\n }\n return 'Sparkline';\n}\n\n// ---------------------------------------------------------------------------\n// Cell renderers\n// ---------------------------------------------------------------------------\n\n/** Render a plain text cell. */\nexport function renderTextCell(cell: TextTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.textContent = cell.formattedValue;\n applyCellStyle(td, cell);\n return td;\n}\n\n/** Render a heatmap-colored cell. */\nexport function renderHeatmapCell(cell: HeatmapTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.className = 'oc-table-heatmap';\n td.textContent = cell.formattedValue;\n applyCellStyle(td, cell);\n return td;\n}\n\n/**\n * Render a category-colored cell as a chip: a dot in the category color, the\n * value in a contrast-safe ink, on a tint of the same hue. The color lives on\n * the chip, never on the cell, so a column of categories reads as labels\n * rather than a block of paint.\n */\nexport function renderCategoryCell(cell: CategoryTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.className = 'oc-table-category';\n\n const chip = document.createElement('span');\n chip.className = 'oc-table-chip';\n if (cell.style.backgroundColor) chip.style.background = cell.style.backgroundColor;\n if (cell.style.color) chip.style.color = cell.style.color;\n\n if (cell.style.accent) {\n const dot = document.createElement('span');\n dot.className = 'oc-table-chip-dot';\n dot.style.background = cell.style.accent;\n chip.appendChild(dot);\n }\n\n chip.appendChild(document.createTextNode(cell.formattedValue));\n td.appendChild(chip);\n return td;\n}\n\n/** Render a cell with an inline bar visualization. */\nexport function renderBarCell(cell: BarTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.className = 'oc-table-bar';\n applyCellStyle(td, cell);\n\n const fill = document.createElement('div');\n fill.className = 'oc-table-bar-fill';\n fill.style.width = `${Math.round(cell.barWidth * 100)}%`;\n fill.style.left = `${Math.round(cell.barOffset * 100)}%`;\n fill.style.background = cell.barColor;\n td.appendChild(fill);\n\n const valueSpan = document.createElement('span');\n valueSpan.className = 'oc-table-bar-value';\n valueSpan.textContent = cell.formattedValue;\n td.appendChild(valueSpan);\n\n return td;\n}\n\n/**\n * Format a sparkline endpoint value for display.\n * Keeps it compact: no decimals for values >= 100, one decimal otherwise.\n */\nfunction formatSparklineValue(v: number): string {\n if (Math.abs(v) >= 1000) {\n return v.toLocaleString('en-US', { maximumFractionDigits: 0 });\n }\n if (Math.abs(v) >= 100) {\n return v.toFixed(0);\n }\n return v.toFixed(1);\n}\n\n/** Render a cell with an inline sparkline SVG. */\nexport function renderSparklineCell(cell: SparklineTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const sparklineData = cell.sparklineData;\n if (!sparklineData || sparklineData.count === 0) {\n td.textContent = cell.formattedValue || '';\n return td;\n }\n\n // Add aria-label describing the trend for screen readers\n const trendDescription = describeSparklineTrend(sparklineData);\n if (!td.getAttribute('aria-label')) {\n td.setAttribute('aria-label', trendDescription);\n }\n\n const wrapper = document.createElement('span');\n wrapper.className = 'oc-table-sparkline';\n\n const svgNS = 'http://www.w3.org/2000/svg';\n\n if (sparklineData.type === 'line') {\n // Infrographic-style sparkline: SVG polyline fills cell width via percentage x-coords.\n // Dots are HTML elements (not SVG circles) to avoid aspect-ratio distortion.\n // Labels are HTML below the SVG.\n const svgH = 28;\n const padY = 4;\n const lineH = svgH - padY * 2;\n\n const svg = document.createElementNS(svgNS, 'svg');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('xmlns', svgNS);\n svg.style.height = `${svgH}px`;\n\n // Compute y positions in pixel space (no viewBox scaling)\n const yPositions = sparklineData.points.map((p) => padY + (1 - p.y) * lineH);\n\n // SVG polyline doesn't support % in points attribute, so use a viewBox\n // with a wide aspect ratio and map x to 0-1000 range. preserveAspectRatio=\"none\"\n // stretches the x-axis to fill the cell width. Y values stay in pixel space\n // since viewBox height matches the SVG height. Only the polyline is in the SVG;\n // dots are HTML elements to avoid circle distortion from the non-uniform scaling.\n const viewW = 1000;\n svg.setAttribute('viewBox', `0 0 ${viewW} ${svgH}`);\n svg.setAttribute('preserveAspectRatio', 'none');\n\n const ptsScaled = sparklineData.points.map((p, i) => ({\n x: p.x * viewW,\n y: yPositions[i],\n }));\n const scaledPointsStr = ptsScaled.map((p) => `${p.x},${p.y}`).join(' ');\n\n const polyline = document.createElementNS(svgNS, 'polyline');\n polyline.setAttribute('points', scaledPointsStr);\n polyline.setAttribute('fill', 'none');\n polyline.setAttribute('stroke', sparklineData.color);\n polyline.setAttribute('stroke-width', '1.25');\n polyline.setAttribute('stroke-linejoin', 'round');\n polyline.setAttribute('vector-effect', 'non-scaling-stroke');\n svg.appendChild(polyline);\n\n wrapper.appendChild(svg);\n\n // HTML dots at start and end (positioned absolutely over the SVG)\n const firstY = yPositions[0];\n const lastY = yPositions[yPositions.length - 1];\n const dotSize = 5;\n\n const startDot = document.createElement('span');\n startDot.className = 'oc-table-sparkline-dot';\n startDot.style.left = '0';\n startDot.style.top = `${firstY - dotSize / 2}px`;\n startDot.style.background = sparklineData.color;\n wrapper.appendChild(startDot);\n\n const endDot = document.createElement('span');\n endDot.className = 'oc-table-sparkline-dot';\n endDot.style.right = '0';\n endDot.style.top = `${lastY - dotSize / 2}px`;\n endDot.style.background = sparklineData.color;\n wrapper.appendChild(endDot);\n\n // HTML labels below the SVG, positioned at left and right edges\n const labelsRow = document.createElement('span');\n labelsRow.className = 'oc-table-sparkline-labels';\n labelsRow.style.color = sparklineData.color;\n\n const startLabel = document.createElement('span');\n startLabel.textContent = formatSparklineValue(sparklineData.startValue);\n labelsRow.appendChild(startLabel);\n\n const endLabel = document.createElement('span');\n endLabel.textContent = formatSparklineValue(sparklineData.endValue);\n labelsRow.appendChild(endLabel);\n\n wrapper.appendChild(labelsRow);\n } else if (sparklineData.type === 'column') {\n // Vertical bars at proportional heights\n const width = 80;\n const height = 20;\n const padding = 2;\n const innerW = width - padding * 2;\n const innerH = height - padding * 2;\n\n const svg = document.createElementNS(svgNS, 'svg');\n svg.setAttribute('width', String(width));\n svg.setAttribute('height', String(height));\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n svg.setAttribute('aria-hidden', 'true');\n\n const barCount = sparklineData.bars.length;\n if (barCount > 0) {\n const gap = 1;\n const barW = Math.max(1, (innerW - gap * (barCount - 1)) / barCount);\n\n for (let i = 0; i < barCount; i++) {\n const barH = Math.max(1, sparklineData.bars[i] * innerH);\n const x = padding + i * (barW + gap);\n const y = padding + innerH - barH;\n\n const rect = document.createElementNS(svgNS, 'rect');\n rect.setAttribute('x', String(x));\n rect.setAttribute('y', String(y));\n rect.setAttribute('width', String(barW));\n rect.setAttribute('height', String(barH));\n rect.setAttribute('rx', '1.5');\n rect.setAttribute('fill', sparklineData.color);\n svg.appendChild(rect);\n }\n }\n\n wrapper.appendChild(svg);\n } else {\n // 'bar' type: horizontal bars at proportional widths\n const width = 80;\n const height = 20;\n const padding = 2;\n const innerW = width - padding * 2;\n const innerH = height - padding * 2;\n\n const svg = document.createElementNS(svgNS, 'svg');\n svg.setAttribute('width', String(width));\n svg.setAttribute('height', String(height));\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n svg.setAttribute('aria-hidden', 'true');\n\n const barCount = sparklineData.bars.length;\n if (barCount > 0) {\n const gap = 1;\n const barH = Math.max(1, (innerH - gap * (barCount - 1)) / barCount);\n\n for (let i = 0; i < barCount; i++) {\n const barW = Math.max(1, sparklineData.bars[i] * innerW);\n const x = padding;\n const y = padding + i * (barH + gap);\n\n const rect = document.createElementNS(svgNS, 'rect');\n rect.setAttribute('x', String(x));\n rect.setAttribute('y', String(y));\n rect.setAttribute('width', String(barW));\n rect.setAttribute('height', String(barH));\n rect.setAttribute('rx', '1.5');\n rect.setAttribute('fill', sparklineData.color);\n svg.appendChild(rect);\n }\n }\n\n wrapper.appendChild(svg);\n }\n\n td.appendChild(wrapper);\n\n return td;\n}\n\n/** Arrow glyph per direction. Flat uses an en dash, not a third arrow. */\nconst DELTA_GLYPH: Record<DeltaTableCell['direction'], string> = {\n up: '\\u25b2',\n down: '\\u25bc',\n flat: '\\u2013',\n};\n\n/** Render a signed change chip. */\nexport function renderDeltaCell(cell: DeltaTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const chip = document.createElement('span');\n chip.className = `oc-table-delta oc-table-delta--${cell.tone}`;\n\n const arrow = document.createElement('span');\n arrow.className = 'oc-table-delta-arrow';\n arrow.setAttribute('aria-hidden', 'true');\n arrow.textContent = DELTA_GLYPH[cell.direction];\n chip.appendChild(arrow);\n\n const value = document.createElement('span');\n value.textContent = cell.formattedValue;\n chip.appendChild(value);\n\n td.appendChild(chip);\n return td;\n}\n\n/** Render a cell with an image. */\nexport function renderImageCell(cell: ImageTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const wrapper = document.createElement('span');\n wrapper.className = `oc-table-image${cell.rounded ? ' oc-table-image-rounded' : ''}`;\n\n const img = document.createElement('img');\n img.src = cell.src;\n img.alt = cell.formattedValue || '';\n img.width = cell.imageWidth;\n img.height = cell.imageHeight;\n img.loading = 'lazy';\n\n wrapper.appendChild(img);\n td.appendChild(wrapper);\n\n return td;\n}\n\n/** Render a cell with a country flag emoji. */\nexport function renderFlagCell(cell: FlagTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const span = document.createElement('span');\n span.className = 'oc-table-flag';\n span.setAttribute('role', 'img');\n\n if (cell.countryCode && cell.countryCode.length === 2) {\n const countryName = getCountryName(cell.countryCode);\n span.textContent = countryToEmoji(cell.countryCode);\n span.setAttribute('aria-label', `Flag: ${countryName}`);\n } else {\n span.textContent = cell.formattedValue;\n span.setAttribute('aria-label', cell.formattedValue);\n }\n\n td.appendChild(span);\n\n return td;\n}\n\n// ---------------------------------------------------------------------------\n// Dispatcher\n// ---------------------------------------------------------------------------\n\n/** Render any table cell by dispatching on its cellType. */\nexport function renderCell(cell: TableCell): HTMLTableCellElement {\n switch (cell.cellType) {\n case 'text':\n return renderTextCell(cell);\n case 'heatmap':\n return renderHeatmapCell(cell);\n case 'category':\n return renderCategoryCell(cell);\n case 'bar':\n return renderBarCell(cell);\n case 'sparkline':\n return renderSparklineCell(cell);\n case 'delta':\n return renderDeltaCell(cell);\n case 'image':\n return renderImageCell(cell);\n case 'flag':\n return renderFlagCell(cell);\n default:\n // Exhaustive check fallback\n return renderTextCell(cell as TextTableCell);\n }\n}\n","/**\n * Sankey mount API: the main entry point for vanilla JS sankey usage.\n *\n * createSankey() takes a container, SankeySpec, and options, compiles the\n * sankey, renders it as SVG, sets up responsive resizing, tooltip interaction,\n * hover highlighting, and returns a SankeyInstance with update/resize/export/destroy.\n */\n\nimport type {\n CompileOptions,\n DarkMode,\n SankeyLayout,\n SankeyLinkMark,\n SankeySpec,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport { compileSankey } from '@opendata-ai/openchart-engine';\nimport { cancelAnimations, setupAnimationCleanup } from './animation';\nimport {\n exportJPG,\n exportPNG,\n exportSVG,\n exportSVGWithFonts,\n type JPGExportOptions,\n type SVGExportOptions,\n} from './export';\nimport { createMeasureText, resolveFontFamily, scheduleFontReload } from './measure-text';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { renderSankeySVG } from './sankey-renderer';\nimport { createTooltipManager, type TooltipManager } from './tooltip';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SankeyMountOptions {\n /** Theme overrides. */\n theme?: ThemeConfig;\n /** Dark mode setting: \"auto\" (system pref), \"force\", or \"off\". */\n darkMode?: DarkMode;\n /** Enable responsive resizing. Defaults to true. */\n responsive?: boolean;\n /** Show the OpenData watermark. Defaults to true. */\n watermark?: boolean;\n /** Show tooltips on hover. Defaults to true. */\n tooltip?: boolean;\n /** Callback when a node is clicked. */\n onNodeClick?: (node: Record<string, unknown>) => void;\n /** Callback when a link is clicked. */\n onLinkClick?: (link: Record<string, unknown>) => void;\n /** Callback when a node is hovered (null on mouse leave). */\n onNodeHover?: (node: Record<string, unknown> | null) => void;\n /** Callback when a link is hovered (null on mouse leave). */\n onLinkHover?: (link: Record<string, unknown> | null) => void;\n}\n\nexport interface SankeyInstance {\n /** Re-compile and re-render with a new spec. */\n update(spec: SankeySpec): void;\n /** Re-compile at current container dimensions. */\n resize(): void;\n /** Export the sankey diagram. */\n export(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options?: JPGExportOptions,\n ): string | Promise<Blob> | Promise<string>;\n /** Remove all DOM elements and disconnect observers. */\n destroy(): void;\n /** The current compiled layout. */\n readonly layout: SankeyLayout;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Opacity for links on the hovered node's path. */\nconst HIGHLIGHT_OPACITY = 0.7;\n/** Opacity for links off the path. Low enough to read as context, not flow. */\nconst DIM_OPACITY = 0.12;\n/** Opacity for nodes and labels off the path. */\nconst NODE_DIM_OPACITY = 0.3;\n\n/**\n * Seeds for a trace: which nodes to walk upstream from, which to walk\n * downstream from, plus any link keys that are on the path by construction.\n *\n * A node hover seeds both directions from that node. A link hover seeds\n * upstream from the source and downstream from the target, so the highlight\n * is the one path running through the hovered link rather than every sibling\n * ribbon out of the source and into the target.\n */\ninterface TraceSeeds {\n up: string[];\n down: string[];\n links?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a sankey instance from a spec and mount it into a container.\n */\nexport function createSankey(\n container: HTMLElement,\n spec: SankeySpec,\n options?: SankeyMountOptions,\n): SankeyInstance {\n let currentSpec = spec;\n let currentLayout: SankeyLayout;\n let destroyed = false;\n\n // DOM\n let svgElement: SVGSVGElement | null = null;\n\n // Subsystems\n let tooltipManager: TooltipManager | null = null;\n let cleanupTooltipEvents: (() => void) | null = null;\n let disconnectResize: (() => void) | null = null;\n\n // Animation state\n let isFirstRender = true;\n let animationCleanup: (() => void) | null = null;\n let pendingResize = false;\n\n // Set when webfonts have loaded and a recompile is owed. The next render()\n // that recompiles flips data-oc-fonts-state to 'ready' and clears this, so\n // the attribute stays honest when resize() defers to pendingResize during\n // the entrance animation.\n let fontsReloadPending = false;\n\n // Apply the root class up front so getComputedStyle sees --oc-font-family\n // before the text measurer is built.\n container.classList.add('oc-sankey-root');\n\n // Resolve the effective font the way compile() will: compile merges\n // { ...spec.theme, ...options.theme }, so options.theme wins over the\n // spec-level theme; fall back to the container's computed font. Measuring a\n // different font than gets rendered desyncs layout metrics and the reload watcher.\n function resolveEffectiveFont(): string {\n return (\n options?.theme?.fonts?.family ??\n currentSpec.theme?.fonts?.family ??\n resolveFontFamily(container)\n );\n }\n let fontFamily = resolveEffectiveFont();\n let measureText = createMeasureText(fontFamily);\n let renderGen = 0;\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: Math.max(rect.width || 600, 100),\n height: Math.max(rect.height || 400, 100),\n };\n }\n\n function compile(): SankeyLayout {\n const { width, height } = getContainerDimensions();\n const darkMode = resolveDarkMode(options?.darkMode);\n\n const compileOpts: CompileOptions = {\n width,\n height,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n measureText,\n };\n\n return compileSankey(currentSpec, compileOpts);\n }\n\n // ---------------------------------------------------------------------------\n // Tooltip and interaction wiring\n // ---------------------------------------------------------------------------\n\n function wireTooltipAndInteraction(svg: SVGSVGElement, layout: SankeyLayout): () => void {\n const cleanups: Array<() => void> = [];\n\n const nodesById = new Map<string, (typeof layout.nodes)[number]>();\n for (const n of layout.nodes) {\n if (!nodesById.has(n.nodeId)) nodesById.set(n.nodeId, n);\n }\n\n // Wire tooltip on node elements\n const nodeElements = svg.querySelectorAll('.oc-sankey-node');\n for (const el of nodeElements) {\n const markId = el.getAttribute('data-mark-id');\n if (!markId) continue;\n\n const content = layout.tooltipDescriptors.get(markId);\n const nodeId = el.getAttribute('data-node-id');\n const nodeData = nodeId ? (nodesById.get(nodeId)?.data ?? {}) : {};\n\n const handleMouseEnter = (e: Event) => {\n const mouseEvent = e as MouseEvent;\n if (content && tooltipManager) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n options?.onNodeHover?.(nodeData);\n if (nodeId) highlightPath(svg, { up: [nodeId], down: [nodeId] }, layout);\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n tooltipManager?.hide();\n options?.onNodeHover?.(null);\n resetLinkOpacity(svg, layout);\n };\n\n const handleClick = () => {\n options?.onNodeClick?.(nodeData);\n };\n\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n // Wire tooltip on link elements\n const linkElements = svg.querySelectorAll('.oc-sankey-link');\n for (const el of linkElements) {\n const markId = el.getAttribute('data-mark-id');\n if (!markId) continue;\n\n const content = layout.tooltipDescriptors.get(markId);\n const sourceId = el.getAttribute('data-source');\n const targetId = el.getAttribute('data-target');\n const linkData = findLinkData(layout, sourceId, targetId);\n\n const handleMouseEnter = (e: Event) => {\n const mouseEvent = e as MouseEvent;\n if (content && tooltipManager) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n options?.onLinkHover?.(linkData);\n if (sourceId && targetId) {\n highlightPath(\n svg,\n { up: [sourceId], down: [targetId], links: [`${sourceId}->${targetId}`] },\n layout,\n );\n }\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n tooltipManager?.hide();\n options?.onLinkHover?.(null);\n resetLinkOpacity(svg, layout);\n };\n\n const handleClick = () => {\n options?.onLinkClick?.(linkData);\n };\n\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n return () => {\n for (const cleanup of cleanups) {\n cleanup();\n }\n };\n }\n\n /**\n * Find the data record for a link by source/target ids.\n */\n function findLinkData(\n layout: SankeyLayout,\n sourceId: string | null,\n targetId: string | null,\n ): Record<string, unknown> {\n if (!sourceId || !targetId) return {};\n const link = layout.links.find((l) => l.sourceId === sourceId && l.targetId === targetId);\n return link?.data ?? {};\n }\n\n /**\n * Trace the path through a set of seed nodes: everything upstream of the\n * `up` seeds and everything downstream of the `down` seeds, links included.\n *\n * A sankey answers \"where did this come from and where does it go\", so\n * lighting only the direct neighbors stops the answer one hop short. Returns\n * the node ids and the \"source->target\" link keys on the path.\n */\n function tracePath(\n layout: SankeyLayout,\n seeds: TraceSeeds,\n ): { nodes: Set<string>; links: Set<string> } {\n const out = new Map<string, typeof layout.links>();\n const inn = new Map<string, typeof layout.links>();\n for (const link of layout.links) {\n const o = out.get(link.sourceId);\n if (o) o.push(link);\n else out.set(link.sourceId, [link]);\n const i = inn.get(link.targetId);\n if (i) i.push(link);\n else inn.set(link.targetId, [link]);\n }\n\n const nodes = new Set<string>([...seeds.up, ...seeds.down]);\n const links = new Set<string>(seeds.links ?? []);\n\n const walk = (\n adjacency: Map<string, typeof layout.links>,\n seedIds: string[],\n nextId: (l: SankeyLinkMark) => string,\n ) => {\n const queue = [...seedIds];\n const seen = new Set<string>(seedIds);\n while (queue.length > 0) {\n const id = queue.shift() as string;\n for (const link of adjacency.get(id) ?? []) {\n links.add(`${link.sourceId}->${link.targetId}`);\n const next = nextId(link);\n nodes.add(next);\n if (!seen.has(next)) {\n seen.add(next);\n queue.push(next);\n }\n }\n }\n };\n\n walk(out, seeds.down, (l) => l.targetId);\n walk(inn, seeds.up, (l) => l.sourceId);\n\n return { nodes, links };\n }\n\n /**\n * Dim everything that is not on the traced path: off-path links go to a whisper,\n * off-path nodes and their labels to the shared hover dim.\n */\n function highlightPath(svg: SVGSVGElement, seeds: TraceSeeds, layout: SankeyLayout): void {\n const { nodes: onNodes, links: onLinks } = tracePath(layout, seeds);\n\n for (const el of svg.querySelectorAll('.oc-sankey-link')) {\n const path = el.querySelector('path');\n if (!path) continue;\n const source = el.getAttribute('data-source');\n const target = el.getAttribute('data-target');\n const onPath = onLinks.has(`${source}->${target}`);\n path.setAttribute('fill-opacity', String(onPath ? HIGHLIGHT_OPACITY : DIM_OPACITY));\n }\n\n for (const el of svg.querySelectorAll('.oc-sankey-node, .oc-sankey-label')) {\n const nid = el.getAttribute('data-node-id');\n if (!nid) continue;\n (el as SVGElement).style.opacity = onNodes.has(nid) ? '1' : String(NODE_DIM_OPACITY);\n }\n }\n\n /**\n * Reset all link opacities and node opacities to their original values.\n */\n function resetLinkOpacity(svg: SVGSVGElement, layout: SankeyLayout): void {\n const linkElements = svg.querySelectorAll('.oc-sankey-link');\n for (const el of linkElements) {\n const path = el.querySelector('path');\n if (!path) continue;\n // Look up the original opacity via data attributes rather than positional index\n const source = el.getAttribute('data-source');\n const target = el.getAttribute('data-target');\n const link = layout.links.find((l) => l.sourceId === source && l.targetId === target);\n path.setAttribute('fill-opacity', String(link?.fillOpacity ?? 0.5));\n }\n\n // Restore all node and label opacities\n for (const el of svg.querySelectorAll('.oc-sankey-node, .oc-sankey-label')) {\n (el as SVGElement).style.opacity = '1';\n }\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n function render(): void {\n if (destroyed) return;\n\n // Cancel in-progress animations before tearing down\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n }\n if (svgElement) {\n cancelAnimations(svgElement);\n }\n\n // Clean up previous tooltip listeners\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n // Remove old SVG\n if (svgElement?.parentNode) {\n svgElement.parentNode.removeChild(svgElement);\n }\n\n // Compile\n currentLayout = compile();\n\n // Determine if we should animate\n const shouldAnimate = isFirstRender && !!currentLayout.animation?.enter;\n isFirstRender = false;\n\n // Render\n const animation = shouldAnimate ? currentLayout.animation : undefined;\n svgElement = renderSankeySVG(currentLayout, animation);\n container.appendChild(svgElement);\n\n // Dark mode class on container\n const isDark = resolveDarkMode(options?.darkMode);\n if (isDark) {\n container.classList.add('oc-dark');\n } else {\n container.classList.remove('oc-dark');\n }\n\n // Wire tooltip + interaction events\n if (options?.tooltip !== false && svgElement) {\n if (!tooltipManager) {\n tooltipManager = createTooltipManager(container);\n }\n cleanupTooltipEvents = wireTooltipAndInteraction(svgElement, currentLayout);\n }\n\n // Animation cleanup on first render\n if (shouldAnimate && svgElement) {\n animationCleanup = setupAnimationCleanup(svgElement, () => {\n animationCleanup = null;\n if (pendingResize) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n\n // This render recompiled with the loaded webfonts; publish 'ready' now\n // rather than right after the fonts-ready resize() (which may have deferred\n // to pendingResize during the entrance animation).\n if (fontsReloadPending) {\n fontsReloadPending = false;\n container.dataset.ocFontsState = 'ready';\n }\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n function update(newSpec: SankeySpec): void {\n if (destroyed) return;\n currentSpec = newSpec;\n // A new spec can change theme.fonts.family; rebuild the measurer so layout\n // measures the font compile will actually render with.\n const nextFont = resolveEffectiveFont();\n if (nextFont !== fontFamily) {\n fontFamily = nextFont;\n measureText = createMeasureText(fontFamily);\n }\n isFirstRender = true; // Allow animation on update\n render();\n }\n\n function resize(): void {\n if (destroyed) return;\n // Skip resize during entrance animation to avoid tearing down the animated SVG.\n // Queued resizes replay once animation completes.\n if (animationCleanup) {\n pendingResize = true;\n return;\n }\n render();\n }\n\n function doExport(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n exportOptions?: JPGExportOptions,\n ): string | Promise<Blob> | Promise<string> {\n if (!svgElement) {\n throw new Error('Sankey is not rendered yet');\n }\n\n switch (format) {\n case 'svg':\n return exportSVG(svgElement);\n case 'svg-with-fonts':\n return exportSVGWithFonts(svgElement, exportOptions as SVGExportOptions);\n case 'png':\n return exportPNG(svgElement, exportOptions);\n case 'jpg':\n return exportJPG(svgElement, exportOptions);\n default:\n throw new Error(`Unsupported export format: ${format}`);\n }\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n // Cancel entrance animations\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n pendingResize = false;\n }\n if (svgElement) {\n cancelAnimations(svgElement);\n }\n\n // Disconnect resize observer\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n\n // Clean up tooltip events\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n // Destroy tooltip manager\n if (tooltipManager) {\n tooltipManager.destroy();\n tooltipManager = null;\n }\n\n // Remove SVG\n if (svgElement?.parentNode) {\n svgElement.parentNode.removeChild(svgElement);\n }\n svgElement = null;\n\n container.classList.remove('oc-dark');\n container.classList.remove('oc-sankey-root');\n }\n\n // ---------------------------------------------------------------------------\n // Initialize\n // ---------------------------------------------------------------------------\n\n try {\n currentLayout = compile();\n\n // Determine if we should animate\n const shouldAnimate = !!currentLayout.animation?.enter;\n isFirstRender = false;\n\n // Render\n const animation = shouldAnimate ? currentLayout.animation : undefined;\n svgElement = renderSankeySVG(currentLayout, animation);\n container.appendChild(svgElement);\n\n // Dark mode class on container\n const isDark = resolveDarkMode(options?.darkMode);\n if (isDark) {\n container.classList.add('oc-dark');\n } else {\n container.classList.remove('oc-dark');\n }\n\n // Wire tooltip + interaction events\n if (options?.tooltip !== false && svgElement) {\n tooltipManager = createTooltipManager(container);\n cleanupTooltipEvents = wireTooltipAndInteraction(svgElement, currentLayout);\n }\n\n // Animation cleanup\n if (shouldAnimate && svgElement) {\n animationCleanup = setupAnimationCleanup(svgElement, () => {\n animationCleanup = null;\n if (pendingResize) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n } catch (err) {\n console.error('[viz] Sankey mount failed:', err);\n // Re-throw so callers can handle the error rather than silently returning a broken instance\n throw err;\n }\n\n // Recompile once after webfonts load so late-swapping fonts don't leave\n // node labels measured against fallback metrics.\n const fontsPending = scheduleFontReload(\n fontFamily,\n () => !destroyed,\n () => {\n // Mark the reload owed, then recompile. render() flips the attribute to\n // 'ready' once it actually recompiles, including the pendingResize replay\n // after the entrance animation finishes.\n fontsReloadPending = true;\n resize();\n },\n );\n container.dataset.ocFontsState = fontsPending ? 'pending' : 'ready';\n\n // Responsive resize\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => {\n resize();\n });\n }\n\n return {\n update,\n resize,\n export: doExport,\n destroy,\n get layout() {\n return currentLayout;\n },\n };\n}\n","/**\n * Sankey SVG renderer: converts a SankeyLayout into SVG DOM elements.\n *\n * Creates an <svg> with gradient defs, links (behind), nodes, labels,\n * legend, and chrome. All styling via inline SVG attributes from layout data.\n * Animation is pure CSS, driven by data attributes and CSS custom properties.\n */\n\nimport type {\n CategoricalLegendLayout,\n LegendLayout,\n MeasureTextFn,\n ResolvedAnimation,\n ResolvedChromeElement,\n SankeyLayout,\n SankeyLinkMark,\n SankeyNodeMark,\n TextStyle,\n} from '@opendata-ai/openchart-core';\nimport {\n BRAND_FONT_SIZE,\n BRAND_MIN_WIDTH,\n estimateTextWidth,\n textAscent,\n wrapText,\n} from '@opendata-ai/openchart-core';\nimport { clampStaggerDelay } from '@opendata-ai/openchart-engine';\nimport { stampAnimationVars } from './animation-vars';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst XLINK_NS = 'http://www.w3.org/1999/xlink';\nconst BRAND_URL = 'https://tryopendata.ai';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createSVGElement(tag: string): SVGElement {\n return document.createElementNS(SVG_NS, tag);\n}\n\nfunction setAttrs(el: SVGElement, attrs: Record<string, string | number>): void {\n for (const [key, value] of Object.entries(attrs)) {\n el.setAttribute(key, String(value));\n }\n}\n\nfunction applyTextStyle(el: SVGElement, style: TextStyle): void {\n setAttrs(el, {\n 'font-family': style.fontFamily,\n 'font-size': style.fontSize,\n 'font-weight': style.fontWeight,\n });\n (el as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', style.fill);\n if (style.textAnchor) {\n el.setAttribute('text-anchor', style.textAnchor);\n }\n if (style.dominantBaseline) {\n el.setAttribute('dominant-baseline', style.dominantBaseline);\n }\n if (style.fontVariant) {\n el.setAttribute('font-variant', style.fontVariant);\n }\n}\n\n/**\n * Stamp animation index attributes on a mark element when animation is enabled.\n */\nfunction stampAnimationAttrs(\n el: SVGElement,\n mark: { animationIndex?: number },\n fallbackIndex: number,\n animation?: ResolvedAnimation,\n): void {\n if (!animation?.enter) return;\n const idx = mark.animationIndex ?? fallbackIndex;\n el.setAttribute('data-animation-index', String(idx));\n (el as SVGElement & ElementCSSInlineStyle).style.setProperty('--oc-mark-index', String(idx));\n}\n\n// ---------------------------------------------------------------------------\n// Chrome rendering\n// ---------------------------------------------------------------------------\n\nfunction renderChromeElement(\n parent: SVGElement,\n element: ResolvedChromeElement,\n className: string,\n chromeKey: string,\n measureText?: MeasureTextFn,\n): void {\n const text = createSVGElement('text');\n // element.y is the TOP of the text box; convert to the alphabetic baseline\n // (see renderers/chrome.ts — WebKit mishandles dominant-baseline:hanging).\n setAttrs(text, { x: element.x, y: element.y + textAscent(element.style.fontSize) });\n applyTextStyle(text, element.style);\n text.setAttribute('class', className);\n text.setAttribute('data-chrome-key', chromeKey);\n\n const lines = wrapText(\n element.text,\n element.style.fontSize,\n element.style.fontWeight,\n element.maxWidth,\n measureText,\n );\n\n if (lines.length === 1) {\n text.textContent = element.text;\n } else {\n const lineHeight = element.style.fontSize * (element.style.lineHeight ?? 1.3);\n for (let i = 0; i < lines.length; i++) {\n const tspan = createSVGElement('tspan');\n setAttrs(tspan, { x: element.x, dy: i === 0 ? 0 : lineHeight });\n tspan.textContent = lines[i];\n text.appendChild(tspan);\n }\n }\n\n parent.appendChild(text);\n}\n\nfunction renderChrome(parent: SVGElement, layout: SankeyLayout): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-chrome');\n\n const { chrome, measureText } = layout;\n\n if (chrome.title) {\n renderChromeElement(g, chrome.title, 'oc-title', 'title', measureText);\n }\n if (chrome.subtitle) {\n renderChromeElement(g, chrome.subtitle, 'oc-subtitle', 'subtitle', measureText);\n }\n\n // Bottom chrome: positioned below the sankey drawing area.\n // Sankey has no x-axis, so no extra axis extent to account for.\n const bottomOffset = layout.area.y + layout.area.height;\n if (chrome.source) {\n renderChromeElement(\n g,\n { ...chrome.source, y: bottomOffset + chrome.source.y },\n 'oc-source',\n 'source',\n measureText,\n );\n }\n if (chrome.byline) {\n renderChromeElement(\n g,\n { ...chrome.byline, y: bottomOffset + chrome.byline.y },\n 'oc-byline',\n 'byline',\n measureText,\n );\n }\n if (chrome.footer) {\n renderChromeElement(\n g,\n { ...chrome.footer, y: bottomOffset + chrome.footer.y },\n 'oc-footer',\n 'footer',\n measureText,\n );\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Brand rendering\n// ---------------------------------------------------------------------------\n\nfunction renderBrand(parent: SVGElement, layout: SankeyLayout): void {\n if (layout.dimensions.width < BRAND_MIN_WIDTH) return;\n\n const { width } = layout.dimensions;\n const padding = layout.theme.spacing.padding;\n const rightEdge = width - padding;\n const fill = layout.theme.colors.axis;\n\n const bottomOffset = layout.area.y + layout.area.height;\n const { chrome } = layout;\n const firstBottom = chrome.source ?? chrome.byline ?? chrome.footer;\n const chromeY = firstBottom\n ? bottomOffset + firstBottom.y\n : bottomOffset + layout.theme.spacing.chartToFooter;\n\n const a = createSVGElement('a');\n a.setAttribute('href', BRAND_URL);\n a.setAttributeNS(XLINK_NS, 'xlink:href', BRAND_URL);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.setAttribute('class', 'oc-chrome-ref');\n\n const BRAND_LARGE = 16;\n const text = createSVGElement('text');\n setAttrs(text, {\n x: rightEdge,\n y: chromeY + BRAND_LARGE,\n 'dominant-baseline': 'alphabetic',\n 'text-anchor': 'end',\n 'font-family': layout.theme.fonts.family,\n 'font-size': BRAND_FONT_SIZE,\n 'fill-opacity': 0.55,\n });\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', fill);\n\n const trySpan = createSVGElement('tspan');\n setAttrs(trySpan, { 'font-weight': 500 });\n trySpan.textContent = 'try';\n\n const openDataSpan = createSVGElement('tspan');\n setAttrs(openDataSpan, { 'font-weight': 600, 'font-size': BRAND_LARGE });\n openDataSpan.textContent = 'OpenData';\n\n const aiSpan = createSVGElement('tspan');\n setAttrs(aiSpan, { 'font-weight': 500 });\n aiSpan.textContent = '.ai';\n\n text.appendChild(trySpan);\n text.appendChild(openDataSpan);\n text.appendChild(aiSpan);\n a.appendChild(text);\n parent.appendChild(a);\n}\n\n// ---------------------------------------------------------------------------\n// Legend rendering\n// ---------------------------------------------------------------------------\n\nfunction renderLegend(parent: SVGElement, legendLayout: LegendLayout): void {\n if (!('entries' in legendLayout) || legendLayout.entries.length === 0) return;\n const legend = legendLayout as CategoricalLegendLayout;\n\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-legend');\n g.setAttribute('role', 'list');\n g.setAttribute('aria-label', 'Chart legend');\n\n const isHorizontal = legend.position === 'top' || legend.position === 'bottom';\n let offsetX = legend.bounds.x;\n let offsetY = legend.bounds.y;\n\n for (let i = 0; i < legend.entries.length; i++) {\n const entry = legend.entries[i];\n\n // Wrap to next line if this entry would overflow bounds\n if (isHorizontal && i > 0) {\n const labelWidth = estimateTextWidth(\n entry.label,\n legend.labelStyle.fontSize,\n legend.labelStyle.fontWeight,\n );\n const entryWidth = legend.swatchSize + legend.swatchGap + labelWidth + legend.entryGap;\n if (offsetX + entryWidth > legend.bounds.x + legend.bounds.width) {\n offsetX = legend.bounds.x;\n offsetY += legend.swatchSize + 6;\n }\n }\n\n const entryG = createSVGElement('g');\n entryG.setAttribute('class', 'oc-legend-entry');\n entryG.setAttribute('role', 'listitem');\n entryG.setAttribute('data-legend-index', String(i));\n entryG.setAttribute('data-legend-label', entry.label);\n\n if (entry.overflow) {\n entryG.setAttribute('data-legend-overflow', 'true');\n entryG.setAttribute('aria-label', entry.label);\n entryG.setAttribute('opacity', '0.5');\n } else {\n entryG.setAttribute(\n 'aria-label',\n `${entry.label}: ${entry.active !== false ? 'visible' : 'hidden'}`,\n );\n entryG.setAttribute('style', 'cursor: pointer');\n if (entry.active === false) {\n entryG.setAttribute('opacity', '0.3');\n }\n }\n\n // Swatch (always rect for sankey)\n const rect = createSVGElement('rect');\n setAttrs(rect, {\n x: offsetX,\n y: offsetY,\n width: legend.swatchSize,\n height: legend.swatchSize,\n fill: entry.color,\n rx: 2,\n });\n entryG.appendChild(rect);\n\n // Label\n const label = createSVGElement('text');\n setAttrs(label, {\n x: offsetX + legend.swatchSize + legend.swatchGap,\n y: offsetY + legend.swatchSize / 2,\n 'dominant-baseline': 'central',\n });\n applyTextStyle(label, legend.labelStyle);\n label.textContent = entry.label;\n entryG.appendChild(label);\n\n g.appendChild(entryG);\n\n // Advance position for next entry\n if (isHorizontal) {\n const labelWidth = estimateTextWidth(\n entry.label,\n legend.labelStyle.fontSize,\n legend.labelStyle.fontWeight,\n );\n const entryWidth = legend.swatchSize + legend.swatchGap + labelWidth + legend.entryGap;\n offsetX += entryWidth;\n } else {\n offsetY += legend.swatchSize + legend.entryGap;\n }\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Gradient defs\n// ---------------------------------------------------------------------------\n\n/**\n * Build a node position lookup for gradient x1/x2 coordinates.\n * Maps nodeId to { x, width } so we can compute gradient endpoints.\n */\nfunction buildNodePositionMap(nodes: SankeyNodeMark[]): Map<string, { x: number; width: number }> {\n const map = new Map<string, { x: number; width: number }>();\n for (const node of nodes) {\n map.set(node.nodeId, { x: node.x, width: node.width });\n }\n return map;\n}\n\n/** Sanitize a string for use as an SVG element ID (no spaces, $, or other invalid chars). */\nfunction sanitizeId(s: string): string {\n return s.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\nfunction renderGradientDefs(\n defs: SVGElement,\n links: SankeyLinkMark[],\n nodePositions: Map<string, { x: number; width: number }>,\n): void {\n for (let i = 0; i < links.length; i++) {\n const link = links[i];\n // Only create gradients when source and target colors differ\n if (link.sourceColor === link.targetColor) continue;\n\n // Use sanitized node names for debuggability, with index suffix for uniqueness\n const gradId = `oc-sg-${sanitizeId(link.sourceId)}-${sanitizeId(link.targetId)}-${i}`;\n const gradient = createSVGElement('linearGradient');\n gradient.setAttribute('id', gradId);\n gradient.setAttribute('gradientUnits', 'userSpaceOnUse');\n\n // x1 = right edge of source node, x2 = left edge of target node\n const sourcePos = nodePositions.get(link.sourceId);\n const targetPos = nodePositions.get(link.targetId);\n const x1 = sourcePos ? sourcePos.x + sourcePos.width : 0;\n const x2 = targetPos ? targetPos.x : 0;\n\n gradient.setAttribute('x1', String(x1));\n gradient.setAttribute('x2', String(x2));\n\n const stop0 = createSVGElement('stop');\n setAttrs(stop0, { offset: '0%', 'stop-color': link.sourceColor });\n gradient.appendChild(stop0);\n\n const stop1 = createSVGElement('stop');\n setAttrs(stop1, { offset: '100%', 'stop-color': link.targetColor });\n gradient.appendChild(stop1);\n\n defs.appendChild(gradient);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Links rendering\n// ---------------------------------------------------------------------------\n\nfunction renderLinks(\n parent: SVGElement,\n links: SankeyLinkMark[],\n _nodePositions: Map<string, { x: number; width: number }>,\n animation?: ResolvedAnimation,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-sankey-links');\n\n for (let i = 0; i < links.length; i++) {\n const link = links[i];\n\n const linkG = createSVGElement('g');\n linkG.setAttribute('class', 'oc-sankey-link');\n linkG.setAttribute('data-mark-id', `link-${link.sourceId}-${link.targetId}-${i}`);\n linkG.setAttribute('data-source', link.sourceId);\n linkG.setAttribute('data-target', link.targetId);\n\n if (link.aria?.label) {\n linkG.setAttribute('aria-label', link.aria.label);\n }\n\n stampAnimationAttrs(linkG, link, i, animation);\n\n const path = createSVGElement('path');\n path.setAttribute('d', link.path);\n path.setAttribute('stroke', 'none');\n path.setAttribute('fill-opacity', String(link.fillOpacity));\n\n // Use gradient fill when colors differ, otherwise solid fill\n if (link.sourceColor !== link.targetColor) {\n const gradId = `oc-sg-${sanitizeId(link.sourceId)}-${sanitizeId(link.targetId)}-${i}`;\n path.setAttribute('fill', `url(#${gradId})`);\n } else {\n path.setAttribute('fill', link.sourceColor);\n }\n\n linkG.appendChild(path);\n g.appendChild(linkG);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Nodes rendering\n// ---------------------------------------------------------------------------\n\nfunction renderNodes(\n parent: SVGElement,\n nodes: SankeyNodeMark[],\n animation?: ResolvedAnimation,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-sankey-nodes');\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n\n const nodeG = createSVGElement('g');\n nodeG.setAttribute('class', 'oc-sankey-node');\n nodeG.setAttribute('data-mark-id', `node-${node.nodeId}`);\n nodeG.setAttribute('data-node-id', node.nodeId);\n\n if (node.aria?.label) {\n nodeG.setAttribute('aria-label', node.aria.label);\n }\n\n stampAnimationAttrs(nodeG, node, i, animation);\n\n const rect = createSVGElement('rect');\n setAttrs(rect, {\n x: node.x,\n y: node.y,\n width: node.width,\n height: Math.max(node.height, 1), // Ensure at least 1px visibility\n fill: node.fill,\n rx: node.cornerRadius,\n });\n\n if (node.stroke) {\n rect.setAttribute('stroke', node.stroke);\n }\n if (node.strokeWidth) {\n rect.setAttribute('stroke-width', String(node.strokeWidth));\n }\n\n nodeG.appendChild(rect);\n g.appendChild(nodeG);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Labels rendering\n// ---------------------------------------------------------------------------\n\nfunction renderLabels(\n parent: SVGElement,\n nodes: SankeyNodeMark[],\n measureText?: MeasureTextFn,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-sankey-labels');\n\n for (const node of nodes) {\n const { label } = node;\n if (!label.visible) continue;\n\n const text = createSVGElement('text');\n setAttrs(text, { x: label.x, y: label.y });\n applyTextStyle(text, label.style);\n // Path highlighting dims labels alongside their node.\n text.setAttribute('class', 'oc-sankey-label');\n text.setAttribute('data-node-id', node.nodeId);\n\n const fontSize = label.style.fontSize ?? 12;\n const fontWeight = label.style.fontWeight ?? 400;\n\n // Wrap label text when maxWidth is set and text would overflow\n let lines = [label.text];\n if (label.maxWidth !== undefined && label.maxWidth > 0) {\n lines = wrapText(label.text, fontSize, fontWeight, label.maxWidth, measureText);\n }\n\n if (lines.length > 1) {\n const lineHeight = fontSize * (label.style.lineHeight ?? 1.3);\n // Center the multi-line block vertically around the label y position\n const totalHeight = (lines.length - 1) * lineHeight;\n const startY = label.y - totalHeight / 2;\n for (let i = 0; i < lines.length; i++) {\n const tspan = createSVGElement('tspan');\n tspan.setAttribute('x', String(label.x));\n tspan.setAttribute('y', String(startY + i * lineHeight));\n tspan.textContent = lines[i];\n text.appendChild(tspan);\n }\n } else {\n text.textContent = lines[0];\n }\n\n // The node's value rides the last line as a lighter tabular tspan. It\n // carries no x/y, so it stays in the same text chunk and the anchor\n // (start or end) still applies to name + value as one block.\n if (node.valueLabel) {\n // A bare textContent has to become a tspan first, or the value tspan\n // would render before it.\n if (text.childNodes.length === 0) {\n const nameSpan = createSVGElement('tspan');\n nameSpan.textContent = text.textContent;\n text.textContent = '';\n text.appendChild(nameSpan);\n }\n const valueSpan = createSVGElement('tspan');\n valueSpan.setAttribute('class', 'oc-sankey-label-value');\n valueSpan.setAttribute('dx', '5');\n applyTextStyle(valueSpan, node.valueLabel.style);\n valueSpan.textContent = node.valueLabel.text;\n text.appendChild(valueSpan);\n }\n\n g.appendChild(text);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Main render function\n// ---------------------------------------------------------------------------\n\n/**\n * Render a SankeyLayout into an SVG element.\n *\n * The SVG structure is: background > defs (gradients) > links > nodes > labels > legend > chrome > brand.\n * Links render before nodes so they appear visually behind.\n */\nexport function renderSankeySVG(\n layout: SankeyLayout,\n animation?: ResolvedAnimation,\n): SVGSVGElement {\n const { width, height } = layout.dimensions;\n\n const svg = createSVGElement('svg') as SVGSVGElement;\n setAttrs(svg, {\n viewBox: `0 0 ${width} ${height}`,\n xmlns: SVG_NS,\n overflow: 'visible',\n });\n svg.style.height = `${height}px`;\n svg.setAttribute('role', layout.a11y.role);\n svg.setAttribute('aria-label', layout.a11y.altText);\n\n // Classes: oc-chart oc-sankey, plus oc-animate if animated\n const enterPhase = animation?.enter;\n const animate = !!enterPhase;\n const classes = animate ? 'oc-chart oc-sankey oc-animate' : 'oc-chart oc-sankey';\n svg.setAttribute('class', classes);\n\n // Set animation CSS custom properties when the enter phase is enabled\n if (enterPhase) {\n const totalMarks = layout.nodes.length + layout.links.length;\n const stagger = clampStaggerDelay(enterPhase.staggerDelay, totalMarks);\n stampAnimationVars(svg, {\n duration: enterPhase.duration,\n stagger,\n annotationDelay: animation!.annotationDelay,\n ease: enterPhase.ease,\n });\n }\n\n // Background\n const bg = createSVGElement('rect');\n bg.setAttribute('class', 'oc-background');\n setAttrs(bg, {\n x: 0,\n y: 0,\n width,\n height,\n fill: layout.theme.colors.background,\n });\n svg.appendChild(bg);\n\n // Defs: gradient definitions for links\n const nodePositions = buildNodePositionMap(layout.nodes);\n const defs = createSVGElement('defs');\n renderGradientDefs(defs, layout.links, nodePositions);\n svg.appendChild(defs);\n\n // Links (behind nodes)\n renderLinks(svg, layout.links, nodePositions, animation);\n\n // Nodes\n renderNodes(svg, layout.nodes, animation);\n\n // Labels\n renderLabels(svg, layout.nodes, layout.measureText);\n\n // Legend\n renderLegend(svg, layout.legend);\n\n // Chrome (title, subtitle, source, byline, footer) renders on top\n renderChrome(svg, layout);\n\n // Brand\n if (layout.watermark) {\n renderBrand(svg, layout);\n }\n\n return svg;\n}\n","/**\n * Table keyboard navigation: arrow-key cell navigation, Enter to sort,\n * Escape to clear search, and aria-activedescendant management.\n *\n * Designed to be wired up by table-mount.ts after render. Returns a\n * cleanup function to remove listeners on re-render or destroy.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface KeyboardNavOptions {\n /** The wrapper element containing the whole table UI. */\n wrapper: HTMLElement;\n /** Callback to trigger sort on a column. */\n onSort: (columnKey: string) => void;\n /** Callback to clear search and return focus to the table body. */\n onClearSearch: () => void;\n /** Callback to announce text to screen readers via the live region. */\n onAnnounce: (message: string) => void;\n}\n\ninterface CellPosition {\n row: number;\n col: number;\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\n/**\n * Attach keyboard navigation to a rendered table.\n *\n * @returns A cleanup function that removes all event listeners.\n */\nexport function attachKeyboardNav(options: KeyboardNavOptions): () => void {\n const { wrapper, onSort, onClearSearch, onAnnounce } = options;\n\n let focusedCell: CellPosition = { row: -1, col: 0 };\n\n const table = wrapper.querySelector('table');\n if (!table) return () => {};\n\n const tbody = table.querySelector('tbody');\n const thead = table.querySelector('thead');\n if (!tbody || !thead) return () => {};\n\n // Make tbody focusable\n tbody.setAttribute('tabindex', '0');\n\n function getRows(): HTMLTableRowElement[] {\n if (!tbody) return [];\n return Array.from(tbody.querySelectorAll('tr'));\n }\n\n function getHeaderCells(): HTMLTableCellElement[] {\n if (!thead) return [];\n const headerRow = thead.querySelector('tr');\n if (!headerRow) return [];\n return Array.from(headerRow.querySelectorAll('th'));\n }\n\n function getCellsInRow(tr: HTMLTableRowElement): HTMLTableCellElement[] {\n return Array.from(tr.querySelectorAll('td'));\n }\n\n function getColCount(): number {\n const rows = getRows();\n if (rows.length === 0) return getHeaderCells().length;\n return getCellsInRow(rows[0]).length;\n }\n\n function clearFocusHighlight(): void {\n const prev = wrapper.querySelector('.oc-table-cell-focus');\n if (prev) {\n prev.classList.remove('oc-table-cell-focus');\n prev.removeAttribute('id');\n }\n }\n\n function setFocusedCell(row: number, col: number): void {\n clearFocusHighlight();\n const rows = getRows();\n const colCount = getColCount();\n\n // Clamp values\n if (rows.length === 0) return;\n row = Math.max(0, Math.min(row, rows.length - 1));\n col = Math.max(0, Math.min(col, colCount - 1));\n\n focusedCell = { row, col };\n\n // Highlight the cell\n const tr = rows[row];\n if (!tr) return;\n const cells = getCellsInRow(tr);\n const cell = cells[col];\n if (!cell) return;\n\n const cellId = `oc-cell-${row}-${col}`;\n cell.id = cellId;\n cell.classList.add('oc-table-cell-focus');\n cell.setAttribute('data-row', String(row));\n cell.setAttribute('data-col', String(col));\n\n // Set aria-activedescendant on tbody\n if (tbody) {\n tbody.setAttribute('aria-activedescendant', cellId);\n }\n\n // Scroll cell into view if needed\n cell.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n }\n\n function handleTbodyFocus(): void {\n // When tbody receives focus, highlight the first cell (or restore last)\n if (focusedCell.row < 0) {\n setFocusedCell(0, 0);\n } else {\n setFocusedCell(focusedCell.row, focusedCell.col);\n }\n }\n\n function handleTbodyKeydown(e: KeyboardEvent): void {\n const rows = getRows();\n if (rows.length === 0) return;\n\n const colCount = getColCount();\n const { row, col } = focusedCell;\n\n switch (e.key) {\n case 'ArrowDown':\n e.preventDefault();\n if (row < rows.length - 1) {\n setFocusedCell(row + 1, col);\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (row > 0) {\n setFocusedCell(row - 1, col);\n } else {\n // Move focus to the header\n focusHeaderCell(col);\n }\n break;\n case 'ArrowRight':\n e.preventDefault();\n if (col < colCount - 1) {\n setFocusedCell(row, col + 1);\n }\n break;\n case 'ArrowLeft':\n e.preventDefault();\n if (col > 0) {\n setFocusedCell(row, col - 1);\n }\n break;\n case 'Home':\n e.preventDefault();\n setFocusedCell(row, 0);\n break;\n case 'End':\n e.preventDefault();\n setFocusedCell(row, colCount - 1);\n break;\n }\n }\n\n // Header cell keyboard handling\n function focusHeaderCell(col: number): void {\n const headers = getHeaderCells();\n if (col >= 0 && col < headers.length) {\n clearFocusHighlight();\n headers[col].focus();\n }\n }\n\n function handleHeaderKeydown(e: KeyboardEvent): void {\n const th = e.currentTarget as HTMLTableCellElement;\n const headers = getHeaderCells();\n const colIndex = headers.indexOf(th);\n if (colIndex < 0) return;\n\n switch (e.key) {\n case 'ArrowRight':\n e.preventDefault();\n if (colIndex < headers.length - 1) {\n headers[colIndex + 1].focus();\n }\n break;\n case 'ArrowLeft':\n e.preventDefault();\n if (colIndex > 0) {\n headers[colIndex - 1].focus();\n }\n break;\n case 'ArrowDown':\n e.preventDefault();\n // Move focus to first body row at this column\n if (tbody) {\n tbody.focus();\n setFocusedCell(0, colIndex);\n }\n break;\n case 'Enter':\n case ' ': {\n e.preventDefault();\n const sortColumn = th.getAttribute('data-column');\n const sortBtn = th.querySelector('[data-sort-column]');\n if (sortColumn && sortBtn) {\n onSort(sortColumn);\n }\n break;\n }\n }\n }\n\n // Search escape handling\n const searchInput = wrapper.querySelector('.oc-table-search input') as HTMLInputElement | null;\n\n function handleSearchKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClearSearch();\n // Return focus to tbody\n if (tbody) {\n tbody.focus();\n onAnnounce('Search cleared');\n }\n }\n }\n\n // Wire up event listeners\n tbody.addEventListener('focus', handleTbodyFocus);\n tbody.addEventListener('keydown', handleTbodyKeydown as EventListener);\n\n // Make header cells focusable and wire keyboard\n const headerCells = getHeaderCells();\n for (const th of headerCells) {\n th.setAttribute('tabindex', '0');\n th.addEventListener('keydown', handleHeaderKeydown as EventListener);\n }\n\n if (searchInput) {\n searchInput.addEventListener('keydown', handleSearchKeydown as EventListener);\n }\n\n // Cleanup\n return () => {\n tbody.removeEventListener('focus', handleTbodyFocus);\n tbody.removeEventListener('keydown', handleTbodyKeydown as EventListener);\n\n for (const th of headerCells) {\n th.removeEventListener('keydown', handleHeaderKeydown as EventListener);\n }\n\n if (searchInput) {\n searchInput.removeEventListener('keydown', handleSearchKeydown as EventListener);\n }\n\n clearFocusHighlight();\n };\n}\n","/**\n * Table mount API: the main entry point for vanilla JS table usage.\n *\n * createTable() takes a container, spec, and options, compiles the table,\n * renders it as HTML, sets up responsive resizing, sort/search/pagination\n * interactivity, and returns a TableInstance with update/resize/export/destroy.\n *\n * Supports both controlled and uncontrolled modes:\n * - Uncontrolled (default): manages sort/search/page internally\n * - Controlled: reads state from externalState, fires onStateChange\n */\n\nimport type {\n CompileTableOptions,\n DarkMode,\n SortState,\n TableLayout,\n TableSpec,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport { BREAKPOINT_COMPACT_MAX } from '@opendata-ai/openchart-core';\nimport { compileTable } from '@opendata-ai/openchart-engine';\nimport { setupTableAnimationCleanup } from './animation';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { attachKeyboardNav } from './table-keyboard';\nimport { renderTable } from './table-renderer';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Width a text column needs before its values start wrapping. */\nconst MIN_READABLE_COLUMN_WIDTH = 96;\n\n/** Below this width even a two-column table reads better condensed. */\nconst AUTO_CONDENSE_MAX_WIDTH = 560;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface TableState {\n sort: SortState | null;\n search: string;\n page: number;\n}\n\nexport interface TableMountOptions {\n theme?: ThemeConfig;\n darkMode?: DarkMode;\n responsive?: boolean;\n /** Show the OpenData watermark. Defaults to true. */\n watermark?: boolean;\n onRowClick?: (row: Record<string, unknown>) => void;\n onStateChange?: (state: TableState) => void;\n externalState?: { sort?: SortState | null; search?: string; page?: number };\n}\n\nexport interface TableInstance {\n update(spec: TableSpec): void;\n resize(): void;\n export(format: 'csv'): string;\n getState(): TableState;\n setState(partial: Partial<TableState>): void;\n destroy(): void;\n}\n\n// ---------------------------------------------------------------------------\n// CSV export\n// ---------------------------------------------------------------------------\n\nfunction csvEscape(value: string): string {\n if (value.includes(',') || value.includes('\"') || value.includes('\\n') || value.includes('\\r')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\n// ---------------------------------------------------------------------------\n// Sort cycling\n// ---------------------------------------------------------------------------\n\n/**\n * Cycle sort state: clicking same column cycles none -> asc -> desc -> none.\n * Clicking a different column resets to asc.\n */\nfunction cycleSort(current: SortState | null, column: string): SortState | null {\n if (!current || current.column !== column) {\n return { column, direction: 'asc' };\n }\n if (current.direction === 'asc') {\n return { column, direction: 'desc' };\n }\n // desc -> none\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a table instance from a spec and mount it into a container.\n *\n * @param container - The DOM element to render into.\n * @param spec - The table spec.\n * @param options - Mount options.\n * @returns A TableInstance with update/resize/export/destroy methods.\n */\nexport function createTable(\n container: HTMLElement,\n spec: TableSpec,\n options?: TableMountOptions,\n): TableInstance {\n let currentSpec = spec;\n let currentLayout: TableLayout;\n let wrapperElement: HTMLElement | null = null;\n let disconnectResize: (() => void) | null = null;\n let cleanupKeyboard: (() => void) | null = null;\n let cleanupAnimations: (() => void) | null = null;\n let isFirstRender = true;\n let destroyed = false;\n // Whether the user has touched sorting. Once they have, a null sort means\n // \"explicitly unsorted\" and must not fall back to the spec/bar-column default.\n let sortTouched = false;\n\n // Internal state (used in uncontrolled mode)\n const internalState: TableState = {\n sort: null,\n search: '',\n page: 0,\n };\n\n // Debounce timers\n let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n let resizeDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const isControlled = options?.externalState !== undefined;\n\n function getState(): TableState {\n if (isControlled && options?.externalState) {\n return {\n sort: options.externalState.sort ?? null,\n search: options.externalState.search ?? '',\n page: options.externalState.page ?? 0,\n };\n }\n return { ...internalState };\n }\n\n function updateState(partial: Partial<TableState>): void {\n if (isControlled) {\n // In controlled mode, notify parent\n const current = getState();\n const next: TableState = {\n sort: partial.sort !== undefined ? partial.sort : current.sort,\n search: partial.search !== undefined ? partial.search : current.search,\n page: partial.page !== undefined ? partial.page : current.page,\n };\n if (partial.sort !== undefined) sortTouched = true;\n options?.onStateChange?.(next);\n } else {\n // In uncontrolled mode, update internal state\n if (partial.sort !== undefined) {\n internalState.sort = partial.sort;\n sortTouched = true;\n }\n if (partial.search !== undefined) internalState.search = partial.search;\n if (partial.page !== undefined) internalState.page = partial.page;\n options?.onStateChange?.({ ...internalState });\n }\n }\n\n function compile(): TableLayout {\n const state = getState();\n const darkMode = resolveDarkMode(options?.darkMode);\n const { width } = getContainerDimensions();\n\n const compileOpts: CompileTableOptions = {\n width,\n height: 600,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n // undefined = \"no opinion, apply the spec default\"; null = the user\n // cycled sorting off and expects the original row order back. A\n // controlled caller's natural initial `sort: null` means \"no opinion\"\n // until the user has actually touched sorting.\n sort: resolveEffectiveSort(state),\n search: state.search || undefined,\n page: state.page,\n };\n\n return compileTable(currentSpec, compileOpts);\n }\n\n /** The sort once the user has touched it, otherwise defer to the spec. */\n function sameSort(a: SortState | null, b: SortState | null): boolean {\n if (a === null || b === null) return a === b;\n return a.column === b.column && a.direction === b.direction;\n }\n\n function resolveEffectiveSort(state: TableState): SortState | null | undefined {\n return sortTouched ? state.sort : (state.sort ?? undefined);\n }\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: Math.max(rect.width || 600, 100),\n height: Math.max(rect.height || 400, 100),\n };\n }\n\n /**\n * Announce a message to screen readers via the live region.\n */\n function announce(message: string): void {\n if (!wrapperElement) return;\n const liveRegion = wrapperElement.querySelector('.oc-table-live-region');\n if (liveRegion) {\n liveRegion.textContent = message;\n }\n }\n\n /**\n * Apply responsive classes based on container width.\n *\n * Cards mode below 400px; auto-condense only under real content pressure\n * (more columns than the width can give 96px each, or a narrow embed).\n * `getBreakpoint` calls everything up to 700px \"medium\", so keying on it\n * condensed every 600-720px editorial column that had room to breathe.\n * An explicit `density` (or the deprecated `compact`) always wins.\n */\n function applyBreakpointClass(): void {\n if (!wrapperElement) return;\n const { width } = getContainerDimensions();\n\n wrapperElement.classList.toggle('oc-table--cards', width < BREAKPOINT_COMPACT_MAX);\n\n if (currentSpec.density !== undefined || currentSpec.compact === true) return;\n\n const columns = currentLayout?.columns.length ?? 0;\n const condensed =\n columns * MIN_READABLE_COLUMN_WIDTH > width || width < AUTO_CONDENSE_MAX_WIDTH;\n\n wrapperElement.classList.toggle('oc-table--condensed', condensed);\n wrapperElement.classList.toggle('oc-table--compact', condensed);\n wrapperElement.classList.toggle('oc-table--regular', !condensed);\n }\n\n function render(): void {\n if (destroyed) return;\n\n try {\n // Cancel any in-flight animations before re-rendering\n if (cleanupAnimations) {\n cleanupAnimations();\n cleanupAnimations = null;\n }\n\n // Clean up previous keyboard nav\n if (cleanupKeyboard) {\n cleanupKeyboard();\n cleanupKeyboard = null;\n }\n\n // Clean up previous render\n if (wrapperElement?.parentNode) {\n wrapperElement.parentNode.removeChild(wrapperElement);\n wrapperElement = null;\n }\n\n currentLayout = compile();\n const shouldAnimate = isFirstRender && !!currentLayout.animation?.enter;\n wrapperElement = renderTable(currentLayout, container, { animate: shouldAnimate });\n\n // Set up animation cleanup on first animated render\n if (shouldAnimate && wrapperElement) {\n cleanupAnimations = setupTableAnimationCleanup(wrapperElement);\n }\n if (isFirstRender) {\n isFirstRender = false;\n }\n\n // Apply dark mode class\n const isDark = resolveDarkMode(options?.darkMode);\n if (isDark) {\n container.classList.add('oc-dark');\n } else {\n container.classList.remove('oc-dark');\n }\n\n // Apply responsive breakpoint\n applyBreakpointClass();\n\n // Add clickable class if onRowClick is provided\n if (options?.onRowClick) {\n wrapperElement.classList.add('oc-table--clickable');\n }\n\n // Wire up event handlers\n wireEvents();\n\n // Wire up keyboard navigation\n if (wrapperElement) {\n cleanupKeyboard = attachKeyboardNav({\n wrapper: wrapperElement,\n onSort: (columnKey: string) => {\n const state = getState();\n const newSort = cycleSort(state.sort, columnKey);\n updateState({ sort: newSort, page: 0 });\n\n // Announce sort change\n if (newSort) {\n const dir = newSort.direction === 'asc' ? 'ascending' : 'descending';\n announce(`Sorted by ${columnKey} ${dir}`);\n } else {\n announce('Sort cleared');\n }\n\n if (!isControlled) {\n rerender();\n }\n },\n onClearSearch: () => {\n updateState({ search: '', page: 0 });\n if (!isControlled) {\n rerender();\n }\n },\n onAnnounce: announce,\n });\n }\n } catch (err) {\n console.error('[viz] Table render failed:', err);\n }\n }\n\n function wireEvents(): void {\n if (!wrapperElement) return;\n\n // Sort click handlers on thead buttons\n const sortBtns = wrapperElement.querySelectorAll('[data-sort-column]');\n for (const btn of sortBtns) {\n btn.addEventListener('click', handleSortClick);\n }\n\n // Search input\n const searchInput = wrapperElement.querySelector(\n '.oc-table-search input',\n ) as HTMLInputElement | null;\n if (searchInput) {\n searchInput.addEventListener('input', handleSearchInput);\n }\n\n // Pagination buttons\n const pageButtons = wrapperElement.querySelectorAll('[data-page-action]');\n for (const btn of pageButtons) {\n btn.addEventListener('click', handlePageClick);\n }\n\n // Row click\n if (options?.onRowClick) {\n const rows = wrapperElement.querySelectorAll('tbody tr');\n for (const row of rows) {\n row.addEventListener('click', handleRowClick);\n }\n }\n }\n\n function handleSortClick(e: Event): void {\n const btn = e.currentTarget as HTMLElement;\n const column = btn.getAttribute('data-sort-column');\n if (!column) return;\n\n const state = getState();\n const newSort = cycleSort(state.sort, column);\n\n updateState({ sort: newSort, page: 0 });\n\n // Announce sort change for screen readers\n if (newSort) {\n const dir = newSort.direction === 'asc' ? 'ascending' : 'descending';\n announce(`Sorted by ${column} ${dir}`);\n } else {\n announce('Sort cleared');\n }\n\n if (!isControlled) {\n rerender();\n }\n }\n\n function handleSearchInput(e: Event): void {\n const input = e.target as HTMLInputElement;\n const query = input.value;\n\n if (searchDebounceTimer !== null) {\n clearTimeout(searchDebounceTimer);\n }\n\n searchDebounceTimer = setTimeout(() => {\n searchDebounceTimer = null;\n updateState({ search: query, page: 0 });\n\n if (!isControlled) {\n rerender();\n // Announce search result count\n const rowCount = currentLayout?.rows?.length ?? 0;\n if (query) {\n announce(`${rowCount} result${rowCount !== 1 ? 's' : ''} found`);\n }\n }\n }, 200);\n }\n\n function handlePageClick(e: Event): void {\n const btn = e.currentTarget as HTMLElement;\n const action = btn.getAttribute('data-page-action');\n const state = getState();\n\n if (action === 'prev' && state.page > 0) {\n updateState({ page: state.page - 1 });\n } else if (action === 'next') {\n updateState({ page: state.page + 1 });\n }\n\n if (!isControlled) {\n rerender();\n }\n }\n\n function handleRowClick(e: Event): void {\n const tr = e.currentTarget as HTMLElement;\n const rowId = tr.getAttribute('data-row-id');\n if (!rowId || !currentLayout) return;\n\n const row = currentLayout.rows.find((r) => r.id === rowId);\n if (row) {\n options?.onRowClick?.(row.data);\n }\n }\n\n /**\n * Re-render the table, preserving search input focus across the DOM rebuild.\n */\n function rerender(): void {\n if (destroyed) return;\n\n // Capture current search input state before re-render\n const searchInput = wrapperElement?.querySelector(\n '.oc-table-search input',\n ) as HTMLInputElement | null;\n const hadFocus = searchInput && document.activeElement === searchInput;\n const selectionStart = searchInput?.selectionStart ?? 0;\n const selectionEnd = searchInput?.selectionEnd ?? 0;\n\n render();\n\n // Restore search focus after re-render\n if (hadFocus) {\n const newInput = wrapperElement?.querySelector(\n '.oc-table-search input',\n ) as HTMLInputElement | null;\n if (newInput) {\n newInput.focus();\n newInput.setSelectionRange(selectionStart, selectionEnd);\n }\n }\n }\n\n function update(newSpec: TableSpec): void {\n if (destroyed) return;\n currentSpec = newSpec;\n render();\n }\n\n function resize(): void {\n if (destroyed) return;\n if (cleanupAnimations) return; // Skip resize during entrance animation\n render();\n }\n\n function doExport(format: 'csv'): string {\n if (format !== 'csv') {\n throw new Error(`Unsupported export format: ${format}`);\n }\n\n // Export all filtered/sorted data (not just current page)\n // Re-compile without pagination\n const state = getState();\n const darkMode = resolveDarkMode(options?.darkMode);\n const { width } = getContainerDimensions();\n\n const fullLayout = compileTable(currentSpec, {\n width,\n height: 600,\n theme: options?.theme,\n darkMode,\n sort: resolveEffectiveSort(state),\n search: state.search || undefined,\n // No page/pageSize: get all rows\n });\n\n const headers = fullLayout.columns.map((c) => c.label);\n const csvRows = [headers.map(csvEscape).join(',')];\n\n for (const row of fullLayout.rows) {\n const values = row.cells.map((cell) => csvEscape(cell.formattedValue));\n csvRows.push(values.join(','));\n }\n\n return csvRows.join('\\n');\n }\n\n function setState(partial: Partial<TableState>): void {\n if (destroyed) return;\n\n // In controlled mode compile() reads from options.externalState, so\n // updating internalState alone would be ignored. Push the new values onto\n // externalState (the source getState() reads) so the render reflects them.\n // An explicit sort that actually changes the state -- including a change\n // to null -- is the caller taking a position on sorting, so from here on a\n // null sort means \"cleared\", not \"no opinion\". A no-op sync (the React and\n // Svelte wrappers push their initial `sort: null` on mount) must not count,\n // or spec.sort would be dropped before the first interaction.\n if (partial.sort !== undefined && !sameSort(partial.sort, getState().sort)) {\n sortTouched = true;\n }\n\n if (isControlled && options?.externalState) {\n if (partial.sort !== undefined) options.externalState.sort = partial.sort;\n if (partial.search !== undefined) options.externalState.search = partial.search;\n if (partial.page !== undefined) options.externalState.page = partial.page;\n } else {\n if (partial.sort !== undefined) internalState.sort = partial.sort;\n if (partial.search !== undefined) internalState.search = partial.search;\n if (partial.page !== undefined) internalState.page = partial.page;\n }\n\n render();\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n if (cleanupAnimations) {\n cleanupAnimations();\n cleanupAnimations = null;\n }\n if (cleanupKeyboard) {\n cleanupKeyboard();\n cleanupKeyboard = null;\n }\n if (searchDebounceTimer !== null) {\n clearTimeout(searchDebounceTimer);\n searchDebounceTimer = null;\n }\n if (resizeDebounceTimer !== null) {\n clearTimeout(resizeDebounceTimer);\n resizeDebounceTimer = null;\n }\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n if (wrapperElement?.parentNode) {\n wrapperElement.parentNode.removeChild(wrapperElement);\n wrapperElement = null;\n }\n container.classList.remove('oc-dark');\n }\n\n // Initial render\n render();\n\n // Set up responsive resize with breakpoint detection\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => {\n if (resizeDebounceTimer !== null) {\n clearTimeout(resizeDebounceTimer);\n }\n resizeDebounceTimer = setTimeout(() => {\n resizeDebounceTimer = null;\n // Update breakpoint class without full re-render when possible\n applyBreakpointClass();\n resize();\n }, 100);\n });\n }\n\n return {\n update,\n resize,\n export: doExport,\n getState,\n setState,\n destroy,\n };\n}\n","/**\n * Table renderer: produces semantic HTML from a TableLayout.\n *\n * renderTable() creates the full DOM structure: chrome, search bar,\n * scrollable table with sticky column support, pagination, and footer.\n * The returned element replaces or appends to the given container.\n */\n\nimport type { ResolvedColumn, TableLayout, TableRow } from '@opendata-ai/openchart-core';\nimport { BRAND_FONT_SIZE, cssTokenDefault } from '@opendata-ai/openchart-core';\nimport { clampStaggerDelay } from '@opendata-ai/openchart-engine';\nimport { stampAnimationVars } from './animation-vars';\nimport { applySrOnlyStyles } from './dom-helpers';\nimport { renderCell } from './renderers/table-cells';\nimport { resolvedSurface } from './theme-tokens';\n\n/** Options for renderTable(). */\nexport interface TableRenderOptions {\n /** Whether to apply entrance animation on this render. */\n animate?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst BRAND_URL = 'https://tryopendata.ai';\n\n// ---------------------------------------------------------------------------\n// Chrome rendering\n// ---------------------------------------------------------------------------\n\n/** Create chrome (title/subtitle or source/footer) block. */\nfunction renderChromeBlock(\n layout: TableLayout,\n position: 'header' | 'footer',\n): HTMLDivElement | null {\n const chrome = layout.chrome;\n\n if (position === 'header') {\n if (!chrome.title && !chrome.subtitle) return null;\n\n const div = document.createElement('div');\n div.className = 'oc-chrome';\n\n if (chrome.title) {\n const h = document.createElement('div');\n h.className = 'oc-table-title';\n h.textContent = chrome.title.text;\n div.appendChild(h);\n }\n if (chrome.subtitle) {\n const sub = document.createElement('div');\n sub.className = 'oc-table-subtitle';\n sub.textContent = chrome.subtitle.text;\n div.appendChild(sub);\n }\n\n return div;\n }\n\n // Footer position\n if (!chrome.source && !chrome.footer) return null;\n\n const div = document.createElement('div');\n div.className = 'oc-chrome oc-chrome-footer';\n\n if (chrome.source) {\n const src = document.createElement('div');\n src.className = 'oc-table-source';\n src.textContent = chrome.source.text;\n div.appendChild(src);\n }\n if (chrome.footer) {\n const foot = document.createElement('div');\n foot.className = 'oc-table-footer-text';\n foot.textContent = chrome.footer.text;\n div.appendChild(foot);\n }\n\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Table head\n// ---------------------------------------------------------------------------\n\nfunction renderThead(\n columns: ResolvedColumn[],\n sort: TableLayout['sort'],\n): HTMLTableSectionElement {\n const thead = document.createElement('thead');\n thead.setAttribute('role', 'rowgroup');\n const tr = document.createElement('tr');\n tr.setAttribute('role', 'row');\n\n for (const col of columns) {\n const th = document.createElement('th');\n th.setAttribute('scope', 'col');\n th.setAttribute('role', 'columnheader');\n th.style.textAlign = col.align;\n th.style.width = `${col.width}px`;\n\n // Sort state: use 'ascending'/'descending' per WAI-ARIA spec\n let ariaSortValue: string = 'none';\n if (sort && sort.column === col.key) {\n ariaSortValue = sort.direction === 'asc' ? 'ascending' : 'descending';\n }\n th.setAttribute('aria-sort', ariaSortValue);\n th.setAttribute('data-column', col.key);\n\n // Label\n const labelSpan = document.createTextNode(col.label);\n th.appendChild(labelSpan);\n\n // Sort button\n if (col.sortable) {\n const btn = document.createElement('button');\n btn.className = 'oc-table-sort-btn';\n btn.setAttribute('aria-label', `Sort by ${col.label}`);\n btn.setAttribute('data-sort-column', col.key);\n btn.type = 'button';\n th.appendChild(btn);\n }\n\n tr.appendChild(th);\n }\n\n thead.appendChild(tr);\n return thead;\n}\n\n// ---------------------------------------------------------------------------\n// Table body\n// ---------------------------------------------------------------------------\n\nfunction renderTbody(rows: TableRow[], columns: ResolvedColumn[]): HTMLTableSectionElement {\n const tbody = document.createElement('tbody');\n tbody.setAttribute('role', 'rowgroup');\n\n for (let r = 0; r < rows.length; r++) {\n const row = rows[r];\n const tr = document.createElement('tr');\n tr.setAttribute('role', 'row');\n tr.setAttribute('data-row-id', row.id);\n tr.style.setProperty('--oc-row-index', String(r));\n\n for (let c = 0; c < columns.length; c++) {\n const cell = row.cells[c];\n if (!cell) continue;\n\n const td = renderCell(cell);\n td.setAttribute('role', 'gridcell');\n td.style.textAlign = columns[c].align;\n // Cards mode (below 400px) hides the header and prints these instead;\n // the CSS reads them through `content: attr(data-label)`.\n td.setAttribute('data-label', columns[c].label);\n td.setAttribute('data-priority', String(columns[c].priority));\n tr.appendChild(td);\n }\n\n tbody.appendChild(tr);\n }\n\n return tbody;\n}\n\n// ---------------------------------------------------------------------------\n// Totals footer\n// ---------------------------------------------------------------------------\n\nfunction renderTfoot(\n totalRow: NonNullable<TableLayout['totalRow']>,\n columns: ResolvedColumn[],\n): HTMLTableSectionElement {\n const tfoot = document.createElement('tfoot');\n tfoot.className = 'oc-table-total';\n tfoot.setAttribute('role', 'rowgroup');\n\n const tr = document.createElement('tr');\n tr.setAttribute('role', 'row');\n\n for (let c = 0; c < columns.length; c++) {\n const cell = totalRow.cells[c];\n const td = cell ? renderCell(cell) : document.createElement('td');\n td.setAttribute('role', 'gridcell');\n td.style.textAlign = columns[c].align;\n td.setAttribute('data-label', columns[c].label);\n td.setAttribute('data-priority', String(columns[c].priority));\n // The label rides in the first column; a blank cell there would leave the\n // footer unreadable out of context.\n if (c === 0 && !td.textContent) {\n td.textContent = totalRow.label;\n }\n tr.appendChild(td);\n }\n\n tfoot.appendChild(tr);\n return tfoot;\n}\n\n// ---------------------------------------------------------------------------\n// Search bar\n// ---------------------------------------------------------------------------\n\nfunction renderSearchBar(layout: TableLayout): HTMLDivElement | null {\n if (!layout.search.enabled) return null;\n\n const div = document.createElement('div');\n div.className = 'oc-table-search';\n\n const input = document.createElement('input');\n input.type = 'search';\n input.placeholder = layout.search.placeholder;\n input.setAttribute('aria-label', 'Search table');\n input.value = layout.search.query;\n\n div.appendChild(input);\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Pagination\n// ---------------------------------------------------------------------------\n\nfunction renderPagination(layout: TableLayout): HTMLDivElement | null {\n if (!layout.pagination) return null;\n\n const { page, pageSize, totalRows, totalPages } = layout.pagination;\n\n const div = document.createElement('div');\n div.className = 'oc-table-pagination';\n\n const info = document.createElement('span');\n info.className = 'oc-table-pagination-info';\n\n if (totalRows === 0) {\n info.textContent = 'No results';\n } else {\n const start = page * pageSize + 1;\n const end = Math.min((page + 1) * pageSize, totalRows);\n info.textContent = `Showing ${start}-${end} of ${totalRows}`;\n }\n\n div.appendChild(info);\n\n const btnGroup = document.createElement('span');\n btnGroup.className = 'oc-table-pagination-btns';\n\n const prevBtn = document.createElement('button');\n prevBtn.setAttribute('aria-label', 'Previous page');\n prevBtn.setAttribute('data-page-action', 'prev');\n prevBtn.textContent = 'Prev';\n prevBtn.disabled = page <= 0;\n btnGroup.appendChild(prevBtn);\n\n const nextBtn = document.createElement('button');\n nextBtn.setAttribute('aria-label', 'Next page');\n nextBtn.setAttribute('data-page-action', 'next');\n nextBtn.textContent = 'Next';\n nextBtn.disabled = page >= totalPages - 1;\n btnGroup.appendChild(nextBtn);\n\n div.appendChild(btnGroup);\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Empty state\n// ---------------------------------------------------------------------------\n\nfunction renderEmptyState(message: string): HTMLDivElement {\n const div = document.createElement('div');\n div.className = 'oc-table-empty';\n div.setAttribute('aria-live', 'polite');\n div.textContent = message;\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Main render\n// ---------------------------------------------------------------------------\n\n/**\n * Render a TableLayout into a full DOM structure.\n *\n * @param layout - The compiled table layout.\n * @param container - The container element to render into.\n * @returns The wrapper element that was created.\n */\nexport function renderTable(\n layout: TableLayout,\n container: HTMLElement,\n opts?: TableRenderOptions,\n): HTMLElement {\n const wrapper = document.createElement('div');\n wrapper.className = 'oc-table-wrapper';\n\n // Apply theme colors as CSS custom properties so table CSS picks them up.\n // Without this, dark-background themes show invisible text since the\n // CSS defaults (--oc-text etc.) are light-mode values.\n const { theme, chrome } = layout;\n if (theme) {\n const s = wrapper.style;\n const n = theme.colors.neutral;\n // Sticky header/column/footer cells paint this to occlude the rows sliding\n // under them, so it has to be an opaque surface. theme.colors.background is\n // 'transparent' on the default theme.\n s.setProperty('--oc-bg', resolvedSurface(theme));\n s.setProperty('--oc-text', theme.colors.text);\n // Secondary grays come from the theme's own text/background mix, the same\n // ramp charts stamp. Deriving them from colors.axis (the tick-label ink)\n // used to pin every table gray to one value and shut token changes out.\n s.setProperty('--oc-text-secondary', n.secondary);\n s.setProperty('--oc-text-muted', n[600]);\n s.setProperty('--oc-text-faint', n.faint);\n s.setProperty('--oc-gray-100', n[100]);\n s.setProperty('--oc-gray-200', n[200]);\n s.setProperty('--oc-gray-300', n[300]);\n s.setProperty('--oc-gray-400', n[400]);\n s.setProperty('--oc-gridline', theme.colors.gridline);\n // The table hairline is a border, not a gridline. Only a theme that sets\n // gridline explicitly gets to drive it; otherwise the derived ramp wins.\n // Compare whitespace-stripped: the theme literal is 'rgba(0,0,0,0.08)' but\n // the CSS token is written 'rgba(0, 0, 0, 0.08)'.\n const stripWs = (c: string) => c.replace(/\\s+/g, '');\n const defaultGridline = cssTokenDefault('--oc-gridline', theme.isDark ? 'dark' : 'light');\n const gridlineOverridden = stripWs(theme.colors.gridline) !== stripWs(defaultGridline);\n s.setProperty('--oc-border', gridlineOverridden ? theme.colors.gridline : n.border);\n s.setProperty('--oc-positive', theme.colors.positive);\n s.setProperty('--oc-negative', theme.colors.negative);\n s.setProperty('--oc-font-family', theme.fonts.family);\n s.fontFamily = theme.fonts.family;\n }\n\n // Set computed chrome CSS custom properties so chrome elements pick up\n // theme-resolved values via CSS fallbacks (e.g. --oc-title-computed-size).\n {\n const s = wrapper.style;\n if (chrome.title) {\n s.setProperty('--oc-title-computed-size', `${chrome.title.style.fontSize}px`);\n s.setProperty('--oc-title-computed-weight', String(chrome.title.style.fontWeight));\n s.setProperty('--oc-title-computed-color', chrome.title.style.fill);\n }\n if (chrome.subtitle) {\n s.setProperty('--oc-subtitle-computed-size', `${chrome.subtitle.style.fontSize}px`);\n s.setProperty('--oc-subtitle-computed-weight', String(chrome.subtitle.style.fontWeight));\n s.setProperty('--oc-subtitle-computed-color', chrome.subtitle.style.fill);\n }\n if (chrome.source) {\n s.setProperty('--oc-source-computed-size', `${chrome.source.style.fontSize}px`);\n s.setProperty('--oc-source-computed-color', chrome.source.style.fill);\n }\n if (chrome.footer) {\n s.setProperty('--oc-footer-computed-size', `${chrome.footer.style.fontSize}px`);\n s.setProperty('--oc-footer-computed-color', chrome.footer.style.fill);\n }\n }\n\n // Apply class modifiers\n wrapper.classList.add(`oc-table--${layout.density}`);\n if (layout.density === 'condensed') {\n // Deprecated alias, kept one release for stylesheets targeting it.\n wrapper.classList.add('oc-table--compact');\n }\n if (layout.striped) {\n wrapper.classList.add('oc-table--striped');\n }\n\n // Header chrome\n const headerChrome = renderChromeBlock(layout, 'header');\n if (headerChrome) {\n wrapper.appendChild(headerChrome);\n }\n\n // Search bar\n const searchBar = renderSearchBar(layout);\n if (searchBar) {\n wrapper.appendChild(searchBar);\n }\n\n // Handle empty data\n if (layout.rows.length === 0) {\n const message = layout.search.query ? 'No results found' : 'No data';\n wrapper.appendChild(renderEmptyState(message));\n } else {\n // Scroll container\n const scroll = document.createElement('div');\n scroll.className = 'oc-table-scroll';\n\n // Table\n const table = document.createElement('table');\n table.setAttribute('role', 'grid');\n table.setAttribute('aria-label', layout.a11y.caption);\n\n if (layout.stickyFirstColumn) {\n table.classList.add('oc-table--sticky');\n }\n\n // Caption (screen reader only – inline styles ensure hiding even without\n // the external stylesheet, e.g. CDN / esm.sh usage)\n const caption = document.createElement('caption');\n caption.className = 'oc-sr-only';\n applySrOnlyStyles(caption);\n caption.textContent = layout.a11y.summary;\n table.appendChild(caption);\n\n // Thead\n table.appendChild(renderThead(layout.columns, layout.sort));\n\n // Tbody\n table.appendChild(renderTbody(layout.rows, layout.columns));\n\n // Totals footer\n if (layout.totalRow) {\n table.appendChild(renderTfoot(layout.totalRow, layout.columns));\n }\n\n scroll.appendChild(table);\n wrapper.appendChild(scroll);\n }\n\n // Pagination\n const pagination = renderPagination(layout);\n if (pagination) {\n wrapper.appendChild(pagination);\n }\n\n // Footer row: source/footer chrome on the left, brand watermark on the\n // right, laid out on a single line via flex. Built up here and appended\n // after the live region so source text and watermark share a baseline.\n const footerRow = document.createElement('div');\n footerRow.className = 'oc-table-footer-row';\n\n const footerChrome = renderChromeBlock(layout, 'footer');\n if (footerChrome) {\n footerRow.appendChild(footerChrome);\n }\n\n // Live region for screen reader announcements (sort changes, search results)\n const liveRegion = document.createElement('div');\n liveRegion.className = 'oc-table-live-region oc-sr-only';\n applySrOnlyStyles(liveRegion);\n liveRegion.setAttribute('aria-live', 'polite');\n liveRegion.setAttribute('aria-atomic', 'true');\n liveRegion.setAttribute('role', 'status');\n wrapper.appendChild(liveRegion);\n\n // Brand watermark — joins the footer row, pushed to the right by the\n // flex container so it sits on the same line as the source text.\n if (layout.watermark) {\n const brandColor = theme ? theme.colors.axis : '#999999';\n const brand = document.createElement('div');\n brand.className = 'oc-table-ref';\n const brandLink = document.createElement('a');\n brandLink.href = BRAND_URL;\n brandLink.target = '_blank';\n brandLink.rel = 'noopener';\n brandLink.style.cssText = `font-size: ${BRAND_FONT_SIZE}px; font-weight: 600; color: ${brandColor}; opacity: 0.55; text-decoration: none; font-family: ${theme ? theme.fonts.family : 'sans-serif'};`;\n brandLink.textContent = 'OpenData';\n brand.appendChild(brandLink);\n footerRow.appendChild(brand);\n }\n\n // Append the footer row only when it has content (source/footer/watermark).\n if (footerRow.childElementCount > 0) {\n wrapper.appendChild(footerRow);\n }\n\n // Animation: stamp CSS custom properties and add oc-animate class BEFORE\n // DOM insertion to avoid a flash of final state.\n if (opts?.animate && layout.animation?.enter) {\n const enterPhase = layout.animation.enter;\n const rowCount = layout.rows.length;\n const stagger = clampStaggerDelay(enterPhase.staggerDelay, rowCount);\n stampAnimationVars(wrapper, {\n duration: enterPhase.duration,\n stagger,\n ease: enterPhase.ease,\n });\n wrapper.classList.add('oc-animate');\n }\n\n container.appendChild(wrapper);\n return wrapper;\n}\n","/**\n * TileMap mount API: the main entry point for vanilla JS tilemap usage.\n *\n * createTileMap() takes a container, TileMapSpec, and options, compiles the\n * tilemap, renders it as SVG, sets up responsive resizing, tooltip interaction,\n * and returns a TileMapInstance with update/resize/export/destroy.\n */\n\nimport type {\n CompileOptions,\n DarkMode,\n ThemeConfig,\n TileMapLayout,\n TileMapSpec,\n} from '@opendata-ai/openchart-core';\nimport { BREAKPOINT_COMPACT_MAX, BREAKPOINT_MEDIUM_MAX } from '@opendata-ai/openchart-core';\nimport { compileTileMap } from '@opendata-ai/openchart-engine';\nimport { cancelAnimations, setupAnimationCleanup } from './animation';\nimport {\n exportJPG,\n exportPNG,\n exportSVG,\n exportSVGWithFonts,\n type JPGExportOptions,\n type SVGExportOptions,\n} from './export';\nimport { createMeasureText, resolveFontFamily, scheduleFontReload } from './measure-text';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { renderTileMapSVG } from './tilemap-renderer';\nimport { createTooltipManager, type TooltipManager } from './tooltip';\n\n// ---------------------------------------------------------------------------\n// Responsive tile sizing\n// ---------------------------------------------------------------------------\n\n// The state grid is 8 rows tall (see engine/tilemap/layout.ts GRID_ROWS).\n// TILEMAP_TILE_GAP must match the gap passed to computeTilePositions in\n// compile-tilemap.ts (currently 5) so the mount's height budget matches the\n// grid the compiler builds.\nconst TILEMAP_GRID_ROWS = 8;\nconst TILEMAP_TILE_GAP = 5;\n// Generous vertical reserve for chrome (title/subtitle/source) + padding +\n// legend. Intentionally over-reserved: on narrow widths we WANT tile size to be\n// bound by width, so any excess height budget just lets the map grow taller\n// (which is the desired mobile behavior) rather than starving the tiles.\nconst TILEMAP_CHROME_RESERVE = 180;\n\n/**\n * Target tile size (px) for a given container width. Drives the height budget\n * on non-desktop widths so the 8-row grid isn't starved to tiny tiles after\n * chrome is subtracted from a square drawing area. Width still caps the actual\n * tile size, so these are ceilings the layout grows toward, not guarantees.\n */\nfunction pickTargetTileSize(width: number): number {\n if (width < BREAKPOINT_COMPACT_MAX) return 34; // compact / mobile\n return 40; // medium (tablet, sidebars)\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface TileMapMountOptions {\n /** Theme overrides. */\n theme?: ThemeConfig;\n /** Dark mode setting: \"auto\" (system pref), \"force\", or \"off\". */\n darkMode?: DarkMode;\n /** Enable responsive resizing. Defaults to true. */\n responsive?: boolean;\n /** Show the OpenData watermark. Defaults to true. */\n watermark?: boolean;\n /** Show tooltips on hover. Defaults to true. */\n tooltip?: boolean;\n /** Callback when a tile is clicked. */\n onTileClick?: (tile: {\n stateCode: string;\n stateName: string;\n value: number | null;\n data: Record<string, unknown>;\n }) => void;\n /** Callback when a tile is hovered (null on mouse leave). */\n onTileHover?: (\n tile: {\n stateCode: string;\n stateName: string;\n value: number | null;\n data: Record<string, unknown>;\n } | null,\n ) => void;\n}\n\nexport interface TileMapInstance {\n /** Re-compile and re-render with a new spec. */\n update(spec: TileMapSpec): void;\n /** Re-compile at current container dimensions. */\n resize(): void;\n /** Export the tilemap. */\n export(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string>;\n /** Remove all DOM elements and disconnect observers. */\n destroy(): void;\n /** The current compiled layout. */\n readonly layout: TileMapLayout;\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a tilemap instance from a spec and mount it into a container.\n */\nexport function createTileMap(\n container: HTMLElement,\n spec: TileMapSpec,\n options?: TileMapMountOptions,\n): TileMapInstance {\n let currentSpec = spec;\n let currentLayout: TileMapLayout;\n let destroyed = false;\n\n // DOM\n let svgElement: SVGSVGElement | null = null;\n\n // Subsystems\n let tooltipManager: TooltipManager | null = null;\n let cleanupTooltipEvents: (() => void) | null = null;\n let disconnectResize: (() => void) | null = null;\n\n // Animation state\n let animationCleanup: (() => void) | null = null;\n let pendingResize = false;\n\n // Latches whether the host constrains our height. Measured once, on the\n // first render that produces a real rect: height 0 with a real width means\n // the host is auto-height and we pick our own budget. Any other height is\n // an explicit box we must fit inside. Re-reading this after the first paint\n // would just measure our own SVG, so the value has to latch.\n let isAutoHeight: boolean | null = null;\n\n // Set when webfonts have loaded and a recompile is owed. The next render()\n // that recompiles flips data-oc-fonts-state to 'ready' and clears this, so\n // the attribute stays honest when resize() defers to pendingResize during\n // the entrance animation.\n let fontsReloadPending = false;\n\n // Apply the root class up front so getComputedStyle sees --oc-font-family\n // before the text measurer is built.\n container.classList.add('oc-tilemap-root');\n\n // Resolve the effective font the way compile() will: compile merges\n // { ...spec.theme, ...options.theme }, so options.theme wins over the\n // spec-level theme; fall back to the container's computed font. Measuring a\n // different font than gets rendered desyncs layout metrics and the reload watcher.\n function resolveEffectiveFont(): string {\n return (\n options?.theme?.fonts?.family ??\n currentSpec.theme?.fonts?.family ??\n resolveFontFamily(container)\n );\n }\n let fontFamily = resolveEffectiveFont();\n let measureText = createMeasureText(fontFamily);\n let renderGen = 0;\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n const width = Math.max(rect.width || 600, 100);\n\n if (isAutoHeight === null && (rect.width > 0 || rect.height > 0)) {\n isAutoHeight = rect.height === 0 && rect.width > 0;\n }\n\n // An explicit host height is a hard budget: the compiler derives a tight\n // content height from whatever we pass, so handing it the container's own\n // height keeps the SVG inside its box instead of overflowing onto whatever\n // sits below it.\n if (isAutoHeight === false && rect.height > 0) {\n return { width, height: Math.max(rect.height, 100) };\n }\n\n // Auto-height host: pick our own budget. The compiler derives its own tight\n // content height and treats the passed height as a cap. On desktop, a square\n // budget (height = width) keeps tiles from ballooning (the 8-row grid becomes\n // the binding constraint at ~width/8). Below desktop, a square budget starves\n // the grid after chrome, so give it a height budget sized to a comfortable\n // target tile instead — the map then grows taller as needed rather than\n // shrinking the tiles.\n if (width >= BREAKPOINT_MEDIUM_MAX) {\n return { width, height: width };\n }\n const targetTile = pickTargetTileSize(width);\n const height =\n targetTile * TILEMAP_GRID_ROWS +\n TILEMAP_TILE_GAP * (TILEMAP_GRID_ROWS - 1) +\n TILEMAP_CHROME_RESERVE;\n return { width, height };\n }\n\n function compile(): TileMapLayout {\n const { width, height } = getContainerDimensions();\n const darkMode = resolveDarkMode(options?.darkMode);\n\n const compileOpts: CompileOptions = {\n width,\n height,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n measureText,\n };\n\n return compileTileMap(currentSpec, compileOpts);\n }\n\n // ---------------------------------------------------------------------------\n // Tooltip and interaction wiring\n // ---------------------------------------------------------------------------\n\n function wireTooltipAndInteraction(svg: SVGSVGElement, layout: TileMapLayout): () => void {\n const cleanups: Array<() => void> = [];\n\n const tilesByStateCode = new Map<string, (typeof layout.tiles)[number]>();\n for (const t of layout.tiles) {\n if (!tilesByStateCode.has(t.stateCode)) tilesByStateCode.set(t.stateCode, t);\n }\n\n // Wire tooltip on tile elements. The group carries the hover state so the\n // dim rule can be a single class toggle rather than 51 of them.\n const tilesGroup = svg.querySelector('.oc-tilemap-tiles');\n const tileElements = svg.querySelectorAll('.oc-tilemap-tile');\n for (const el of tileElements) {\n const stateCode = el.getAttribute('data-state');\n if (!stateCode) continue;\n\n const content = layout.tooltipDescriptors.get(stateCode);\n const tile = tilesByStateCode.get(stateCode);\n\n const handleMouseEnter = (e: Event) => {\n const mouseEvent = e as MouseEvent;\n tilesGroup?.classList.add('oc-hover-active');\n el.classList.add('oc-tilemap-tile--hover');\n if (content && tooltipManager && options?.tooltip !== false) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n if (tile) {\n options?.onTileHover?.({\n stateCode: tile.stateCode,\n stateName: tile.data.stateName as string,\n value: tile.value,\n data: tile.data,\n });\n }\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager && options?.tooltip !== false) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n tilesGroup?.classList.remove('oc-hover-active');\n el.classList.remove('oc-tilemap-tile--hover');\n tooltipManager?.hide();\n options?.onTileHover?.(null);\n };\n\n const handleClick = () => {\n if (tile) {\n options?.onTileClick?.({\n stateCode: tile.stateCode,\n stateName: tile.data.stateName as string,\n value: tile.value,\n data: tile.data,\n });\n }\n };\n\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n return () => {\n for (const cleanup of cleanups) {\n cleanup();\n }\n };\n }\n\n // ---------------------------------------------------------------------------\n // Render + update\n // ---------------------------------------------------------------------------\n\n function render(animate = false): void {\n // Cancel running animations\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n }\n\n // Remove old SVG\n if (svgElement) {\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n svgElement.remove();\n }\n\n // Render new SVG\n const newSvg = renderTileMapSVG(currentLayout, { animate });\n container.appendChild(newSvg);\n svgElement = newSvg;\n\n // Wire interactions\n cleanupTooltipEvents = wireTooltipAndInteraction(newSvg, currentLayout);\n\n // Setup tooltips if enabled\n if (options?.tooltip !== false) {\n if (!tooltipManager) {\n tooltipManager = createTooltipManager(container);\n }\n }\n\n // Setup animation cleanup only when actually animating\n if (animate && currentLayout.animation?.enter) {\n animationCleanup = setupAnimationCleanup(newSvg, () => {\n // On animation complete, check if resize was pending\n if (pendingResize && !destroyed) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n\n // This render recompiled with the loaded webfonts; publish 'ready' now\n // rather than right after the fonts-ready resize() (which may have deferred\n // to pendingResize during the entrance animation).\n if (fontsReloadPending) {\n fontsReloadPending = false;\n container.dataset.ocFontsState = 'ready';\n }\n }\n\n function update(newSpec: TileMapSpec): void {\n currentSpec = newSpec;\n // A new spec can change theme.fonts.family; rebuild the measurer so layout\n // measures the font compile will actually render with.\n const nextFont = resolveEffectiveFont();\n if (nextFont !== fontFamily) {\n fontFamily = nextFont;\n measureText = createMeasureText(fontFamily);\n }\n currentLayout = compile();\n render();\n }\n\n function resize(): void {\n if (destroyed) return;\n\n // If animation is running, queue the resize for after it completes\n if (animationCleanup) {\n pendingResize = true;\n return;\n }\n\n currentLayout = compile();\n render();\n }\n\n // ---------------------------------------------------------------------------\n // Export\n // ---------------------------------------------------------------------------\n\n function exportChart(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options_?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string> {\n if (!svgElement) return '';\n\n switch (format) {\n case 'svg':\n return exportSVG(svgElement);\n case 'svg-with-fonts':\n return exportSVGWithFonts(svgElement);\n case 'png':\n return exportPNG(svgElement, options_ as JPGExportOptions);\n case 'jpg':\n return exportJPG(svgElement, options_ as JPGExportOptions);\n default:\n return '';\n }\n }\n\n // ---------------------------------------------------------------------------\n // Destroy\n // ---------------------------------------------------------------------------\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n // Cancel running animations\n if (animationCleanup) {\n cancelAnimations(svgElement);\n animationCleanup();\n animationCleanup = null;\n }\n\n // Clean up events\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n // Remove SVG\n if (svgElement) {\n svgElement.remove();\n svgElement = null;\n }\n\n // Unmount tooltip manager\n if (tooltipManager) {\n tooltipManager.destroy();\n tooltipManager = null;\n }\n\n // Disconnect resize observer\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n\n // Remove root classes\n container.classList.remove('oc-tilemap-root', 'oc-dark');\n }\n\n // ---------------------------------------------------------------------------\n // Initialize\n // ---------------------------------------------------------------------------\n\n // Root class was applied before the measurer was built (see above); dark\n // mode class still applies here.\n if (resolveDarkMode(options?.darkMode)) {\n container.classList.add('oc-dark');\n }\n\n // Initial compile and render (animate on first mount)\n currentLayout = compile();\n render(true);\n\n // Recompile once after webfonts load so labels aren't stuck measured\n // against fallback metrics on real devices.\n const fontsPending = scheduleFontReload(\n fontFamily,\n () => !destroyed,\n () => {\n // Mark the reload owed, then recompile. render() flips the attribute to\n // 'ready' once it actually recompiles, including the pendingResize replay\n // after the entrance animation finishes.\n fontsReloadPending = true;\n resize();\n },\n );\n container.dataset.ocFontsState = fontsPending ? 'pending' : 'ready';\n\n // Setup responsive resizing\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => {\n resize();\n });\n }\n\n return {\n update,\n resize,\n export: exportChart,\n destroy,\n get layout(): TileMapLayout {\n return currentLayout;\n },\n };\n}\n"],"mappings":"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","names":["live","textAscent","SVG_NS","XLINK_NS","BRAND_URL","createSVGElement","setAttrs","textAscent","renderChrome","BRAND_FONT_SIZE","clampStaggerDelay","BRAND_URL","div","BRAND_FONT_SIZE","clampStaggerDelay","BREAKPOINT_COMPACT_MAX","BREAKPOINT_COMPACT_MAX"]}
|
|
1
|
+
{"version":3,"sources":["../src/barlist-mount.ts","../src/barlist-renderer.ts","../src/export-sequence.ts","../src/graph/simulation-worker-url.ts","../src/reader.ts","../src/renderers/table-cells.ts","../src/sankey-mount.ts","../src/sankey-renderer.ts","../src/table-keyboard.ts","../src/table-responsive.ts","../src/table-mount.ts","../src/table-renderer.ts","../src/tilemap-mount.ts"],"sourcesContent":["/**\n * BarList mount API: the main entry point for vanilla JS barlist usage.\n *\n * createBarList() takes a container, BarListSpec, and options, compiles the\n * barlist, renders it as SVG, sets up responsive resizing, tooltip interaction,\n * and returns a BarListInstance with update/resize/export/destroy.\n */\n\nimport type {\n BarListLayout,\n BarListSpec,\n CompileOptions,\n DarkMode,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport { compileBarList } from '@opendata-ai/openchart-engine';\nimport { cancelAnimations, setupAnimationCleanup } from './animation';\nimport { renderBarListSVG } from './barlist-renderer';\nimport {\n exportJPG,\n exportPNG,\n exportSVG,\n exportSVGWithFonts,\n type JPGExportOptions,\n type SVGExportOptions,\n} from './export';\nimport {\n captureMarkFocus,\n type NavigableMark,\n restoreMarkFocus,\n wireMarkNavigation,\n} from './interactions/mark-navigation';\nimport { createMeasureText, resolveFontFamily, scheduleFontReload } from './measure-text';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { createTooltipManager, type TooltipManager } from './tooltip';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface BarListMountOptions {\n theme?: ThemeConfig;\n darkMode?: DarkMode;\n responsive?: boolean;\n watermark?: boolean;\n tooltip?: boolean;\n onRowClick?: (row: { label: string; value: number; data: Record<string, unknown> }) => void;\n onRowHover?: (\n row: { label: string; value: number; data: Record<string, unknown> } | null,\n ) => void;\n}\n\nexport interface BarListInstance {\n update(spec: BarListSpec): void;\n resize(): void;\n export(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string>;\n destroy(): void;\n readonly layout: BarListLayout;\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\nexport function createBarList(\n container: HTMLElement,\n spec: BarListSpec,\n options?: BarListMountOptions,\n): BarListInstance {\n let currentSpec = spec;\n let currentLayout: BarListLayout;\n let destroyed = false;\n\n let svgElement: SVGSVGElement | null = null;\n let tooltipManager: TooltipManager | null = null;\n let cleanupTooltipEvents: (() => void) | null = null;\n let disconnectResize: (() => void) | null = null;\n let animationCleanup: (() => void) | null = null;\n let pendingResize = false;\n\n // Set when webfonts have loaded and a recompile is owed. The next render()\n // that recompiles flips data-oc-fonts-state to 'ready' and clears this, so\n // the attribute stays honest when resize() defers to pendingResize during\n // the entrance animation.\n let fontsReloadPending = false;\n\n // Apply the root class up front so getComputedStyle sees --oc-font-family\n // before the text measurer is built.\n container.classList.add('oc-barlist-root');\n\n // Resolve the effective font the way compile() will: compile merges\n // { ...spec.theme, ...options.theme }, so options.theme wins over the\n // spec-level theme; fall back to the container's computed font. Measuring a\n // different font than gets rendered desyncs layout metrics and the reload watcher.\n function resolveEffectiveFont(candidate = currentSpec): string {\n return (\n options?.theme?.fonts?.family ??\n candidate.theme?.fonts?.family ??\n resolveFontFamily(container)\n );\n }\n let fontFamily = resolveEffectiveFont();\n let measureText = createMeasureText(fontFamily);\n let renderGen = 0;\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: Math.max(rect.width || 600, 100),\n height: Math.max(rect.height || 400, 100),\n };\n }\n\n function compile(candidate = currentSpec, measure = measureText): BarListLayout {\n const { width, height } = getContainerDimensions();\n const darkMode = resolveDarkMode(options?.darkMode);\n\n const compileOpts: CompileOptions = {\n width,\n height,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n measureText: measure,\n };\n\n const layout = compileBarList(candidate, compileOpts);\n\n // Auto-size height to content so few-row lists don't leave empty space.\n if (layout.rows.length > 0) {\n const lastRow = layout.rows[layout.rows.length - 1];\n const contentBottom =\n lastRow.y + lastRow.height + layout.chrome.bottomHeight + layout.theme.spacing.padding;\n if (contentBottom < layout.height) {\n layout.height = contentBottom;\n layout.area.height =\n contentBottom - layout.area.y - layout.chrome.bottomHeight - layout.theme.spacing.padding;\n }\n }\n\n return layout;\n }\n\n function wireTooltipAndInteraction(svg: SVGSVGElement, layout: BarListLayout): () => void {\n const cleanups: Array<() => void> = [];\n const navigation: NavigableMark[] = [];\n let activeLeave: (() => void) | null = null;\n\n const rowElements = svg.querySelectorAll('.oc-barlist-row');\n for (const el of rowElements) {\n const indexStr = el.getAttribute('data-row-index');\n if (indexStr === null) continue;\n\n const content = layout.tooltipDescriptors.get(indexStr);\n const row = layout.rows[Number(indexStr)];\n\n const handleMouseEnter = (e: Event) => {\n activeLeave?.();\n activeLeave = handleMouseLeave;\n const mouseEvent = e as MouseEvent;\n if (content && tooltipManager && options?.tooltip !== false) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n if (row) {\n options?.onRowHover?.({\n label: row.label.text,\n value: row.value,\n data: row.data,\n });\n }\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager && options?.tooltip !== false) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n if (activeLeave !== handleMouseLeave) return;\n activeLeave = null;\n tooltipManager?.hide();\n options?.onRowHover?.(null);\n };\n\n const handleClick = () => {\n if (row) {\n options?.onRowClick?.({\n label: row.label.text,\n value: row.value,\n data: row.data,\n });\n }\n };\n\n navigation.push({\n element: el,\n key: row?.label.text ?? indexStr,\n enter: handleMouseEnter,\n leave: handleMouseLeave,\n activate: handleClick,\n });\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n cleanups.push(wireMarkNavigation(svg, navigation));\n return () => {\n activeLeave?.();\n for (const cleanup of cleanups) cleanup();\n };\n }\n\n function render(animate = false): void {\n const focusedMark = captureMarkFocus(svgElement);\n tooltipManager?.hide();\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n }\n\n if (svgElement) {\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n svgElement.remove();\n }\n\n const newSvg = renderBarListSVG(currentLayout, { animate });\n container.appendChild(newSvg);\n svgElement = newSvg;\n\n cleanupTooltipEvents = wireTooltipAndInteraction(newSvg, currentLayout);\n\n if (options?.tooltip !== false) {\n if (!tooltipManager) {\n tooltipManager = createTooltipManager(container);\n }\n }\n\n if (animate && currentLayout.animation?.enter) {\n animationCleanup = setupAnimationCleanup(newSvg, () => {\n // Null the handle BEFORE replaying, or the deferred resize hits the\n // entrance-in-flight gate and re-defers forever (mount.ts pattern).\n animationCleanup = null;\n if (pendingResize && !destroyed) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n\n // This render recompiled with the loaded webfonts; publish 'ready' now\n // rather than right after the fonts-ready resize() (which may have deferred\n // to pendingResize during the entrance animation).\n if (fontsReloadPending) {\n fontsReloadPending = false;\n container.dataset.ocFontsState = 'ready';\n }\n if (svgElement) restoreMarkFocus(svgElement, focusedMark);\n }\n\n function update(newSpec: BarListSpec): void {\n if (destroyed) return;\n // Compile before adopting an edit: a rejected spec must leave the last\n // valid view, its interactions, and future resize/export calls intact.\n const nextFont = resolveEffectiveFont(newSpec);\n const nextMeasure = nextFont === fontFamily ? measureText : createMeasureText(nextFont);\n const nextLayout = compile(newSpec, nextMeasure);\n currentSpec = newSpec;\n fontFamily = nextFont;\n measureText = nextMeasure;\n\n currentLayout = nextLayout;\n render();\n }\n\n function resize(): void {\n if (destroyed) return;\n if (animationCleanup) {\n pendingResize = true;\n return;\n }\n currentLayout = compile();\n render();\n }\n\n function exportChart(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options_?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string> {\n if (!svgElement) return '';\n // Export settled geometry, independent of transient hover and animation.\n const terminalSvg = renderBarListSVG(currentLayout, { animate: false });\n const resolvedOptions = { theme: currentLayout.theme, ...options_ };\n\n switch (format) {\n case 'svg':\n return exportSVG(terminalSvg);\n case 'svg-with-fonts':\n return exportSVGWithFonts(terminalSvg, resolvedOptions);\n case 'png':\n return exportPNG(terminalSvg, resolvedOptions);\n case 'jpg':\n return exportJPG(terminalSvg, resolvedOptions);\n default:\n return '';\n }\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n if (animationCleanup) {\n cancelAnimations(svgElement);\n animationCleanup();\n animationCleanup = null;\n }\n\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n if (svgElement) {\n svgElement.remove();\n svgElement = null;\n }\n\n if (tooltipManager) {\n tooltipManager.destroy();\n tooltipManager = null;\n }\n\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n\n container.classList.remove('oc-barlist-root', 'oc-dark');\n }\n\n // Initialize\n if (resolveDarkMode(options?.darkMode)) {\n container.classList.add('oc-dark');\n }\n\n currentLayout = compile();\n render(true);\n\n // Recompile once after webfonts load so row labels aren't stuck measured\n // against fallback metrics on real devices.\n const fontsPending = scheduleFontReload(\n fontFamily,\n () => !destroyed,\n () => {\n // Mark the reload owed, then recompile. render() flips the attribute to\n // 'ready' once it actually recompiles, including the pendingResize replay\n // after the entrance animation finishes.\n fontsReloadPending = true;\n resize();\n },\n );\n container.dataset.ocFontsState = fontsPending ? 'pending' : 'ready';\n\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => resize());\n }\n\n return {\n update,\n resize,\n export: exportChart,\n destroy,\n get layout(): BarListLayout {\n return currentLayout;\n },\n };\n}\n","/**\n * BarList SVG renderer: converts a BarListLayout into SVG DOM elements.\n *\n * Creates an <svg> with rows of label + track + bar + value. Animation is\n * pure CSS, driven by data attributes and CSS custom properties.\n */\n\nimport type { BarListLayout, BarListRowMark, ResolvedAnimation } from '@opendata-ai/openchart-core';\nimport { stampAnimationVars } from './animation-vars';\nimport { renderChromeElement } from './renderers/chrome';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst XLINK_NS = 'http://www.w3.org/1999/xlink';\nconst BRAND_URL = 'https://tryopendata.ai';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createSVGElement(tag: string): SVGElement {\n return document.createElementNS(SVG_NS, tag);\n}\n\nfunction setAttrs(el: SVGElement, attrs: Record<string, string | number>): void {\n for (const [key, value] of Object.entries(attrs)) {\n el.setAttribute(key, String(value));\n }\n}\n\n// ---------------------------------------------------------------------------\n// Chrome rendering\n// ---------------------------------------------------------------------------\n\nfunction renderChrome(parent: SVGElement, layout: BarListLayout): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-chrome');\n\n const { chrome } = layout;\n const bottomOffset = layout.area.y + layout.area.height;\n\n for (const key of ['title', 'subtitle', 'source', 'byline', 'footer'] as const) {\n const el = chrome[key];\n if (!el) continue;\n\n const isBottom = key === 'source' || key === 'byline' || key === 'footer';\n renderChromeElement(\n g,\n isBottom ? { ...el, y: bottomOffset + el.y } : el,\n `oc-${key}`,\n key,\n layout.measureText,\n );\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Watermark rendering\n// ---------------------------------------------------------------------------\n\nfunction renderWatermark(parent: SVGElement, layout: BarListLayout): void {\n if (layout.width < 480) return;\n\n const { width, height, theme } = layout;\n const padding = theme.spacing.padding;\n const rightEdge = width - padding;\n const bottomEdge = height - padding;\n const fill = theme.colors.axis;\n\n const a = createSVGElement('a');\n a.setAttribute('href', BRAND_URL);\n a.setAttributeNS(XLINK_NS, 'xlink:href', BRAND_URL);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.setAttribute('class', 'oc-chrome-ref');\n\n const text = createSVGElement('text');\n setAttrs(text, {\n x: rightEdge,\n y: bottomEdge,\n 'dominant-baseline': 'alphabetic',\n 'text-anchor': 'end',\n 'font-family': theme.fonts.family,\n 'font-size': 12,\n 'fill-opacity': 0.55,\n });\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', fill);\n\n setAttrs(text, { 'font-weight': 600, 'font-size': 16 });\n text.textContent = 'OpenData';\n a.appendChild(text);\n parent.appendChild(a);\n}\n\n// ---------------------------------------------------------------------------\n// Row rendering\n// ---------------------------------------------------------------------------\n\nfunction renderRows(\n parent: SVGElement,\n rows: BarListRowMark[],\n animation?: ResolvedAnimation,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-barlist-rows');\n g.setAttribute('role', 'list');\n\n for (const row of rows) {\n const rowGroup = createSVGElement('g');\n rowGroup.setAttribute('class', 'oc-barlist-row');\n rowGroup.setAttribute('data-row-index', String(row.index));\n rowGroup.setAttribute('role', 'listitem');\n if (row.aria?.label) {\n rowGroup.setAttribute('aria-label', row.aria.label);\n }\n\n if (animation?.enter) {\n rowGroup.setAttribute('data-animation-index', String(row.animationIndex));\n const style = (rowGroup as SVGElement & ElementCSSInlineStyle).style;\n style.setProperty('--oc-mark-index', String(row.animationIndex));\n style.setProperty('--oc-row-delay', `${row.animationIndex * 40}ms`);\n }\n\n // Label text\n const labelEl = createSVGElement('text');\n setAttrs(labelEl, {\n x: row.label.x,\n y: row.label.y,\n 'dominant-baseline': 'central',\n 'text-anchor': 'start',\n 'font-family': row.label.style.fontFamily,\n 'font-size': row.label.style.fontSize,\n 'font-weight': row.label.style.fontWeight,\n });\n (labelEl as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', row.label.style.fill);\n labelEl.textContent = row.label.text;\n rowGroup.appendChild(labelEl);\n\n // Subtitle text (if present)\n if (row.subtitle?.visible) {\n const subEl = createSVGElement('text');\n setAttrs(subEl, {\n x: row.subtitle.x,\n y: row.subtitle.y,\n 'dominant-baseline': 'central',\n 'text-anchor': 'start',\n 'font-family': row.subtitle.style.fontFamily,\n 'font-size': row.subtitle.style.fontSize,\n 'font-weight': row.subtitle.style.fontWeight,\n });\n (subEl as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n row.subtitle.style.fill,\n );\n subEl.textContent = row.subtitle.text;\n rowGroup.appendChild(subEl);\n }\n\n // Track (muted background bar)\n const trackRect = createSVGElement('rect');\n setAttrs(trackRect, {\n x: row.track.x,\n y: row.track.y,\n width: row.track.width,\n height: row.track.height,\n rx: row.track.cornerRadius,\n fill: 'currentColor',\n 'fill-opacity': 0.06,\n });\n trackRect.setAttribute('class', 'oc-barlist-track');\n rowGroup.appendChild(trackRect);\n\n // Fill bar\n const barRect = createSVGElement('rect');\n setAttrs(barRect, {\n x: row.bar.x,\n y: row.bar.y,\n width: row.bar.width,\n height: row.bar.height,\n rx: row.bar.cornerRadius,\n fill: row.bar.fill,\n });\n barRect.setAttribute('class', 'oc-barlist-bar');\n rowGroup.appendChild(barRect);\n\n // Value label (right-aligned)\n const valueEl = createSVGElement('text');\n setAttrs(valueEl, {\n x: row.valueLabel.x,\n y: row.valueLabel.y,\n 'dominant-baseline': 'central',\n 'text-anchor': 'end',\n 'font-family': row.valueLabel.style.fontFamily,\n 'font-size': row.valueLabel.style.fontSize,\n 'font-weight': row.valueLabel.style.fontWeight,\n });\n (valueEl as SVGElement & ElementCSSInlineStyle).style.setProperty(\n 'fill',\n row.valueLabel.style.fill,\n );\n valueEl.textContent = row.valueLabel.text;\n rowGroup.appendChild(valueEl);\n\n g.appendChild(rowGroup);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Public API\n// ---------------------------------------------------------------------------\n\nexport function renderBarListSVG(\n layout: BarListLayout,\n opts?: { animate?: boolean },\n): SVGSVGElement {\n const { width, height, rows, a11y, watermark, animation } = layout;\n const animate = opts?.animate && !!animation?.enter;\n\n const svg = createSVGElement('svg') as SVGSVGElement;\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n svg.setAttribute('role', 'list');\n // No explicit width attribute — CSS width:100% on .oc-barlist-root handles it.\n // Explicit pixel height via inline style avoids iOS Safari's height:100% quirk.\n svg.style.height = `${height}px`;\n if (a11y.altText) {\n svg.setAttribute('aria-label', a11y.altText);\n }\n\n const classes = animate ? 'oc-barlist oc-animate' : 'oc-barlist';\n svg.setAttribute('class', classes);\n\n if (animate && animation?.enter) {\n stampAnimationVars(svg, {\n duration: animation.enter.duration,\n spring: animation.enter.spring,\n stagger: 40,\n });\n }\n\n renderChrome(svg, layout);\n renderRows(svg, rows, animate ? animation : undefined);\n\n if (watermark) {\n renderWatermark(svg, layout);\n }\n\n return svg;\n}\n","/**\n * Multi-spec (\"keyframe\") GIF export.\n *\n * The single-chart GIF export (`exportGIF`) reproduces ONE chart's entrance\n * animation. Some charts animate a different way: a component swaps in a whole\n * new spec on a timer (e.g. a year-by-year stepper), and the on-screen chart\n * tweens between them via `chart.update()` (bars grow/shrink smoothly). The DATA\n * changes across frames, and the motion is the update transition — neither of\n * which `exportGIF` can express.\n *\n * `exportSpecSequence` reproduces that. It mounts one offscreen chart, holds the\n * first spec, then walks the rest by driving `chart.beginManualUpdate(spec)` and\n * stepping the returned transition frame-by-frame (no rAF clock), rasterizing\n * each step. Between transitions it holds the settled frame for `dwellMs`. The\n * result is the same bar tween the reader sees on screen, captured to GIF.\n *\n * `gifenc` is an optional peer dependency, loaded dynamically.\n */\n\nimport type {\n AnimationSpec,\n ChartSpec,\n LayerSpec,\n ResolvedTheme,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport {\n embedFonts,\n ensureSVGDimensions,\n exportSVG,\n getSVGBackgroundColor,\n getSVGDimensions,\n rasterizeSVGToCanvas,\n} from './export';\nimport { isModuleNotFound, resolveRepeat } from './export-gif';\nimport { paletteFromCanvas, readCanvasSRGB } from './gif-encode';\nimport { createChart } from './mount';\nimport { injectThemeStyleBlock } from './theme-style-block';\n\nexport interface SpecSequenceOptions {\n /** DPI scaling factor, matching PNG export. Defaults to 2. */\n dpi?: number;\n /** Frames per second for the tween between specs. Defaults to 25. */\n fps?: number;\n /** How long to hold each spec's settled frame, in ms. Defaults to 1200 (the common stepper cadence). */\n dwellMs?: number;\n /**\n * Loop behavior, same semantics as `exportGIF`:\n * - `false` / omitted: play once, then hold the final frame\n * - `true`: loop forever\n * - a number: loop that many times, then hold\n */\n loop?: boolean | number;\n /** Render width in CSS px. Required — pass the on-screen chart width so the export matches. */\n width: number;\n /** Render height in CSS px. Required — pass the on-screen chart height so the export matches. */\n height: number;\n /** Dark mode for the rendered charts. Defaults to 'off' (light). */\n darkMode?: 'auto' | 'force' | 'off';\n /**\n * Rendering backend for point marks; see `MountOptions.renderer`. Pass the\n * SAME value your on-screen chart mounts with so the export matches.\n */\n renderer?: 'auto' | 'svg' | 'canvas';\n /**\n * Theme overrides applied when rendering, exactly as a consumer's live wrapper\n * would apply them. Pass the SAME theme your on-screen chart uses (e.g. the\n * blog's `blogChartTheme(isDark)`), or the export won't match — its background,\n * gridlines, and chrome colors fall back to openchart's raw defaults.\n */\n theme?: ThemeConfig;\n /** Embed fonts as base64 so text matches on-screen. Defaults to true. */\n embedFonts?: boolean;\n /** Opaque background fill. Defaults to the chart's own background (white if transparent). */\n backgroundColor?: string;\n}\n\n/**\n * Force `enter:false` (each spec must render settled) while KEEPING the author's\n * own update config when they wrote one as an object. Replacing it wholesale\n * would drop fields like `update.maxMarks`, so a spec that deliberately raised\n * the tween cap above 500 marks would silently swap instead of tween on export.\n */\nexport function settleAnimation(spec: ChartSpec | LayerSpec): ChartSpec | LayerSpec {\n const authored = (spec as { animation?: AnimationSpec }).animation;\n const update =\n typeof authored === 'object' && typeof authored.update === 'object'\n ? { ...authored.update }\n : true;\n return {\n ...(spec as unknown as Record<string, unknown>),\n animation: { enter: false, update },\n } as unknown as ChartSpec | LayerSpec;\n}\n\n/**\n * Mount one live chart offscreen (used as the persistent host we step through\n * every spec). Entrance is disabled so the first spec renders settled; update\n * transitions are enabled so `beginManualUpdate` can tween between specs.\n */\nfunction mountOffscreen(\n spec: ChartSpec | LayerSpec,\n width: number,\n height: number,\n darkMode: 'auto' | 'force' | 'off',\n themeConfig: ThemeConfig | undefined,\n renderer: 'auto' | 'svg' | 'canvas' | undefined,\n): {\n instance: ReturnType<typeof createChart>;\n svg: SVGElement;\n container: HTMLElement;\n} {\n const container = document.createElement('div');\n // Offscreen but laid out, so text measurement (needs a live DOM) works.\n container.style.cssText = `position:absolute;left:-99999px;top:0;width:${width}px;height:${height}px;visibility:hidden;`;\n document.body.appendChild(container);\n\n // enter:false → first spec settled immediately; update:true → tween on\n // beginManualUpdate. responsive:false → no ResizeObserver on a detached node.\n const settledSpec = settleAnimation(spec);\n let instance: ReturnType<typeof createChart>;\n try {\n instance = createChart(container, settledSpec, {\n darkMode,\n theme: themeConfig,\n renderer,\n responsive: false,\n });\n } catch (err) {\n // A spec that fails to compile must not leak the offscreen container.\n container.remove();\n throw err;\n }\n\n const svg = container.querySelector('svg');\n if (!svg) {\n instance.destroy();\n container.remove();\n throw new Error('exportSpecSequence: chart produced no SVG');\n }\n return { instance, svg, container };\n}\n\n/**\n * Render an ordered list of specs to an animated GIF Blob. Holds the first spec,\n * then tweens to each subsequent spec (openchart's update transition, driven\n * frame-by-frame) and holds it — reproducing the on-screen bar grow/shrink.\n *\n * @param specs - Ordered specs, one per keyframe (e.g. one per year).\n * @param options - dpi, fps, dwell, loop, size (required), dark mode, theme, fonts.\n * @returns A Promise resolving to the GIF Blob.\n */\nexport async function exportSpecSequence(\n specs: Array<ChartSpec | LayerSpec>,\n options: SpecSequenceOptions,\n): Promise<Blob> {\n if (specs.length === 0) {\n throw new Error('exportSpecSequence requires at least one spec');\n }\n\n let gifenc: typeof import('gifenc');\n try {\n gifenc = await import('gifenc');\n } catch (err) {\n if (isModuleNotFound(err)) {\n throw new Error(\n \"GIF export requires the optional 'gifenc' peer dependency. Install it: npm install gifenc\",\n );\n }\n throw new Error('GIF export failed to load the gifenc encoder', {\n cause: err,\n });\n }\n const { GIFEncoder, quantize, applyPalette } = gifenc;\n\n const dpi = options.dpi ?? 2;\n const fps = options.fps ?? 25;\n const dwellMs = options.dwellMs ?? 1200;\n const frameDelay = Math.round(1000 / fps);\n const { width, height } = options;\n const darkMode = options.darkMode ?? 'off';\n const themeConfig = options.theme;\n const shouldEmbed = options.embedFonts ?? true;\n const repeat = resolveRepeat(options.loop);\n\n const { instance, svg, container } = mountOffscreen(\n specs[0],\n width,\n height,\n darkMode,\n themeConfig,\n options.renderer,\n );\n\n try {\n const w = getSVGDimensions(svg).width || width;\n const h = getSVGDimensions(svg).height || height;\n const theme = (): ResolvedTheme | undefined => {\n const layout = instance.layout;\n return layout && 'theme' in layout ? (layout.theme as ResolvedTheme) : undefined;\n };\n // The theme background is the fallback: canvas mark mode suppresses the SVG\n // background rect, so there's nothing in the markup to read it from.\n const bgColor =\n options.backgroundColor ?? getSVGBackgroundColor(svg, theme()?.colors.background);\n const fillBackground = (ctx: CanvasRenderingContext2D, cv: HTMLCanvasElement): void => {\n ctx.fillStyle = bgColor;\n ctx.fillRect(0, 0, cv.width, cv.height);\n };\n\n // `beginManualUpdate`/`render` REPLACES the live <svg> node each spec, so the\n // injected theme + @font-face blocks don't carry over. Re-inject them into\n // whatever <svg> is currently live. Fonts embed once per spec (not per frame\n // — embedding fetches font files, which across a tween would be far too slow).\n const prepareLiveSvg = async (): Promise<SVGElement> => {\n const live = container.querySelector('svg');\n if (!live) throw new Error('exportSpecSequence: live SVG vanished mid-sequence');\n injectThemeStyleBlock(live, theme());\n if (shouldEmbed) await embedFonts(live);\n return live;\n };\n\n // Rasterize the given live svg at its current (stepped) state.\n const grab = async (live: SVGElement): Promise<HTMLCanvasElement> => {\n const svgString = ensureSVGDimensions(exportSVG(live), w, h);\n return rasterizeSVGToCanvas(svgString, w, h, dpi, fillBackground);\n };\n\n // frames: each canvas with its hold duration. Hold the first spec, then for\n // each subsequent spec step its tween (frameDelay each) and hold the result.\n const frames: Array<{ canvas: HTMLCanvasElement; delayMs: number }> = [];\n let live = await prepareLiveSvg();\n frames.push({ canvas: await grab(live), delayMs: dwellMs });\n\n for (let i = 1; i < specs.length; i++) {\n // Re-apply the same settle/animation wrapper the offscreen mount used, so\n // update transitions stay enabled for each step.\n const nextSpec = settleAnimation(specs[i]);\n const handle = instance.beginManualUpdate(nextSpec);\n // render() replaced the <svg>; re-inject theme/fonts into the new one.\n live = await prepareLiveSvg();\n\n if (handle) {\n const totalMs = handle.totalMs;\n // Step across the tween at fps; capture each frame. Start one frame in\n // (t=0 is the previous held frame) and go through the final step.\n for (let t = frameDelay; t < totalMs; t += frameDelay) {\n handle.step(t);\n frames.push({ canvas: await grab(live), delayMs: frameDelay });\n }\n // Final settled frame of this spec, held for the dwell.\n handle.step(totalMs);\n handle.cancel();\n }\n frames.push({ canvas: await grab(live), delayMs: dwellMs });\n }\n\n // One global palette from the last frame — a full-color settled frame, and\n // stepper frames share a palette by construction.\n const globalPalette = paletteFromCanvas(frames[frames.length - 1].canvas, quantize);\n\n const gif = GIFEncoder();\n frames.forEach(({ canvas, delayMs }, i) => {\n const index = applyPalette(readCanvasSRGB(canvas), globalPalette);\n gif.writeFrame(index, canvas.width, canvas.height, {\n palette: globalPalette,\n delay: delayMs,\n // `repeat` writes the loop extension; only meaningful on the first frame.\n ...(i === 0 ? { repeat } : {}),\n });\n });\n\n gif.finish();\n return new Blob([gif.bytes() as BlobPart], { type: 'image/gif' });\n } finally {\n instance.destroy();\n container.remove();\n }\n}\n","/**\n * Creates a Web Worker running the force simulation.\n *\n * References the built .js file via `new URL` + `import.meta.url`.\n * The consuming app's bundler resolves the worker path at build time.\n *\n * Note: SimulationManager handles .js/.ts fallback internally. This\n * helper is exported for consumers who want to manage the worker directly.\n */\nexport function createSimulationWorker(): Worker {\n return new Worker(new URL('./simulation-worker.js', import.meta.url), { type: 'module' });\n}\n","import type {\n ChartLayout,\n ChartSpec,\n DataRow,\n LayerSpec,\n ReaderObservation,\n ReaderSelection,\n} from '@opendata-ai/openchart-core';\nimport {\n observationKey,\n reconcileReaderSelection,\n resolveObservationIdentities,\n} from '@opendata-ai/openchart-engine';\nimport type { ChartInstance } from './mount';\n\nexport interface ReaderController {\n readonly selection: ReaderSelection;\n /** Call after chart.update(). Without an override, visibility follows compiled marks. */\n update(spec: ChartSpec | LayerSpec, visibleKeys?: ReadonlySet<string>): void;\n pin(datum: DataRow): void;\n clear(): void;\n destroy(): void;\n}\n\nconst LAYER_UNSUPPORTED =\n 'Reader inspection is unavailable for layered charts: observations cannot be bound to a single dataset.';\nconst seriesField = (spec: ChartSpec) =>\n spec.encoding.color && 'field' in spec.encoding.color ? spec.encoding.color.field : undefined;\n\n/**\n * Persistent reader interaction, separate from editor ElementRef selection.\n * Layered specs clear/disable inspection and announce the unsupported binding;\n * updating back to a single chart resumes inspection without choosing a leaf.\n */\nexport function createReader(\n container: HTMLElement,\n instance: ChartInstance,\n initial: ChartSpec | LayerSpec,\n onChange: (selection: ReaderSelection) => void,\n): ReaderController {\n let spec = 'layer' in initial ? null : initial;\n let state: ReaderSelection = {\n preview: null,\n pinned: [],\n announcement: spec ? '' : LAYER_UNSUPPORTED,\n };\n let keyboardIndex = -1;\n let settleFrame: number | null = null;\n let visibilityOverride: ReadonlySet<string> | undefined;\n let identities = spec\n ? resolveObservationIdentities(spec.data, spec.encoding.key?.field, seriesField(spec))\n : [];\n const emit = () => onChange({ ...state, pinned: [...state.pinned] });\n const visibleData = (\n layout: ChartLayout = instance.sampleLayout(),\n ): Array<{ datum: DataRow; key?: string }> => {\n const rows = layout.marks.flatMap((mark) => {\n if ('opacity' in mark && mark.opacity === 0) return [];\n if (mark.type === 'line' || mark.type === 'area')\n return (mark.dataPoints ?? []).map((point, index) => ({\n datum: point.datum,\n key: mark.pointKeys?.[index],\n }));\n if ('data' in mark) return [{ datum: mark.data as DataRow, key: mark.key }];\n return [];\n });\n // A line and its point overlay share rows. Distinct duplicate rows must not\n // collapse merely because their serialized values happen to be identical.\n return [...new Map(rows.map((row) => [row.datum, row])).values()];\n };\n const compiledVisibleKeys = (observations: ReaderObservation[]): ReadonlySet<string> => {\n const keys = new Set<string>();\n if (!spec || !observations.length) return keys;\n // Use the destination layout, not interpolated geometry or exit ghosts.\n // Zero-length marks still count; absence retains the pin as filtered.\n const rows = visibleData(instance.layout);\n const references = new Set(rows.map(({ datum }) => datum));\n const signatures = new Set(rows.map(({ datum }) => JSON.stringify(datum)));\n const keyField = spec.encoding.key?.field;\n const visibleSourceKeys = new Set(\n keyField ? rows.map(({ datum }) => observationKey(datum[keyField])) : [],\n );\n for (const observation of observations) {\n if (observation.kind === 'aggregate') {\n if (signatures.has(JSON.stringify(observation.datum))) keys.add(observation.observation);\n continue;\n }\n const index = identities.findIndex((id) => id.observation === observation.observation);\n if (index < 0) continue;\n const row = spec.data[index];\n const signature = JSON.stringify(row);\n const visible = observation.persistent\n ? visibleSourceKeys.has(observation.observation)\n : references.has(row) ||\n (signatures.has(signature) &&\n spec.data.filter((source) => JSON.stringify(source) === signature).length === 1);\n if (visible) keys.add(observation.observation);\n }\n return keys;\n };\n const resolve = (datum: DataRow): ReaderObservation | null => {\n if (!spec) return null;\n const keyField = spec.encoding.key?.field;\n let index = spec.data.indexOf(datum);\n if (index >= 0 && spec.data.lastIndexOf(datum) !== index) return null;\n if (index < 0 && keyField)\n index = spec.data.findIndex(\n (_row, i) =>\n identities[i].persistent && identities[i].observation === observationKey(datum[keyField]),\n );\n // Compilers may normalize a row. Within one revision, a unique exact row\n // match is safe; an ambiguous match must never pick the first observation.\n if (index < 0) {\n const matches = spec.data.flatMap((row, i) =>\n JSON.stringify(row) === JSON.stringify(datum) ? [i] : [],\n );\n if (matches.length > 1) return null;\n if (matches.length === 1) index = matches[0];\n }\n if (index >= 0) return { ...identities[index], datum: spec.data[index], state: 'visible' };\n // Aggregated/bin observations describe visible groups, not a raw source row.\n // Their identity includes the transformation and grouping mark; replacement\n // clears them until an explicit host mapping supplies revision persistence.\n const group = visibleData(instance.layout).find(\n (row) => row.datum === datum || JSON.stringify(row.datum) === JSON.stringify(datum),\n );\n return group\n ? {\n observation: `aggregate:${JSON.stringify([spec.mark, spec.encoding, spec.transform])}:${group.key ?? JSON.stringify(datum)}`,\n persistent: false,\n datum: group.datum,\n kind: 'aggregate',\n state: 'visible',\n }\n : null;\n };\n const pin = (datum: DataRow) => {\n const observation = resolve(datum);\n if (!observation) return;\n observation.state = (visibilityOverride ?? compiledVisibleKeys([observation])).has(\n observation.observation,\n )\n ? 'visible'\n : 'filtered';\n state = {\n ...state,\n preview: observation,\n announcement: 'Observation pinned.',\n pinned: [\n ...state.pinned.filter((item) => item.observation !== observation.observation),\n observation,\n ].slice(-2),\n };\n emit();\n };\n const clear = () => {\n state = {\n preview: null,\n pinned: [],\n announcement: spec ? 'Selection dismissed.' : LAYER_UNSUPPORTED,\n };\n emit();\n };\n function hit(event: MouseEvent | PointerEvent): DataRow | null {\n if (!spec) return null;\n const svg = container.querySelector('svg');\n if (!svg) return null;\n const bounds = svg.getBoundingClientRect();\n if (!bounds.width || !bounds.height) return null;\n const layout = instance.sampleLayout();\n const x = ((event.clientX - bounds.left) * layout.dimensions.width) / bounds.width;\n const y = ((event.clientY - bounds.top) * layout.dimensions.height) / bounds.height;\n if (\n x < layout.area.x ||\n x > layout.area.x + layout.area.width ||\n y < layout.area.y ||\n y > layout.area.y + layout.area.height\n )\n return null;\n let nearest: DataRow | null = null;\n let distance = 32;\n const consider = (datum: DataRow, dx: number, dy: number) => {\n const d = Math.hypot(dx, dy);\n if (d <= distance) {\n distance = d;\n nearest = datum;\n }\n };\n for (const mark of layout.marks) {\n if ('opacity' in mark && mark.opacity === 0) continue;\n if (mark.type === 'point') consider(mark.data, x - mark.cx, y - mark.cy);\n else if (mark.type === 'rect')\n consider(\n mark.data,\n Math.max(mark.x - x, 0, x - mark.x - mark.width),\n Math.max(mark.y - y, 0, y - mark.y - mark.height),\n );\n else if (mark.type === 'arc') {\n const dx = x - mark.center.x;\n const dy = y - mark.center.y;\n const radius = Math.hypot(dx, dy);\n const angle = (Math.atan2(dy, dx) + Math.PI / 2 + Math.PI * 2) % (Math.PI * 2);\n const start = (mark.startAngle + Math.PI * 2) % (Math.PI * 2);\n const sweep = mark.endAngle - mark.startAngle;\n if (\n radius >= mark.innerRadius &&\n radius <= mark.outerRadius &&\n (angle - start + Math.PI * 2) % (Math.PI * 2) <= sweep\n )\n consider(mark.data, 0, 0);\n } else if (mark.type === 'line' || mark.type === 'area') {\n for (const point of mark.dataPoints ?? []) consider(point.datum, x - point.x, y - point.y);\n }\n }\n return nearest;\n }\n const preview = (event: PointerEvent) => {\n if (event.pointerType === 'touch') return;\n const datum = hit(event);\n state = { ...state, preview: datum ? resolve(datum) : null };\n emit();\n };\n const click = (event: MouseEvent) => {\n const datum = hit(event);\n if (datum) pin(datum);\n };\n const leave = () => {\n state = { ...state, preview: null };\n emit();\n };\n const keydown = (event: KeyboardEvent) => {\n if (!spec) return;\n if (\n (event.target as HTMLElement).closest(\n 'input, textarea, select, button, [contenteditable=true]',\n )\n )\n return;\n if (event.key === 'Escape') {\n clear();\n return;\n }\n if (event.key === 'Enter' && state.preview) {\n event.preventDefault();\n pin(state.preview.datum);\n return;\n }\n const rows = visibleData();\n if (!['ArrowLeft', 'ArrowRight', 'ArrowUp', 'ArrowDown'].includes(event.key) || !rows.length)\n return;\n event.preventDefault();\n event.stopPropagation();\n const backwards = event.key === 'ArrowLeft' || event.key === 'ArrowUp';\n keyboardIndex =\n keyboardIndex < 0\n ? backwards\n ? rows.length - 1\n : 0\n : (keyboardIndex + (backwards ? -1 : 1) + rows.length) % rows.length;\n state = { ...state, preview: resolve(rows[keyboardIndex].datum) };\n emit();\n };\n container.addEventListener('pointermove', preview);\n container.addEventListener('pointerleave', leave);\n container.addEventListener('click', click);\n container.addEventListener('keydown', keydown, true);\n if (!spec) emit();\n return {\n get selection() {\n return state;\n },\n pin,\n clear,\n update(next, visibleKeys) {\n if (settleFrame !== null) {\n cancelAnimationFrame(settleFrame);\n settleFrame = null;\n }\n visibilityOverride = visibleKeys;\n if ('layer' in next) {\n spec = null;\n identities = [];\n keyboardIndex = -1;\n state = { preview: null, pinned: [], announcement: LAYER_UNSUPPORTED };\n emit();\n return;\n }\n const meaningChanged =\n !spec ||\n JSON.stringify([next.mark, next.encoding, next.transform]) !==\n JSON.stringify([spec.mark, spec.encoding, spec.transform]);\n if (\n meaningChanged &&\n (state.pinned.some((item) => item.kind === 'aggregate') ||\n state.preview?.kind === 'aggregate')\n ) {\n state = {\n ...state,\n preview: null,\n pinned: state.pinned.filter((item) => item.kind !== 'aggregate'),\n announcement:\n 'Aggregate selection cleared because its grouping or transformation changed.',\n };\n }\n const replaced =\n !spec || next.data !== spec.data || next.encoding.key?.field !== spec.encoding.key?.field;\n const resuming = !spec;\n spec = next;\n identities = resolveObservationIdentities(\n spec.data,\n spec.encoding.key?.field,\n seriesField(spec),\n );\n const effectiveVisibility = visibleKeys ?? compiledVisibleKeys(state.pinned);\n if (replaced)\n state = reconcileReaderSelection(\n state,\n spec.data,\n spec.encoding.key?.field,\n seriesField(spec),\n effectiveVisibility,\n );\n else\n state = {\n ...state,\n preview: null,\n pinned: state.pinned.map((item) => ({\n ...item,\n ...(item.kind !== 'aggregate'\n ? identities.find((id) => id.observation === item.observation)\n : {}),\n state: effectiveVisibility.has(item.observation) ? 'visible' : 'filtered',\n })),\n };\n if (resuming) state = { ...state, announcement: '' };\n if (replaced || meaningChanged) keyboardIndex = -1;\n emit();\n const settle = () => {\n settleFrame = null;\n if (!state.pinned.some((item) => item.previous)) return;\n if (instance.sampleLayout() !== instance.layout) {\n settleFrame = requestAnimationFrame(settle);\n return;\n }\n state = { ...state, pinned: state.pinned.map(({ previous: _previous, ...item }) => item) };\n emit();\n };\n settleFrame = requestAnimationFrame(settle);\n },\n destroy() {\n if (settleFrame !== null) cancelAnimationFrame(settleFrame);\n container.removeEventListener('pointermove', preview);\n container.removeEventListener('pointerleave', leave);\n container.removeEventListener('click', click);\n container.removeEventListener('keydown', keydown, true);\n },\n };\n}\n","/**\n * Table cell renderers: produce DOM elements for each cell type.\n *\n * Each renderer takes a resolved TableCell and returns an HTMLElement\n * (typically a <td>) with appropriate content, styling, and classes.\n */\n\nimport type {\n BarTableCell,\n CategoryTableCell,\n DeltaTableCell,\n FlagTableCell,\n HeatmapTableCell,\n ImageTableCell,\n SparklineData,\n SparklineTableCell,\n TableCell,\n TextTableCell,\n} from '@opendata-ai/openchart-core';\n\n// ---------------------------------------------------------------------------\n// Utility\n// ---------------------------------------------------------------------------\n\n/** Apply common cell styles (background, color, font weight, font variant). */\nfunction applyCellStyle(td: HTMLTableCellElement, cell: TableCell): void {\n if (cell.style.backgroundColor) {\n td.style.background = cell.style.backgroundColor;\n }\n if (cell.style.color) {\n td.style.color = cell.style.color;\n }\n if (cell.style.fontWeight) {\n td.style.fontWeight = String(cell.style.fontWeight);\n }\n if (cell.style.fontVariant) {\n td.style.fontVariant = cell.style.fontVariant;\n }\n if (cell.aria) {\n td.setAttribute('aria-label', cell.aria);\n }\n}\n\n/**\n * Convert a 2-char ISO 3166-1 alpha-2 country code to a flag emoji.\n * Each letter maps to a Regional Indicator Symbol (offset 0x1F1A5 from ASCII).\n */\nfunction countryToEmoji(code: string): string {\n return [...code.toUpperCase()]\n .map((c) => String.fromCodePoint(c.charCodeAt(0) + 0x1f1a5))\n .join('');\n}\n\n/**\n * Lookup map for common country names by ISO 3166-1 alpha-2 code.\n * Falls back to the raw code for unrecognized values.\n */\nconst COUNTRY_NAMES: Record<string, string> = {\n US: 'United States',\n CN: 'China',\n IN: 'India',\n ID: 'Indonesia',\n BR: 'Brazil',\n PK: 'Pakistan',\n NG: 'Nigeria',\n BD: 'Bangladesh',\n RU: 'Russia',\n MX: 'Mexico',\n JP: 'Japan',\n DE: 'Germany',\n GB: 'United Kingdom',\n FR: 'France',\n IT: 'Italy',\n CA: 'Canada',\n AU: 'Australia',\n KR: 'South Korea',\n ES: 'Spain',\n AR: 'Argentina',\n CO: 'Colombia',\n ZA: 'South Africa',\n TR: 'Turkey',\n SA: 'Saudi Arabia',\n UA: 'Ukraine',\n PL: 'Poland',\n NL: 'Netherlands',\n SE: 'Sweden',\n NO: 'Norway',\n DK: 'Denmark',\n FI: 'Finland',\n CH: 'Switzerland',\n AT: 'Austria',\n BE: 'Belgium',\n PT: 'Portugal',\n IE: 'Ireland',\n NZ: 'New Zealand',\n SG: 'Singapore',\n IL: 'Israel',\n AE: 'United Arab Emirates',\n EG: 'Egypt',\n TH: 'Thailand',\n VN: 'Vietnam',\n PH: 'Philippines',\n MY: 'Malaysia',\n CL: 'Chile',\n PE: 'Peru',\n CZ: 'Czech Republic',\n GR: 'Greece',\n HU: 'Hungary',\n RO: 'Romania',\n ET: 'Ethiopia',\n};\n\n/** Get a human-readable name for a country code. */\nfunction getCountryName(code: string): string {\n return COUNTRY_NAMES[code.toUpperCase()] || code.toUpperCase();\n}\n\n/**\n * Describe a sparkline trend for screen readers.\n * Compares first and last values to determine direction.\n */\nfunction describeSparklineTrend(data: SparklineData): string {\n if (data.type === 'line' && data.points.length >= 2) {\n const first = data.points[0].y;\n const last = data.points[data.points.length - 1].y;\n const count = data.points.length;\n if (last > first) return `Sparkline with ${count} points, trending upward`;\n if (last < first) return `Sparkline with ${count} points, trending downward`;\n return `Sparkline with ${count} points, roughly flat`;\n }\n if ((data.type === 'bar' || data.type === 'column') && data.bars.length > 0) {\n return `${data.type === 'column' ? 'Column' : 'Bar'} sparkline with ${data.bars.length} values`;\n }\n return 'Sparkline';\n}\n\n// ---------------------------------------------------------------------------\n// Cell renderers\n// ---------------------------------------------------------------------------\n\n/** Render a plain text cell. */\nexport function renderTextCell(cell: TextTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.textContent = cell.formattedValue;\n applyCellStyle(td, cell);\n return td;\n}\n\n/** Render a heatmap-colored cell. */\nexport function renderHeatmapCell(cell: HeatmapTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.className = 'oc-table-heatmap';\n td.textContent = cell.formattedValue;\n applyCellStyle(td, cell);\n return td;\n}\n\n/**\n * Render a category-colored cell as a chip: a dot in the category color, the\n * value in a contrast-safe ink, on a tint of the same hue. The color lives on\n * the chip, never on the cell, so a column of categories reads as labels\n * rather than a block of paint.\n */\nexport function renderCategoryCell(cell: CategoryTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.className = 'oc-table-category';\n\n const chip = document.createElement('span');\n chip.className = 'oc-table-chip';\n if (cell.style.backgroundColor) chip.style.background = cell.style.backgroundColor;\n if (cell.style.color) chip.style.color = cell.style.color;\n\n if (cell.style.accent) {\n const dot = document.createElement('span');\n dot.className = 'oc-table-chip-dot';\n dot.style.background = cell.style.accent;\n chip.appendChild(dot);\n }\n\n chip.appendChild(document.createTextNode(cell.formattedValue));\n td.appendChild(chip);\n return td;\n}\n\n/** Render a cell with an inline bar visualization. */\nexport function renderBarCell(cell: BarTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n td.className = 'oc-table-bar';\n applyCellStyle(td, cell);\n\n const fill = document.createElement('div');\n fill.className = 'oc-table-bar-fill';\n fill.style.width = `${Math.round(cell.barWidth * 100)}%`;\n fill.style.left = `${Math.round(cell.barOffset * 100)}%`;\n fill.style.background = cell.barColor;\n td.appendChild(fill);\n\n const valueSpan = document.createElement('span');\n valueSpan.className = 'oc-table-bar-value';\n valueSpan.textContent = cell.formattedValue;\n td.appendChild(valueSpan);\n\n return td;\n}\n\n/**\n * Format a sparkline endpoint value for display.\n * Keeps it compact: no decimals for values >= 100, one decimal otherwise.\n */\nfunction formatSparklineValue(v: number): string {\n if (Math.abs(v) >= 1000) {\n return v.toLocaleString('en-US', { maximumFractionDigits: 0 });\n }\n if (Math.abs(v) >= 100) {\n return v.toFixed(0);\n }\n return v.toFixed(1);\n}\n\n/** Render a cell with an inline sparkline SVG. */\nexport function renderSparklineCell(cell: SparklineTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const sparklineData = cell.sparklineData;\n if (!sparklineData || sparklineData.count === 0) {\n td.textContent = cell.formattedValue || '';\n return td;\n }\n\n // Add aria-label describing the trend for screen readers\n const trendDescription = describeSparklineTrend(sparklineData);\n if (!td.getAttribute('aria-label')) {\n td.setAttribute('aria-label', trendDescription);\n }\n\n const wrapper = document.createElement('span');\n wrapper.className = 'oc-table-sparkline';\n\n const svgNS = 'http://www.w3.org/2000/svg';\n\n if (sparklineData.type === 'line') {\n // Infrographic-style sparkline: SVG polyline fills cell width via percentage x-coords.\n // Dots are HTML elements (not SVG circles) to avoid aspect-ratio distortion.\n // Labels are HTML below the SVG.\n const svgH = 28;\n const padY = 4;\n const lineH = svgH - padY * 2;\n\n const svg = document.createElementNS(svgNS, 'svg');\n svg.setAttribute('aria-hidden', 'true');\n svg.setAttribute('xmlns', svgNS);\n svg.style.height = `${svgH}px`;\n\n // Compute y positions in pixel space (no viewBox scaling)\n const yPositions = sparklineData.points.map((p) => padY + (1 - p.y) * lineH);\n\n // SVG polyline doesn't support % in points attribute, so use a viewBox\n // with a wide aspect ratio and map x to 0-1000 range. preserveAspectRatio=\"none\"\n // stretches the x-axis to fill the cell width. Y values stay in pixel space\n // since viewBox height matches the SVG height. Only the polyline is in the SVG;\n // dots are HTML elements to avoid circle distortion from the non-uniform scaling.\n const viewW = 1000;\n svg.setAttribute('viewBox', `0 0 ${viewW} ${svgH}`);\n svg.setAttribute('preserveAspectRatio', 'none');\n\n const ptsScaled = sparklineData.points.map((p, i) => ({\n x: p.x * viewW,\n y: yPositions[i],\n }));\n const scaledPointsStr = ptsScaled.map((p) => `${p.x},${p.y}`).join(' ');\n\n const polyline = document.createElementNS(svgNS, 'polyline');\n polyline.setAttribute('points', scaledPointsStr);\n polyline.setAttribute('fill', 'none');\n polyline.setAttribute('stroke', sparklineData.color);\n polyline.setAttribute('stroke-width', '1.25');\n polyline.setAttribute('stroke-linejoin', 'round');\n polyline.setAttribute('vector-effect', 'non-scaling-stroke');\n svg.appendChild(polyline);\n\n wrapper.appendChild(svg);\n\n // HTML dots at start and end (positioned absolutely over the SVG)\n const firstY = yPositions[0];\n const lastY = yPositions[yPositions.length - 1];\n const dotSize = 5;\n\n const startDot = document.createElement('span');\n startDot.className = 'oc-table-sparkline-dot';\n startDot.style.left = '0';\n startDot.style.top = `${firstY - dotSize / 2}px`;\n startDot.style.background = sparklineData.color;\n wrapper.appendChild(startDot);\n\n const endDot = document.createElement('span');\n endDot.className = 'oc-table-sparkline-dot';\n endDot.style.right = '0';\n endDot.style.top = `${lastY - dotSize / 2}px`;\n endDot.style.background = sparklineData.color;\n wrapper.appendChild(endDot);\n\n // HTML labels below the SVG, positioned at left and right edges\n const labelsRow = document.createElement('span');\n labelsRow.className = 'oc-table-sparkline-labels';\n labelsRow.style.color = sparklineData.color;\n\n const startLabel = document.createElement('span');\n startLabel.textContent = formatSparklineValue(sparklineData.startValue);\n labelsRow.appendChild(startLabel);\n\n const endLabel = document.createElement('span');\n endLabel.textContent = formatSparklineValue(sparklineData.endValue);\n labelsRow.appendChild(endLabel);\n\n wrapper.appendChild(labelsRow);\n } else if (sparklineData.type === 'column') {\n // Vertical bars at proportional heights\n const width = 80;\n const height = 20;\n const padding = 2;\n const innerW = width - padding * 2;\n const innerH = height - padding * 2;\n\n const svg = document.createElementNS(svgNS, 'svg');\n svg.setAttribute('width', String(width));\n svg.setAttribute('height', String(height));\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n svg.setAttribute('aria-hidden', 'true');\n\n const barCount = sparklineData.bars.length;\n if (barCount > 0) {\n const gap = 1;\n const barW = Math.max(1, (innerW - gap * (barCount - 1)) / barCount);\n\n for (let i = 0; i < barCount; i++) {\n const barH = Math.max(1, sparklineData.bars[i] * innerH);\n const x = padding + i * (barW + gap);\n const y = padding + innerH - barH;\n\n const rect = document.createElementNS(svgNS, 'rect');\n rect.setAttribute('x', String(x));\n rect.setAttribute('y', String(y));\n rect.setAttribute('width', String(barW));\n rect.setAttribute('height', String(barH));\n rect.setAttribute('rx', '1.5');\n rect.setAttribute('fill', sparklineData.color);\n svg.appendChild(rect);\n }\n }\n\n wrapper.appendChild(svg);\n } else {\n // 'bar' type: horizontal bars at proportional widths\n const width = 80;\n const height = 20;\n const padding = 2;\n const innerW = width - padding * 2;\n const innerH = height - padding * 2;\n\n const svg = document.createElementNS(svgNS, 'svg');\n svg.setAttribute('width', String(width));\n svg.setAttribute('height', String(height));\n svg.setAttribute('viewBox', `0 0 ${width} ${height}`);\n svg.setAttribute('aria-hidden', 'true');\n\n const barCount = sparklineData.bars.length;\n if (barCount > 0) {\n const gap = 1;\n const barH = Math.max(1, (innerH - gap * (barCount - 1)) / barCount);\n\n for (let i = 0; i < barCount; i++) {\n const barW = Math.max(1, sparklineData.bars[i] * innerW);\n const x = padding;\n const y = padding + i * (barH + gap);\n\n const rect = document.createElementNS(svgNS, 'rect');\n rect.setAttribute('x', String(x));\n rect.setAttribute('y', String(y));\n rect.setAttribute('width', String(barW));\n rect.setAttribute('height', String(barH));\n rect.setAttribute('rx', '1.5');\n rect.setAttribute('fill', sparklineData.color);\n svg.appendChild(rect);\n }\n }\n\n wrapper.appendChild(svg);\n }\n\n td.appendChild(wrapper);\n\n return td;\n}\n\n/** Arrow glyph per direction. Flat uses an en dash, not a third arrow. */\nconst DELTA_GLYPH: Record<DeltaTableCell['direction'], string> = {\n up: '\\u25b2',\n down: '\\u25bc',\n flat: '\\u2013',\n};\n\n/** Render a signed change chip. */\nexport function renderDeltaCell(cell: DeltaTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const chip = document.createElement('span');\n chip.className = `oc-table-delta oc-table-delta--${cell.tone}`;\n\n const arrow = document.createElement('span');\n arrow.className = 'oc-table-delta-arrow';\n arrow.setAttribute('aria-hidden', 'true');\n arrow.textContent = DELTA_GLYPH[cell.direction];\n chip.appendChild(arrow);\n\n const value = document.createElement('span');\n value.textContent = cell.formattedValue;\n chip.appendChild(value);\n\n td.appendChild(chip);\n return td;\n}\n\n/** Render a cell with an image. */\nexport function renderImageCell(cell: ImageTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const wrapper = document.createElement('span');\n wrapper.className = `oc-table-image${cell.rounded ? ' oc-table-image-rounded' : ''}`;\n\n const img = document.createElement('img');\n img.src = cell.src;\n img.alt = cell.formattedValue || '';\n img.width = cell.imageWidth;\n img.height = cell.imageHeight;\n img.loading = 'lazy';\n\n wrapper.appendChild(img);\n td.appendChild(wrapper);\n\n return td;\n}\n\n/** Render a cell with a country flag emoji. */\nexport function renderFlagCell(cell: FlagTableCell): HTMLTableCellElement {\n const td = document.createElement('td');\n applyCellStyle(td, cell);\n\n const span = document.createElement('span');\n span.className = 'oc-table-flag';\n span.setAttribute('role', 'img');\n\n if (cell.countryCode && cell.countryCode.length === 2) {\n const countryName = getCountryName(cell.countryCode);\n span.textContent = countryToEmoji(cell.countryCode);\n span.setAttribute('aria-label', `Flag: ${countryName}`);\n } else {\n span.textContent = cell.formattedValue;\n span.setAttribute('aria-label', cell.formattedValue);\n }\n\n td.appendChild(span);\n\n return td;\n}\n\n// ---------------------------------------------------------------------------\n// Dispatcher\n// ---------------------------------------------------------------------------\n\n/** Render any table cell by dispatching on its cellType. */\nexport function renderCell(cell: TableCell): HTMLTableCellElement {\n switch (cell.cellType) {\n case 'text':\n return renderTextCell(cell);\n case 'heatmap':\n return renderHeatmapCell(cell);\n case 'category':\n return renderCategoryCell(cell);\n case 'bar':\n return renderBarCell(cell);\n case 'sparkline':\n return renderSparklineCell(cell);\n case 'delta':\n return renderDeltaCell(cell);\n case 'image':\n return renderImageCell(cell);\n case 'flag':\n return renderFlagCell(cell);\n default:\n // Exhaustive check fallback\n return renderTextCell(cell as TextTableCell);\n }\n}\n","/**\n * Sankey mount API: the main entry point for vanilla JS sankey usage.\n *\n * createSankey() takes a container, SankeySpec, and options, compiles the\n * sankey, renders it as SVG, sets up responsive resizing, tooltip interaction,\n * hover highlighting, and returns a SankeyInstance with update/resize/export/destroy.\n */\n\nimport type {\n CompileOptions,\n DarkMode,\n SankeyLayout,\n SankeyLinkMark,\n SankeySpec,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport { compileSankey } from '@opendata-ai/openchart-engine';\nimport { cancelAnimations, setupAnimationCleanup } from './animation';\nimport {\n exportJPG,\n exportPNG,\n exportSVG,\n exportSVGWithFonts,\n type JPGExportOptions,\n type SVGExportOptions,\n} from './export';\nimport {\n captureMarkFocus,\n type NavigableMark,\n restoreMarkFocus,\n wireMarkNavigation,\n} from './interactions/mark-navigation';\nimport { createMeasureText, resolveFontFamily, scheduleFontReload } from './measure-text';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { renderSankeySVG } from './sankey-renderer';\nimport { createTooltipManager, type TooltipManager } from './tooltip';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface SankeyMountOptions {\n /** Theme overrides. */\n theme?: ThemeConfig;\n /** Dark mode setting: \"auto\" (system pref), \"force\", or \"off\". */\n darkMode?: DarkMode;\n /** Enable responsive resizing. Defaults to true. */\n responsive?: boolean;\n /** Show the OpenData watermark. Defaults to true. */\n watermark?: boolean;\n /** Show tooltips on hover. Defaults to true. */\n tooltip?: boolean;\n /** Callback when a node is clicked. */\n onNodeClick?: (node: Record<string, unknown>) => void;\n /** Callback when a link is clicked. */\n onLinkClick?: (link: Record<string, unknown>) => void;\n /** Callback when a node is hovered (null on mouse leave). */\n onNodeHover?: (node: Record<string, unknown> | null) => void;\n /** Callback when a link is hovered (null on mouse leave). */\n onLinkHover?: (link: Record<string, unknown> | null) => void;\n}\n\nexport interface SankeyInstance {\n /** Re-compile and re-render with a new spec. */\n update(spec: SankeySpec): void;\n /** Re-compile at current container dimensions. */\n resize(): void;\n /** Export the sankey diagram. */\n export(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string>;\n /** Remove all DOM elements and disconnect observers. */\n destroy(): void;\n /** The current compiled layout. */\n readonly layout: SankeyLayout;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Opacity for links on the hovered node's path. */\nconst HIGHLIGHT_OPACITY = 0.7;\n/** Opacity for links off the path. Low enough to read as context, not flow. */\nconst DIM_OPACITY = 0.12;\n/** Opacity for nodes and labels off the path. */\nconst NODE_DIM_OPACITY = 0.3;\n\n/**\n * Seeds for a trace: which nodes to walk upstream from, which to walk\n * downstream from, plus any link keys that are on the path by construction.\n *\n * A node hover seeds both directions from that node. A link hover seeds\n * upstream from the source and downstream from the target, so the highlight\n * is the one path running through the hovered link rather than every sibling\n * ribbon out of the source and into the target.\n */\ninterface TraceSeeds {\n up: string[];\n down: string[];\n links?: string[];\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a sankey instance from a spec and mount it into a container.\n */\nexport function createSankey(\n container: HTMLElement,\n spec: SankeySpec,\n options?: SankeyMountOptions,\n): SankeyInstance {\n let currentSpec = spec;\n let currentLayout: SankeyLayout;\n let destroyed = false;\n\n // DOM\n let svgElement: SVGSVGElement | null = null;\n\n // Subsystems\n let tooltipManager: TooltipManager | null = null;\n let cleanupTooltipEvents: (() => void) | null = null;\n let disconnectResize: (() => void) | null = null;\n\n // Animation state\n let isFirstRender = true;\n let animationCleanup: (() => void) | null = null;\n let pendingResize = false;\n\n // Set when webfonts have loaded and a recompile is owed. The next render()\n // that recompiles flips data-oc-fonts-state to 'ready' and clears this, so\n // the attribute stays honest when resize() defers to pendingResize during\n // the entrance animation.\n let fontsReloadPending = false;\n\n // Apply the root class up front so getComputedStyle sees --oc-font-family\n // before the text measurer is built.\n container.classList.add('oc-sankey-root');\n\n // Resolve the effective font the way compile() will: compile merges\n // { ...spec.theme, ...options.theme }, so options.theme wins over the\n // spec-level theme; fall back to the container's computed font. Measuring a\n // different font than gets rendered desyncs layout metrics and the reload watcher.\n function resolveEffectiveFont(candidate = currentSpec): string {\n return (\n options?.theme?.fonts?.family ??\n candidate.theme?.fonts?.family ??\n resolveFontFamily(container)\n );\n }\n let fontFamily = resolveEffectiveFont();\n let measureText = createMeasureText(fontFamily);\n let renderGen = 0;\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: Math.max(rect.width || 600, 100),\n height: Math.max(rect.height || 400, 100),\n };\n }\n\n function compile(candidate = currentSpec, measure = measureText): SankeyLayout {\n const { width, height } = getContainerDimensions();\n const darkMode = resolveDarkMode(options?.darkMode);\n\n const compileOpts: CompileOptions = {\n width,\n height,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n measureText: measure,\n };\n\n return compileSankey(candidate, compileOpts);\n }\n\n // ---------------------------------------------------------------------------\n // Tooltip and interaction wiring\n // ---------------------------------------------------------------------------\n\n function wireTooltipAndInteraction(svg: SVGSVGElement, layout: SankeyLayout): () => void {\n const cleanups: Array<() => void> = [];\n const navigation: NavigableMark[] = [];\n let activeLeave: (() => void) | null = null;\n\n const nodesById = new Map<string, (typeof layout.nodes)[number]>();\n for (const n of layout.nodes) {\n if (!nodesById.has(n.nodeId)) nodesById.set(n.nodeId, n);\n }\n\n // Wire tooltip on node elements\n const nodeElements = svg.querySelectorAll('.oc-sankey-node');\n for (const el of nodeElements) {\n const markId = el.getAttribute('data-mark-id');\n if (!markId) continue;\n\n const content = layout.tooltipDescriptors.get(markId);\n const nodeId = el.getAttribute('data-node-id');\n const nodeData = nodeId ? (nodesById.get(nodeId)?.data ?? {}) : {};\n\n const handleMouseEnter = (e: Event) => {\n activeLeave?.();\n activeLeave = handleMouseLeave;\n const mouseEvent = e as MouseEvent;\n if (content && tooltipManager) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n options?.onNodeHover?.(nodeData);\n if (nodeId) highlightPath(svg, { up: [nodeId], down: [nodeId] }, layout);\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n if (activeLeave !== handleMouseLeave) return;\n activeLeave = null;\n tooltipManager?.hide();\n options?.onNodeHover?.(null);\n resetLinkOpacity(svg, layout);\n };\n\n const handleClick = () => {\n options?.onNodeClick?.(nodeData);\n };\n\n navigation.push({\n element: el,\n key: nodeId ? `node:${nodeId}` : markId,\n enter: handleMouseEnter,\n leave: handleMouseLeave,\n activate: handleClick,\n });\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n // Wire tooltip on link elements\n const linkElements = svg.querySelectorAll('.oc-sankey-link');\n for (const [index, el] of linkElements.entries()) {\n const markId = el.getAttribute('data-mark-id');\n if (!markId) continue;\n\n const content = layout.tooltipDescriptors.get(markId);\n const sourceId = el.getAttribute('data-source');\n const targetId = el.getAttribute('data-target');\n const linkData = layout.links[index]?.data ?? {};\n\n const handleMouseEnter = (e: Event) => {\n activeLeave?.();\n activeLeave = handleMouseLeave;\n const mouseEvent = e as MouseEvent;\n if (content && tooltipManager) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n options?.onLinkHover?.(linkData);\n if (sourceId && targetId) {\n highlightPath(\n svg,\n { up: [sourceId], down: [targetId], links: [`${sourceId}->${targetId}`] },\n layout,\n );\n }\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n if (activeLeave !== handleMouseLeave) return;\n activeLeave = null;\n tooltipManager?.hide();\n options?.onLinkHover?.(null);\n resetLinkOpacity(svg, layout);\n };\n\n const handleClick = () => {\n options?.onLinkClick?.(linkData);\n };\n\n navigation.push({\n element: el,\n key: JSON.stringify(['link', sourceId, targetId]),\n enter: handleMouseEnter,\n leave: handleMouseLeave,\n activate: handleClick,\n });\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n cleanups.push(wireMarkNavigation(svg, navigation));\n return () => {\n activeLeave?.();\n for (const cleanup of cleanups) {\n cleanup();\n }\n };\n }\n\n /**\n * Trace the path through a set of seed nodes: everything upstream of the\n * `up` seeds and everything downstream of the `down` seeds, links included.\n *\n * A sankey answers \"where did this come from and where does it go\", so\n * lighting only the direct neighbors stops the answer one hop short. Returns\n * the node ids and the \"source->target\" link keys on the path.\n */\n function tracePath(\n layout: SankeyLayout,\n seeds: TraceSeeds,\n ): { nodes: Set<string>; links: Set<string> } {\n const out = new Map<string, typeof layout.links>();\n const inn = new Map<string, typeof layout.links>();\n for (const link of layout.links) {\n const o = out.get(link.sourceId);\n if (o) o.push(link);\n else out.set(link.sourceId, [link]);\n const i = inn.get(link.targetId);\n if (i) i.push(link);\n else inn.set(link.targetId, [link]);\n }\n\n const nodes = new Set<string>([...seeds.up, ...seeds.down]);\n const links = new Set<string>(seeds.links ?? []);\n\n const walk = (\n adjacency: Map<string, typeof layout.links>,\n seedIds: string[],\n nextId: (l: SankeyLinkMark) => string,\n ) => {\n const queue = [...seedIds];\n const seen = new Set<string>(seedIds);\n while (queue.length > 0) {\n const id = queue.shift() as string;\n for (const link of adjacency.get(id) ?? []) {\n links.add(`${link.sourceId}->${link.targetId}`);\n const next = nextId(link);\n nodes.add(next);\n if (!seen.has(next)) {\n seen.add(next);\n queue.push(next);\n }\n }\n }\n };\n\n walk(out, seeds.down, (l) => l.targetId);\n walk(inn, seeds.up, (l) => l.sourceId);\n\n return { nodes, links };\n }\n\n /**\n * Dim everything that is not on the traced path: off-path links go to a whisper,\n * off-path nodes and their labels to the shared hover dim.\n */\n function highlightPath(svg: SVGSVGElement, seeds: TraceSeeds, layout: SankeyLayout): void {\n const { nodes: onNodes, links: onLinks } = tracePath(layout, seeds);\n\n for (const el of svg.querySelectorAll('.oc-sankey-link')) {\n const path = el.querySelector('path');\n if (!path) continue;\n const source = el.getAttribute('data-source');\n const target = el.getAttribute('data-target');\n const onPath = onLinks.has(`${source}->${target}`);\n path.setAttribute('fill-opacity', String(onPath ? HIGHLIGHT_OPACITY : DIM_OPACITY));\n }\n\n for (const el of svg.querySelectorAll('.oc-sankey-node, .oc-sankey-label')) {\n const nid = el.getAttribute('data-node-id');\n if (!nid) continue;\n (el as SVGElement).style.opacity = onNodes.has(nid) ? '1' : String(NODE_DIM_OPACITY);\n }\n }\n\n /**\n * Reset all link opacities and node opacities to their original values.\n */\n function resetLinkOpacity(svg: SVGSVGElement, layout: SankeyLayout): void {\n const linkElements = svg.querySelectorAll('.oc-sankey-link');\n for (const [index, el] of linkElements.entries()) {\n const path = el.querySelector('path');\n if (!path) continue;\n const link = layout.links[index];\n path.setAttribute('fill-opacity', String(link?.fillOpacity ?? 0.5));\n }\n\n // Restore all node and label opacities\n for (const el of svg.querySelectorAll('.oc-sankey-node, .oc-sankey-label')) {\n (el as SVGElement).style.opacity = '1';\n }\n }\n\n // ---------------------------------------------------------------------------\n // Render\n // ---------------------------------------------------------------------------\n\n function render(prepared?: SankeyLayout): void {\n if (destroyed) return;\n const nextLayout = prepared ?? compile();\n const focusedMark = captureMarkFocus(svgElement);\n tooltipManager?.hide();\n\n // Cancel in-progress animations before tearing down\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n }\n if (svgElement) {\n cancelAnimations(svgElement);\n }\n\n // Clean up previous tooltip listeners\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n // Remove old SVG\n if (svgElement?.parentNode) {\n svgElement.parentNode.removeChild(svgElement);\n }\n\n currentLayout = nextLayout;\n\n // Determine if we should animate\n const shouldAnimate = isFirstRender && !!currentLayout.animation?.enter;\n isFirstRender = false;\n\n // Render\n const animation = shouldAnimate ? currentLayout.animation : undefined;\n svgElement = renderSankeySVG(currentLayout, animation);\n container.appendChild(svgElement);\n\n // Dark mode class on container\n const isDark = resolveDarkMode(options?.darkMode);\n if (isDark) {\n container.classList.add('oc-dark');\n } else {\n container.classList.remove('oc-dark');\n }\n\n // Wire tooltip + interaction events\n if (options?.tooltip !== false && svgElement) {\n if (!tooltipManager) {\n tooltipManager = createTooltipManager(container);\n }\n }\n cleanupTooltipEvents = wireTooltipAndInteraction(svgElement, currentLayout);\n\n // Animation cleanup on first render\n if (shouldAnimate && svgElement) {\n animationCleanup = setupAnimationCleanup(svgElement, () => {\n animationCleanup = null;\n if (pendingResize) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n\n // This render recompiled with the loaded webfonts; publish 'ready' now\n // rather than right after the fonts-ready resize() (which may have deferred\n // to pendingResize during the entrance animation).\n if (fontsReloadPending) {\n fontsReloadPending = false;\n container.dataset.ocFontsState = 'ready';\n }\n if (svgElement) restoreMarkFocus(svgElement, focusedMark);\n }\n\n // ---------------------------------------------------------------------------\n // Public API\n // ---------------------------------------------------------------------------\n\n function update(newSpec: SankeySpec): void {\n if (destroyed) return;\n // Compile before adopting an edit: a rejected spec must leave the last\n // valid view, its interactions, and future resize/export calls intact.\n const nextFont = resolveEffectiveFont(newSpec);\n const nextMeasure = nextFont === fontFamily ? measureText : createMeasureText(nextFont);\n const nextLayout = compile(newSpec, nextMeasure);\n currentSpec = newSpec;\n fontFamily = nextFont;\n measureText = nextMeasure;\n\n render(nextLayout);\n }\n\n function resize(): void {\n if (destroyed) return;\n // Skip resize during entrance animation to avoid tearing down the animated SVG.\n // Queued resizes replay once animation completes.\n if (animationCleanup) {\n pendingResize = true;\n return;\n }\n render();\n }\n\n function doExport(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n exportOptions?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string> {\n if (!svgElement) {\n throw new Error('Sankey is not rendered yet');\n }\n\n // Export settled geometry, independent of transient hover and animation.\n const terminalSvg = renderSankeySVG(currentLayout);\n const resolvedOptions = { theme: currentLayout.theme, ...exportOptions };\n\n switch (format) {\n case 'svg':\n return exportSVG(terminalSvg);\n case 'svg-with-fonts':\n return exportSVGWithFonts(terminalSvg, resolvedOptions);\n case 'png':\n return exportPNG(terminalSvg, resolvedOptions);\n case 'jpg':\n return exportJPG(terminalSvg, resolvedOptions);\n default:\n throw new Error(`Unsupported export format: ${format}`);\n }\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n // Cancel entrance animations\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n pendingResize = false;\n }\n if (svgElement) {\n cancelAnimations(svgElement);\n }\n\n // Disconnect resize observer\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n\n // Clean up tooltip events\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n // Destroy tooltip manager\n if (tooltipManager) {\n tooltipManager.destroy();\n tooltipManager = null;\n }\n\n // Remove SVG\n if (svgElement?.parentNode) {\n svgElement.parentNode.removeChild(svgElement);\n }\n svgElement = null;\n\n container.classList.remove('oc-dark');\n container.classList.remove('oc-sankey-root');\n }\n\n // ---------------------------------------------------------------------------\n // Initialize\n // ---------------------------------------------------------------------------\n\n try {\n currentLayout = compile();\n\n // Determine if we should animate\n const shouldAnimate = !!currentLayout.animation?.enter;\n isFirstRender = false;\n\n // Render\n const animation = shouldAnimate ? currentLayout.animation : undefined;\n svgElement = renderSankeySVG(currentLayout, animation);\n container.appendChild(svgElement);\n\n // Dark mode class on container\n const isDark = resolveDarkMode(options?.darkMode);\n if (isDark) {\n container.classList.add('oc-dark');\n } else {\n container.classList.remove('oc-dark');\n }\n\n // Wire tooltip + interaction events\n if (options?.tooltip !== false && svgElement) {\n tooltipManager = createTooltipManager(container);\n }\n cleanupTooltipEvents = wireTooltipAndInteraction(svgElement, currentLayout);\n\n // Animation cleanup\n if (shouldAnimate && svgElement) {\n animationCleanup = setupAnimationCleanup(svgElement, () => {\n animationCleanup = null;\n if (pendingResize) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n } catch (err) {\n console.error('[viz] Sankey mount failed:', err);\n // Re-throw so callers can handle the error rather than silently returning a broken instance\n throw err;\n }\n\n // Recompile once after webfonts load so late-swapping fonts don't leave\n // node labels measured against fallback metrics.\n const fontsPending = scheduleFontReload(\n fontFamily,\n () => !destroyed,\n () => {\n // Mark the reload owed, then recompile. render() flips the attribute to\n // 'ready' once it actually recompiles, including the pendingResize replay\n // after the entrance animation finishes.\n fontsReloadPending = true;\n resize();\n },\n );\n container.dataset.ocFontsState = fontsPending ? 'pending' : 'ready';\n\n // Responsive resize\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => {\n resize();\n });\n }\n\n return {\n update,\n resize,\n export: doExport,\n destroy,\n get layout() {\n return currentLayout;\n },\n };\n}\n","/**\n * Sankey SVG renderer: converts a SankeyLayout into SVG DOM elements.\n *\n * Creates an <svg> with gradient defs, links (behind), nodes, labels,\n * legend, and chrome. All styling via inline SVG attributes from layout data.\n * Animation is pure CSS, driven by data attributes and CSS custom properties.\n */\n\nimport type {\n CategoricalLegendLayout,\n LegendLayout,\n MeasureTextFn,\n ResolvedAnimation,\n SankeyLayout,\n SankeyLinkMark,\n SankeyNodeMark,\n} from '@opendata-ai/openchart-core';\nimport {\n BRAND_FONT_SIZE,\n BRAND_MIN_WIDTH,\n estimateTextWidth,\n wrapText,\n} from '@opendata-ai/openchart-core';\nimport { clampStaggerDelay } from '@opendata-ai/openchart-engine';\nimport { stampAnimationVars } from './animation-vars';\nimport { renderChromeElement } from './renderers/chrome';\nimport { applyTextStyle } from './renderers/svg-dom';\n\nconst SVG_NS = 'http://www.w3.org/2000/svg';\nconst XLINK_NS = 'http://www.w3.org/1999/xlink';\nconst BRAND_URL = 'https://tryopendata.ai';\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction createSVGElement(tag: string): SVGElement {\n return document.createElementNS(SVG_NS, tag);\n}\n\nfunction setAttrs(el: SVGElement, attrs: Record<string, string | number>): void {\n for (const [key, value] of Object.entries(attrs)) {\n el.setAttribute(key, String(value));\n }\n}\n\n/**\n * Stamp animation index attributes on a mark element when animation is enabled.\n */\nfunction stampAnimationAttrs(\n el: SVGElement,\n mark: { animationIndex?: number },\n fallbackIndex: number,\n animation?: ResolvedAnimation,\n): void {\n if (!animation?.enter) return;\n const idx = mark.animationIndex ?? fallbackIndex;\n el.setAttribute('data-animation-index', String(idx));\n (el as SVGElement & ElementCSSInlineStyle).style.setProperty('--oc-mark-index', String(idx));\n}\n\n// ---------------------------------------------------------------------------\n// Chrome rendering\n// ---------------------------------------------------------------------------\n\nfunction renderChrome(parent: SVGElement, layout: SankeyLayout): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-chrome');\n\n const { chrome, measureText } = layout;\n\n if (chrome.title) {\n renderChromeElement(g, chrome.title, 'oc-title', 'title', measureText);\n }\n if (chrome.subtitle) {\n renderChromeElement(g, chrome.subtitle, 'oc-subtitle', 'subtitle', measureText);\n }\n\n // Bottom chrome: positioned below the sankey drawing area.\n // Sankey has no x-axis, so no extra axis extent to account for.\n const bottomOffset = layout.area.y + layout.area.height;\n if (chrome.source) {\n renderChromeElement(\n g,\n { ...chrome.source, y: bottomOffset + chrome.source.y },\n 'oc-source',\n 'source',\n measureText,\n );\n }\n if (chrome.byline) {\n renderChromeElement(\n g,\n { ...chrome.byline, y: bottomOffset + chrome.byline.y },\n 'oc-byline',\n 'byline',\n measureText,\n );\n }\n if (chrome.footer) {\n renderChromeElement(\n g,\n { ...chrome.footer, y: bottomOffset + chrome.footer.y },\n 'oc-footer',\n 'footer',\n measureText,\n );\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Brand rendering\n// ---------------------------------------------------------------------------\n\nfunction renderBrand(parent: SVGElement, layout: SankeyLayout): void {\n if (layout.dimensions.width < BRAND_MIN_WIDTH) return;\n\n const { width } = layout.dimensions;\n const padding = layout.theme.spacing.padding;\n const rightEdge = width - padding;\n const fill = layout.theme.colors.axis;\n\n const bottomOffset = layout.area.y + layout.area.height;\n const { chrome } = layout;\n const firstBottom = chrome.source ?? chrome.byline ?? chrome.footer;\n const chromeY = firstBottom\n ? bottomOffset + firstBottom.y\n : bottomOffset + layout.theme.spacing.chartToFooter;\n\n const a = createSVGElement('a');\n a.setAttribute('href', BRAND_URL);\n a.setAttributeNS(XLINK_NS, 'xlink:href', BRAND_URL);\n a.setAttribute('target', '_blank');\n a.setAttribute('rel', 'noopener');\n a.setAttribute('class', 'oc-chrome-ref');\n\n const BRAND_LARGE = 16;\n const text = createSVGElement('text');\n setAttrs(text, {\n x: rightEdge,\n y: chromeY + BRAND_LARGE,\n 'dominant-baseline': 'alphabetic',\n 'text-anchor': 'end',\n 'font-family': layout.theme.fonts.family,\n 'font-size': BRAND_FONT_SIZE,\n 'fill-opacity': 0.55,\n });\n (text as SVGElement & ElementCSSInlineStyle).style.setProperty('fill', fill);\n\n const trySpan = createSVGElement('tspan');\n setAttrs(trySpan, { 'font-weight': 500 });\n trySpan.textContent = 'try';\n\n const openDataSpan = createSVGElement('tspan');\n setAttrs(openDataSpan, { 'font-weight': 600, 'font-size': BRAND_LARGE });\n openDataSpan.textContent = 'OpenData';\n\n const aiSpan = createSVGElement('tspan');\n setAttrs(aiSpan, { 'font-weight': 500 });\n aiSpan.textContent = '.ai';\n\n text.appendChild(trySpan);\n text.appendChild(openDataSpan);\n text.appendChild(aiSpan);\n a.appendChild(text);\n parent.appendChild(a);\n}\n\n// ---------------------------------------------------------------------------\n// Legend rendering\n// ---------------------------------------------------------------------------\n\nfunction renderLegend(parent: SVGElement, legendLayout: LegendLayout): void {\n if (!('entries' in legendLayout) || legendLayout.entries.length === 0) return;\n const legend = legendLayout as CategoricalLegendLayout;\n\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-legend');\n g.setAttribute('role', 'list');\n g.setAttribute('aria-label', 'Chart legend');\n\n const isHorizontal = legend.position === 'top' || legend.position === 'bottom';\n let offsetX = legend.bounds.x;\n let offsetY = legend.bounds.y;\n\n for (let i = 0; i < legend.entries.length; i++) {\n const entry = legend.entries[i];\n\n // Wrap to next line if this entry would overflow bounds\n if (isHorizontal && i > 0) {\n const labelWidth = estimateTextWidth(\n entry.label,\n legend.labelStyle.fontSize,\n legend.labelStyle.fontWeight,\n );\n const entryWidth = legend.swatchSize + legend.swatchGap + labelWidth + legend.entryGap;\n if (offsetX + entryWidth > legend.bounds.x + legend.bounds.width) {\n offsetX = legend.bounds.x;\n offsetY += legend.swatchSize + 6;\n }\n }\n\n const entryG = createSVGElement('g');\n entryG.setAttribute('class', 'oc-legend-entry');\n entryG.setAttribute('role', 'listitem');\n entryG.setAttribute('data-legend-index', String(i));\n entryG.setAttribute('data-legend-label', entry.label);\n\n if (entry.overflow) {\n entryG.setAttribute('data-legend-overflow', 'true');\n entryG.setAttribute('aria-label', entry.label);\n entryG.setAttribute('opacity', '0.5');\n } else {\n entryG.setAttribute(\n 'aria-label',\n `${entry.label}: ${entry.active !== false ? 'visible' : 'hidden'}`,\n );\n entryG.setAttribute('style', 'cursor: pointer');\n if (entry.active === false) {\n entryG.setAttribute('opacity', '0.3');\n }\n }\n\n // Swatch (always rect for sankey)\n const rect = createSVGElement('rect');\n setAttrs(rect, {\n x: offsetX,\n y: offsetY,\n width: legend.swatchSize,\n height: legend.swatchSize,\n fill: entry.color,\n rx: 2,\n });\n entryG.appendChild(rect);\n\n // Label\n const label = createSVGElement('text');\n setAttrs(label, {\n x: offsetX + legend.swatchSize + legend.swatchGap,\n y: offsetY + legend.swatchSize / 2,\n 'dominant-baseline': 'central',\n });\n applyTextStyle(label, legend.labelStyle);\n label.textContent = entry.label;\n entryG.appendChild(label);\n\n g.appendChild(entryG);\n\n // Advance position for next entry\n if (isHorizontal) {\n const labelWidth = estimateTextWidth(\n entry.label,\n legend.labelStyle.fontSize,\n legend.labelStyle.fontWeight,\n );\n const entryWidth = legend.swatchSize + legend.swatchGap + labelWidth + legend.entryGap;\n offsetX += entryWidth;\n } else {\n offsetY += legend.swatchSize + legend.entryGap;\n }\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Gradient defs\n// ---------------------------------------------------------------------------\n\n/**\n * Build a node position lookup for gradient x1/x2 coordinates.\n * Maps nodeId to { x, width } so we can compute gradient endpoints.\n */\nfunction buildNodePositionMap(nodes: SankeyNodeMark[]): Map<string, { x: number; width: number }> {\n const map = new Map<string, { x: number; width: number }>();\n for (const node of nodes) {\n map.set(node.nodeId, { x: node.x, width: node.width });\n }\n return map;\n}\n\n/** Sanitize a string for use as an SVG element ID (no spaces, $, or other invalid chars). */\nfunction sanitizeId(s: string): string {\n return s.replace(/[^a-zA-Z0-9_-]/g, '_');\n}\n\nfunction renderGradientDefs(\n defs: SVGElement,\n links: SankeyLinkMark[],\n nodePositions: Map<string, { x: number; width: number }>,\n): void {\n for (let i = 0; i < links.length; i++) {\n const link = links[i];\n // Only create gradients when source and target colors differ\n if (link.sourceColor === link.targetColor) continue;\n\n // Use sanitized node names for debuggability, with index suffix for uniqueness\n const gradId = `oc-sg-${sanitizeId(link.sourceId)}-${sanitizeId(link.targetId)}-${i}`;\n const gradient = createSVGElement('linearGradient');\n gradient.setAttribute('id', gradId);\n gradient.setAttribute('gradientUnits', 'userSpaceOnUse');\n\n // x1 = right edge of source node, x2 = left edge of target node\n const sourcePos = nodePositions.get(link.sourceId);\n const targetPos = nodePositions.get(link.targetId);\n const x1 = sourcePos ? sourcePos.x + sourcePos.width : 0;\n const x2 = targetPos ? targetPos.x : 0;\n\n gradient.setAttribute('x1', String(x1));\n gradient.setAttribute('x2', String(x2));\n\n const stop0 = createSVGElement('stop');\n setAttrs(stop0, { offset: '0%', 'stop-color': link.sourceColor });\n gradient.appendChild(stop0);\n\n const stop1 = createSVGElement('stop');\n setAttrs(stop1, { offset: '100%', 'stop-color': link.targetColor });\n gradient.appendChild(stop1);\n\n defs.appendChild(gradient);\n }\n}\n\n// ---------------------------------------------------------------------------\n// Links rendering\n// ---------------------------------------------------------------------------\n\nfunction renderLinks(\n parent: SVGElement,\n links: SankeyLinkMark[],\n _nodePositions: Map<string, { x: number; width: number }>,\n animation?: ResolvedAnimation,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-sankey-links');\n\n for (let i = 0; i < links.length; i++) {\n const link = links[i];\n\n const linkG = createSVGElement('g');\n linkG.setAttribute('class', 'oc-sankey-link');\n linkG.setAttribute('data-mark-id', `link-${link.sourceId}-${link.targetId}-${i}`);\n linkG.setAttribute('data-source', link.sourceId);\n linkG.setAttribute('data-target', link.targetId);\n\n if (link.aria?.label) {\n linkG.setAttribute('aria-label', link.aria.label);\n }\n\n stampAnimationAttrs(linkG, link, i, animation);\n\n const path = createSVGElement('path');\n path.setAttribute('d', link.path);\n path.setAttribute('stroke', 'none');\n path.setAttribute('fill-opacity', String(link.fillOpacity));\n\n // Use gradient fill when colors differ, otherwise solid fill\n if (link.sourceColor !== link.targetColor) {\n const gradId = `oc-sg-${sanitizeId(link.sourceId)}-${sanitizeId(link.targetId)}-${i}`;\n path.setAttribute('fill', `url(#${gradId})`);\n } else {\n path.setAttribute('fill', link.sourceColor);\n }\n\n linkG.appendChild(path);\n g.appendChild(linkG);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Nodes rendering\n// ---------------------------------------------------------------------------\n\nfunction renderNodes(\n parent: SVGElement,\n nodes: SankeyNodeMark[],\n animation?: ResolvedAnimation,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-sankey-nodes');\n\n for (let i = 0; i < nodes.length; i++) {\n const node = nodes[i];\n\n const nodeG = createSVGElement('g');\n nodeG.setAttribute('class', 'oc-sankey-node');\n nodeG.setAttribute('data-mark-id', `node-${node.nodeId}`);\n nodeG.setAttribute('data-node-id', node.nodeId);\n\n if (node.aria?.label) {\n nodeG.setAttribute('aria-label', node.aria.label);\n }\n\n stampAnimationAttrs(nodeG, node, i, animation);\n\n const rect = createSVGElement('rect');\n setAttrs(rect, {\n x: node.x,\n y: node.y,\n width: node.width,\n height: Math.max(node.height, 1), // Ensure at least 1px visibility\n fill: node.fill,\n rx: node.cornerRadius,\n });\n\n if (node.stroke) {\n rect.setAttribute('stroke', node.stroke);\n }\n if (node.strokeWidth) {\n rect.setAttribute('stroke-width', String(node.strokeWidth));\n }\n\n nodeG.appendChild(rect);\n g.appendChild(nodeG);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Labels rendering\n// ---------------------------------------------------------------------------\n\nfunction renderLabels(\n parent: SVGElement,\n nodes: SankeyNodeMark[],\n measureText?: MeasureTextFn,\n): void {\n const g = createSVGElement('g');\n g.setAttribute('class', 'oc-sankey-labels');\n\n for (const node of nodes) {\n const { label } = node;\n if (!label.visible) continue;\n\n const text = createSVGElement('text');\n setAttrs(text, { x: label.x, y: label.y });\n applyTextStyle(text, label.style);\n // Path highlighting dims labels alongside their node.\n text.setAttribute('class', 'oc-sankey-label');\n text.setAttribute('data-node-id', node.nodeId);\n\n const fontSize = label.style.fontSize ?? 12;\n const fontWeight = label.style.fontWeight ?? 400;\n\n // Wrap label text when maxWidth is set and text would overflow\n let lines = [label.text];\n if (label.maxWidth !== undefined && label.maxWidth > 0) {\n lines = wrapText(label.text, fontSize, fontWeight, label.maxWidth, measureText);\n }\n\n if (lines.length > 1) {\n const lineHeight = fontSize * (label.style.lineHeight ?? 1.3);\n // Center the multi-line block vertically around the label y position\n const totalHeight = (lines.length - 1) * lineHeight;\n const startY = label.y - totalHeight / 2;\n for (let i = 0; i < lines.length; i++) {\n const tspan = createSVGElement('tspan');\n tspan.setAttribute('x', String(label.x));\n tspan.setAttribute('y', String(startY + i * lineHeight));\n tspan.textContent = lines[i];\n text.appendChild(tspan);\n }\n } else {\n text.textContent = lines[0];\n }\n\n // The node's value rides the last line as a lighter tabular tspan. It\n // carries no x/y, so it stays in the same text chunk and the anchor\n // (start or end) still applies to name + value as one block.\n if (node.valueLabel) {\n // A bare textContent has to become a tspan first, or the value tspan\n // would render before it.\n if (text.childNodes.length === 0) {\n const nameSpan = createSVGElement('tspan');\n nameSpan.textContent = text.textContent;\n text.textContent = '';\n text.appendChild(nameSpan);\n }\n const valueSpan = createSVGElement('tspan');\n valueSpan.setAttribute('class', 'oc-sankey-label-value');\n valueSpan.setAttribute('dx', '5');\n applyTextStyle(valueSpan, node.valueLabel.style);\n valueSpan.textContent = node.valueLabel.text;\n text.appendChild(valueSpan);\n }\n\n g.appendChild(text);\n }\n\n parent.appendChild(g);\n}\n\n// ---------------------------------------------------------------------------\n// Main render function\n// ---------------------------------------------------------------------------\n\n/**\n * Render a SankeyLayout into an SVG element.\n *\n * The SVG structure is: background > defs (gradients) > links > nodes > labels > legend > chrome > brand.\n * Links render before nodes so they appear visually behind.\n */\nexport function renderSankeySVG(\n layout: SankeyLayout,\n animation?: ResolvedAnimation,\n): SVGSVGElement {\n const { width, height } = layout.dimensions;\n\n const svg = createSVGElement('svg') as SVGSVGElement;\n setAttrs(svg, {\n viewBox: `0 0 ${width} ${height}`,\n xmlns: SVG_NS,\n overflow: 'visible',\n });\n svg.style.height = `${height}px`;\n svg.setAttribute('role', layout.a11y.role);\n svg.setAttribute('aria-label', layout.a11y.altText);\n\n // Classes: oc-chart oc-sankey, plus oc-animate if animated\n const enterPhase = animation?.enter;\n const animate = !!enterPhase;\n const classes = animate ? 'oc-chart oc-sankey oc-animate' : 'oc-chart oc-sankey';\n svg.setAttribute('class', classes);\n\n // Set animation CSS custom properties when the enter phase is enabled\n if (enterPhase) {\n const totalMarks = layout.nodes.length + layout.links.length;\n const stagger = clampStaggerDelay(enterPhase.staggerDelay, totalMarks);\n stampAnimationVars(svg, {\n duration: enterPhase.duration,\n spring: enterPhase.spring,\n stagger,\n annotationDelay: animation!.annotationDelay,\n ease: enterPhase.ease,\n });\n }\n\n // Background\n const bg = createSVGElement('rect');\n bg.setAttribute('class', 'oc-background');\n setAttrs(bg, {\n x: 0,\n y: 0,\n width,\n height,\n fill: layout.theme.colors.background,\n });\n svg.appendChild(bg);\n\n // Defs: gradient definitions for links\n const nodePositions = buildNodePositionMap(layout.nodes);\n const defs = createSVGElement('defs');\n renderGradientDefs(defs, layout.links, nodePositions);\n svg.appendChild(defs);\n\n // Links (behind nodes)\n renderLinks(svg, layout.links, nodePositions, animation);\n\n // Nodes\n renderNodes(svg, layout.nodes, animation);\n\n // Labels\n renderLabels(svg, layout.nodes, layout.measureText);\n\n // Legend\n renderLegend(svg, layout.legend);\n\n // Chrome (title, subtitle, source, byline, footer) renders on top\n renderChrome(svg, layout);\n\n // Brand\n if (layout.watermark) {\n renderBrand(svg, layout);\n }\n\n return svg;\n}\n","/**\n * Table keyboard navigation: arrow-key cell navigation, Enter to sort,\n * Escape to clear search, and aria-activedescendant management.\n *\n * Designed to be wired up by table-mount.ts after render. Returns a\n * cleanup function to remove listeners on re-render or destroy.\n */\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface KeyboardNavOptions {\n /** The wrapper element containing the whole table UI. */\n wrapper: HTMLElement;\n /** Logical cell to restore after a resize, sort, or data update. */\n initialCell?: { rowId: string; columnKey: string };\n /** Callback to trigger sort on a column. */\n onSort: (columnKey: string) => void;\n /** Activate the focused row through the host's existing row-click callback. */\n onRowActivate?: (rowId: string) => void;\n /** Callback to clear search and return focus to the table body. */\n onClearSearch: () => void;\n /** Callback to announce text to screen readers via the live region. */\n onAnnounce: (message: string) => void;\n}\n\ninterface CellPosition {\n row: number;\n col: number;\n}\n\n// ---------------------------------------------------------------------------\n// Main\n// ---------------------------------------------------------------------------\n\nlet navigationId = 0;\n\n/**\n * Attach keyboard navigation to a rendered table.\n *\n * @returns A cleanup function that removes all event listeners.\n */\nexport function attachKeyboardNav(options: KeyboardNavOptions): () => void {\n const { wrapper, onSort, onClearSearch, onAnnounce } = options;\n\n let focusedCell: CellPosition = { row: -1, col: 0 };\n const idPrefix = `oc-table-${++navigationId}`;\n\n const table = wrapper.querySelector('table');\n if (!table) return () => {};\n\n const tbody = table.querySelector('tbody');\n const thead = table.querySelector('thead');\n if (!tbody || !thead) return () => {};\n\n // Make tbody focusable\n tbody.setAttribute('tabindex', '0');\n\n function getRows(): HTMLTableRowElement[] {\n if (!tbody) return [];\n return Array.from(tbody.querySelectorAll('tr'));\n }\n\n function getHeaderCells(): HTMLTableCellElement[] {\n if (!thead) return [];\n const headerRow = thead.querySelector('tr');\n if (!headerRow) return [];\n return Array.from(headerRow.querySelectorAll('th')).filter((cell) => !cell.hidden);\n }\n\n function getCellsInRow(tr: HTMLTableRowElement): HTMLTableCellElement[] {\n return Array.from(tr.querySelectorAll('td')).filter((cell) => !cell.hidden);\n }\n\n function getColCount(): number {\n const rows = getRows();\n if (rows.length === 0) return getHeaderCells().length;\n return getCellsInRow(rows[0]).length;\n }\n\n function clearFocusHighlight(): void {\n const prev = wrapper.querySelector('.oc-table-cell-focus');\n if (prev) {\n prev.classList.remove('oc-table-cell-focus');\n prev.removeAttribute('id');\n }\n }\n\n function setFocusedCell(row: number, col: number): void {\n clearFocusHighlight();\n const rows = getRows();\n const colCount = getColCount();\n\n // Clamp values\n if (rows.length === 0) return;\n row = Math.max(0, Math.min(row, rows.length - 1));\n col = Math.max(0, Math.min(col, colCount - 1));\n\n focusedCell = { row, col };\n\n // Highlight the cell\n const tr = rows[row];\n if (!tr) return;\n const cells = getCellsInRow(tr);\n const cell = cells[col];\n if (!cell) return;\n\n const cellId = `${idPrefix}-cell-${row}-${col}`;\n cell.id = cellId;\n cell.classList.add('oc-table-cell-focus');\n cell.setAttribute('data-row', String(row));\n cell.setAttribute('data-col', String(col));\n\n // Set aria-activedescendant on tbody\n if (tbody) {\n tbody.setAttribute('aria-activedescendant', cellId);\n }\n\n // Scroll cell into view if needed\n cell.scrollIntoView({ block: 'nearest', inline: 'nearest' });\n }\n\n function handleTbodyFocus(): void {\n // When tbody receives focus, highlight the first cell (or restore last)\n if (focusedCell.row < 0) {\n const row = getRows().findIndex(\n (item) => item.getAttribute('data-row-id') === options.initialCell?.rowId,\n );\n const col = getHeaderCells().findIndex(\n (item) => item.getAttribute('data-column') === options.initialCell?.columnKey,\n );\n setFocusedCell(Math.max(0, row), Math.max(0, col));\n } else {\n setFocusedCell(focusedCell.row, focusedCell.col);\n }\n }\n\n function handleTbodyKeydown(e: KeyboardEvent): void {\n // Native links and priority-row disclosures own their keyboard behavior.\n if (e.target !== tbody) return;\n const rows = getRows();\n if (rows.length === 0) return;\n\n const colCount = getColCount();\n const { row, col } = focusedCell;\n\n switch (e.key) {\n case 'Enter':\n case ' ': {\n const rowId = rows[Math.max(row, 0)]?.getAttribute('data-row-id');\n if (rowId && options.onRowActivate) {\n e.preventDefault();\n options.onRowActivate(rowId);\n }\n break;\n }\n case 'ArrowDown':\n e.preventDefault();\n if (row < rows.length - 1) {\n setFocusedCell(row + 1, col);\n }\n break;\n case 'ArrowUp':\n e.preventDefault();\n if (row > 0) {\n setFocusedCell(row - 1, col);\n } else {\n // Move focus to the header\n focusHeaderCell(col);\n }\n break;\n case 'ArrowRight':\n e.preventDefault();\n if (col < colCount - 1) {\n setFocusedCell(row, col + 1);\n }\n break;\n case 'ArrowLeft':\n e.preventDefault();\n if (col > 0) {\n setFocusedCell(row, col - 1);\n }\n break;\n case 'Home':\n e.preventDefault();\n setFocusedCell(row, 0);\n break;\n case 'End':\n e.preventDefault();\n setFocusedCell(row, colCount - 1);\n break;\n }\n }\n\n // Header cell keyboard handling\n function focusHeaderCell(col: number): void {\n const headers = getHeaderCells();\n if (col >= 0 && col < headers.length) {\n clearFocusHighlight();\n headers[col].focus();\n }\n }\n\n function handleHeaderKeydown(e: KeyboardEvent): void {\n const th = e.currentTarget as HTMLTableCellElement;\n const headers = getHeaderCells();\n const colIndex = headers.indexOf(th);\n if (colIndex < 0) return;\n\n switch (e.key) {\n case 'ArrowRight':\n e.preventDefault();\n if (colIndex < headers.length - 1) {\n headers[colIndex + 1].focus();\n }\n break;\n case 'ArrowLeft':\n e.preventDefault();\n if (colIndex > 0) {\n headers[colIndex - 1].focus();\n }\n break;\n case 'ArrowDown':\n e.preventDefault();\n // Move focus to first body row at this column\n if (tbody) {\n tbody.focus();\n setFocusedCell(0, colIndex);\n }\n break;\n case 'Enter':\n case ' ': {\n e.preventDefault();\n const sortColumn = th.getAttribute('data-column');\n const sortBtn = th.querySelector('[data-sort-column]');\n if (sortColumn && sortBtn) {\n onSort(sortColumn);\n }\n break;\n }\n }\n }\n\n // Search escape handling\n const searchInput = wrapper.querySelector('.oc-table-search input') as HTMLInputElement | null;\n\n function handleSearchKeydown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n onClearSearch();\n // The host may replace the body; focus the old one only if it survived.\n if (tbody?.isConnected) {\n tbody.focus();\n onAnnounce('Search cleared');\n }\n }\n }\n\n // Wire up event listeners\n tbody.addEventListener('focus', handleTbodyFocus);\n tbody.addEventListener('keydown', handleTbodyKeydown as EventListener);\n\n // Make header cells focusable and wire keyboard\n const headerCells = getHeaderCells();\n for (const th of headerCells) {\n th.setAttribute('tabindex', '0');\n th.addEventListener('keydown', handleHeaderKeydown as EventListener);\n }\n\n if (searchInput) {\n searchInput.addEventListener('keydown', handleSearchKeydown as EventListener);\n }\n\n // Cleanup\n return () => {\n tbody.removeEventListener('focus', handleTbodyFocus);\n tbody.removeEventListener('keydown', handleTbodyKeydown as EventListener);\n\n for (const th of headerCells) {\n th.removeEventListener('keydown', handleHeaderKeydown as EventListener);\n }\n\n if (searchInput) {\n searchInput.removeEventListener('keydown', handleSearchKeydown as EventListener);\n }\n\n clearFocusHighlight();\n };\n}\n","import type { TableLayout } from '@opendata-ai/openchart-core';\n\n/** Keep identifying/priority columns comparable; reveal secondary evidence per row. */\nexport function applyPriorityTable(\n wrapper: HTMLElement,\n layout: TableLayout,\n enabled: boolean,\n): void {\n wrapper.classList.toggle('oc-table--priority', enabled);\n for (const old of wrapper.querySelectorAll('.oc-table-details')) old.remove();\n const secondary = layout.columns.flatMap((column, index) => (column.priority > 1 ? [index] : []));\n const hidden = new Set(secondary);\n for (const row of wrapper.querySelectorAll('thead tr, tbody tr, tfoot tr')) {\n const cells = Array.from(row.children) as HTMLElement[];\n cells.forEach((cell, index) => {\n cell.hidden = enabled && hidden.has(index);\n });\n if (!enabled || !secondary.length) continue;\n const cell = document.createElement(row.parentElement?.tagName === 'THEAD' ? 'th' : 'td');\n cell.className = 'oc-table-details';\n if (cell.tagName === 'TH') {\n cell.textContent = 'Details';\n cell.setAttribute('scope', 'col');\n } else if (row.parentElement?.tagName === 'TBODY') {\n const details = document.createElement('details');\n const summary = document.createElement('summary');\n summary.textContent = 'More';\n summary.setAttribute('aria-label', `More details for ${cells[0]?.textContent ?? 'row'}`);\n details.appendChild(summary);\n const list = document.createElement('dl');\n for (const index of secondary) {\n const term = document.createElement('dt');\n term.textContent = layout.columns[index].label;\n const description = document.createElement('dd');\n // Clone cell content, not the td: table semantics stay valid.\n for (const child of Array.from(cells[index]?.childNodes ?? []))\n description.appendChild(child.cloneNode(true));\n list.append(term, description);\n }\n details.appendChild(list);\n details.addEventListener('click', (event) => event.stopPropagation());\n cell.appendChild(details);\n }\n row.appendChild(cell);\n }\n}\n","import { applyPriorityTable } from './table-responsive';\n/**\n * Table mount API: the main entry point for vanilla JS table usage.\n *\n * createTable() takes a container, spec, and options, compiles the table,\n * renders it as HTML, sets up responsive resizing, sort/search/pagination\n * interactivity, and returns a TableInstance with update/resize/export/destroy.\n *\n * Supports both controlled and uncontrolled modes:\n * - Uncontrolled (default): manages sort/search/page internally\n * - Controlled: reads state from externalState, fires onStateChange\n */\n\nimport type {\n CompileTableOptions,\n DarkMode,\n SortState,\n TableLayout,\n TableSpec,\n ThemeConfig,\n} from '@opendata-ai/openchart-core';\nimport { BREAKPOINT_COMPACT_MAX } from '@opendata-ai/openchart-core';\nimport { compileTable } from '@opendata-ai/openchart-engine';\nimport { setupTableAnimationCleanup } from './animation';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { attachKeyboardNav } from './table-keyboard';\nimport { renderTable } from './table-renderer';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/** Width a text column needs before its values start wrapping. */\nconst MIN_READABLE_COLUMN_WIDTH = 96;\n\n/** Below this width even a two-column table reads better condensed. */\nconst AUTO_CONDENSE_MAX_WIDTH = 560;\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface TableState {\n sort: SortState | null;\n search: string;\n page: number;\n}\n\nexport interface TableMountOptions {\n theme?: ThemeConfig;\n darkMode?: DarkMode;\n responsive?: boolean;\n /** Show the OpenData watermark. Defaults to true. */\n watermark?: boolean;\n onRowClick?: (row: Record<string, unknown>) => void;\n onStateChange?: (state: TableState) => void;\n externalState?: { sort?: SortState | null; search?: string; page?: number };\n}\n\nexport interface TableInstance {\n update(spec: TableSpec): void;\n resize(): void;\n export(format: 'csv'): string;\n getState(): TableState;\n setState(partial: Partial<TableState>): void;\n destroy(): void;\n}\n\n// ---------------------------------------------------------------------------\n// CSV export\n// ---------------------------------------------------------------------------\n\nfunction csvEscape(value: string): string {\n if (value.includes(',') || value.includes('\"') || value.includes('\\n') || value.includes('\\r')) {\n return `\"${value.replace(/\"/g, '\"\"')}\"`;\n }\n return value;\n}\n\n// ---------------------------------------------------------------------------\n// Sort cycling\n// ---------------------------------------------------------------------------\n\n/**\n * Cycle sort state: clicking same column cycles none -> asc -> desc -> none.\n * Clicking a different column resets to asc.\n */\nfunction cycleSort(current: SortState | null, column: string): SortState | null {\n if (!current || current.column !== column) {\n return { column, direction: 'asc' };\n }\n if (current.direction === 'asc') {\n return { column, direction: 'desc' };\n }\n // desc -> none\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a table instance from a spec and mount it into a container.\n *\n * @param container - The DOM element to render into.\n * @param spec - The table spec.\n * @param options - Mount options.\n * @returns A TableInstance with update/resize/export/destroy methods.\n */\nexport function createTable(\n container: HTMLElement,\n spec: TableSpec,\n options?: TableMountOptions,\n): TableInstance {\n let currentSpec = spec;\n let currentLayout: TableLayout;\n let wrapperElement: HTMLElement | null = null;\n let disconnectResize: (() => void) | null = null;\n let cleanupKeyboard: (() => void) | null = null;\n let cleanupAnimations: (() => void) | null = null;\n let pendingResize = false;\n let isFirstRender = true;\n let destroyed = false;\n // Whether the user has touched sorting. Once they have, a null sort means\n // \"explicitly unsorted\" and must not fall back to the spec/bar-column default.\n let sortTouched = false;\n\n // Internal state (used in uncontrolled mode)\n const internalState: TableState = {\n sort: null,\n search: '',\n page: 0,\n };\n\n // Debounce timers\n let searchDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n let resizeDebounceTimer: ReturnType<typeof setTimeout> | null = null;\n\n const isControlled = options?.externalState !== undefined;\n\n function getState(): TableState {\n if (isControlled && options?.externalState) {\n return {\n sort: options.externalState.sort ?? null,\n search: options.externalState.search ?? '',\n page: options.externalState.page ?? 0,\n };\n }\n return { ...internalState };\n }\n\n function updateState(partial: Partial<TableState>): void {\n if (isControlled) {\n // In controlled mode, notify parent\n const current = getState();\n const next: TableState = {\n sort: partial.sort !== undefined ? partial.sort : current.sort,\n search: partial.search !== undefined ? partial.search : current.search,\n page: partial.page !== undefined ? partial.page : current.page,\n };\n if (partial.sort !== undefined) sortTouched = true;\n options?.onStateChange?.(next);\n } else {\n // In uncontrolled mode, update internal state\n if (partial.sort !== undefined) {\n internalState.sort = partial.sort;\n sortTouched = true;\n }\n if (partial.search !== undefined) internalState.search = partial.search;\n if (partial.page !== undefined) internalState.page = partial.page;\n options?.onStateChange?.({ ...internalState });\n }\n }\n\n function compile(candidate = currentSpec): TableLayout {\n const state = getState();\n const darkMode = resolveDarkMode(options?.darkMode);\n const { width } = getContainerDimensions();\n\n const compileOpts: CompileTableOptions = {\n width,\n height: 600,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n // undefined = \"no opinion, apply the spec default\"; null = the user\n // cycled sorting off and expects the original row order back. A\n // controlled caller's natural initial `sort: null` means \"no opinion\"\n // until the user has actually touched sorting.\n sort: resolveEffectiveSort(state),\n search: state.search || undefined,\n page: state.page,\n };\n\n return compileTable(candidate, compileOpts);\n }\n\n /** The sort once the user has touched it, otherwise defer to the spec. */\n function sameSort(a: SortState | null, b: SortState | null): boolean {\n if (a === null || b === null) return a === b;\n return a.column === b.column && a.direction === b.direction;\n }\n\n function resolveEffectiveSort(state: TableState): SortState | null | undefined {\n return sortTouched ? state.sort : (state.sort ?? undefined);\n }\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n return {\n width: Math.max(rect.width || 600, 100),\n height: Math.max(rect.height || 400, 100),\n };\n }\n\n /**\n * Announce a message to screen readers via the live region.\n */\n function announce(message: string): void {\n if (!wrapperElement) return;\n const liveRegion = wrapperElement.querySelector('.oc-table-live-region');\n if (liveRegion) {\n liveRegion.textContent = message;\n }\n }\n\n /**\n * Apply responsive classes based on container width.\n *\n * Cards mode below 400px; auto-condense only under real content pressure\n * (more columns than the width can give 96px each, or a narrow embed).\n * `getBreakpoint` calls everything up to 700px \"medium\", so keying on it\n * condensed every 600-720px editorial column that had room to breathe.\n * An explicit `density` (or the deprecated `compact`) always wins.\n */\n function applyBreakpointClass(): void {\n if (!wrapperElement) return;\n const { width } = getContainerDimensions();\n\n const compact = width < BREAKPOINT_COMPACT_MAX;\n wrapperElement.classList.toggle(\n 'oc-table--cards',\n compact && (currentSpec.mobileLayout ?? 'cards') === 'cards',\n );\n if (currentLayout)\n applyPriorityTable(\n wrapperElement,\n currentLayout,\n compact && currentSpec.mobileLayout === 'priority',\n );\n\n if (currentSpec.density !== undefined || currentSpec.compact === true) return;\n\n const columns = currentLayout?.columns.length ?? 0;\n const condensed =\n columns * MIN_READABLE_COLUMN_WIDTH > width || width < AUTO_CONDENSE_MAX_WIDTH;\n\n wrapperElement.classList.toggle('oc-table--condensed', condensed);\n wrapperElement.classList.toggle('oc-table--compact', condensed);\n wrapperElement.classList.toggle('oc-table--regular', !condensed);\n }\n\n function render(candidate = currentSpec): void {\n if (destroyed) return;\n\n // Keep the previous view usable if validation or compilation rejects an edit.\n const nextLayout = compile(candidate);\n const active = document.activeElement as HTMLElement | null;\n const bodyFocused = active === wrapperElement?.querySelector('tbody');\n const focusedCell = wrapperElement?.querySelector('.oc-table-cell-focus');\n const initialCell =\n bodyFocused && focusedCell\n ? {\n rowId: focusedCell.closest('tr')?.getAttribute('data-row-id') ?? '',\n columnKey: focusedCell.getAttribute('data-column') ?? '',\n }\n : undefined;\n const headerKey = wrapperElement?.contains(active)\n ? active?.closest('th')?.getAttribute('data-column')\n : null;\n const pageAction = wrapperElement?.contains(active)\n ? active?.getAttribute('data-page-action')\n : null;\n currentSpec = candidate;\n // Cancel any in-flight animations before re-rendering\n if (cleanupAnimations) {\n cleanupAnimations();\n cleanupAnimations = null;\n }\n\n // Clean up previous keyboard nav\n if (cleanupKeyboard) {\n cleanupKeyboard();\n cleanupKeyboard = null;\n }\n\n // Clean up previous render\n if (wrapperElement?.parentNode) {\n wrapperElement.parentNode.removeChild(wrapperElement);\n wrapperElement = null;\n }\n\n currentLayout = nextLayout;\n const shouldAnimate = isFirstRender && !!currentLayout.animation?.enter;\n wrapperElement = renderTable(currentLayout, container, { animate: shouldAnimate });\n\n // Set up animation cleanup on first animated render\n if (shouldAnimate && wrapperElement) {\n cleanupAnimations = setupTableAnimationCleanup(wrapperElement, () => {\n cleanupAnimations = null;\n if (pendingResize && !destroyed) {\n pendingResize = false;\n resize();\n }\n });\n }\n if (isFirstRender) {\n isFirstRender = false;\n }\n\n // Apply dark mode class\n const isDark = resolveDarkMode(options?.darkMode);\n if (isDark) {\n container.classList.add('oc-dark');\n } else {\n container.classList.remove('oc-dark');\n }\n\n // Apply responsive breakpoint\n applyBreakpointClass();\n\n // Add clickable class if onRowClick is provided\n if (options?.onRowClick) {\n wrapperElement.classList.add('oc-table--clickable');\n }\n\n // Wire up event handlers\n wireEvents();\n\n // Wire up keyboard navigation\n if (wrapperElement) {\n cleanupKeyboard = attachKeyboardNav({\n wrapper: wrapperElement,\n initialCell,\n onRowActivate: options?.onRowClick\n ? (rowId) => {\n const row = currentLayout.rows.find((item) => item.id === rowId);\n if (row) options.onRowClick?.(row.data);\n }\n : undefined,\n onSort: (columnKey: string) => {\n const state = getState();\n const newSort = cycleSort(state.sort, columnKey);\n updateState({ sort: newSort, page: 0 });\n\n // Announce sort change\n if (newSort) {\n const dir = newSort.direction === 'asc' ? 'ascending' : 'descending';\n announce(`Sorted by ${columnKey} ${dir}`);\n } else {\n announce('Sort cleared');\n }\n\n if (!isControlled) {\n rerender();\n }\n },\n onClearSearch: () => {\n if (searchDebounceTimer !== null) clearTimeout(searchDebounceTimer);\n searchDebounceTimer = null;\n updateState({ search: '', page: 0 });\n if (!isControlled) {\n rerender();\n }\n wrapperElement?.querySelector<HTMLElement>('tbody')?.focus();\n announce('Search cleared');\n },\n onAnnounce: announce,\n });\n }\n if (bodyFocused) wrapperElement?.querySelector<HTMLElement>('tbody')?.focus();\n else if (headerKey) {\n [...(wrapperElement?.querySelectorAll<HTMLElement>('th[data-column]') ?? [])]\n .find((element) => element.dataset.column === headerKey)\n ?.focus();\n } else if (pageAction) {\n const buttons = [\n ...(wrapperElement?.querySelectorAll<HTMLButtonElement>('[data-page-action]') ?? []),\n ];\n (\n buttons.find((button) => button.dataset.pageAction === pageAction && !button.disabled) ??\n buttons.find((button) => !button.disabled) ??\n wrapperElement?.querySelector<HTMLElement>('tbody')\n )?.focus();\n }\n }\n\n function wireEvents(): void {\n if (!wrapperElement) return;\n\n // Sort click handlers on thead buttons\n const sortBtns = wrapperElement.querySelectorAll('[data-sort-column]');\n for (const btn of sortBtns) {\n btn.addEventListener('click', handleSortClick);\n }\n\n // Search input\n const searchInput = wrapperElement.querySelector(\n '.oc-table-search input',\n ) as HTMLInputElement | null;\n if (searchInput) {\n searchInput.addEventListener('input', handleSearchInput);\n }\n\n // Pagination buttons\n const pageButtons = wrapperElement.querySelectorAll('[data-page-action]');\n for (const btn of pageButtons) {\n btn.addEventListener('click', handlePageClick);\n }\n\n // Row click\n if (options?.onRowClick) {\n const rows = wrapperElement.querySelectorAll('tbody tr');\n for (const row of rows) {\n row.addEventListener('click', handleRowClick);\n }\n }\n }\n\n function handleSortClick(e: Event): void {\n const btn = e.currentTarget as HTMLElement;\n const column = btn.getAttribute('data-sort-column');\n if (!column) return;\n\n const state = getState();\n const newSort = cycleSort(state.sort, column);\n\n updateState({ sort: newSort, page: 0 });\n\n // Announce sort change for screen readers\n if (newSort) {\n const dir = newSort.direction === 'asc' ? 'ascending' : 'descending';\n announce(`Sorted by ${column} ${dir}`);\n } else {\n announce('Sort cleared');\n }\n\n if (!isControlled) {\n rerender();\n }\n }\n\n function handleSearchInput(e: Event): void {\n const input = e.target as HTMLInputElement;\n const query = input.value;\n\n if (searchDebounceTimer !== null) {\n clearTimeout(searchDebounceTimer);\n }\n\n searchDebounceTimer = setTimeout(() => {\n searchDebounceTimer = null;\n updateState({ search: query, page: 0 });\n\n if (!isControlled) {\n rerender();\n // Announce search result count\n const rowCount = currentLayout?.rows?.length ?? 0;\n if (query) {\n announce(`${rowCount} result${rowCount !== 1 ? 's' : ''} found`);\n }\n }\n }, 200);\n }\n\n function handlePageClick(e: Event): void {\n const btn = e.currentTarget as HTMLElement;\n const action = btn.getAttribute('data-page-action');\n const state = getState();\n\n if (action === 'prev' && state.page > 0) {\n updateState({ page: state.page - 1 });\n } else if (action === 'next') {\n updateState({ page: state.page + 1 });\n }\n\n if (!isControlled) {\n rerender();\n }\n }\n\n function handleRowClick(e: Event): void {\n const tr = e.currentTarget as HTMLElement;\n const rowId = tr.getAttribute('data-row-id');\n if (!rowId || !currentLayout) return;\n\n const row = currentLayout.rows.find((r) => r.id === rowId);\n if (row) {\n options?.onRowClick?.(row.data);\n }\n }\n\n /**\n * Re-render the table, preserving search input focus across the DOM rebuild.\n */\n function rerender(candidate = currentSpec): void {\n if (destroyed) return;\n\n // Capture current search input state before re-render\n const searchInput = wrapperElement?.querySelector(\n '.oc-table-search input',\n ) as HTMLInputElement | null;\n const hadFocus = searchInput && document.activeElement === searchInput;\n const pendingQuery = searchDebounceTimer !== null ? searchInput?.value : undefined;\n const selectionStart = searchInput?.selectionStart ?? 0;\n const selectionEnd = searchInput?.selectionEnd ?? 0;\n\n render(candidate);\n\n // Restore search focus after re-render\n if (hadFocus) {\n const newInput = wrapperElement?.querySelector(\n '.oc-table-search input',\n ) as HTMLInputElement | null;\n if (newInput) {\n if (pendingQuery !== undefined) newInput.value = pendingQuery;\n newInput.focus();\n newInput.setSelectionRange(selectionStart, selectionEnd);\n }\n }\n }\n\n function update(newSpec: TableSpec): void {\n if (destroyed) return;\n rerender(newSpec);\n }\n\n function resize(): void {\n if (destroyed) return;\n if (cleanupAnimations) {\n pendingResize = true;\n return;\n }\n rerender();\n }\n\n function doExport(format: 'csv'): string {\n if (format !== 'csv') {\n throw new Error(`Unsupported export format: ${format}`);\n }\n\n // Export all filtered/sorted data (not just current page)\n // Re-compile without pagination\n const state = getState();\n const darkMode = resolveDarkMode(options?.darkMode);\n const { width } = getContainerDimensions();\n\n const fullLayout = compileTable(\n { ...currentSpec, pagination: false },\n {\n width,\n height: 600,\n theme: options?.theme,\n darkMode,\n sort: resolveEffectiveSort(state),\n search: state.search || undefined,\n // No page/pageSize: get all rows\n },\n );\n\n const headers = fullLayout.columns.map((c) => c.label);\n const csvRows = [headers.map(csvEscape).join(',')];\n\n for (const row of fullLayout.rows) {\n const values = row.cells.map((cell) => csvEscape(cell.formattedValue));\n csvRows.push(values.join(','));\n }\n\n return csvRows.join('\\n');\n }\n\n function setState(partial: Partial<TableState>): void {\n if (destroyed) return;\n // An explicit replacement wins over queued typing. No-op framework sync\n // and unrelated state changes must leave the reader's pending edit intact.\n if (\n partial.search !== undefined &&\n partial.search !== getState().search &&\n searchDebounceTimer !== null\n ) {\n clearTimeout(searchDebounceTimer);\n searchDebounceTimer = null;\n }\n\n // In controlled mode compile() reads from options.externalState, so\n // updating internalState alone would be ignored. Push the new values onto\n // externalState (the source getState() reads) so the render reflects them.\n // An explicit sort that actually changes the state -- including a change\n // to null -- is the caller taking a position on sorting, so from here on a\n // null sort means \"cleared\", not \"no opinion\". A no-op sync (the React and\n // Svelte wrappers push their initial `sort: null` on mount) must not count,\n // or spec.sort would be dropped before the first interaction.\n if (partial.sort !== undefined && !sameSort(partial.sort, getState().sort)) {\n sortTouched = true;\n }\n\n if (isControlled && options?.externalState) {\n if (partial.sort !== undefined) options.externalState.sort = partial.sort;\n if (partial.search !== undefined) options.externalState.search = partial.search;\n if (partial.page !== undefined) options.externalState.page = partial.page;\n } else {\n if (partial.sort !== undefined) internalState.sort = partial.sort;\n if (partial.search !== undefined) internalState.search = partial.search;\n if (partial.page !== undefined) internalState.page = partial.page;\n }\n\n rerender();\n }\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n if (cleanupAnimations) {\n cleanupAnimations();\n cleanupAnimations = null;\n }\n if (cleanupKeyboard) {\n cleanupKeyboard();\n cleanupKeyboard = null;\n }\n if (searchDebounceTimer !== null) {\n clearTimeout(searchDebounceTimer);\n searchDebounceTimer = null;\n }\n if (resizeDebounceTimer !== null) {\n clearTimeout(resizeDebounceTimer);\n resizeDebounceTimer = null;\n }\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n if (wrapperElement?.parentNode) {\n wrapperElement.parentNode.removeChild(wrapperElement);\n wrapperElement = null;\n }\n container.classList.remove('oc-dark');\n }\n\n // Initial render\n render();\n\n // Set up responsive resize with breakpoint detection\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => {\n if (resizeDebounceTimer !== null) {\n clearTimeout(resizeDebounceTimer);\n }\n resizeDebounceTimer = setTimeout(() => {\n resizeDebounceTimer = null;\n // Update breakpoint class without full re-render when possible\n applyBreakpointClass();\n resize();\n }, 100);\n });\n }\n\n return {\n update,\n resize,\n export: doExport,\n getState,\n setState,\n destroy,\n };\n}\n","/**\n * Table renderer: produces semantic HTML from a TableLayout.\n *\n * renderTable() creates the full DOM structure: chrome, search bar,\n * scrollable table with sticky column support, pagination, and footer.\n * The returned element replaces or appends to the given container.\n */\n\nimport type { ResolvedColumn, TableLayout, TableRow } from '@opendata-ai/openchart-core';\nimport { BRAND_FONT_SIZE, cssTokenDefault } from '@opendata-ai/openchart-core';\nimport { clampStaggerDelay } from '@opendata-ai/openchart-engine';\nimport { stampAnimationVars } from './animation-vars';\nimport { applySrOnlyStyles } from './dom-helpers';\nimport { renderCell } from './renderers/table-cells';\nimport { resolvedSurface } from './theme-tokens';\n\n/** Options for renderTable(). */\nexport interface TableRenderOptions {\n /** Whether to apply entrance animation on this render. */\n animate?: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst BRAND_URL = 'https://tryopendata.ai';\n\n// ---------------------------------------------------------------------------\n// Chrome rendering\n// ---------------------------------------------------------------------------\n\n/** Create chrome (title/subtitle or source/footer) block. */\nfunction renderChromeBlock(\n layout: TableLayout,\n position: 'header' | 'footer',\n): HTMLDivElement | null {\n const chrome = layout.chrome;\n\n if (position === 'header') {\n if (!chrome.title && !chrome.subtitle) return null;\n\n const div = document.createElement('div');\n div.className = 'oc-chrome';\n\n if (chrome.title) {\n const h = document.createElement('div');\n h.className = 'oc-table-title';\n h.textContent = chrome.title.text;\n div.appendChild(h);\n }\n if (chrome.subtitle) {\n const sub = document.createElement('div');\n sub.className = 'oc-table-subtitle';\n sub.textContent = chrome.subtitle.text;\n div.appendChild(sub);\n }\n\n return div;\n }\n\n // Footer position\n if (!chrome.source && !chrome.footer) return null;\n\n const div = document.createElement('div');\n div.className = 'oc-chrome oc-chrome-footer';\n\n if (chrome.source) {\n const src = document.createElement('div');\n src.className = 'oc-table-source';\n src.textContent = chrome.source.text;\n div.appendChild(src);\n }\n if (chrome.footer) {\n const foot = document.createElement('div');\n foot.className = 'oc-table-footer-text';\n foot.textContent = chrome.footer.text;\n div.appendChild(foot);\n }\n\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Table head\n// ---------------------------------------------------------------------------\n\nfunction renderThead(\n columns: ResolvedColumn[],\n sort: TableLayout['sort'],\n): HTMLTableSectionElement {\n const thead = document.createElement('thead');\n thead.setAttribute('role', 'rowgroup');\n const tr = document.createElement('tr');\n tr.setAttribute('role', 'row');\n\n for (const col of columns) {\n const th = document.createElement('th');\n th.setAttribute('scope', 'col');\n th.setAttribute('role', 'columnheader');\n th.style.textAlign = col.align;\n th.style.width = `${col.width}px`;\n\n // Sort state: use 'ascending'/'descending' per WAI-ARIA spec\n let ariaSortValue: string = 'none';\n if (sort && sort.column === col.key) {\n ariaSortValue = sort.direction === 'asc' ? 'ascending' : 'descending';\n }\n th.setAttribute('aria-sort', ariaSortValue);\n th.setAttribute('data-column', col.key);\n\n // Label\n const labelSpan = document.createTextNode(col.label);\n th.appendChild(labelSpan);\n\n // Sort button\n if (col.sortable) {\n const btn = document.createElement('button');\n btn.className = 'oc-table-sort-btn';\n btn.setAttribute('aria-label', `Sort by ${col.label}`);\n btn.setAttribute('data-sort-column', col.key);\n btn.type = 'button';\n th.appendChild(btn);\n }\n\n tr.appendChild(th);\n }\n\n thead.appendChild(tr);\n return thead;\n}\n\n// ---------------------------------------------------------------------------\n// Table body\n// ---------------------------------------------------------------------------\n\nfunction renderTbody(rows: TableRow[], columns: ResolvedColumn[]): HTMLTableSectionElement {\n const tbody = document.createElement('tbody');\n tbody.setAttribute('role', 'rowgroup');\n\n for (let r = 0; r < rows.length; r++) {\n const row = rows[r];\n const tr = document.createElement('tr');\n tr.setAttribute('role', 'row');\n tr.setAttribute('data-row-id', row.id);\n tr.style.setProperty('--oc-row-index', String(r));\n\n for (let c = 0; c < columns.length; c++) {\n const cell = row.cells[c];\n if (!cell) continue;\n\n const td = renderCell(cell);\n td.setAttribute('role', 'gridcell');\n td.setAttribute('data-column', columns[c].key);\n td.style.textAlign = columns[c].align;\n // Cards mode (below 400px) hides the header and prints these instead;\n // the CSS reads them through `content: attr(data-label)`.\n td.setAttribute('data-label', columns[c].label);\n td.setAttribute('data-priority', String(columns[c].priority));\n tr.appendChild(td);\n }\n\n tbody.appendChild(tr);\n }\n\n return tbody;\n}\n\n// ---------------------------------------------------------------------------\n// Totals footer\n// ---------------------------------------------------------------------------\n\nfunction renderTfoot(\n totalRow: NonNullable<TableLayout['totalRow']>,\n columns: ResolvedColumn[],\n): HTMLTableSectionElement {\n const tfoot = document.createElement('tfoot');\n tfoot.className = 'oc-table-total';\n tfoot.setAttribute('role', 'rowgroup');\n\n const tr = document.createElement('tr');\n tr.setAttribute('role', 'row');\n\n for (let c = 0; c < columns.length; c++) {\n const cell = totalRow.cells[c];\n const td = cell ? renderCell(cell) : document.createElement('td');\n td.setAttribute('role', 'gridcell');\n td.setAttribute('data-column', columns[c].key);\n td.style.textAlign = columns[c].align;\n td.setAttribute('data-label', columns[c].label);\n td.setAttribute('data-priority', String(columns[c].priority));\n // The label rides in the first column; a blank cell there would leave the\n // footer unreadable out of context.\n if (c === 0 && !td.textContent) {\n td.textContent = totalRow.label;\n }\n tr.appendChild(td);\n }\n\n tfoot.appendChild(tr);\n return tfoot;\n}\n\n// ---------------------------------------------------------------------------\n// Search bar\n// ---------------------------------------------------------------------------\n\nfunction renderSearchBar(layout: TableLayout): HTMLDivElement | null {\n if (!layout.search.enabled) return null;\n\n const div = document.createElement('div');\n div.className = 'oc-table-search';\n\n const input = document.createElement('input');\n input.type = 'search';\n input.placeholder = layout.search.placeholder;\n input.setAttribute('aria-label', 'Search table');\n input.value = layout.search.query;\n\n div.appendChild(input);\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Pagination\n// ---------------------------------------------------------------------------\n\nfunction renderPagination(layout: TableLayout): HTMLDivElement | null {\n if (!layout.pagination) return null;\n\n const { page, pageSize, totalRows, totalPages } = layout.pagination;\n\n const div = document.createElement('div');\n div.className = 'oc-table-pagination';\n\n const info = document.createElement('span');\n info.className = 'oc-table-pagination-info';\n\n if (totalRows === 0) {\n info.textContent = 'No results';\n } else {\n const start = page * pageSize + 1;\n const end = Math.min((page + 1) * pageSize, totalRows);\n info.textContent = `Showing ${start}-${end} of ${totalRows}`;\n }\n\n div.appendChild(info);\n\n const btnGroup = document.createElement('span');\n btnGroup.className = 'oc-table-pagination-btns';\n\n const prevBtn = document.createElement('button');\n prevBtn.setAttribute('aria-label', 'Previous page');\n prevBtn.setAttribute('data-page-action', 'prev');\n prevBtn.textContent = 'Prev';\n prevBtn.disabled = page <= 0;\n btnGroup.appendChild(prevBtn);\n\n const nextBtn = document.createElement('button');\n nextBtn.setAttribute('aria-label', 'Next page');\n nextBtn.setAttribute('data-page-action', 'next');\n nextBtn.textContent = 'Next';\n nextBtn.disabled = page >= totalPages - 1;\n btnGroup.appendChild(nextBtn);\n\n div.appendChild(btnGroup);\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Empty state\n// ---------------------------------------------------------------------------\n\nfunction renderEmptyState(message: string): HTMLDivElement {\n const div = document.createElement('div');\n div.className = 'oc-table-empty';\n div.setAttribute('aria-live', 'polite');\n div.textContent = message;\n return div;\n}\n\n// ---------------------------------------------------------------------------\n// Main render\n// ---------------------------------------------------------------------------\n\n/**\n * Render a TableLayout into a full DOM structure.\n *\n * @param layout - The compiled table layout.\n * @param container - The container element to render into.\n * @returns The wrapper element that was created.\n */\nexport function renderTable(\n layout: TableLayout,\n container: HTMLElement,\n opts?: TableRenderOptions,\n): HTMLElement {\n const wrapper = document.createElement('div');\n wrapper.className = 'oc-table-wrapper';\n\n // Apply theme colors as CSS custom properties so table CSS picks them up.\n // Without this, dark-background themes show invisible text since the\n // CSS defaults (--oc-text etc.) are light-mode values.\n const { theme, chrome } = layout;\n if (theme) {\n const s = wrapper.style;\n const n = theme.colors.neutral;\n // Sticky header/column/footer cells paint this to occlude the rows sliding\n // under them, so it has to be an opaque surface. theme.colors.background is\n // 'transparent' on the default theme.\n s.setProperty('--oc-bg', resolvedSurface(theme));\n s.setProperty('--oc-text', theme.colors.text);\n // Secondary grays come from the theme's own text/background mix, the same\n // ramp charts stamp. Deriving them from colors.axis (the tick-label ink)\n // used to pin every table gray to one value and shut token changes out.\n s.setProperty('--oc-text-secondary', n.secondary);\n s.setProperty('--oc-text-muted', n[600]);\n s.setProperty('--oc-text-faint', n.faint);\n s.setProperty('--oc-gray-100', n[100]);\n s.setProperty('--oc-gray-200', n[200]);\n s.setProperty('--oc-gray-300', n[300]);\n s.setProperty('--oc-gray-400', n[400]);\n s.setProperty('--oc-gridline', theme.colors.gridline);\n // The table hairline is a border, not a gridline. Only a theme that sets\n // gridline explicitly gets to drive it; otherwise the derived ramp wins.\n // Compare whitespace-stripped: the theme literal is 'rgba(0,0,0,0.08)' but\n // the CSS token is written 'rgba(0, 0, 0, 0.08)'.\n const stripWs = (c: string) => c.replace(/\\s+/g, '');\n const defaultGridline = cssTokenDefault('--oc-gridline', theme.isDark ? 'dark' : 'light');\n const gridlineOverridden = stripWs(theme.colors.gridline) !== stripWs(defaultGridline);\n s.setProperty('--oc-border', gridlineOverridden ? theme.colors.gridline : n.border);\n s.setProperty('--oc-positive', theme.colors.positive);\n s.setProperty('--oc-negative', theme.colors.negative);\n s.setProperty('--oc-font-family', theme.fonts.family);\n s.fontFamily = theme.fonts.family;\n }\n\n // Set computed chrome CSS custom properties so chrome elements pick up\n // theme-resolved values via CSS fallbacks (e.g. --oc-title-computed-size).\n {\n const s = wrapper.style;\n if (chrome.title) {\n s.setProperty('--oc-title-computed-size', `${chrome.title.style.fontSize}px`);\n s.setProperty('--oc-title-computed-weight', String(chrome.title.style.fontWeight));\n s.setProperty('--oc-title-computed-color', chrome.title.style.fill);\n }\n if (chrome.subtitle) {\n s.setProperty('--oc-subtitle-computed-size', `${chrome.subtitle.style.fontSize}px`);\n s.setProperty('--oc-subtitle-computed-weight', String(chrome.subtitle.style.fontWeight));\n s.setProperty('--oc-subtitle-computed-color', chrome.subtitle.style.fill);\n }\n if (chrome.source) {\n s.setProperty('--oc-source-computed-size', `${chrome.source.style.fontSize}px`);\n s.setProperty('--oc-source-computed-color', chrome.source.style.fill);\n }\n if (chrome.footer) {\n s.setProperty('--oc-footer-computed-size', `${chrome.footer.style.fontSize}px`);\n s.setProperty('--oc-footer-computed-color', chrome.footer.style.fill);\n }\n }\n\n // Apply class modifiers\n wrapper.classList.add(`oc-table--${layout.density}`);\n if (layout.density === 'condensed') {\n // Deprecated alias, kept one release for stylesheets targeting it.\n wrapper.classList.add('oc-table--compact');\n }\n if (layout.striped) {\n wrapper.classList.add('oc-table--striped');\n }\n\n // Header chrome\n const headerChrome = renderChromeBlock(layout, 'header');\n if (headerChrome) {\n wrapper.appendChild(headerChrome);\n }\n\n // Search bar\n const searchBar = renderSearchBar(layout);\n if (searchBar) {\n wrapper.appendChild(searchBar);\n }\n\n // Handle empty data\n if (layout.rows.length === 0) {\n const message = layout.search.query ? 'No results found' : 'No data';\n wrapper.appendChild(renderEmptyState(message));\n } else {\n // Scroll container\n const scroll = document.createElement('div');\n scroll.className = 'oc-table-scroll';\n\n // Table\n const table = document.createElement('table');\n table.setAttribute('role', 'grid');\n table.setAttribute('aria-label', layout.a11y.caption);\n\n if (layout.stickyFirstColumn) {\n table.classList.add('oc-table--sticky');\n }\n\n // Caption (screen reader only – inline styles ensure hiding even without\n // the external stylesheet, e.g. CDN / esm.sh usage)\n const caption = document.createElement('caption');\n caption.className = 'oc-sr-only';\n applySrOnlyStyles(caption);\n caption.textContent = layout.a11y.summary;\n table.appendChild(caption);\n\n // Thead\n table.appendChild(renderThead(layout.columns, layout.sort));\n\n // Tbody\n table.appendChild(renderTbody(layout.rows, layout.columns));\n\n // Totals footer\n if (layout.totalRow) {\n table.appendChild(renderTfoot(layout.totalRow, layout.columns));\n }\n\n scroll.appendChild(table);\n wrapper.appendChild(scroll);\n }\n\n // Pagination\n const pagination = renderPagination(layout);\n if (pagination) {\n wrapper.appendChild(pagination);\n }\n\n // Footer row: source/footer chrome on the left, brand watermark on the\n // right, laid out on a single line via flex. Built up here and appended\n // after the live region so source text and watermark share a baseline.\n const footerRow = document.createElement('div');\n footerRow.className = 'oc-table-footer-row';\n\n const footerChrome = renderChromeBlock(layout, 'footer');\n if (footerChrome) {\n footerRow.appendChild(footerChrome);\n }\n\n // Live region for screen reader announcements (sort changes, search results)\n const liveRegion = document.createElement('div');\n liveRegion.className = 'oc-table-live-region oc-sr-only';\n applySrOnlyStyles(liveRegion);\n liveRegion.setAttribute('aria-live', 'polite');\n liveRegion.setAttribute('aria-atomic', 'true');\n liveRegion.setAttribute('role', 'status');\n wrapper.appendChild(liveRegion);\n\n // Brand watermark — joins the footer row, pushed to the right by the\n // flex container so it sits on the same line as the source text.\n if (layout.watermark) {\n const brandColor = theme ? theme.colors.axis : '#999999';\n const brand = document.createElement('div');\n brand.className = 'oc-table-ref';\n const brandLink = document.createElement('a');\n brandLink.href = BRAND_URL;\n brandLink.target = '_blank';\n brandLink.rel = 'noopener';\n brandLink.style.cssText = `font-size: ${BRAND_FONT_SIZE}px; font-weight: 600; color: ${brandColor}; opacity: 0.55; text-decoration: none; font-family: ${theme ? theme.fonts.family : 'sans-serif'};`;\n brandLink.textContent = 'OpenData';\n brand.appendChild(brandLink);\n footerRow.appendChild(brand);\n }\n\n // Append the footer row only when it has content (source/footer/watermark).\n if (footerRow.childElementCount > 0) {\n wrapper.appendChild(footerRow);\n }\n\n // Animation: stamp CSS custom properties and add oc-animate class BEFORE\n // DOM insertion to avoid a flash of final state.\n if (opts?.animate && layout.animation?.enter) {\n const enterPhase = layout.animation.enter;\n const rowCount = layout.rows.length;\n const stagger = clampStaggerDelay(enterPhase.staggerDelay, rowCount);\n stampAnimationVars(wrapper, {\n duration: enterPhase.duration,\n spring: enterPhase.spring,\n stagger,\n ease: enterPhase.ease,\n });\n wrapper.classList.add('oc-animate');\n }\n\n container.appendChild(wrapper);\n return wrapper;\n}\n","/**\n * TileMap mount API: the main entry point for vanilla JS tilemap usage.\n *\n * createTileMap() takes a container, TileMapSpec, and options, compiles the\n * tilemap, renders it as SVG, sets up responsive resizing, tooltip interaction,\n * and returns a TileMapInstance with update/resize/export/destroy.\n */\n\nimport type {\n CompileOptions,\n DarkMode,\n ThemeConfig,\n TileMapLayout,\n TileMapSpec,\n} from '@opendata-ai/openchart-core';\nimport { BREAKPOINT_COMPACT_MAX, BREAKPOINT_MEDIUM_MAX } from '@opendata-ai/openchart-core';\nimport { compileTileMap } from '@opendata-ai/openchart-engine';\nimport { cancelAnimations, setupAnimationCleanup } from './animation';\nimport {\n exportJPG,\n exportPNG,\n exportSVG,\n exportSVGWithFonts,\n type JPGExportOptions,\n type SVGExportOptions,\n} from './export';\nimport {\n captureMarkFocus,\n type NavigableMark,\n restoreMarkFocus,\n wireMarkNavigation,\n} from './interactions/mark-navigation';\nimport { createMeasureText, resolveFontFamily, scheduleFontReload } from './measure-text';\nimport { observeResize } from './resize-observer';\nimport { resolveDarkMode } from './resolve-dark-mode';\nimport { renderTileMapSVG } from './tilemap-renderer';\nimport { createTooltipManager, type TooltipManager } from './tooltip';\n\n// ---------------------------------------------------------------------------\n// Responsive tile sizing\n// ---------------------------------------------------------------------------\n\n// The state grid is 8 rows tall (see engine/tilemap/layout.ts GRID_ROWS).\n// TILEMAP_TILE_GAP must match the gap passed to computeTilePositions in\n// compile-tilemap.ts (currently 5) so the mount's height budget matches the\n// grid the compiler builds.\nconst TILEMAP_GRID_ROWS = 8;\nconst TILEMAP_TILE_GAP = 5;\n// Generous vertical reserve for chrome (title/subtitle/source) + padding +\n// legend. Intentionally over-reserved: on narrow widths we WANT tile size to be\n// bound by width, so any excess height budget just lets the map grow taller\n// (which is the desired mobile behavior) rather than starving the tiles.\nconst TILEMAP_CHROME_RESERVE = 180;\n\n/**\n * Target tile size (px) for a given container width. Drives the height budget\n * on non-desktop widths so the 8-row grid isn't starved to tiny tiles after\n * chrome is subtracted from a square drawing area. Width still caps the actual\n * tile size, so these are ceilings the layout grows toward, not guarantees.\n */\nfunction pickTargetTileSize(width: number): number {\n if (width < BREAKPOINT_COMPACT_MAX) return 34; // compact / mobile\n return 40; // medium (tablet, sidebars)\n}\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface TileMapMountOptions {\n /** Theme overrides. */\n theme?: ThemeConfig;\n /** Dark mode setting: \"auto\" (system pref), \"force\", or \"off\". */\n darkMode?: DarkMode;\n /** Enable responsive resizing. Defaults to true. */\n responsive?: boolean;\n /** Show the OpenData watermark. Defaults to true. */\n watermark?: boolean;\n /** Show tooltips on hover. Defaults to true. */\n tooltip?: boolean;\n /** Callback when a tile is clicked. */\n onTileClick?: (tile: {\n stateCode: string;\n stateName: string;\n value: number | null;\n data: Record<string, unknown>;\n }) => void;\n /** Callback when a tile is hovered (null on mouse leave). */\n onTileHover?: (\n tile: {\n stateCode: string;\n stateName: string;\n value: number | null;\n data: Record<string, unknown>;\n } | null,\n ) => void;\n}\n\nexport interface TileMapInstance {\n /** Re-compile and re-render with a new spec. */\n update(spec: TileMapSpec): void;\n /** Re-compile at current container dimensions. */\n resize(): void;\n /** Export the tilemap. */\n export(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string>;\n /** Remove all DOM elements and disconnect observers. */\n destroy(): void;\n /** The current compiled layout. */\n readonly layout: TileMapLayout;\n}\n\n// ---------------------------------------------------------------------------\n// Main API\n// ---------------------------------------------------------------------------\n\n/**\n * Create a tilemap instance from a spec and mount it into a container.\n */\nexport function createTileMap(\n container: HTMLElement,\n spec: TileMapSpec,\n options?: TileMapMountOptions,\n): TileMapInstance {\n let currentSpec = spec;\n let currentLayout: TileMapLayout;\n let destroyed = false;\n\n // DOM\n let svgElement: SVGSVGElement | null = null;\n\n // Subsystems\n let tooltipManager: TooltipManager | null = null;\n let cleanupTooltipEvents: (() => void) | null = null;\n let disconnectResize: (() => void) | null = null;\n\n // Animation state\n let animationCleanup: (() => void) | null = null;\n let pendingResize = false;\n\n // Latches whether the host constrains our height. Measured once, on the\n // first render that produces a real rect: height 0 with a real width means\n // the host is auto-height and we pick our own budget. Any other height is\n // an explicit box we must fit inside. Re-reading this after the first paint\n // would just measure our own SVG, so the value has to latch.\n let isAutoHeight: boolean | null = null;\n\n // Set when webfonts have loaded and a recompile is owed. The next render()\n // that recompiles flips data-oc-fonts-state to 'ready' and clears this, so\n // the attribute stays honest when resize() defers to pendingResize during\n // the entrance animation.\n let fontsReloadPending = false;\n\n // Apply the root class up front so getComputedStyle sees --oc-font-family\n // before the text measurer is built.\n container.classList.add('oc-tilemap-root');\n\n // Resolve the effective font the way compile() will: compile merges\n // { ...spec.theme, ...options.theme }, so options.theme wins over the\n // spec-level theme; fall back to the container's computed font. Measuring a\n // different font than gets rendered desyncs layout metrics and the reload watcher.\n function resolveEffectiveFont(candidate = currentSpec): string {\n return (\n options?.theme?.fonts?.family ??\n candidate.theme?.fonts?.family ??\n resolveFontFamily(container)\n );\n }\n let fontFamily = resolveEffectiveFont();\n let measureText = createMeasureText(fontFamily);\n let renderGen = 0;\n\n // ---------------------------------------------------------------------------\n // Helpers\n // ---------------------------------------------------------------------------\n\n function getContainerDimensions(): { width: number; height: number } {\n const rect = container.getBoundingClientRect();\n const width = Math.max(rect.width || 600, 100);\n\n if (isAutoHeight === null && (rect.width > 0 || rect.height > 0)) {\n isAutoHeight = rect.height === 0 && rect.width > 0;\n }\n\n // An explicit host height is a hard budget: the compiler derives a tight\n // content height from whatever we pass, so handing it the container's own\n // height keeps the SVG inside its box instead of overflowing onto whatever\n // sits below it.\n if (isAutoHeight === false && rect.height > 0) {\n return { width, height: Math.max(rect.height, 100) };\n }\n\n // Auto-height host: pick our own budget. The compiler derives its own tight\n // content height and treats the passed height as a cap. On desktop, a square\n // budget (height = width) keeps tiles from ballooning (the 8-row grid becomes\n // the binding constraint at ~width/8). Below desktop, a square budget starves\n // the grid after chrome, so give it a height budget sized to a comfortable\n // target tile instead — the map then grows taller as needed rather than\n // shrinking the tiles.\n if (width >= BREAKPOINT_MEDIUM_MAX) {\n return { width, height: width };\n }\n const targetTile = pickTargetTileSize(width);\n const height =\n targetTile * TILEMAP_GRID_ROWS +\n TILEMAP_TILE_GAP * (TILEMAP_GRID_ROWS - 1) +\n TILEMAP_CHROME_RESERVE;\n return { width, height };\n }\n\n function compile(candidate = currentSpec, measure = measureText): TileMapLayout {\n const { width, height } = getContainerDimensions();\n const darkMode = resolveDarkMode(options?.darkMode);\n\n const compileOpts: CompileOptions = {\n width,\n height,\n theme: options?.theme,\n darkMode,\n watermark: options?.watermark,\n measureText: measure,\n };\n\n return compileTileMap(candidate, compileOpts);\n }\n\n // ---------------------------------------------------------------------------\n // Tooltip and interaction wiring\n // ---------------------------------------------------------------------------\n\n function wireTooltipAndInteraction(svg: SVGSVGElement, layout: TileMapLayout): () => void {\n const cleanups: Array<() => void> = [];\n const navigation: NavigableMark[] = [];\n let activeLeave: (() => void) | null = null;\n\n const tilesByStateCode = new Map<string, (typeof layout.tiles)[number]>();\n for (const t of layout.tiles) {\n if (!tilesByStateCode.has(t.stateCode)) tilesByStateCode.set(t.stateCode, t);\n }\n\n // Wire tooltip on tile elements. The group carries the hover state so the\n // dim rule can be a single class toggle rather than 51 of them.\n const tilesGroup = svg.querySelector('.oc-tilemap-tiles');\n const tileElements = svg.querySelectorAll('.oc-tilemap-tile');\n for (const el of tileElements) {\n const stateCode = el.getAttribute('data-state');\n if (!stateCode) continue;\n\n const content = layout.tooltipDescriptors.get(stateCode);\n const tile = tilesByStateCode.get(stateCode);\n\n const handleMouseEnter = (e: Event) => {\n activeLeave?.();\n activeLeave = handleMouseLeave;\n const mouseEvent = e as MouseEvent;\n tilesGroup?.classList.add('oc-hover-active');\n el.classList.add('oc-tilemap-tile--hover');\n if (content && tooltipManager && options?.tooltip !== false) {\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n if (tile) {\n options?.onTileHover?.({\n stateCode: tile.stateCode,\n stateName: tile.data.stateName as string,\n value: tile.value,\n data: tile.data,\n });\n }\n };\n\n const handleMouseMove = (e: Event) => {\n if (content && tooltipManager && options?.tooltip !== false) {\n const mouseEvent = e as MouseEvent;\n const svgRect = svg.getBoundingClientRect();\n const x = mouseEvent.clientX - svgRect.left;\n const y = mouseEvent.clientY - svgRect.top;\n tooltipManager.show(content, x, y);\n }\n };\n\n const handleMouseLeave = () => {\n if (activeLeave !== handleMouseLeave) return;\n activeLeave = null;\n tilesGroup?.classList.remove('oc-hover-active');\n el.classList.remove('oc-tilemap-tile--hover');\n tooltipManager?.hide();\n options?.onTileHover?.(null);\n };\n\n const handleClick = () => {\n if (tile) {\n options?.onTileClick?.({\n stateCode: tile.stateCode,\n stateName: tile.data.stateName as string,\n value: tile.value,\n data: tile.data,\n });\n }\n };\n\n navigation.push({\n element: el,\n key: stateCode,\n enter: handleMouseEnter,\n leave: handleMouseLeave,\n activate: handleClick,\n });\n el.addEventListener('mouseenter', handleMouseEnter);\n el.addEventListener('mousemove', handleMouseMove);\n el.addEventListener('mouseleave', handleMouseLeave);\n el.addEventListener('click', handleClick);\n\n cleanups.push(() => {\n el.removeEventListener('mouseenter', handleMouseEnter);\n el.removeEventListener('mousemove', handleMouseMove);\n el.removeEventListener('mouseleave', handleMouseLeave);\n el.removeEventListener('click', handleClick);\n });\n }\n\n cleanups.push(wireMarkNavigation(svg, navigation));\n return () => {\n activeLeave?.();\n for (const cleanup of cleanups) {\n cleanup();\n }\n };\n }\n\n // ---------------------------------------------------------------------------\n // Render + update\n // ---------------------------------------------------------------------------\n\n function render(animate = false): void {\n const focusedMark = captureMarkFocus(svgElement);\n tooltipManager?.hide();\n // Cancel running animations\n if (animationCleanup) {\n animationCleanup();\n animationCleanup = null;\n }\n\n // Remove old SVG\n if (svgElement) {\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n svgElement.remove();\n }\n\n // Render new SVG\n const newSvg = renderTileMapSVG(currentLayout, { animate });\n container.appendChild(newSvg);\n svgElement = newSvg;\n\n // Wire interactions\n cleanupTooltipEvents = wireTooltipAndInteraction(newSvg, currentLayout);\n\n // Setup tooltips if enabled\n if (options?.tooltip !== false) {\n if (!tooltipManager) {\n tooltipManager = createTooltipManager(container);\n }\n }\n\n // Setup animation cleanup only when actually animating\n if (animate && currentLayout.animation?.enter) {\n animationCleanup = setupAnimationCleanup(newSvg, () => {\n animationCleanup = null;\n // On animation complete, check if resize was pending\n if (pendingResize && !destroyed) {\n pendingResize = false;\n resize();\n }\n });\n }\n\n renderGen += 1;\n container.dataset.ocRenderGen = String(renderGen);\n\n // This render recompiled with the loaded webfonts; publish 'ready' now\n // rather than right after the fonts-ready resize() (which may have deferred\n // to pendingResize during the entrance animation).\n if (fontsReloadPending) {\n fontsReloadPending = false;\n container.dataset.ocFontsState = 'ready';\n }\n if (svgElement) restoreMarkFocus(svgElement, focusedMark);\n }\n\n function update(newSpec: TileMapSpec): void {\n if (destroyed) return;\n // Compile before adopting an edit: a rejected spec must leave the last\n // valid view, its interactions, and future resize/export calls intact.\n const nextFont = resolveEffectiveFont(newSpec);\n const nextMeasure = nextFont === fontFamily ? measureText : createMeasureText(nextFont);\n const nextLayout = compile(newSpec, nextMeasure);\n currentSpec = newSpec;\n fontFamily = nextFont;\n measureText = nextMeasure;\n\n currentLayout = nextLayout;\n render();\n }\n\n function resize(): void {\n if (destroyed) return;\n\n // If animation is running, queue the resize for after it completes\n if (animationCleanup) {\n pendingResize = true;\n return;\n }\n\n currentLayout = compile();\n render();\n }\n\n // ---------------------------------------------------------------------------\n // Export\n // ---------------------------------------------------------------------------\n\n function exportChart(\n format: 'svg' | 'svg-with-fonts' | 'png' | 'jpg',\n options_?: JPGExportOptions | SVGExportOptions,\n ): string | Promise<Blob> | Promise<string> {\n if (!svgElement) return '';\n\n // Export settled geometry, independent of transient hover and animation.\n const terminalSvg = renderTileMapSVG(currentLayout, { animate: false });\n const resolvedOptions = { theme: currentLayout.theme, ...options_ };\n\n switch (format) {\n case 'svg':\n return exportSVG(terminalSvg);\n case 'svg-with-fonts':\n return exportSVGWithFonts(terminalSvg, resolvedOptions);\n case 'png':\n return exportPNG(terminalSvg, resolvedOptions);\n case 'jpg':\n return exportJPG(terminalSvg, resolvedOptions);\n default:\n return '';\n }\n }\n\n // ---------------------------------------------------------------------------\n // Destroy\n // ---------------------------------------------------------------------------\n\n function destroy(): void {\n if (destroyed) return;\n destroyed = true;\n\n // Cancel running animations\n if (animationCleanup) {\n cancelAnimations(svgElement);\n animationCleanup();\n animationCleanup = null;\n }\n\n // Clean up events\n if (cleanupTooltipEvents) {\n cleanupTooltipEvents();\n cleanupTooltipEvents = null;\n }\n\n // Remove SVG\n if (svgElement) {\n svgElement.remove();\n svgElement = null;\n }\n\n // Unmount tooltip manager\n if (tooltipManager) {\n tooltipManager.destroy();\n tooltipManager = null;\n }\n\n // Disconnect resize observer\n if (disconnectResize) {\n disconnectResize();\n disconnectResize = null;\n }\n\n // Remove root classes\n container.classList.remove('oc-tilemap-root', 'oc-dark');\n }\n\n // ---------------------------------------------------------------------------\n // Initialize\n // ---------------------------------------------------------------------------\n\n // Root class was applied before the measurer was built (see above); dark\n // mode class still applies here.\n if (resolveDarkMode(options?.darkMode)) {\n container.classList.add('oc-dark');\n }\n\n // Initial compile and render (animate on first mount)\n currentLayout = compile();\n render(true);\n\n // Recompile once after webfonts load so labels aren't stuck measured\n // against fallback metrics on real devices.\n const fontsPending = scheduleFontReload(\n fontFamily,\n () => !destroyed,\n () => {\n // Mark the reload owed, then recompile. render() flips the attribute to\n // 'ready' once it actually recompiles, including the pendingResize replay\n // after the entrance animation finishes.\n fontsReloadPending = true;\n resize();\n },\n );\n container.dataset.ocFontsState = fontsPending ? 'pending' : 'ready';\n\n // Setup responsive resizing\n if (options?.responsive !== false) {\n disconnectResize = observeResize(container, () => {\n resize();\n });\n }\n\n return {\n update,\n resize,\n export: exportChart,\n destroy,\n get layout(): TileMapLayout {\n return currentLayout;\n },\n };\n}\n"],"mappings":"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","names":["live","SVG_NS","XLINK_NS","BRAND_URL","createSVGElement","setAttrs","renderChrome","cell","BRAND_FONT_SIZE","clampStaggerDelay","BRAND_URL","div","BRAND_FONT_SIZE","clampStaggerDelay","BREAKPOINT_COMPACT_MAX","BREAKPOINT_COMPACT_MAX"]}
|