From 7e382b5922da7d791a35df6127862842158b84e9 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Wed, 9 Sep 2026 15:08:53 -0400 Subject: [PATCH 01/15] feat(docs): Add in-page editing for live examples --- docs/generated/releases/layerchart-2.4.0.md | 32 ++ docs/generated/releases/layerchart-2.4.1.md | 18 + docs/package.json | 10 +- docs/src/lib/sandbox/CodeEditor.svelte | 315 ++++++++++++++++++ docs/src/lib/sandbox/LiveExample.svelte | 257 ++++++++++++++ docs/src/lib/sandbox/compile.ts | 78 +++++ docs/src/lib/sandbox/lazy.ts | 10 + docs/src/lib/sandbox/link.ts | 79 +++++ docs/src/lib/sandbox/registry.ts | 47 +++ docs/src/routes/docs/playground/+page.svelte | 16 +- .../routes/docs/playground/CodeEditor.svelte | 131 -------- docs/src/routes/docs/sandbox-poc/+page.svelte | 40 +++ pnpm-lock.yaml | 198 +++++------ 13 files changed, 988 insertions(+), 243 deletions(-) create mode 100644 docs/generated/releases/layerchart-2.4.0.md create mode 100644 docs/generated/releases/layerchart-2.4.1.md create mode 100644 docs/src/lib/sandbox/CodeEditor.svelte create mode 100644 docs/src/lib/sandbox/LiveExample.svelte create mode 100644 docs/src/lib/sandbox/compile.ts create mode 100644 docs/src/lib/sandbox/lazy.ts create mode 100644 docs/src/lib/sandbox/link.ts create mode 100644 docs/src/lib/sandbox/registry.ts delete mode 100644 docs/src/routes/docs/playground/CodeEditor.svelte create mode 100644 docs/src/routes/docs/sandbox-poc/+page.svelte diff --git a/docs/generated/releases/layerchart-2.4.0.md b/docs/generated/releases/layerchart-2.4.0.md new file mode 100644 index 0000000000..1c380f8605 --- /dev/null +++ b/docs/generated/releases/layerchart-2.4.0.md @@ -0,0 +1,32 @@ +--- +title: "layerchart@2.4.0" +tag: "layerchart@2.4.0" +date: "2026-09-04T14:33:43Z" +url: "https://github.com/techniq/layerchart/releases/tag/layerchart%402.4.0" +draft: false +prerelease: false +author: "github-actions[bot]" +--- +### Minor Changes + +- feat(Axis): Add `tickOcclusion` to drop ticks whose labels would overlap, measured at the size they render (including rotation), with `priority` of `'end'` (default), `'start'`, or `'start-end'` to choose which survive ([#909](https://github.com/techniq/layerchart/pull/909)) + +- feat(utils): Add `rotate` and multiline support to `getTextRect`, so a rotated or stacked `` can be measured for `occlude` without the caller reproducing ``'s pivot ([#909](https://github.com/techniq/layerchart/pull/909)) + +### Patch Changes + +- fix(Area): Apply `mask`, `filter`, and `clip-path` to the `line` path as well as the fill (unless overrideden by `line={{...}}`) ([#909](https://github.com/techniq/layerchart/pull/909)) + +- fix(Calendar): Adjust month labels after recent Text verticalAnchor improvements ([#909](https://github.com/techniq/layerchart/pull/909)) + +- fix(Calendar): Size cells to fit `monthPath`, which can extend past the last cell when the range ends mid-month ([#909](https://github.com/techniq/layerchart/pull/909)) + +- perf(Chart): Measure the container before building the subtree, so marks are only built once ([#909](https://github.com/techniq/layerchart/pull/909)) + +- fix(downloadImage, downloadSvg): Inline `stop-color`/`stop-opacity` so gradients don't export as solid black ([#909](https://github.com/techniq/layerchart/pull/909)) + +- fix(Chart): Return `undefined` from `xGet`/`yGet` when that axis has no accessor, instead of throwing `accessor is not a function` ([#909](https://github.com/techniq/layerchart/pull/909)) + +- fix(Spline, Area): Animate each path when the mark is split by `z`, which `motion` previously skipped — segments split by a style function are still redrawn outright ([#909](https://github.com/techniq/layerchart/pull/909)) + +- fix(Path, Spline): Render `endContent` without a `draw` transition ([#909](https://github.com/techniq/layerchart/pull/909)) \ No newline at end of file diff --git a/docs/generated/releases/layerchart-2.4.1.md b/docs/generated/releases/layerchart-2.4.1.md new file mode 100644 index 0000000000..389b654cc0 --- /dev/null +++ b/docs/generated/releases/layerchart-2.4.1.md @@ -0,0 +1,18 @@ +--- +title: "layerchart@2.4.1" +tag: "layerchart@2.4.1" +date: "2026-09-08T20:16:46Z" +url: "https://github.com/techniq/layerchart/releases/tag/layerchart%402.4.1" +draft: false +prerelease: false +author: "github-actions[bot]" +--- +### Patch Changes + +- fix(deps): Bump `@layerstack/*` dependencies to fix `Package subpath is not defined by exports` when bundling without Vite (issue #913) ([#915](https://github.com/techniq/layerchart/pull/915)) + +- fix(Spline): Render `startContent`, `endContent`, `markerStart`, and `markerEnd` once per line rather than once per style-split segment ([#914](https://github.com/techniq/layerchart/pull/914)) + +- fix(Spline): Keep the line's color on segments split by a `class`, `opacity`, or `fill` function ([#914](https://github.com/techniq/layerchart/pull/914)) + +- fix(Spline): Animate segments split by a style function, which `motion` previously skipped ([#914](https://github.com/techniq/layerchart/pull/914)) \ No newline at end of file diff --git a/docs/package.json b/docs/package.json index a23bfb7e39..2ad1b41a29 100644 --- a/docs/package.json +++ b/docs/package.json @@ -109,17 +109,23 @@ "zod": "^4.4.3" }, "dependencies": { + "@codemirror/autocomplete": "^6.20.1", + "@codemirror/commands": "^6.10.0", "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-html": "^6.4.11", "@codemirror/lang-javascript": "^6.2.5", + "@codemirror/lang-json": "^6.0.2", + "@codemirror/language": "^6.12.2", + "@codemirror/lint": "^6.9.5", "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.40.0", "@fontsource/inter": "^5.2.8", + "@lezer/highlight": "^1.2.3", + "@replit/codemirror-lang-svelte": "^6.0.0", "@resvg/resvg-js": "^2.6.2", "@stackblitz/sdk": "^1.11.0", - "@uiw/codemirror-theme-github": "^4.25.10", "@webcontainer/api": "^1.6.4", "ansi_up": "^6.0.6", - "codemirror": "^6.0.2", "d3-geo-projection": "^4.0.0", "satori": "^0.26.0", "satori-html": "^0.3.2" diff --git a/docs/src/lib/sandbox/CodeEditor.svelte b/docs/src/lib/sandbox/CodeEditor.svelte new file mode 100644 index 0000000000..cc691322ac --- /dev/null +++ b/docs/src/lib/sandbox/CodeEditor.svelte @@ -0,0 +1,315 @@ + + +
diff --git a/docs/src/lib/sandbox/LiveExample.svelte b/docs/src/lib/sandbox/LiveExample.svelte new file mode 100644 index 0000000000..5a89fe5162 --- /dev/null +++ b/docs/src/lib/sandbox/LiveExample.svelte @@ -0,0 +1,257 @@ + + +
+
+ {#if mode === 'edit' && sandbox} + + {:else} + + + {/if} + + + +
+ {#if editorValue !== original} + +
+ + {#if loadError} +
+ Couldn't load the editor: {loadError} +
+ {/if} +
+ +
+ {#if live} +
+ {:else} + {@render preview?.()} + {/if} + + {#if status} +
+ {status} +
+ {/if} +
+
+ + diff --git a/docs/src/lib/sandbox/compile.ts b/docs/src/lib/sandbox/compile.ts new file mode 100644 index 0000000000..510464fa51 --- /dev/null +++ b/docs/src/lib/sandbox/compile.ts @@ -0,0 +1,78 @@ +import { compile } from 'svelte/compiler'; +import { link } from './link'; + +export type Diagnostic = { + from: number; + to: number; + severity: 'error' | 'warning'; + message: string; +}; + +export type CompileResult = { + /** Blob URL of the linked module, or `null` when compilation failed. */ + url: string | null; + diagnostics: Diagnostic[]; + /** Time spent compiling + linking, in ms. */ + elapsed: number; +}; + +/** Strip the trailing `https://svelte.dev/e/...` docs link the compiler appends. */ +function cleanMessage(message: string) { + return message.replace(/\s*https:\/\/svelte\.dev\/[ew]\/\S+\s*$/, ''); +} + +export function compileSource(source: string): CompileResult { + const started = performance.now(); + const diagnostics: Diagnostic[] = []; + + let js: string; + let warnings: { message: string; start?: { character: number }; end?: { character: number } }[]; + + try { + const result = compile(source, { + filename: 'Example.svelte', + generate: 'client', + css: 'injected', + runes: true, + dev: false + }); + js = result.js.code; + warnings = result.warnings ?? []; + } catch (err: any) { + // `position` is a `[from, to]` character-offset pair, which is what the editor wants. + const [from, to] = err.position ?? [0, 0]; + return { + url: null, + diagnostics: [ + { from, to, severity: 'error', message: cleanMessage(err.message ?? String(err)) } + ], + elapsed: performance.now() - started + }; + } + + for (const warning of warnings) { + diagnostics.push({ + from: warning.start?.character ?? 0, + to: warning.end?.character ?? 0, + severity: 'warning', + message: cleanMessage(warning.message) + }); + } + + const linked = link(js); + if (!linked.ok) { + // No source position for an unresolved import — pin it to the offending specifier. + for (const specifier of linked.unresolved) { + const at = source.indexOf(specifier); + diagnostics.push({ + from: at === -1 ? 0 : at, + to: at === -1 ? 0 : at + specifier.length, + severity: 'error', + message: `'${specifier}' is not available in the sandbox` + }); + } + return { url: null, diagnostics, elapsed: performance.now() - started }; + } + + return { url: linked.url, diagnostics, elapsed: performance.now() - started }; +} diff --git a/docs/src/lib/sandbox/lazy.ts b/docs/src/lib/sandbox/lazy.ts new file mode 100644 index 0000000000..b0e59b7ab8 --- /dev/null +++ b/docs/src/lib/sandbox/lazy.ts @@ -0,0 +1,10 @@ +/** + * Single dynamic-import boundary for the sandbox. + * + * Everything reachable from here — `svelte/compiler`, CodeMirror, and the module + * registry — must only ever be loaded via `import('./lazy')`, so that docs pages + * that are never edited don't pay for any of it. Don't import this module statically. + */ +export { compileSource, type Diagnostic, type CompileResult } from './compile'; +export { availableModules } from './link'; +export { default as CodeEditor } from './CodeEditor.svelte'; diff --git a/docs/src/lib/sandbox/link.ts b/docs/src/lib/sandbox/link.ts new file mode 100644 index 0000000000..a1171990ef --- /dev/null +++ b/docs/src/lib/sandbox/link.ts @@ -0,0 +1,79 @@ +import { registry } from './registry'; + +const GLOBAL_KEY = '__layerchartSandboxRegistry'; + +/** Blob URL per specifier — a module's export shape never changes, so build each shim once. */ +const shimUrls = new Map(); + +function ensureGlobal() { + (globalThis as any)[GLOBAL_KEY] = registry; +} + +/** + * Build an ES module that re-exports a registry entry. + * + * Export names are read off the live namespace object, so this covers reserved + * words (`default`, `class`) and anything else that isn't a bare identifier. + */ +function shimFor(specifier: string): string | undefined { + const cached = shimUrls.get(specifier); + if (cached) return cached; + + const ns = registry[specifier]; + if (!ns) return undefined; + + const names = Object.keys(ns); + const lines = [`const m = globalThis[${JSON.stringify(GLOBAL_KEY)}][${JSON.stringify(specifier)}];`]; + const exports: string[] = []; + names.forEach((name, i) => { + lines.push(`const _${i} = m[${JSON.stringify(name)}];`); + exports.push(`_${i} as ${JSON.stringify(name)}`); + }); + lines.push(exports.length ? `export { ${exports.join(', ')} };` : 'export {};'); + + const url = URL.createObjectURL(new Blob([lines.join('\n')], { type: 'text/javascript' })); + shimUrls.set(specifier, url); + return url; +} + +/** + * Import statements in compiled Svelte output are machine-generated, one per line, at the top. + * The `[^'"\n]` classes keep this from running past the statement into unrelated string + * literals (`export default function …` followed later by `value: 'integer'`). + * + * A production version should lex with `es-module-lexer` rather than pattern-match. + */ +const IMPORT_RE = /^(\s*(?:import|export)\b(?:[^'"\n]*?\bfrom)?\s*)(['"])([^'"\n]+)\2/gm; + +export type LinkResult = { ok: true; url: string } | { ok: false; unresolved: string[] }; + +/** Rewrite bare specifiers to registry shims and return a blob URL for the module. */ +export function link(js: string): LinkResult { + ensureGlobal(); + const unresolved: string[] = []; + + const rewritten = js.replace(IMPORT_RE, (match, prefix, quote, specifier) => { + if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('blob:')) { + return match; + } + const url = shimFor(specifier); + if (!url) { + unresolved.push(specifier); + return match; + } + return prefix + quote + url + quote; + }); + + if (unresolved.length) { + return { ok: false, unresolved }; + } + + return { + ok: true, + url: URL.createObjectURL(new Blob([rewritten], { type: 'text/javascript' })) + }; +} + +export function availableModules() { + return Object.keys(registry).filter((k) => !k.startsWith('svelte/internal')); +} diff --git a/docs/src/lib/sandbox/registry.ts b/docs/src/lib/sandbox/registry.ts new file mode 100644 index 0000000000..c7b7785326 --- /dev/null +++ b/docs/src/lib/sandbox/registry.ts @@ -0,0 +1,47 @@ +/** + * Modules the sandbox exposes to user code. + * + * These are the *same* instances the docs app itself is built with, so an edited + * example runs against the workspace build of `layerchart` (not a published copy + * fetched from a CDN) and shares a single Svelte runtime with the host page. + */ +import * as svelte from 'svelte'; +// Compiled components import this; it's deliberately untyped by Svelte, and we only +// ever hand the namespace object back out again. +// @ts-expect-error - no declarations for 'svelte/internal/client' +import * as svelteInternalClient from 'svelte/internal/client'; +import * as svelteEasing from 'svelte/easing'; +import * as svelteTransition from 'svelte/transition'; +import * as layerchart from 'layerchart'; +import * as d3Array from 'd3-array'; +import * as d3Scale from 'd3-scale'; +import * as d3ScaleChromatic from 'd3-scale-chromatic'; +import * as d3Time from 'd3-time'; +import * as d3Shape from 'd3-shape'; +import * as svelteUx from 'svelte-ux'; +import * as layerstackUtils from '@layerstack/utils'; +import * as layerstackTailwind from '@layerstack/tailwind'; +import * as data from '$lib/utils/data'; + +const empty = {}; + +export const registry: Record> = { + svelte, + 'svelte/internal/client': svelteInternalClient, + // Side-effect-only imports in compiled output — nothing to re-export. + 'svelte/internal/disclose-version': empty, + 'svelte/internal/flags/legacy': empty, + 'svelte/easing': svelteEasing, + 'svelte/transition': svelteTransition, + layerchart, + 'd3-array': d3Array, + 'd3-scale': d3Scale, + 'd3-scale-chromatic': d3ScaleChromatic, + 'd3-time': d3Time, + 'd3-shape': d3Shape, + 'svelte-ux': svelteUx, + '@layerstack/utils': layerstackUtils, + '@layerstack/tailwind': layerstackTailwind, + '$lib/utils/data': data, + '$lib/utils/data.js': data +}; diff --git a/docs/src/routes/docs/playground/+page.svelte b/docs/src/routes/docs/playground/+page.svelte index 6377bf7437..6f528ffe12 100644 --- a/docs/src/routes/docs/playground/+page.svelte +++ b/docs/src/routes/docs/playground/+page.svelte @@ -29,7 +29,6 @@ - -
diff --git a/docs/src/routes/docs/sandbox-poc/+page.svelte b/docs/src/routes/docs/sandbox-poc/+page.svelte new file mode 100644 index 0000000000..1ce0989615 --- /dev/null +++ b/docs/src/routes/docs/sandbox-poc/+page.svelte @@ -0,0 +1,40 @@ + + +
+
+

Sandbox proof of concept

+

+ The chart on the right is the real example component. Click into the code and it's replaced by + an in-page compile of whatever you type — the compiler and editor load on that first click. +

+
+ +
+

AreaChart / series-stack

+ + {#snippet preview()} + + {/snippet} + +
+ +
+

LineChart / basic

+ + {#snippet preview()} + + {/snippet} + +
+
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f2b8410c9d..2db089d47b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -50,6 +50,12 @@ importers: docs: dependencies: + '@codemirror/autocomplete': + specifier: ^6.20.1 + version: 6.20.1 + '@codemirror/commands': + specifier: ^6.10.0 + version: 6.10.0 '@codemirror/lang-css': specifier: ^6.3.1 version: 6.3.1 @@ -59,30 +65,42 @@ importers: '@codemirror/lang-javascript': specifier: ^6.2.5 version: 6.2.5 + '@codemirror/lang-json': + specifier: ^6.0.2 + version: 6.0.2 + '@codemirror/language': + specifier: ^6.12.2 + version: 6.12.2 + '@codemirror/lint': + specifier: ^6.9.5 + version: 6.9.5 '@codemirror/state': specifier: ^6.6.0 version: 6.6.0 + '@codemirror/view': + specifier: ^6.40.0 + version: 6.40.0 '@fontsource/inter': specifier: ^5.2.8 version: 5.2.8 + '@lezer/highlight': + specifier: ^1.2.3 + version: 1.2.3 + '@replit/codemirror-lang-svelte': + specifier: ^6.0.0 + version: 6.0.0(@codemirror/autocomplete@6.20.1)(@codemirror/lang-css@6.3.1)(@codemirror/lang-html@6.4.11)(@codemirror/lang-javascript@6.2.5)(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0)(@lezer/common@1.5.1)(@lezer/highlight@1.2.3)(@lezer/javascript@1.5.4)(@lezer/lr@1.4.8) '@resvg/resvg-js': specifier: ^2.6.2 version: 2.6.2 '@stackblitz/sdk': specifier: ^1.11.0 version: 1.11.0 - '@uiw/codemirror-theme-github': - specifier: ^4.25.10 - version: 4.25.10(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0) '@webcontainer/api': specifier: ^1.6.4 version: 1.6.4 ansi_up: specifier: ^6.0.6 version: 6.0.6 - codemirror: - specifier: ^6.0.2 - version: 6.0.2 d3-geo-projection: specifier: ^4.0.0 version: 4.0.0 @@ -302,7 +320,7 @@ importers: version: 5.56.1(@typescript-eslint/types@8.60.1) svelte-check: specifier: ^4.5.0 - version: 4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) + version: 4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) svelte-ux: specifier: 2.0.0-next.22 version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0))(postcss@8.5.15)(svelte@5.56.1(@typescript-eslint/types@8.60.1)) @@ -1095,9 +1113,6 @@ packages: '@cloudflare/workers-types@4.20260219.0': resolution: {integrity: sha512-jL2BNnDqbKXDrxhtKx+wVmQpv/P6w8J4WVFiuT9OMEPsw8V2TfTozoWTcCZ2AhE09yK406xQFE4mBq9IIgobuw==} - '@codemirror/autocomplete@6.20.0': - resolution: {integrity: sha512-bOwvTOIJcG5FVo5gUUupiwYh8MioPLQ4UcqbcRf7UQ98X90tCa9E1kZ3Z7tqwpZxYyOvh1YTYbmZE9RTfTp5hg==} - '@codemirror/autocomplete@6.20.1': resolution: {integrity: sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A==} @@ -1113,27 +1128,18 @@ packages: '@codemirror/lang-javascript@6.2.5': resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} - '@codemirror/language@6.11.3': - resolution: {integrity: sha512-9HBM2XnwDj7fnu0551HkGdrUrrqmYq/WC5iv6nbY2WdicXdGbhR/gfbZOH73Aqj4351alY1+aoG9rCNfiwS1RA==} + '@codemirror/lang-json@6.0.2': + resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} '@codemirror/language@6.12.2': resolution: {integrity: sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==} - '@codemirror/lint@6.9.2': - resolution: {integrity: sha512-sv3DylBiIyi+xKwRCJAAsBZZZWo82shJ/RTMymLabAdtbkV5cSKwWDeCgtUq3v8flTaXS2y1kKkICuRYtUswyQ==} - '@codemirror/lint@6.9.5': resolution: {integrity: sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA==} - '@codemirror/search@6.5.11': - resolution: {integrity: sha512-KmWepDE6jUdL6n8cAAqIpRmLPBZ5ZKnicE8oGU/s3QrAVID+0VhLFrzUucVKHG5035/BSykhExDL/Xm7dHthiA==} - '@codemirror/state@6.6.0': resolution: {integrity: sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ==} - '@codemirror/view@6.38.8': - resolution: {integrity: sha512-XcE9fcnkHCbWkjeKyi0lllwXmBLtyYb5dt89dJyx23I9+LSh5vZDIuk7OLG4VM1lgrXZQcY6cxyZyk5WVPRv/A==} - '@codemirror/view@6.40.0': resolution: {integrity: sha512-WA0zdU7xfF10+5I3HhUUq3kqOx3KjqmtQ9lqZjfK7jtYk4G72YW9rezcSywpaUMCWOMlq+6E0pO1IWg1TNIhtg==} @@ -2002,8 +2008,8 @@ packages: '@lezer/javascript@1.5.4': resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==} - '@lezer/lr@1.4.4': - resolution: {integrity: sha512-LHL17Mq0OcFXm1pGQssuGTQFPPdxARjKM8f7GA5+sGtHi0K3R84YaSbmche0+RKWHnCsx9asEe5OWOI4FHfe4A==} + '@lezer/json@1.0.3': + resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} '@lezer/lr@1.4.8': resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} @@ -2363,6 +2369,21 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} + '@replit/codemirror-lang-svelte@6.0.0': + resolution: {integrity: sha512-U2OqqgMM6jKelL0GNWbAmqlu1S078zZNoBqlJBW+retTc5M4Mha6/Y2cf4SVg6ddgloJvmcSpt4hHrVoM4ePRA==} + peerDependencies: + '@codemirror/autocomplete': ^6.0.0 + '@codemirror/lang-css': ^6.0.1 + '@codemirror/lang-html': ^6.2.0 + '@codemirror/lang-javascript': ^6.1.1 + '@codemirror/language': ^6.0.0 + '@codemirror/state': ^6.0.0 + '@codemirror/view': ^6.0.0 + '@lezer/common': ^1.0.0 + '@lezer/highlight': ^1.0.0 + '@lezer/javascript': ^1.2.0 + '@lezer/lr': ^1.0.0 + '@resvg/resvg-js-android-arm-eabi@2.6.2': resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==} engines: {node: '>= 10'} @@ -3153,16 +3174,6 @@ packages: resolution: {integrity: sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@uiw/codemirror-theme-github@4.25.10': - resolution: {integrity: sha512-iMM2QT4FaebJMO4W7lXmxNkRPIjKzgY26wL0QG0Ugy0gzsnxoNz4zgNeFIblPA8rvrN3vOIhNNh4nk9UOlFKxA==} - - '@uiw/codemirror-themes@4.25.10': - resolution: {integrity: sha512-Fqiz1HIuDlDftcL+/O53V333UOH6MqQ84VbiQB5egn6u+uDwAqACp1FrdAoi4wgpR3b3TGW4Gr0wIYcrJSSz1A==} - peerDependencies: - '@codemirror/language': '>=6.0.0' - '@codemirror/state': '>=6.0.0' - '@codemirror/view': '>=6.0.0' - '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} deprecated: Potential CWE-502 - Update to 1.3.1 or higher @@ -3832,9 +3843,6 @@ packages: code-red@1.0.4: resolution: {integrity: sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==} - codemirror@6.0.2: - resolution: {integrity: sha512-VhydHotNW5w1UGK0Qj96BwSk/Zqbp9WbnyK2W/eVMv4QyF41INRGpjUhFJY7/uDNuudSc33a/PKr4iDqRduvHw==} - color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} @@ -6425,13 +6433,6 @@ snapshots: '@cloudflare/workers-types@4.20260219.0': {} - '@codemirror/autocomplete@6.20.0': - dependencies: - '@codemirror/language': 6.11.3 - '@codemirror/state': 6.6.0 - '@codemirror/view': 6.38.8 - '@lezer/common': 1.4.0 - '@codemirror/autocomplete@6.20.1': dependencies: '@codemirror/language': 6.12.2 @@ -6441,27 +6442,27 @@ snapshots: '@codemirror/commands@6.10.0': dependencies: - '@codemirror/language': 6.11.3 + '@codemirror/language': 6.12.2 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.38.8 - '@lezer/common': 1.4.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 '@codemirror/lang-css@6.3.1': dependencies: - '@codemirror/autocomplete': 6.20.0 - '@codemirror/language': 6.11.3 + '@codemirror/autocomplete': 6.20.1 + '@codemirror/language': 6.12.2 '@codemirror/state': 6.6.0 '@lezer/common': 1.4.0 '@lezer/css': 1.3.0 '@codemirror/lang-html@6.4.11': dependencies: - '@codemirror/autocomplete': 6.20.0 + '@codemirror/autocomplete': 6.20.1 '@codemirror/lang-css': 6.3.1 '@codemirror/lang-javascript': 6.2.5 - '@codemirror/language': 6.11.3 + '@codemirror/language': 6.12.2 '@codemirror/state': 6.6.0 - '@codemirror/view': 6.38.8 + '@codemirror/view': 6.40.0 '@lezer/common': 1.4.0 '@lezer/css': 1.3.0 '@lezer/html': 1.3.12 @@ -6476,14 +6477,10 @@ snapshots: '@lezer/common': 1.5.1 '@lezer/javascript': 1.5.4 - '@codemirror/language@6.11.3': + '@codemirror/lang-json@6.0.2': dependencies: - '@codemirror/state': 6.6.0 - '@codemirror/view': 6.38.8 - '@lezer/common': 1.4.0 - '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.4 - style-mod: 4.1.3 + '@codemirror/language': 6.12.2 + '@lezer/json': 1.0.3 '@codemirror/language@6.12.2': dependencies: @@ -6494,35 +6491,16 @@ snapshots: '@lezer/lr': 1.4.8 style-mod: 4.1.3 - '@codemirror/lint@6.9.2': - dependencies: - '@codemirror/state': 6.6.0 - '@codemirror/view': 6.38.8 - crelt: 1.0.6 - '@codemirror/lint@6.9.5': dependencies: '@codemirror/state': 6.6.0 '@codemirror/view': 6.40.0 crelt: 1.0.6 - '@codemirror/search@6.5.11': - dependencies: - '@codemirror/state': 6.6.0 - '@codemirror/view': 6.38.8 - crelt: 1.0.6 - '@codemirror/state@6.6.0': dependencies: '@marijn/find-cluster-break': 1.0.2 - '@codemirror/view@6.38.8': - dependencies: - '@codemirror/state': 6.6.0 - crelt: 1.0.6 - style-mod: 4.1.3 - w3c-keyname: 2.2.8 - '@codemirror/view@6.40.0': dependencies: '@codemirror/state': 6.6.0 @@ -7235,19 +7213,19 @@ snapshots: '@lezer/css@1.3.0': dependencies: - '@lezer/common': 1.4.0 + '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.4 + '@lezer/lr': 1.4.8 '@lezer/highlight@1.2.3': dependencies: - '@lezer/common': 1.4.0 + '@lezer/common': 1.5.1 '@lezer/html@1.3.12': dependencies: - '@lezer/common': 1.4.0 + '@lezer/common': 1.5.1 '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.4 + '@lezer/lr': 1.4.8 '@lezer/javascript@1.5.4': dependencies: @@ -7255,9 +7233,11 @@ snapshots: '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.8 - '@lezer/lr@1.4.4': + '@lezer/json@1.0.3': dependencies: - '@lezer/common': 1.4.0 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/lr': 1.4.8 '@lezer/lr@1.4.8': dependencies: @@ -7545,6 +7525,20 @@ snapshots: dependencies: quansync: 1.0.0 + '@replit/codemirror-lang-svelte@6.0.0(@codemirror/autocomplete@6.20.1)(@codemirror/lang-css@6.3.1)(@codemirror/lang-html@6.4.11)(@codemirror/lang-javascript@6.2.5)(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0)(@lezer/common@1.5.1)(@lezer/highlight@1.2.3)(@lezer/javascript@1.5.4)(@lezer/lr@1.4.8)': + dependencies: + '@codemirror/autocomplete': 6.20.1 + '@codemirror/lang-css': 6.3.1 + '@codemirror/lang-html': 6.4.11 + '@codemirror/lang-javascript': 6.2.5 + '@codemirror/language': 6.12.2 + '@codemirror/state': 6.6.0 + '@codemirror/view': 6.40.0 + '@lezer/common': 1.5.1 + '@lezer/highlight': 1.2.3 + '@lezer/javascript': 1.5.4 + '@lezer/lr': 1.4.8 + '@resvg/resvg-js-android-arm-eabi@2.6.2': optional: true @@ -8343,20 +8337,6 @@ snapshots: '@typescript-eslint/types': 8.60.1 eslint-visitor-keys: 5.0.1 - '@uiw/codemirror-theme-github@4.25.10(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0)': - dependencies: - '@uiw/codemirror-themes': 4.25.10(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0) - transitivePeerDependencies: - - '@codemirror/language' - - '@codemirror/state' - - '@codemirror/view' - - '@uiw/codemirror-themes@4.25.10(@codemirror/language@6.12.2)(@codemirror/state@6.6.0)(@codemirror/view@6.40.0)': - dependencies: - '@codemirror/language': 6.12.2 - '@codemirror/state': 6.6.0 - '@codemirror/view': 6.40.0 - '@ungap/structured-clone@1.3.0': {} '@unocss/cli@66.7.0': @@ -9566,16 +9546,6 @@ snapshots: estree-walker: 3.0.3 periscopic: 3.1.0 - codemirror@6.0.2: - dependencies: - '@codemirror/autocomplete': 6.20.0 - '@codemirror/commands': 6.10.0 - '@codemirror/language': 6.11.3 - '@codemirror/lint': 6.9.2 - '@codemirror/search': 6.5.11 - '@codemirror/state': 6.6.0 - '@codemirror/view': 6.38.8 - color-name@1.1.4: {} colorette@2.0.20: {} @@ -11702,6 +11672,18 @@ snapshots: - stylus - sugarss + svelte-check@4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + chokidar: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.56.1(@typescript-eslint/types@8.60.1) + typescript: 6.0.3 + transitivePeerDependencies: + - picomatch + svelte-check@4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 From d781cbb5ebdeec66e1643a398b9effc2713dc94c Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Wed, 9 Sep 2026 16:13:22 -0400 Subject: [PATCH 02/15] feat(docs): Add in-page editing for all examples --- docs/generated/releases/layerchart-2.5.0.md | 12 + docs/src/lib/components/Example.svelte | 48 +++- docs/src/lib/sandbox/CodePanel.svelte | 132 +++++++++++ docs/src/lib/sandbox/LiveExample.svelte | 236 +------------------- docs/src/lib/sandbox/state.svelte.ts | 195 ++++++++++++++++ docs/src/lib/utils/exampleSource.ts | 41 ++++ 6 files changed, 435 insertions(+), 229 deletions(-) create mode 100644 docs/generated/releases/layerchart-2.5.0.md create mode 100644 docs/src/lib/sandbox/CodePanel.svelte create mode 100644 docs/src/lib/sandbox/state.svelte.ts create mode 100644 docs/src/lib/utils/exampleSource.ts diff --git a/docs/generated/releases/layerchart-2.5.0.md b/docs/generated/releases/layerchart-2.5.0.md new file mode 100644 index 0000000000..55cc0d42ba --- /dev/null +++ b/docs/generated/releases/layerchart-2.5.0.md @@ -0,0 +1,12 @@ +--- +title: "layerchart@2.5.0" +tag: "layerchart@2.5.0" +date: "2026-09-09T18:15:53Z" +url: "https://github.com/techniq/layerchart/releases/tag/layerchart%402.5.0" +draft: false +prerelease: false +author: "github-actions[bot]" +--- +### Minor Changes + +- feat(Group|Hull|Rule): Support `seriesKey` prop to fade the mark while another series is highlighted and remove it while the legend has that series hidden ([#917](https://github.com/techniq/layerchart/pull/917)) \ No newline at end of file diff --git a/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte index aec89ab4e1..b905ff94e7 100644 --- a/docs/src/lib/components/Example.svelte +++ b/docs/src/lib/components/Example.svelte @@ -20,9 +20,13 @@ import { resolveExamplePath } from '@layerstack/docs/content'; import { exampleViewTransitionName } from '@layerstack/docs/utils'; import { untrack } from 'svelte'; - import { Code, Json } from '@layerstack/docs/components'; + import { Json } from '@layerstack/docs/components'; + import CodePanel from '$lib/sandbox/CodePanel.svelte'; + import { createSandbox } from '$lib/sandbox/state.svelte'; + import { exposeData } from '$lib/utils/exampleSource'; import LucideCode from '~icons/lucide/code'; + import LucideRotateCcw from '~icons/lucide/rotate-ccw'; import LucideFullscreen from '~icons/lucide/fullscreen'; import LucideTable from '~icons/lucide/table'; import LucideFilePen from '~icons/lucide/file-pen'; @@ -128,9 +132,17 @@ } let ref = $state(null); + + /** + * In-page editing. `example.source` resolves asynchronously, so the sandbox seeds + * itself from the getter rather than a constructor argument. + */ + const sandbox = createSandbox(() => example?.source ?? '', exposeData); + let data = $derived.by(() => { try { - return ref?.data; + // Once edited, the chart on screen is the sandbox's, so `Data` must read from it. + return sandbox.live ? sandbox.instance?.data : ref?.data; } catch { return undefined; } @@ -270,7 +282,12 @@ > {#if isVisible} - + {#if sandbox.live} + +
+ {:else} + + {/if} {#snippet failed(error, reset)}
@@ -315,7 +332,16 @@ {#if showCode}
- + +
+ {/if} + + {#if sandbox.status && sandbox.hasError} +
+ {sandbox.status}
{/if} @@ -331,6 +357,20 @@ {/if} + + {#if sandbox.dirty} + + {/if} + {#if data}
+ + {#if sandbox.loadError} +
+ Couldn't load the editor: {sandbox.loadError} +
+ {/if} +
+ + diff --git a/docs/src/lib/sandbox/LiveExample.svelte b/docs/src/lib/sandbox/LiveExample.svelte index 5a89fe5162..921cc521f0 100644 --- a/docs/src/lib/sandbox/LiveExample.svelte +++ b/docs/src/lib/sandbox/LiveExample.svelte @@ -1,13 +1,8 @@
-
- {#if mode === 'edit' && sandbox} - - {:else} - - - {/if} - - - -
- {#if editorValue !== original} - -
- - {#if loadError} -
- Couldn't load the editor: {loadError} -
- {/if} -
+
- {#if live} -
+ {#if sandbox.live} +
{:else} {@render preview?.()} {/if} - {#if status} + {#if sandbox.status}
- {status} + {sandbox.status}
{/if}
- - diff --git a/docs/src/lib/sandbox/state.svelte.ts b/docs/src/lib/sandbox/state.svelte.ts new file mode 100644 index 0000000000..beb1677a8d --- /dev/null +++ b/docs/src/lib/sandbox/state.svelte.ts @@ -0,0 +1,195 @@ +import { mount, unmount, untrack } from 'svelte'; +import type { Attachment } from 'svelte/attachments'; +import { normalizeSource } from '$lib/utils/exampleSource'; +import type { Diagnostic } from './compile'; + +type SandboxModule = typeof import('./lazy'); + +/** + * Everything needed to turn a read-only example into an editable one, shared by + * `Example` (stacked, code behind a disclosure) and `LiveExample` (side-by-side). + * + * Must be called during component initialisation — it registers effects. + */ +export function createSandbox( + getSource: () => string, + /** Applied to the source before compiling only — never shown in the editor. */ + transform?: (source: string) => string +) { + let module = $state(null); + let loading = $state(false); + let pending = $state(false); + let loadError = $state(null); + + let mode = $state<'view' | 'edit'>('view'); + let live = $state(false); + + /** + * `Example` resolves its source asynchronously, so these are seeded on first sight of a + * non-empty source rather than at construction. Normalised so the editor starts from + * exactly the text `Code` displays — otherwise Edit shows a trailing blank line View + * doesn't have. + */ + const seed = () => normalizeSource(getSource()); + let original = $state(untrack(seed)); + let editorValue = $state(untrack(seed)); + let debounced = $state(untrack(seed)); + + let diagnostics = $state([]); + let elapsed = $state(0); + let runtimeError = $state(null); + /** + * `$state.raw` — `mount()` returns an exports object whose properties are getters onto + * the component's reactive state. Wrapping that in a `$state` proxy breaks them, so + * `instance.data` reads back `undefined` and the Data dialog vanishes after an edit. + */ + let instance = $state.raw | null>(null); + + $effect(() => { + const next = seed(); + untrack(() => { + if (next && !original) { + original = next; + editorValue = next; + debounced = next; + } + }); + }); + + /** + * The real example keeps rendering until the source actually changes. Compiling on + * activation instead would remount the chart the moment the editor opens, and examples + * built on `createDateSeries` and friends draw fresh `Math.random()` data every mount — + * so merely looking at the source would appear to redraw the chart. Latched, because + * toggling back on undo would reshuffle again. + */ + $effect(() => { + if (editorValue !== untrack(() => original)) live = true; + }); + + $effect(() => { + const next = editorValue; + const timer = setTimeout(() => (debounced = next), 120); + return () => clearTimeout(timer); + }); + + /** + * Returns the in-flight promise rather than bailing out when a fetch is already running: + * a click landing mid-prefetch has to await the *same* load, otherwise it resolves + * immediately and switches to a mode whose editor doesn't exist yet. + */ + let inFlight: Promise | null = null; + function load() { + if (module) return Promise.resolve(); + if (!inFlight) { + loading = true; + inFlight = import('./lazy') + .then((m) => { + module = m; + }) + .catch((err) => { + loadError = err instanceof Error ? err.message : String(err); + }) + .finally(() => { + loading = false; + }); + } + return inFlight; + } + + async function setMode(next: 'view' | 'edit') { + if (next === 'edit' && !module) { + // `pending` is distinct from `loading`: the hover prefetch sets `loading` too, and + // showing progress for a speculative fetch the user never asked for is just noise. + pending = true; + await load(); + pending = false; + } + mode = next; + } + + /** Compiles the current source and mounts it into the attached element. */ + const preview: Attachment = (el) => { + const sb = module; + const src = debounced; + if (!sb || !live) return; + + const result = sb.compileSource(transform ? transform(src) : src); + diagnostics = result.diagnostics; + elapsed = Math.round(result.elapsed); + if (!result.url) return; + + let mounted: Record | null = null; + let disposed = false; + + import(/* @vite-ignore */ result.url) + .then((mod) => { + URL.revokeObjectURL(result.url!); + if (disposed) return; + runtimeError = null; + mounted = mount(mod.default, { target: el as HTMLElement }); + instance = mounted; + }) + .catch((err) => { + URL.revokeObjectURL(result.url!); + if (!disposed) runtimeError = err instanceof Error ? err.message : String(err); + }); + + return () => { + disposed = true; + if (mounted) { + unmount(mounted); + if (instance === mounted) instance = null; + } + }; + }; + + const errors = $derived(diagnostics.filter((d) => d.severity === 'error')); + + return { + preview, + load, + setMode, + reset: () => (editorValue = original), + + get module() { + return module; + }, + get mode() { + return mode; + }, + get live() { + return live; + }, + get pending() { + return pending; + }, + get loadError() { + return loadError; + }, + get diagnostics() { + return diagnostics; + }, + get instance() { + return instance; + }, + get dirty() { + return editorValue !== original; + }, + get source() { + return editorValue; + }, + set source(next: string) { + editorValue = next; + }, + /** `null` until the user has edited — nothing worth reporting before that. */ + get status() { + return runtimeError ?? errors[0]?.message ?? (live ? `${elapsed}ms` : null); + }, + get hasError() { + return runtimeError !== null || errors.length > 0; + } + }; +} + +export type Sandbox = ReturnType; diff --git a/docs/src/lib/utils/exampleSource.ts b/docs/src/lib/utils/exampleSource.ts new file mode 100644 index 0000000000..33ac507a01 --- /dev/null +++ b/docs/src/lib/utils/exampleSource.ts @@ -0,0 +1,41 @@ +const CLOSE_SCRIPT = ''; + +/** + * Mirrors what `Code` actually renders — it displays `stripIndent(source)`, which strips + * the common leading indent and trims both ends. Seeding the editor with the raw source + * instead leaves the file's trailing newline as a visible empty last line, so Edit shows + * one more line than View. + * + * Kept in step by hand: `stripIndent` lives in `@layerstack/docs` but isn't re-exported + * from its public `utils` entry. + */ +export function normalizeSource(text: string) { + const lines = text.split('\n'); + const minIndent = lines + .filter((line) => line.trim().length > 0) + .reduce((min, line) => Math.min(min, line.match(/^(\s*)/)?.[1].length ?? 0), Infinity); + return lines + .map((line) => line.slice(minIndent)) + .join('\n') + .trim(); +} + +/** + * Examples end in `export { data };` on disk, but the docs pipeline strips it from the + * source it hands `Example` — it exists purely so the Data dialog can read the example's + * data, and showing it would just confuse readers. Put it back before compiling an edited + * example, or the Data button disappears the moment anyone types. + * + * Deliberately narrow: only when the source declares a top-level `data`, doesn't already + * export it, and has exactly one closing script tag to append to (a ` + + + diff --git a/docs/src/lib/sandbox/compile.ts b/docs/src/lib/sandbox/compile.ts index 510464fa51..2916ca4bfa 100644 --- a/docs/src/lib/sandbox/compile.ts +++ b/docs/src/lib/sandbox/compile.ts @@ -6,6 +6,9 @@ export type Diagnostic = { to: number; severity: 'error' | 'warning'; message: string; + /** 1-based, for the error overlay. Absent when the compiler gave no position. */ + line?: number; + column?: number; }; export type CompileResult = { @@ -39,12 +42,20 @@ export function compileSource(source: string): CompileResult { js = result.js.code; warnings = result.warnings ?? []; } catch (err: any) { - // `position` is a `[from, to]` character-offset pair, which is what the editor wants. + // `position` is a `[from, to]` character-offset pair, which is what the editor wants; + // `start` carries the line/column the overlay reports. const [from, to] = err.position ?? [0, 0]; return { url: null, diagnostics: [ - { from, to, severity: 'error', message: cleanMessage(err.message ?? String(err)) } + { + from, + to, + severity: 'error', + message: cleanMessage(err.message ?? String(err)), + line: err.start?.line, + column: err.start?.column != null ? err.start.column + 1 : undefined + } ], elapsed: performance.now() - started }; diff --git a/docs/src/lib/sandbox/state.svelte.ts b/docs/src/lib/sandbox/state.svelte.ts index beb1677a8d..c6d5195fca 100644 --- a/docs/src/lib/sandbox/state.svelte.ts +++ b/docs/src/lib/sandbox/state.svelte.ts @@ -108,8 +108,17 @@ export function createSandbox( mode = next; } - /** Compiles the current source and mounts it into the attached element. */ - const preview: Attachment = (el) => { + /** + * Compiling and mounting are deliberately separate. + * + * Compiling on every keystroke but only publishing *successful* builds means a broken + * edit leaves the last good render on screen instead of blanking the preview — you can + * still see what you were working on while you fix the typo, which is the whole point + * of a live editor. + */ + let build = $state(null); + + $effect(() => { const sb = module; const src = debounced; if (!sb || !live) return; @@ -117,21 +126,30 @@ export function createSandbox( const result = sb.compileSource(transform ? transform(src) : src); diagnostics = result.diagnostics; elapsed = Math.round(result.elapsed); - if (!result.url) return; + if (result.url) { + build = result.url; + runtimeError = null; + } + }); + + /** Mounts the newest successful build. Only re-runs when `build` changes. */ + const preview: Attachment = (el) => { + const url = build; + if (!url) return; let mounted: Record | null = null; let disposed = false; - import(/* @vite-ignore */ result.url) + import(/* @vite-ignore */ url) .then((mod) => { - URL.revokeObjectURL(result.url!); + URL.revokeObjectURL(url); if (disposed) return; runtimeError = null; mounted = mount(mod.default, { target: el as HTMLElement }); instance = mounted; }) .catch((err) => { - URL.revokeObjectURL(result.url!); + URL.revokeObjectURL(url); if (!disposed) runtimeError = err instanceof Error ? err.message : String(err); }); @@ -146,6 +164,13 @@ export function createSandbox( const errors = $derived(diagnostics.filter((d) => d.severity === 'error')); + /** The one thing worth surfacing over the preview, or `null` when the build is good. */ + const error = $derived.by(() => { + if (runtimeError) return { message: runtimeError, line: undefined, column: undefined }; + const first = errors[0]; + return first ? { message: first.message, line: first.line, column: first.column } : null; + }); + return { preview, load, @@ -182,12 +207,12 @@ export function createSandbox( set source(next: string) { editorValue = next; }, - /** `null` until the user has edited — nothing worth reporting before that. */ - get status() { - return runtimeError ?? errors[0]?.message ?? (live ? `${elapsed}ms` : null); + get error() { + return error; }, - get hasError() { - return runtimeError !== null || errors.length > 0; + /** Compile timing, or `null` until the user has edited. */ + get status() { + return live ? `${elapsed}ms` : null; } }; } From e2f6aea9d118ec12cbb35195fe91b88eb427915c Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Sun, 11 Oct 2026 20:44:51 -0400 Subject: [PATCH 04/15] Remove preview route based on WebContainers (editable examples provides a better experience) --- docs/package.json | 4 - docs/src/hooks.server.ts | 14 - docs/src/lib/components/DocsMenu.svelte | 6 - docs/src/lib/sandbox/CodeEditor.svelte | 43 +- docs/src/lib/sandbox/CodePanel.svelte | 1 + .../routes/docs/playground/+page.server.ts | 40 -- docs/src/routes/docs/playground/+page.svelte | 570 ------------------ docs/src/routes/docs/playground/+page.ts | 9 - .../docs/playground/FileTree/FileTree.svelte | 98 --- .../FileTree/TreeView/TreeView.svelte | 10 - .../FileTree/TreeView/TreeViewNode.svelte | 106 ---- .../playground/FileTree/TreeView/index.ts | 4 - .../playground/FileTree/TreeView/types.ts | 16 - .../docs/playground/template/package.json | 31 - .../docs/playground/template/src/app.css | 4 - .../docs/playground/template/src/app.html | 56 -- .../template/src/routes/+layout.svelte | 9 - .../template/src/routes/+page.svelte | 8 - .../docs/playground/template/svelte.config.js | 21 - .../docs/playground/template/vite.config.js | 7 - docs/src/routes/docs/search/searchContent.ts | 7 - pnpm-lock.yaml | 82 +-- 22 files changed, 10 insertions(+), 1136 deletions(-) delete mode 100644 docs/src/hooks.server.ts delete mode 100644 docs/src/routes/docs/playground/+page.server.ts delete mode 100644 docs/src/routes/docs/playground/+page.svelte delete mode 100644 docs/src/routes/docs/playground/+page.ts delete mode 100644 docs/src/routes/docs/playground/FileTree/FileTree.svelte delete mode 100644 docs/src/routes/docs/playground/FileTree/TreeView/TreeView.svelte delete mode 100644 docs/src/routes/docs/playground/FileTree/TreeView/TreeViewNode.svelte delete mode 100644 docs/src/routes/docs/playground/FileTree/TreeView/index.ts delete mode 100644 docs/src/routes/docs/playground/FileTree/TreeView/types.ts delete mode 100644 docs/src/routes/docs/playground/template/package.json delete mode 100644 docs/src/routes/docs/playground/template/src/app.css delete mode 100644 docs/src/routes/docs/playground/template/src/app.html delete mode 100644 docs/src/routes/docs/playground/template/src/routes/+layout.svelte delete mode 100644 docs/src/routes/docs/playground/template/src/routes/+page.svelte delete mode 100644 docs/src/routes/docs/playground/template/svelte.config.js delete mode 100644 docs/src/routes/docs/playground/template/vite.config.js diff --git a/docs/package.json b/docs/package.json index 2ad1b41a29..5fd916541f 100644 --- a/docs/package.json +++ b/docs/package.json @@ -85,7 +85,6 @@ "layerchart": "workspace:*", "mathjs": "^15.2.0", "mdsx": "^0.0.7", - "paneforge": "^1.0.2", "playwright": "^1.60.0", "posthog-js": "^1.379.0", "prettier": "^3.8.3", @@ -114,7 +113,6 @@ "@codemirror/lang-css": "^6.3.1", "@codemirror/lang-html": "^6.4.11", "@codemirror/lang-javascript": "^6.2.5", - "@codemirror/lang-json": "^6.0.2", "@codemirror/language": "^6.12.2", "@codemirror/lint": "^6.9.5", "@codemirror/state": "^6.6.0", @@ -124,8 +122,6 @@ "@replit/codemirror-lang-svelte": "^6.0.0", "@resvg/resvg-js": "^2.6.2", "@stackblitz/sdk": "^1.11.0", - "@webcontainer/api": "^1.6.4", - "ansi_up": "^6.0.6", "d3-geo-projection": "^4.0.0", "satori": "^0.26.0", "satori-html": "^0.3.2" diff --git a/docs/src/hooks.server.ts b/docs/src/hooks.server.ts deleted file mode 100644 index 630ccfa011..0000000000 --- a/docs/src/hooks.server.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { Handle } from '@sveltejs/kit'; - -export const handle: Handle = async ({ event, resolve }) => { - const response = await resolve(event); - - // Set Cross-Origin headers for WebContainer support (SharedArrayBuffer requirement) - // Only apply to the playground page to minimize impact - if (event.url.pathname.startsWith('/docs/playground')) { - response.headers.set('Cross-Origin-Embedder-Policy', 'require-corp'); - response.headers.set('Cross-Origin-Opener-Policy', 'same-origin'); - } - - return response; -}; diff --git a/docs/src/lib/components/DocsMenu.svelte b/docs/src/lib/components/DocsMenu.svelte index 07436c6956..080f1e9263 100644 --- a/docs/src/lib/components/DocsMenu.svelte +++ b/docs/src/lib/components/DocsMenu.svelte @@ -19,7 +19,6 @@ import LucideFileCode2 from '~icons/lucide/file-code-2'; import LucideCirclePlay from '~icons/lucide/circle-play'; import LucideParentheses from '~icons/lucide/parentheses'; - import SimpleIconsStackblitz from '~icons/simple-icons/stackblitz'; let { onItemClick, class: className }: { onItemClick?: () => void; class?: string } = $props(); @@ -64,11 +63,6 @@ path: '/docs/examples', icon: LucideFileCode2 })} - {@render navItem({ label: 'Showcase', path: '/docs/showcase', icon: LucideGalleryVertical })} {@render navItem({ label: 'Releases', diff --git a/docs/src/lib/sandbox/CodeEditor.svelte b/docs/src/lib/sandbox/CodeEditor.svelte index cc691322ac..bbaaadbfd0 100644 --- a/docs/src/lib/sandbox/CodeEditor.svelte +++ b/docs/src/lib/sandbox/CodeEditor.svelte @@ -8,9 +8,7 @@ rectangularSelection, crosshairCursor, highlightSpecialChars, - lineNumbers as lineNumbersExt, - highlightActiveLine, - highlightActiveLineGutter + lineNumbers as lineNumbersExt } from '@codemirror/view'; import { EditorState, Compartment } from '@codemirror/state'; import { @@ -30,30 +28,22 @@ import { closeBrackets, closeBracketsKeymap } from '@codemirror/autocomplete'; import { setDiagnostics, lintKeymap } from '@codemirror/lint'; import { svelte } from '@replit/codemirror-lang-svelte'; - import { javascript } from '@codemirror/lang-javascript'; - import { css } from '@codemirror/lang-css'; - import { html } from '@codemirror/lang-html'; - import { json } from '@codemirror/lang-json'; import { getSettings } from 'svelte-ux'; import type { Diagnostic } from './compile'; let { value = $bindable(''), - /** Drives syntax highlighting. Defaults to Svelte. */ - filename = 'Example.svelte', diagnostics = [], autofocus = false, /** - * Off by default: inline example editors swap in for a `Code` block that has no - * gutter, and adding one would shift every line sideways on activation. The - * playground, which has no read-only view to match, turns it on. + * Mirrors the `Code` block's `showLineNumbers`, so the gutter is there in Edit + * exactly when it was in View — adding or dropping one shifts every line sideways. */ lineNumbers = false, oninput, class: className }: { value?: string; - filename?: string; diagnostics?: Diagnostic[]; autofocus?: boolean; lineNumbers?: boolean; @@ -66,7 +56,6 @@ let view = $state(null); const themeCompartment = new Compartment(); - const languageCompartment = new Compartment(); const { currentTheme } = getSettings(); /** @@ -170,16 +159,6 @@ const theme = (dark: boolean) => [chrome(dark), syntaxHighlighting(styles[dark ? 'dark' : 'light'])]; - function languageFor(name: string) { - if (name.endsWith('.svelte')) return svelte(); - if (name.endsWith('.ts')) return javascript({ typescript: true }); - if (name.endsWith('.js')) return javascript(); - if (name.endsWith('.css')) return css(); - if (name.endsWith('.json')) return json(); - if (name.endsWith('.html')) return html(); - return svelte(); - } - /** * Matched to the read-only `Code` component so swapping one for the other doesn't * move a single character: same mono stack, `text-sm` metrics (14px/20px), the same @@ -211,14 +190,13 @@ }); /** - * `basicSetup` minus line numbers, fold gutter, active-line highlight and the search - * panel — the things that would either shift the layout or bloat the chunk. Lint state + * `basicSetup` minus the fold gutter, active-line highlight and search panel, with line + * numbers only on request — the things that would either shift the layout or bloat the + * chunk. Lint state * isn't listed because `setDiagnostics` appends it on first use. */ const setup = [ - ...(untrack(() => lineNumbers) - ? [lineNumbersExt(), highlightActiveLineGutter(), highlightActiveLine()] - : []), + ...(untrack(() => lineNumbers) ? [lineNumbersExt()] : []), highlightSpecialChars(), history(), drawSelection(), @@ -252,7 +230,7 @@ doc: untrack(() => value), extensions: [ setup, - languageCompartment.of(languageFor(untrack(() => filename))), + svelte(), keymap.of([indentWithTab]), themeCompartment.of(theme(untrack(() => $currentTheme.dark))), appearance, @@ -289,11 +267,6 @@ view?.dispatch({ effects: themeCompartment.reconfigure(theme(dark)) }); }); - $effect(() => { - const name = filename; - view?.dispatch({ effects: languageCompartment.reconfigure(languageFor(name)) }); - }); - $effect(() => { if (!view) return; const length = view.state.doc.length; diff --git a/docs/src/lib/sandbox/CodePanel.svelte b/docs/src/lib/sandbox/CodePanel.svelte index 97f925e83e..0164527da7 100644 --- a/docs/src/lib/sandbox/CodePanel.svelte +++ b/docs/src/lib/sandbox/CodePanel.svelte @@ -34,6 +34,7 @@ diff --git a/docs/src/routes/docs/playground/+page.server.ts b/docs/src/routes/docs/playground/+page.server.ts deleted file mode 100644 index 3363075e00..0000000000 --- a/docs/src/routes/docs/playground/+page.server.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { PageServerLoad } from './$types'; -import { buildWebContainerFiles } from '@layerstack/docs/node/stackblitz'; - -// Import source files for the playground examples -import dataTs from '../../../lib/utils/data.ts?raw'; - -// Dynamically import all template files using Vite's import.meta.glob -const templateFiles = import.meta.glob('./template/**/*', { - query: '?raw', - import: 'default', - eager: true -}); - -// Build flat file structure using imported template files -function generatePlaygroundFiles(): Record { - const files: Record = {}; - - // Process all template files - for (const [path, content] of Object.entries(templateFiles)) { - // Extract relative path from the full import path - // Example: "./template/package.json" -> "package.json" - const relativePath = path.replace('./template/', ''); - - files[relativePath] = content as string; - } - - // Add utility data file - files['src/lib/utils/data.ts'] = dataTs; - - return files; -} - -// Convert to WebContainer nested structure -const templateProjectFiles = buildWebContainerFiles(generatePlaygroundFiles()); - -export const load: PageServerLoad = () => { - return { - templateProjectFiles - }; -}; diff --git a/docs/src/routes/docs/playground/+page.svelte b/docs/src/routes/docs/playground/+page.svelte deleted file mode 100644 index 6f528ffe12..0000000000 --- a/docs/src/routes/docs/playground/+page.svelte +++ /dev/null @@ -1,570 +0,0 @@ - - - - - - -
- - - -
-
- -
- {#if fileTreeShowing} -
- { - handleFileSelect(path); - fileTreeShowing = false; - }} - /> -
- {/if} - -
- -
- - -
- {#if isLoadingFile} -
-
Loading...
-
- {:else if CodeEditor} - - {/if} -
-
-
- - - - - - - -
- {#if loadingStatus} - - -
{loadingStatus}
-
- {:else} - - - - {/if} - -
-
- - - - - -
{ - if (e.key === 'Enter' || e.key === ' ') { - e.preventDefault(); - toggleConsole(); - } - }} - > -
- - Console -
- -
-
- - - -
- -
- {@html consoleOutput} -
-
-
-
-
-
-
diff --git a/docs/src/routes/docs/playground/+page.ts b/docs/src/routes/docs/playground/+page.ts deleted file mode 100644 index 46c88bbfaf..0000000000 --- a/docs/src/routes/docs/playground/+page.ts +++ /dev/null @@ -1,9 +0,0 @@ -export const load = async ({ data }) => { - return { - ...data, - meta: { - fullWidth: true, - hideEditLink: true - } - }; -}; diff --git a/docs/src/routes/docs/playground/FileTree/FileTree.svelte b/docs/src/routes/docs/playground/FileTree/FileTree.svelte deleted file mode 100644 index c9cf53650a..0000000000 --- a/docs/src/routes/docs/playground/FileTree/FileTree.svelte +++ /dev/null @@ -1,98 +0,0 @@ - - -
- {#snippet renderNodes(nodes: TreeNode[])} - {#each nodes as node (node.path)} - { - selectedFile = path; - onSelect?.(path); - }} - > - {@render renderNodes(node.children)} - - {/each} - {/snippet} - - - {@render renderNodes(tree)} - -
diff --git a/docs/src/routes/docs/playground/FileTree/TreeView/TreeView.svelte b/docs/src/routes/docs/playground/FileTree/TreeView/TreeView.svelte deleted file mode 100644 index fd6f1307eb..0000000000 --- a/docs/src/routes/docs/playground/FileTree/TreeView/TreeView.svelte +++ /dev/null @@ -1,10 +0,0 @@ - - -
- {@render children?.()} -
diff --git a/docs/src/routes/docs/playground/FileTree/TreeView/TreeViewNode.svelte b/docs/src/routes/docs/playground/FileTree/TreeView/TreeViewNode.svelte deleted file mode 100644 index 7ff41afb6c..0000000000 --- a/docs/src/routes/docs/playground/FileTree/TreeView/TreeViewNode.svelte +++ /dev/null @@ -1,106 +0,0 @@ - - -{#if name.includes('.')} - - -{:else} - -
- - {#if open} -
-
- -
-
- {@render children?.()} -
-
-
- {/if} -
-{/if} diff --git a/docs/src/routes/docs/playground/FileTree/TreeView/index.ts b/docs/src/routes/docs/playground/FileTree/TreeView/index.ts deleted file mode 100644 index c723f13884..0000000000 --- a/docs/src/routes/docs/playground/FileTree/TreeView/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import TreeView from './TreeView.svelte'; -import TreeViewNode from './TreeViewNode.svelte'; - -export { TreeView, TreeViewNode, TreeView as Root, TreeViewNode as Node }; diff --git a/docs/src/routes/docs/playground/FileTree/TreeView/types.ts b/docs/src/routes/docs/playground/FileTree/TreeView/types.ts deleted file mode 100644 index 65b202bd20..0000000000 --- a/docs/src/routes/docs/playground/FileTree/TreeView/types.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { WithChildren } from 'bits-ui'; -import type { Snippet } from 'svelte'; -import type { HTMLAttributes, HTMLButtonAttributes } from 'svelte/elements'; - -export type TreeViewRootProps = HTMLAttributes; - -export type TreeViewNodeProps = WithChildren< - Omit & { - name: string; - path?: string; - open?: boolean; - selected?: boolean; - onSelect?: (path: string) => void; - icon?: Snippet<[{ name: string; open: boolean }]>; - } ->; diff --git a/docs/src/routes/docs/playground/template/package.json b/docs/src/routes/docs/playground/template/package.json deleted file mode 100644 index 6df53fce39..0000000000 --- a/docs/src/routes/docs/playground/template/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "layerchart-example", - "type": "module", - "private": true, - "version": "0.0.1", - "scripts": { - "dev": "vite dev", - "build": "vite build", - "preview": "vite preview" - }, - "devDependencies": { - "@layerstack/tailwind": "2.0.0-next.21", - "@sveltejs/adapter-auto": "^7.0.0", - "@sveltejs/kit": "^2.15.3", - "@sveltejs/vite-plugin-svelte": "^6.2.1", - "@tailwindcss/vite": "^4.1.16", - "@types/d3-geo": "^3.1.0", - "@types/topojson-client": "^3.1.5", - "d3-array": "^3.2.4", - "d3-geo": "^3.1.1", - "d3-random": "^3.0.1", - "d3-time": "^3.1.0", - "topojson-client": "^3.1.0", - "svelte": "^5.39.13", - "tailwindcss": "^4.1.16", - "vite": "^7.1.12" - }, - "dependencies": { - "layerchart": "https://pkg.pr.new/layerchart@659" - } -} diff --git a/docs/src/routes/docs/playground/template/src/app.css b/docs/src/routes/docs/playground/template/src/app.css deleted file mode 100644 index 3c3d8926b2..0000000000 --- a/docs/src/routes/docs/playground/template/src/app.css +++ /dev/null @@ -1,4 +0,0 @@ -@import 'tailwindcss'; -@import '@layerstack/tailwind/core.css'; -@import '@layerstack/tailwind/utils.css'; -@import '@layerstack/tailwind/themes/basic.css'; diff --git a/docs/src/routes/docs/playground/template/src/app.html b/docs/src/routes/docs/playground/template/src/app.html deleted file mode 100644 index f93d787940..0000000000 --- a/docs/src/routes/docs/playground/template/src/app.html +++ /dev/null @@ -1,56 +0,0 @@ - - - - - - - %sveltekit.head% - - - -
%sveltekit.body%
- - diff --git a/docs/src/routes/docs/playground/template/src/routes/+layout.svelte b/docs/src/routes/docs/playground/template/src/routes/+layout.svelte deleted file mode 100644 index c5cd34fcca..0000000000 --- a/docs/src/routes/docs/playground/template/src/routes/+layout.svelte +++ /dev/null @@ -1,9 +0,0 @@ - - -
- {@render children?.()} -
diff --git a/docs/src/routes/docs/playground/template/src/routes/+page.svelte b/docs/src/routes/docs/playground/template/src/routes/+page.svelte deleted file mode 100644 index c2670ec795..0000000000 --- a/docs/src/routes/docs/playground/template/src/routes/+page.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/docs/src/routes/docs/playground/template/svelte.config.js b/docs/src/routes/docs/playground/template/svelte.config.js deleted file mode 100644 index f571400f54..0000000000 --- a/docs/src/routes/docs/playground/template/svelte.config.js +++ /dev/null @@ -1,21 +0,0 @@ -import adapter from '@sveltejs/adapter-auto'; - -/** @type {import('@sveltejs/kit').Config} */ -const config = { - kit: { - adapter: adapter(), - alias: { - '$static/*': 'static/*' - }, - experimental: { - remoteFunctions: true - } - }, - compilerOptions: { - experimental: { - async: true - } - } -}; - -export default config; diff --git a/docs/src/routes/docs/playground/template/vite.config.js b/docs/src/routes/docs/playground/template/vite.config.js deleted file mode 100644 index 2f222dba34..0000000000 --- a/docs/src/routes/docs/playground/template/vite.config.js +++ /dev/null @@ -1,7 +0,0 @@ -import { sveltekit } from '@sveltejs/kit/vite'; -import { defineConfig } from 'vite'; -import tailwindcss from '@tailwindcss/vite'; - -export default defineConfig({ - plugins: [tailwindcss(), sveltekit()] -}); diff --git a/docs/src/routes/docs/search/searchContent.ts b/docs/src/routes/docs/search/searchContent.ts index 3a423597e3..418a723ba9 100644 --- a/docs/src/routes/docs/search/searchContent.ts +++ b/docs/src/routes/docs/search/searchContent.ts @@ -48,13 +48,6 @@ const topLevelPages: SearchEntry[] = [ content: 'Browse example charts and visualizations', type: 'page' }, - { - title: 'Playground', - slug: 'docs/playground', - content: - 'Interactive playground to experiment with LayerChart components. Try code examples in StackBlitz.', - type: 'page' - }, { title: 'Showcase', slug: 'docs/showcase', diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2db089d47b..5ee4d5d09b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -65,9 +65,6 @@ importers: '@codemirror/lang-javascript': specifier: ^6.2.5 version: 6.2.5 - '@codemirror/lang-json': - specifier: ^6.0.2 - version: 6.0.2 '@codemirror/language': specifier: ^6.12.2 version: 6.12.2 @@ -95,12 +92,6 @@ importers: '@stackblitz/sdk': specifier: ^1.11.0 version: 1.11.0 - '@webcontainer/api': - specifier: ^1.6.4 - version: 1.6.4 - ansi_up: - specifier: ^6.0.6 - version: 6.0.6 d3-geo-projection: specifier: ^4.0.0 version: 4.0.0 @@ -291,9 +282,6 @@ importers: mdsx: specifier: ^0.0.7 version: 0.0.7(svelte@5.56.1(@typescript-eslint/types@8.60.1)) - paneforge: - specifier: ^1.0.2 - version: 1.0.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)) playwright: specifier: ^1.60.0 version: 1.60.0 @@ -320,7 +308,7 @@ importers: version: 5.56.1(@typescript-eslint/types@8.60.1) svelte-check: specifier: ^4.5.0 - version: 4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) + version: 4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) svelte-ux: specifier: 2.0.0-next.22 version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0))(postcss@8.5.15)(svelte@5.56.1(@typescript-eslint/types@8.60.1)) @@ -1128,9 +1116,6 @@ packages: '@codemirror/lang-javascript@6.2.5': resolution: {integrity: sha512-zD4e5mS+50htS7F+TYjBPsiIFGanfVqg4HyUz6WNFikgOPf2BgKlx+TQedI1w6n/IqRBVBbBWmGFdLB/7uxO4A==} - '@codemirror/lang-json@6.0.2': - resolution: {integrity: sha512-x2OtO+AvwEHrEwR0FyyPtfDUiloG3rnVTSZV1W8UteaLL8/MajQd8DpvUb2YVzC+/T18aSDv0H9mu+xw0EStoQ==} - '@codemirror/language@6.12.2': resolution: {integrity: sha512-jEPmz2nGGDxhRTg3lTpzmIyGKxz3Gp3SJES4b0nAuE5SWQoKdT5GoQ69cwMmFd+wvFUhYirtDTr0/DRHpQAyWg==} @@ -2008,9 +1993,6 @@ packages: '@lezer/javascript@1.5.4': resolution: {integrity: sha512-vvYx3MhWqeZtGPwDStM2dwgljd5smolYD2lR2UyFcHfxbBQebqx8yjmFmxtJ/E6nN6u1D9srOiVWm3Rb4tmcUA==} - '@lezer/json@1.0.3': - resolution: {integrity: sha512-BP9KzdF9Y35PDpv04r0VeSTKDeox5vVr3efE7eBbx3r4s3oNLfunchejZhjArmeieBH+nVOpgIiBJpEAv8ilqQ==} - '@lezer/lr@1.4.8': resolution: {integrity: sha512-bPWa0Pgx69ylNlMlPvBPryqeLYQjyJjqPx+Aupm5zydLIF3NE+6MMLT8Yi23Bd9cif9VS00aUebn+6fDIGBcDA==} @@ -3710,9 +3692,6 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansi_up@6.0.6: - resolution: {integrity: sha512-yIa1x3Ecf8jWP4UWEunNjqNX6gzE4vg2gGz+xqRGY+TBSucnYp6RRdPV4brmtg6bQ1ljD48mZ5iGSEj7QEpRKA==} - argparse@1.0.10: resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} @@ -5071,11 +5050,6 @@ packages: pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} - paneforge@1.0.2: - resolution: {integrity: sha512-KzmIXQH1wCfwZ4RsMohD/IUtEjVhteR+c+ulb/CHYJHX8SuDXoJmChtsc/Xs5Wl8NHS4L5Q7cxL8MG40gSU1bA==} - peerDependencies: - svelte: ^5.29.0 - parse-css-color@0.2.1: resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==} @@ -5482,11 +5456,6 @@ packages: peerDependencies: svelte: ^5.7.0 - runed@0.29.2: - resolution: {integrity: sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA==} - peerDependencies: - svelte: ^5.7.0 - runed@0.35.1: resolution: {integrity: sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==} peerDependencies: @@ -5729,12 +5698,6 @@ packages: peerDependencies: svelte: ^5.0.0 - svelte-toolbelt@0.9.3: - resolution: {integrity: sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw==} - engines: {node: '>=18', pnpm: '>=8.7.0'} - peerDependencies: - svelte: ^5.30.2 - svelte-ux@2.0.0-next.19: resolution: {integrity: sha512-d6a4MdNgwdLod9GrrFPrw76MufHD+nx5siSoHlsKuRVur3z2wCY8O15R7dL461h/DBGOn78an4zLJIk/E8LFzw==} peerDependencies: @@ -6477,11 +6440,6 @@ snapshots: '@lezer/common': 1.5.1 '@lezer/javascript': 1.5.4 - '@codemirror/lang-json@6.0.2': - dependencies: - '@codemirror/language': 6.12.2 - '@lezer/json': 1.0.3 - '@codemirror/language@6.12.2': dependencies: '@codemirror/state': 6.6.0 @@ -7233,12 +7191,6 @@ snapshots: '@lezer/highlight': 1.2.3 '@lezer/lr': 1.4.8 - '@lezer/json@1.0.3': - dependencies: - '@lezer/common': 1.5.1 - '@lezer/highlight': 1.2.3 - '@lezer/lr': 1.4.8 - '@lezer/lr@1.4.8': dependencies: '@lezer/common': 1.5.1 @@ -9437,8 +9389,6 @@ snapshots: ansi-styles@6.2.3: {} - ansi_up@6.0.6: {} - argparse@1.0.10: dependencies: sprintf-js: 1.0.3 @@ -11023,12 +10973,6 @@ snapshots: pako@0.2.9: {} - paneforge@1.0.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)): - dependencies: - runed: 0.23.4(svelte@5.56.1(@typescript-eslint/types@8.60.1)) - svelte: 5.56.1(@typescript-eslint/types@8.60.1) - svelte-toolbelt: 0.9.3(svelte@5.56.1(@typescript-eslint/types@8.60.1)) - parse-css-color@0.2.1: dependencies: color-name: 1.1.4 @@ -11455,11 +11399,6 @@ snapshots: esm-env: 1.2.2 svelte: 5.56.1(@typescript-eslint/types@8.60.1) - runed@0.29.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)): - dependencies: - esm-env: 1.2.2 - svelte: 5.56.1(@typescript-eslint/types@8.60.1) - runed@0.35.1(@sveltejs/kit@2.62.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.60.1))(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.60.1)): dependencies: dequal: 2.0.3 @@ -11672,18 +11611,6 @@ snapshots: - stylus - sugarss - svelte-check@4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - chokidar: 4.0.3 - fdir: 6.5.0(picomatch@4.0.4) - picocolors: 1.1.1 - sade: 1.8.1 - svelte: 5.56.1(@typescript-eslint/types@8.60.1) - typescript: 6.0.3 - transitivePeerDependencies: - - picomatch - svelte-check@4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -11732,13 +11659,6 @@ snapshots: style-to-object: 1.0.14 svelte: 5.56.1(@typescript-eslint/types@8.60.1) - svelte-toolbelt@0.9.3(svelte@5.56.1(@typescript-eslint/types@8.60.1)): - dependencies: - clsx: 2.1.1 - runed: 0.29.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)) - style-to-object: 1.0.14 - svelte: 5.56.1(@typescript-eslint/types@8.60.1) - svelte-ux@2.0.0-next.19(postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0))(postcss@8.5.15)(svelte@5.56.1(@typescript-eslint/types@8.60.1)): dependencies: '@floating-ui/dom': 1.7.4 From 723cca4d3ca1eb8cd940de6e646da15368cb2106 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Sun, 11 Oct 2026 20:46:36 -0400 Subject: [PATCH 05/15] Revert release/changelog files (shouldn't be in this PR) --- docs/generated/releases/layerchart-2.4.0.md | 32 --------------------- docs/generated/releases/layerchart-2.4.1.md | 18 ------------ docs/generated/releases/layerchart-2.5.0.md | 12 -------- 3 files changed, 62 deletions(-) delete mode 100644 docs/generated/releases/layerchart-2.4.0.md delete mode 100644 docs/generated/releases/layerchart-2.4.1.md delete mode 100644 docs/generated/releases/layerchart-2.5.0.md diff --git a/docs/generated/releases/layerchart-2.4.0.md b/docs/generated/releases/layerchart-2.4.0.md deleted file mode 100644 index 1c380f8605..0000000000 --- a/docs/generated/releases/layerchart-2.4.0.md +++ /dev/null @@ -1,32 +0,0 @@ ---- -title: "layerchart@2.4.0" -tag: "layerchart@2.4.0" -date: "2026-09-04T14:33:43Z" -url: "https://github.com/techniq/layerchart/releases/tag/layerchart%402.4.0" -draft: false -prerelease: false -author: "github-actions[bot]" ---- -### Minor Changes - -- feat(Axis): Add `tickOcclusion` to drop ticks whose labels would overlap, measured at the size they render (including rotation), with `priority` of `'end'` (default), `'start'`, or `'start-end'` to choose which survive ([#909](https://github.com/techniq/layerchart/pull/909)) - -- feat(utils): Add `rotate` and multiline support to `getTextRect`, so a rotated or stacked `` can be measured for `occlude` without the caller reproducing ``'s pivot ([#909](https://github.com/techniq/layerchart/pull/909)) - -### Patch Changes - -- fix(Area): Apply `mask`, `filter`, and `clip-path` to the `line` path as well as the fill (unless overrideden by `line={{...}}`) ([#909](https://github.com/techniq/layerchart/pull/909)) - -- fix(Calendar): Adjust month labels after recent Text verticalAnchor improvements ([#909](https://github.com/techniq/layerchart/pull/909)) - -- fix(Calendar): Size cells to fit `monthPath`, which can extend past the last cell when the range ends mid-month ([#909](https://github.com/techniq/layerchart/pull/909)) - -- perf(Chart): Measure the container before building the subtree, so marks are only built once ([#909](https://github.com/techniq/layerchart/pull/909)) - -- fix(downloadImage, downloadSvg): Inline `stop-color`/`stop-opacity` so gradients don't export as solid black ([#909](https://github.com/techniq/layerchart/pull/909)) - -- fix(Chart): Return `undefined` from `xGet`/`yGet` when that axis has no accessor, instead of throwing `accessor is not a function` ([#909](https://github.com/techniq/layerchart/pull/909)) - -- fix(Spline, Area): Animate each path when the mark is split by `z`, which `motion` previously skipped — segments split by a style function are still redrawn outright ([#909](https://github.com/techniq/layerchart/pull/909)) - -- fix(Path, Spline): Render `endContent` without a `draw` transition ([#909](https://github.com/techniq/layerchart/pull/909)) \ No newline at end of file diff --git a/docs/generated/releases/layerchart-2.4.1.md b/docs/generated/releases/layerchart-2.4.1.md deleted file mode 100644 index 389b654cc0..0000000000 --- a/docs/generated/releases/layerchart-2.4.1.md +++ /dev/null @@ -1,18 +0,0 @@ ---- -title: "layerchart@2.4.1" -tag: "layerchart@2.4.1" -date: "2026-09-08T20:16:46Z" -url: "https://github.com/techniq/layerchart/releases/tag/layerchart%402.4.1" -draft: false -prerelease: false -author: "github-actions[bot]" ---- -### Patch Changes - -- fix(deps): Bump `@layerstack/*` dependencies to fix `Package subpath is not defined by exports` when bundling without Vite (issue #913) ([#915](https://github.com/techniq/layerchart/pull/915)) - -- fix(Spline): Render `startContent`, `endContent`, `markerStart`, and `markerEnd` once per line rather than once per style-split segment ([#914](https://github.com/techniq/layerchart/pull/914)) - -- fix(Spline): Keep the line's color on segments split by a `class`, `opacity`, or `fill` function ([#914](https://github.com/techniq/layerchart/pull/914)) - -- fix(Spline): Animate segments split by a style function, which `motion` previously skipped ([#914](https://github.com/techniq/layerchart/pull/914)) \ No newline at end of file diff --git a/docs/generated/releases/layerchart-2.5.0.md b/docs/generated/releases/layerchart-2.5.0.md deleted file mode 100644 index 55cc0d42ba..0000000000 --- a/docs/generated/releases/layerchart-2.5.0.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -title: "layerchart@2.5.0" -tag: "layerchart@2.5.0" -date: "2026-09-09T18:15:53Z" -url: "https://github.com/techniq/layerchart/releases/tag/layerchart%402.5.0" -draft: false -prerelease: false -author: "github-actions[bot]" ---- -### Minor Changes - -- feat(Group|Hull|Rule): Support `seriesKey` prop to fade the mark while another series is highlighted and remove it while the legend has that series hidden ([#917](https://github.com/techniq/layerchart/pull/917)) \ No newline at end of file From 20caac6a0c7f3d5fe82d370b3975a31a49301030 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Sun, 11 Oct 2026 20:46:46 -0400 Subject: [PATCH 06/15] Consolidate sandbox controls and preserve edits in StackBlitz --- docs/src/lib/components/Example.svelte | 35 +++--------- docs/src/lib/sandbox/CodeEditor.svelte | 48 ++++++++++------- docs/src/lib/sandbox/CodePanel.svelte | 71 +++++++++++++++++++++---- docs/src/lib/stackblitz.remote.ts | 12 +++-- docs/src/lib/utils/stackblitz.svelte.ts | 5 +- 5 files changed, 110 insertions(+), 61 deletions(-) diff --git a/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte index f14d86166c..eb92a2610c 100644 --- a/docs/src/lib/components/Example.svelte +++ b/docs/src/lib/components/Example.svelte @@ -27,10 +27,8 @@ import { exposeData } from '$lib/utils/exampleSource'; import LucideCode from '~icons/lucide/code'; - import LucideRotateCcw from '~icons/lucide/rotate-ccw'; import LucideFullscreen from '~icons/lucide/fullscreen'; import LucideTable from '~icons/lucide/table'; - import LucideFilePen from '~icons/lucide/file-pen'; import LucideGripVertical from '~icons/lucide/grip-vertical'; import LucideImageDown from '~icons/lucide/image-down'; import LucideCopy from '~icons/lucide/copy'; @@ -337,7 +335,14 @@ {#if showCode}
- + openInStackBlitz(component, name, sandbox.dirty ? sandbox.source : undefined) + : undefined} + />
{/if} @@ -353,20 +358,6 @@ {/if} - - {#if sandbox.dirty} - - {/if} - {#if data} {/if} - {#if component && name} - - {/if} - + {#if sandbox.loadError} diff --git a/docs/src/lib/stackblitz.remote.ts b/docs/src/lib/stackblitz.remote.ts index d048d62426..db6a338f0e 100644 --- a/docs/src/lib/stackblitz.remote.ts +++ b/docs/src/lib/stackblitz.remote.ts @@ -163,19 +163,23 @@ ${functionBodies.join('\n\n')} export const getExample = query( z.object({ component: z.string(), - name: z.string() + name: z.string(), + /** In-page edits, used in place of the example file (supporting files follow its imports) */ + source: z.string().optional() }), - async ({ component, name }) => { + async ({ component, name, source }) => { // Construct the path to match import.meta.glob pattern const examplePath = `/src/examples/components/${component}/${name}.svelte`; // Get the source code from the pre-loaded modules - const code = exampleModules[examplePath] as string | undefined; + const exampleCode = exampleModules[examplePath] as string | undefined; - if (!code) { + if (!exampleCode) { throw new Error('Example not found'); } + const code = source ?? exampleCode; + // Remove `export { data };` from the code const cleanCode = code.replace(/(\n\s*)*^.*export .*;.*$(\n\s*)*/gm, '\n'); diff --git a/docs/src/lib/utils/stackblitz.svelte.ts b/docs/src/lib/utils/stackblitz.svelte.ts index 33bee7b688..5aacb3c5eb 100644 --- a/docs/src/lib/utils/stackblitz.svelte.ts +++ b/docs/src/lib/utils/stackblitz.svelte.ts @@ -1,9 +1,10 @@ import sdk from '@stackblitz/sdk'; import { getExample } from '$lib/stackblitz.remote'; -export async function openInStackBlitz(component: string, name: string) { +/** `source` opens in-page edits instead of the original example. */ +export async function openInStackBlitz(component: string, name: string, source?: string) { try { - const { code: exampleCode, files } = await getExample({ component, name }); + const { code: exampleCode, files } = await getExample({ component, name, source }); sdk.openProject( { From 6da63a1cdba13be5919f7c9f09a85852904055da Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 12 Oct 2026 08:49:27 -0400 Subject: [PATCH 07/15] Support editable examples with lazy import resolution --- docs/package.json | 1 + docs/src/lib/components/Example.svelte | 5 +- docs/src/lib/sandbox/LiveExample.svelte | 40 ---- docs/src/lib/sandbox/compile-options.ts | 15 ++ docs/src/lib/sandbox/compile.ts | 44 ++-- docs/src/lib/sandbox/lazy.ts | 1 - docs/src/lib/sandbox/link.ts | 143 +++++++++---- docs/src/lib/sandbox/registry-plugin.ts | 192 ++++++++++++++++++ docs/src/lib/sandbox/registry.test.ts | 40 ++++ docs/src/lib/sandbox/registry.ts | 87 ++++---- docs/src/lib/sandbox/state.svelte.ts | 57 ++++-- docs/src/lib/sandbox/virtual.d.ts | 4 + docs/src/lib/stackblitz.remote.ts | 6 +- docs/src/routes/docs/sandbox-poc/+page.svelte | 40 ---- docs/vite.config.ts | 6 +- pnpm-lock.yaml | 3 + 16 files changed, 488 insertions(+), 196 deletions(-) delete mode 100644 docs/src/lib/sandbox/LiveExample.svelte create mode 100644 docs/src/lib/sandbox/compile-options.ts create mode 100644 docs/src/lib/sandbox/registry-plugin.ts create mode 100644 docs/src/lib/sandbox/registry.test.ts create mode 100644 docs/src/lib/sandbox/virtual.d.ts delete mode 100644 docs/src/routes/docs/sandbox-poc/+page.svelte diff --git a/docs/package.json b/docs/package.json index 5fd916541f..b249a9a831 100644 --- a/docs/package.json +++ b/docs/package.json @@ -123,6 +123,7 @@ "@resvg/resvg-js": "^2.6.2", "@stackblitz/sdk": "^1.11.0", "d3-geo-projection": "^4.0.0", + "es-module-lexer": "^2.1.0", "satori": "^0.26.0", "satori-html": "^0.3.2" } diff --git a/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte index eb92a2610c..9f21952ee8 100644 --- a/docs/src/lib/components/Example.svelte +++ b/docs/src/lib/components/Example.svelte @@ -136,7 +136,10 @@ * In-page editing. `example.source` resolves asynchronously, so the sandbox seeds * itself from the getter rather than a constructor argument. */ - const sandbox = createSandbox(() => example?.source ?? '', exposeData); + const sandbox = createSandbox(() => example?.source ?? '', { + transform: exposeData, + base: () => (component ? `/src/examples/components/${component}/` : undefined) + }); let data = $derived.by(() => { try { diff --git a/docs/src/lib/sandbox/LiveExample.svelte b/docs/src/lib/sandbox/LiveExample.svelte deleted file mode 100644 index 13db5e6942..0000000000 --- a/docs/src/lib/sandbox/LiveExample.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - -
- - -
- {#if sandbox.live} -
- {:else} - {@render preview?.()} - {/if} - - {#if sandbox.error} - - {:else if sandbox.status} -
- {sandbox.status} -
- {/if} -
-
diff --git a/docs/src/lib/sandbox/compile-options.ts b/docs/src/lib/sandbox/compile-options.ts new file mode 100644 index 0000000000..707d1eff97 --- /dev/null +++ b/docs/src/lib/sandbox/compile-options.ts @@ -0,0 +1,15 @@ +import type { CompileOptions } from 'svelte/compiler'; + +/** + * Matches the docs app's own config — examples use top-level `await` for their data. + * Shared with `registry-plugin.ts`, which compiles every example the same way to learn + * which Svelte runtime functions the sandbox has to offer. + */ +export const compileOptions = { + filename: 'Example.svelte', + generate: 'client', + css: 'injected', + runes: true, + dev: false, + experimental: { async: true } +} satisfies CompileOptions; diff --git a/docs/src/lib/sandbox/compile.ts b/docs/src/lib/sandbox/compile.ts index 2916ca4bfa..1ecd3c8943 100644 --- a/docs/src/lib/sandbox/compile.ts +++ b/docs/src/lib/sandbox/compile.ts @@ -1,4 +1,5 @@ import { compile } from 'svelte/compiler'; +import { compileOptions } from './compile-options'; import { link } from './link'; export type Diagnostic = { @@ -24,7 +25,11 @@ function cleanMessage(message: string) { return message.replace(/\s*https:\/\/svelte\.dev\/[ew]\/\S+\s*$/, ''); } -export function compileSource(source: string): CompileResult { +/** `base` is the example's directory, so relative imports of sibling modules resolve. */ +export async function compileSource( + source: string, + { base }: { base?: string } = {} +): Promise { const started = performance.now(); const diagnostics: Diagnostic[] = []; @@ -32,13 +37,7 @@ export function compileSource(source: string): CompileResult { let warnings: { message: string; start?: { character: number }; end?: { character: number } }[]; try { - const result = compile(source, { - filename: 'Example.svelte', - generate: 'client', - css: 'injected', - runes: true, - dev: false - }); + const result = compile(source, compileOptions); js = result.js.code; warnings = result.warnings ?? []; } catch (err: any) { @@ -70,16 +69,37 @@ export function compileSource(source: string): CompileResult { }); } - const linked = link(js); + const linked = await link(js, base); if (!linked.ok) { - // No source position for an unresolved import — pin it to the offending specifier. - for (const specifier of linked.unresolved) { + const problems = [ + ...linked.unresolved.map((specifier) => ({ + specifier, + message: `'${specifier}' is not available in the sandbox` + })), + ...linked.failed.map(({ specifier, message }) => ({ + specifier, + message: `Couldn't load '${specifier}': ${message}` + })), + ...linked.missing.map(({ specifier, names }) => + specifier === 'svelte/internal/client' + ? { + specifier: '', + message: `Uses Svelte features no example uses, so the sandbox doesn't include them (${names.map((name) => `$.${name}`).join(', ')})` + } + : { + specifier: names[0], + message: `'${specifier}' doesn't provide ${names.map((name) => `'${name}'`).join(', ')} in the sandbox, which only offers what the examples use` + } + ) + ]; + // No source position for an import problem — pin it to the offending specifier. + for (const { specifier, message } of problems) { const at = source.indexOf(specifier); diagnostics.push({ from: at === -1 ? 0 : at, to: at === -1 ? 0 : at + specifier.length, severity: 'error', - message: `'${specifier}' is not available in the sandbox` + message }); } return { url: null, diagnostics, elapsed: performance.now() - started }; diff --git a/docs/src/lib/sandbox/lazy.ts b/docs/src/lib/sandbox/lazy.ts index b0e59b7ab8..1132eeddfd 100644 --- a/docs/src/lib/sandbox/lazy.ts +++ b/docs/src/lib/sandbox/lazy.ts @@ -6,5 +6,4 @@ * that are never edited don't pay for any of it. Don't import this module statically. */ export { compileSource, type Diagnostic, type CompileResult } from './compile'; -export { availableModules } from './link'; export { default as CodeEditor } from './CodeEditor.svelte'; diff --git a/docs/src/lib/sandbox/link.ts b/docs/src/lib/sandbox/link.ts index a1171990ef..56cd4223dd 100644 --- a/docs/src/lib/sandbox/link.ts +++ b/docs/src/lib/sandbox/link.ts @@ -1,29 +1,26 @@ -import { registry } from './registry'; +import { init, parse } from 'es-module-lexer'; +import { resolve, type Namespace } from './registry'; const GLOBAL_KEY = '__layerchartSandboxRegistry'; -/** Blob URL per specifier — a module's export shape never changes, so build each shim once. */ -const shimUrls = new Map(); +/** Loaded namespaces by module id, read by the shims through `globalThis`. */ +const loaded: Record = ((globalThis as any)[GLOBAL_KEY] ??= {}); -function ensureGlobal() { - (globalThis as any)[GLOBAL_KEY] = registry; -} +/** Blob URL per module id — a module's export shape never changes, so build each shim once. */ +const shimUrls = new Map(); /** - * Build an ES module that re-exports a registry entry. + * Build an ES module that re-exports a loaded namespace. * * Export names are read off the live namespace object, so this covers reserved * words (`default`, `class`) and anything else that isn't a bare identifier. */ -function shimFor(specifier: string): string | undefined { - const cached = shimUrls.get(specifier); +function shimFor(id: string): string { + const cached = shimUrls.get(id); if (cached) return cached; - const ns = registry[specifier]; - if (!ns) return undefined; - - const names = Object.keys(ns); - const lines = [`const m = globalThis[${JSON.stringify(GLOBAL_KEY)}][${JSON.stringify(specifier)}];`]; + const names = Object.keys(loaded[id]); + const lines = [`const m = globalThis[${JSON.stringify(GLOBAL_KEY)}][${JSON.stringify(id)}];`]; const exports: string[] = []; names.forEach((name, i) => { lines.push(`const _${i} = m[${JSON.stringify(name)}];`); @@ -32,40 +29,106 @@ function shimFor(specifier: string): string | undefined { lines.push(exports.length ? `export { ${exports.join(', ')} };` : 'export {};'); const url = URL.createObjectURL(new Blob([lines.join('\n')], { type: 'text/javascript' })); - shimUrls.set(specifier, url); + shimUrls.set(id, url); return url; } /** - * Import statements in compiled Svelte output are machine-generated, one per line, at the top. - * The `[^'"\n]` classes keep this from running past the statement into unrelated string - * literals (`export default function …` followed later by `value: 'integer'`). - * - * A production version should lex with `es-module-lexer` rather than pattern-match. + * Imports with a known specifier: static `import`/`export … from` (`d === -1`) and + * `import('literal')`. `import.meta` (`d === -2`) and computed `import(expr)` (no `n`) + * are left alone. */ -const IMPORT_RE = /^(\s*(?:import|export)\b(?:[^'"\n]*?\bfrom)?\s*)(['"])([^'"\n]+)\2/gm; +async function moduleImports(js: string) { + await init; + const [imports] = parse(js); + return imports.filter((entry) => entry.n && entry.d !== -2); +} -export type LinkResult = { ok: true; url: string } | { ok: false; unresolved: string[] }; +/** Every module specifier compiled output imports, without duplicates. */ +export async function importSpecifiers(js: string) { + return [...new Set((await moduleImports(js)).map((entry) => entry.n!))]; +} -/** Rewrite bare specifiers to registry shims and return a blob URL for the module. */ -export function link(js: string): LinkResult { - ensureGlobal(); +/** + * The names a static import asks of its module, or `null` when it can't tell. A + * namespace import (`import * as $ from …`) asks for whatever is read off the namespace, + * which is how compiled output uses the Svelte runtime. + */ +function requestedNames(js: string, statement: string): string[] | null { + const namespace = statement.match(/^import\s*\*\s*as\s+([\w$]+)/); + if (namespace) { + const alias = namespace[1].replace(/\$/g, '\\$'); + const members = js.matchAll(new RegExp(`(? match[1]))]; + } + const clause = statement.match(/^import\s*([\w$]+)?\s*,?\s*(?:\{([^}]*)\})?\s*from\b/); + if (!clause) return null; + const names = clause[1] ? ['default'] : []; + for (const part of (clause[2] ?? '').split(',')) { + const name = part.trim().split(/\s+as\s+/)[0]; + if (name) names.push(name.replace(/^['"]|['"]$/g, '')); + } + return names; +} + +export type LinkResult = + | { ok: true; url: string } + | { + ok: false; + unresolved: string[]; + failed: { specifier: string; message: string }[]; + /** Names the sandbox's copy of a module doesn't offer (see `registry-plugin.ts`). */ + missing: { specifier: string; names: string[] }[]; + }; + +/** + * Load every module the compiled output imports, rewrite its specifiers to shims, and + * return a blob URL for the result. `base` is the example's directory, for relative imports. + */ +export async function link(js: string, base?: string): Promise { + const imports = await moduleImports(js); const unresolved: string[] = []; + const failed: { specifier: string; message: string }[] = []; + const ids = new Map(); - const rewritten = js.replace(IMPORT_RE, (match, prefix, quote, specifier) => { - if (specifier.startsWith('.') || specifier.startsWith('/') || specifier.startsWith('blob:')) { - return match; - } - const url = shimFor(specifier); - if (!url) { - unresolved.push(specifier); - return match; - } - return prefix + quote + url + quote; - }); + await Promise.all( + [...new Set(imports.map((entry) => entry.n!))].map(async (specifier) => { + const module = resolve(specifier, base); + if (!module) { + unresolved.push(specifier); + return; + } + try { + loaded[module.id] ??= await module.load(); + ids.set(specifier, module.id); + } catch (err) { + failed.push({ specifier, message: err instanceof Error ? err.message : String(err) }); + } + }) + ); - if (unresolved.length) { - return { ok: false, unresolved }; + // Modules are offered with only the names the examples use, so check before the + // browser fails on a blob URL it can't name. + const missing: { specifier: string; names: string[] }[] = []; + for (const entry of imports) { + const id = ids.get(entry.n!); + if (!id || entry.d !== -1) continue; + const names = requestedNames(js, js.slice(entry.ss, entry.se)); + const absent = names?.filter((name) => !(name in loaded[id])) ?? []; + if (absent.length) missing.push({ specifier: entry.n!, names: absent }); + } + + if (unresolved.length || failed.length || missing.length) { + return { ok: false, unresolved, failed, missing }; + } + + // Splice from the end so earlier positions stay valid. + let rewritten = js; + for (const entry of imports.toReversed()) { + const url = shimFor(ids.get(entry.n!)!); + // A static import's range is the bare specifier; a dynamic one's includes the quotes. + const replacement = entry.d === -1 ? url : JSON.stringify(url); + rewritten = rewritten.slice(0, entry.s) + replacement + rewritten.slice(entry.e); } return { @@ -73,7 +136,3 @@ export function link(js: string): LinkResult { url: URL.createObjectURL(new Blob([rewritten], { type: 'text/javascript' })) }; } - -export function availableModules() { - return Object.keys(registry).filter((k) => !k.startsWith('svelte/internal')); -} diff --git a/docs/src/lib/sandbox/registry-plugin.ts b/docs/src/lib/sandbox/registry-plugin.ts new file mode 100644 index 0000000000..b9b539665e --- /dev/null +++ b/docs/src/lib/sandbox/registry-plugin.ts @@ -0,0 +1,192 @@ +import { globSync, readFileSync } from 'node:fs'; +import { join, relative, resolve } from 'node:path'; +import { compile, parse } from 'svelte/compiler'; +import type { Plugin } from 'vite'; +import { exposeData } from '../utils/exampleSource'; +import { compileOptions } from './compile-options'; + +/** + * Generates `virtual:sandbox-registry`: the packages edited examples may import, as loaders. + * + * Each package is offered with only the names some example imports, through a small + * re-export module, not as its whole namespace. Exposing a whole namespace (`import('layerchart')`) + * stops the bundler dropping unused exports, and the extra code lands in chunks every docs + * page loads. Names an example already imports are already in the build, so offering + * them costs pages nothing. + * + * The Svelte runtime is treated the same way. Compiled components import all of + * `svelte/internal/client`, so every example is compiled here to learn which of its + * functions they call. + * + * An edit can use any name, or any template feature, some example uses. `link.ts` + * reports anything else by name rather than letting the browser fail on it. + */ + +const REGISTRY_ID = 'virtual:sandbox-registry'; +const EXPORTS_PREFIX = 'virtual:sandbox-exports/'; +const RUNTIME = 'svelte/internal/client'; + +/** + * Specifiers this plugin doesn't offer: `registry.ts` finds `$lib` and sibling files by + * glob, and the runtime's side-effect-only modules by hand. The runtime itself is + * gathered from compiled output below. + */ +const handledElsewhere = (specifier: string) => + specifier.startsWith('$lib/') || + specifier.startsWith('.') || + specifier.startsWith('/') || + specifier === 'svelte/internal' || + specifier.startsWith('svelte/internal/'); + +type Usage = { names: Set; whole: boolean }; + +/** Compiled output imports the runtime as `import * as $ from 'svelte/internal/client'`. */ +const RUNTIME_MEMBER = /(? + readFileSync(join(examplesDir, path), 'utf8') + ); +} + +/** Every package import across the examples, with the names each one uses. */ +function scanImports(sources: string[]) { + const usage = new Map(); + const use = (specifier: string) => { + let entry = usage.get(specifier); + if (!entry) usage.set(specifier, (entry = { names: new Set(), whole: false })); + return entry; + }; + + for (const source of sources) { + let ast; + try { + ast = parse(source, { modern: true }); + } catch { + continue; // a broken example fails its own build; nothing to offer from it + } + + for (const script of [ast.instance, ast.module]) { + if (!script) continue; + for (const node of script.content.body as any[]) { + if (node.type !== 'ImportDeclaration' || node.importKind === 'type') continue; + const specifier: string = node.source.value; + if (handledElsewhere(specifier)) continue; + const entry = use(specifier); + for (const spec of node.specifiers) { + if (spec.importKind === 'type') continue; + if (spec.type === 'ImportNamespaceSpecifier') entry.whole = true; + else if (spec.type === 'ImportDefaultSpecifier') entry.names.add('default'); + else entry.names.add(spec.imported.name ?? spec.imported.value); + } + } + + // `import('pkg')` hands back the whole namespace. + const text = source.slice(script.start, script.end); + for (const match of text.matchAll(/\bimport\(\s*(['"])([^'"]+)\1\s*\)/g)) { + if (!handledElsewhere(match[2])) use(match[2]).whole = true; + } + } + } + return usage; +} + +/** The runtime functions compiled examples call. Compiles every example, so only on demand. */ +function scanRuntime(sources: string[]) { + const names = new Set(); + for (const source of sources) { + try { + // Compiled exactly as the sandbox compiles, so these are the calls it makes. + const { js } = compile(exposeData(source), compileOptions); + for (const match of js.code.matchAll(RUNTIME_MEMBER)) names.add(match[1]); + } catch { + // a broken example fails its own build + } + } + return names; +} + +/** What the editor chunk imports (`lazy.ts`), so Vite doesn't discover it mid-edit. */ +const EDITOR_DEPS = [ + '@codemirror/autocomplete', + '@codemirror/commands', + '@codemirror/language', + '@codemirror/lint', + '@codemirror/state', + '@codemirror/view', + '@lezer/highlight', + '@replit/codemirror-lang-svelte', + 'es-module-lexer', + 'svelte/compiler' +]; + +export function sandboxRegistry(): Plugin { + let examplesDir = ''; + let sources: string[] | null = null; + let usage: Map | null = null; + let runtime: Set | null = null; + const examples = () => (sources ??= readExamples(examplesDir)); + const imports = () => (usage ??= scanImports(examples())); + const runtimeNames = () => (runtime ??= scanRuntime(examples())); + + return { + name: 'layerchart-docs:sandbox-registry', + + config(config, { command }) { + examplesDir = resolve(config.root ?? '', 'src/examples/components'); + if (command !== 'serve') return; + // Everything here loads lazily on first edit. Undiscovered, each one makes the dev + // server re-optimize and reload the page in the middle of that edit. + const packages = [...imports().keys()].filter( + (specifier) => !/^(\$|~|svelte(\/|$)|layerchart(\/|$))/.test(specifier) + ); + return { optimizeDeps: { include: [...EDITOR_DEPS, ...packages] } }; + }, + + resolveId(id) { + if (id === REGISTRY_ID || id.startsWith(EXPORTS_PREFIX)) return '\0' + id; + }, + + async load(id) { + if (id === '\0' + REGISTRY_ID) { + const entries = [...imports(), [RUNTIME, { names: new Set(), whole: false }] as const]; + const lines = entries + .sort(([a], [b]) => a.localeCompare(b)) + .map(([specifier, { whole }]) => { + const target = whole ? specifier : EXPORTS_PREFIX + encodeURIComponent(specifier); + return `\t${JSON.stringify(specifier)}: () => import(${JSON.stringify(target)}),`; + }); + return `export default {\n${lines.join('\n')}\n};\n`; + } + + if (id.startsWith('\0' + EXPORTS_PREFIX)) { + const specifier = decodeURIComponent(id.slice(EXPORTS_PREFIX.length + 1)); + let names = [...(imports().get(specifier)?.names ?? [])]; + if (specifier === RUNTIME) { + // `$.` read off compiled output; drop anything that only looked like a call. + // @ts-expect-error - no declarations for 'svelte/internal/client' + const exported = await import('svelte/internal/client'); // eslint-disable-line svelte/no-svelte-internal -- reads what it exports + names = [...runtimeNames()].filter((name) => name in exported); + } + names = names + .sort() + .map((name) => + /^[\p{ID_Start}$_][\p{ID_Continue}$]*$/u.test(name) ? name : JSON.stringify(name) + ); + return `export { ${names.join(', ')} } from ${JSON.stringify(specifier)};\n`; + } + }, + + // An edited, added or removed example can change what's offered. + hotUpdate({ file }) { + if (!file.endsWith('.svelte') || relative(examplesDir, file).startsWith('..')) return; + sources = usage = runtime = null; + for (const id of this.environment.moduleGraph.idToModuleMap.keys()) { + if (id === '\0' + REGISTRY_ID || id.startsWith('\0' + EXPORTS_PREFIX)) { + const module = this.environment.moduleGraph.getModuleById(id); + if (module) this.environment.moduleGraph.invalidateModule(module); + } + } + } + }; +} diff --git a/docs/src/lib/sandbox/registry.test.ts b/docs/src/lib/sandbox/registry.test.ts new file mode 100644 index 0000000000..ebbd8995e5 --- /dev/null +++ b/docs/src/lib/sandbox/registry.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, it } from 'vitest'; +import { compile } from 'svelte/compiler'; +import { exposeData } from '$lib/utils/exampleSource'; +import { compileOptions } from './compile-options'; +import { importSpecifiers } from './link'; +import { resolve } from './registry'; + +const examples = import.meta.glob('/src/examples/components/**/*.svelte', { + query: '?raw', + import: 'default', + eager: true +}); + +describe('sandbox registry', () => { + it('resolves every import of every example', async () => { + const unresolved: string[] = []; + + for (const [path, source] of Object.entries(examples)) { + // Compiled exactly as the sandbox does, so type-only imports (erased) and the + // runtime's own `svelte/internal/*` imports are checked as the browser sees them. + const { js } = compile(exposeData(source), compileOptions); + const base = path.slice(0, path.lastIndexOf('/') + 1); + for (const specifier of await importSpecifiers(js.code)) { + if (!resolve(specifier, base)) unresolved.push(`${path}: ${specifier}`); + } + } + + // Add the module to `registry.ts` — otherwise editing these examples fails. + expect(unresolved).toEqual([]); + }); +}); + +describe('importSpecifiers', () => { + it('finds imports that span several lines', async () => { + // Compiled output keeps the source's formatting, so long import lists wrap. + const js = + "import * as $ from 'svelte/internal/client';\nimport {\n\tArea,\n\tChart\n} from 'layerchart';\n"; + expect(await importSpecifiers(js)).toEqual(['svelte/internal/client', 'layerchart']); + }); +}); diff --git a/docs/src/lib/sandbox/registry.ts b/docs/src/lib/sandbox/registry.ts index c7b7785326..3639816638 100644 --- a/docs/src/lib/sandbox/registry.ts +++ b/docs/src/lib/sandbox/registry.ts @@ -4,44 +4,59 @@ * These are the *same* instances the docs app itself is built with, so an edited * example runs against the workspace build of `layerchart` (not a published copy * fetched from a CDN) and shares a single Svelte runtime with the host page. + * + * Every entry is a loader, so an edit only fetches what that example imports. Packages + * come from `virtual:sandbox-registry` (see `registry-plugin.ts`), which offers only the + * names the examples use, so the sandbox doesn't make docs pages load more. + * `registry.test.ts` checks every example's imports resolve here. */ -import * as svelte from 'svelte'; -// Compiled components import this; it's deliberately untyped by Svelte, and we only -// ever hand the namespace object back out again. -// @ts-expect-error - no declarations for 'svelte/internal/client' -import * as svelteInternalClient from 'svelte/internal/client'; -import * as svelteEasing from 'svelte/easing'; -import * as svelteTransition from 'svelte/transition'; -import * as layerchart from 'layerchart'; -import * as d3Array from 'd3-array'; -import * as d3Scale from 'd3-scale'; -import * as d3ScaleChromatic from 'd3-scale-chromatic'; -import * as d3Time from 'd3-time'; -import * as d3Shape from 'd3-shape'; -import * as svelteUx from 'svelte-ux'; -import * as layerstackUtils from '@layerstack/utils'; -import * as layerstackTailwind from '@layerstack/tailwind'; -import * as data from '$lib/utils/data'; +import generated from 'virtual:sandbox-registry'; + +export type Namespace = Record; +type Loader = () => Promise; -const empty = {}; +/** Side-effect-only imports in compiled output — the host runtime has already run them. */ +const empty: Loader = async () => ({}); -export const registry: Record> = { - svelte, - 'svelte/internal/client': svelteInternalClient, - // Side-effect-only imports in compiled output — nothing to re-export. +const packages: Record = { + ...generated, + // Side-effect-only modules compiled components import. `svelte/internal/client` itself + // is generated, with only the functions compiled examples call. 'svelte/internal/disclose-version': empty, - 'svelte/internal/flags/legacy': empty, - 'svelte/easing': svelteEasing, - 'svelte/transition': svelteTransition, - layerchart, - 'd3-array': d3Array, - 'd3-scale': d3Scale, - 'd3-scale-chromatic': d3ScaleChromatic, - 'd3-time': d3Time, - 'd3-shape': d3Shape, - 'svelte-ux': svelteUx, - '@layerstack/utils': layerstackUtils, - '@layerstack/tailwind': layerstackTailwind, - '$lib/utils/data': data, - '$lib/utils/data.js': data + 'svelte/internal/flags/async': empty, + 'svelte/internal/flags/legacy': empty }; + +/** The `$lib` modules examples import: data loaders, controls and small helpers. */ +const lib = import.meta.glob([ + '/src/lib/{data,geo,graph}.remote.ts', + '/src/lib/utils/*.ts', + '!/src/lib/utils/*.test.ts', + '/src/lib/actions/*.ts', + '/src/lib/attachments/*.ts', + '/src/lib/components/controls/**/*.svelte' +]); + +/** Helper modules that sit next to an example and are imported relatively. */ +const exampleModules = import.meta.glob('/src/examples/components/**/*.{js,ts}'); + +/** Imports are written with `.js`, with no extension, or with the real one. */ +function fromFiles(files: Record, path: string) { + const candidates = [path, path.replace(/\.js$/, '.ts'), `${path}.ts`, `${path}.js`]; + const id = candidates.find((candidate) => candidate in files); + return id ? { id, load: files[id] } : undefined; +} + +/** + * Finds the module for an import specifier. `base` is the example's directory + * (`/src/examples/components/GeoPath/`), needed only for relative imports. `id` is + * stable across examples, so callers can cache per module rather than per spelling. + */ +export function resolve(specifier: string, base?: string) { + if (Object.hasOwn(packages, specifier)) return { id: specifier, load: packages[specifier] }; + if (specifier.startsWith('$lib/')) return fromFiles(lib, `/src/lib/${specifier.slice(5)}`); + if (base && /^\.\.?\//.test(specifier)) { + return fromFiles(exampleModules, new URL(specifier, `file://${base}`).pathname); + } + return undefined; +} diff --git a/docs/src/lib/sandbox/state.svelte.ts b/docs/src/lib/sandbox/state.svelte.ts index c6d5195fca..5d4429382c 100644 --- a/docs/src/lib/sandbox/state.svelte.ts +++ b/docs/src/lib/sandbox/state.svelte.ts @@ -6,15 +6,21 @@ import type { Diagnostic } from './compile'; type SandboxModule = typeof import('./lazy'); /** - * Everything needed to turn a read-only example into an editable one, shared by - * `Example` (stacked, code behind a disclosure) and `LiveExample` (side-by-side). + * Everything `Example` needs to turn a read-only example into an editable one. * * Must be called during component initialisation — it registers effects. */ export function createSandbox( getSource: () => string, - /** Applied to the source before compiling only — never shown in the editor. */ - transform?: (source: string) => string + { + transform, + base + }: { + /** Applied to the source before compiling only — never shown in the editor. */ + transform?: (source: string) => string; + /** The example's directory (`/src/examples/components/GeoPath/`), for relative imports. */ + base?: () => string | undefined; + } = {} ) { let module = $state(null); let loading = $state(false); @@ -25,8 +31,8 @@ export function createSandbox( let live = $state(false); /** - * `Example` resolves its source asynchronously, so these are seeded on first sight of a - * non-empty source rather than at construction. Normalised so the editor starts from + * `Example` resolves its source asynchronously, so these are seeded when a non-empty + * source arrives rather than at construction. Normalised so the editor starts from * exactly the text `Code` displays — otherwise Edit shows a trailing blank line View * doesn't have. */ @@ -45,14 +51,21 @@ export function createSandbox( */ let instance = $state.raw | null>(null); + /** + * A different source is a different example: SvelteKit keeps the same `Example` when + * navigating between examples, so start over rather than keep showing (and running) + * the previous one. Edits never change `getSource()`, so typing can't land here. + */ $effect(() => { const next = seed(); untrack(() => { - if (next && !original) { - original = next; - editorValue = next; - debounced = next; - } + if (!next || next === original) return; + original = editorValue = debounced = next; + live = false; + build = null; + diagnostics = []; + runtimeError = null; + instance = null; }); }); @@ -123,13 +136,21 @@ export function createSandbox( const src = debounced; if (!sb || !live) return; - const result = sb.compileSource(transform ? transform(src) : src); - diagnostics = result.diagnostics; - elapsed = Math.round(result.elapsed); - if (result.url) { - build = result.url; - runtimeError = null; - } + // Compiling is async (imports load on demand), so a slow build can finish after a + // newer one — drop it rather than let it replace what the user typed since. + let stale = false; + sb.compileSource(transform ? transform(src) : src, { base: base?.() }).then((result) => { + if (stale) return; + diagnostics = result.diagnostics; + elapsed = Math.round(result.elapsed); + if (result.url) { + build = result.url; + runtimeError = null; + } + }); + return () => { + stale = true; + }; }); /** Mounts the newest successful build. Only re-runs when `build` changes. */ diff --git a/docs/src/lib/sandbox/virtual.d.ts b/docs/src/lib/sandbox/virtual.d.ts new file mode 100644 index 0000000000..47ad4b3f32 --- /dev/null +++ b/docs/src/lib/sandbox/virtual.d.ts @@ -0,0 +1,4 @@ +declare module 'virtual:sandbox-registry' { + const packages: Record Promise>>; + export default packages; +} diff --git a/docs/src/lib/stackblitz.remote.ts b/docs/src/lib/stackblitz.remote.ts index db6a338f0e..01e389bd0b 100644 --- a/docs/src/lib/stackblitz.remote.ts +++ b/docs/src/lib/stackblitz.remote.ts @@ -1,4 +1,4 @@ -import { query, getRequestEvent } from '$app/server'; +import { command, getRequestEvent } from '$app/server'; import { z } from 'zod'; import stackblitzFiles from '$static/stackblitz-files.json'; import remoteSources from '$static/remote-sources.json'; @@ -160,7 +160,9 @@ ${functionBodies.join('\n\n')} `; } -export const getExample = query( +// A `command` rather than a `query` so the edited source travels in a POST body: queries +// put their arguments in the URL, and large examples exceed URL length limits. +export const getExample = command( z.object({ component: z.string(), name: z.string(), diff --git a/docs/src/routes/docs/sandbox-poc/+page.svelte b/docs/src/routes/docs/sandbox-poc/+page.svelte deleted file mode 100644 index 1ce0989615..0000000000 --- a/docs/src/routes/docs/sandbox-poc/+page.svelte +++ /dev/null @@ -1,40 +0,0 @@ - - -
-
-

Sandbox proof of concept

-

- The chart on the right is the real example component. Click into the code and it's replaced by - an in-page compile of whatever you type — the compiler and editor load on that first click. -

-
- -
-

AreaChart / series-stack

- - {#snippet preview()} - - {/snippet} - -
- -
-

LineChart / basic

- - {#snippet preview()} - - {/snippet} - -
-
diff --git a/docs/vite.config.ts b/docs/vite.config.ts index 718325941a..ff306f0b7e 100644 --- a/docs/vite.config.ts +++ b/docs/vite.config.ts @@ -4,6 +4,7 @@ import tailwindcss from '@tailwindcss/vite'; import { sveltekit } from '@sveltejs/kit/vite'; import contentCollections from '@content-collections/vite'; import Icons from 'unplugin-icons/vite'; +import { sandboxRegistry } from './src/lib/sandbox/registry-plugin'; // import devtoolsJson from 'vite-plugin-devtools-json'; const isTest = process.env.VITEST === 'true'; @@ -31,6 +32,7 @@ export default defineConfig({ plugins: [ tailwindcss(), sveltekit(), + sandboxRegistry(), !isTest && contentCollections(), Icons({ compiler: 'svelte', @@ -50,10 +52,6 @@ export default defineConfig({ // allowedHosts: ['.trycloudflare.com'], fs: { allow: ['.live-code'] - }, - headers: { - 'Cross-Origin-Embedder-Policy': 'require-corp', - 'Cross-Origin-Opener-Policy': 'same-origin' } }, test: { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5ee4d5d09b..67b6c89dc3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -95,6 +95,9 @@ importers: d3-geo-projection: specifier: ^4.0.0 version: 4.0.0 + es-module-lexer: + specifier: ^2.1.0 + version: 2.1.0 satori: specifier: ^0.26.0 version: 0.26.0 From 4f8736c1a7491edcf9457af3f0852307ae3d6add Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 12 Oct 2026 11:04:23 -0400 Subject: [PATCH 08/15] Avoid loading editor dependencies during server rendering --- docs/src/lib/sandbox/state.svelte.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/src/lib/sandbox/state.svelte.ts b/docs/src/lib/sandbox/state.svelte.ts index 5d4429382c..0008511ec7 100644 --- a/docs/src/lib/sandbox/state.svelte.ts +++ b/docs/src/lib/sandbox/state.svelte.ts @@ -93,6 +93,10 @@ export function createSandbox( */ let inFlight: Promise | null = null; function load() { + // Constant per build, so the server build drops the editor chunk entirely. It only + // ever loads on a click, and server-side it would pull the compiler, CodeMirror and + // every package an edit can import into the Cloudflare Worker. + if (import.meta.env.SSR) return Promise.resolve(); if (module) return Promise.resolve(); if (!inFlight) { loading = true; From 16525cceb48a4bbb226e4fa58f5b9acdfb8575f9 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Mon, 12 Oct 2026 11:26:00 -0400 Subject: [PATCH 09/15] Keep the previous example visible while sandbox previews load --- docs/src/lib/components/Example.svelte | 16 +++- docs/src/lib/sandbox/state.svelte.ts | 103 +++++++++++++++++++------ 2 files changed, 92 insertions(+), 27 deletions(-) diff --git a/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte index 9f21952ee8..0ffce2d74a 100644 --- a/docs/src/lib/components/Example.svelte +++ b/docs/src/lib/components/Example.svelte @@ -144,7 +144,7 @@ let data = $derived.by(() => { try { // Once edited, the chart on screen is the sandbox's, so `Data` must read from it. - return sandbox.live ? sandbox.instance?.data : ref?.data; + return sandbox.showing ? sandbox.instance?.data : ref?.data; } catch { return undefined; } @@ -285,9 +285,17 @@ {#if isVisible} {#if sandbox.live} - -
- {:else} + +
+ {/if} + {#if !sandbox.showing} {/if} {#snippet failed(error, reset)} diff --git a/docs/src/lib/sandbox/state.svelte.ts b/docs/src/lib/sandbox/state.svelte.ts index 0008511ec7..f4266a0cf3 100644 --- a/docs/src/lib/sandbox/state.svelte.ts +++ b/docs/src/lib/sandbox/state.svelte.ts @@ -1,4 +1,4 @@ -import { mount, unmount, untrack } from 'svelte'; +import { mount, settled, unmount, untrack } from 'svelte'; import type { Attachment } from 'svelte/attachments'; import { normalizeSource } from '$lib/utils/exampleSource'; import type { Diagnostic } from './compile'; @@ -157,33 +157,67 @@ export function createSandbox( }; }); - /** Mounts the newest successful build. Only re-runs when `build` changes. */ - const preview: Attachment = (el) => { - const url = build; - if (!url) return; + /** Whether an edited build is on screen. Until then `Example` keeps the real example up. */ + let showing = $state(false); - let mounted: Record | null = null; - let disposed = false; + /** + * Mounts each successful build without blanking the preview. + * + * Unmounting the old component and then mounting the new one leaves the preview empty + * for a frame or more (the module import is async, and charts draw only after + * measuring their container), and the collapsed height makes the page jump. Instead + * the new component mounts into a hidden layer the preview's width, gets time to + * finish (async data, then a couple of frames to measure and draw), and replaces + * what's on screen in one step. A build that throws while mounting leaves the last + * one up. + */ + const preview: Attachment = (el) => { + let current: Mounted | null = null; + + $effect(() => { + const url = build; + if (!url) return; + let superseded = false; + + (async () => { + const layer = document.createElement('div'); + layer.style.cssText = HIDDEN_LAYER; + let next: Mounted | null = null; + try { + const mod = await import(/* @vite-ignore */ url); + if (superseded) return; + el.append(layer); + next = { layer, component: mount(mod.default, { target: layer }) }; + await Promise.race([settled(), delay(1000)]); + await frames(2); + } catch (err) { + dispose(next); + layer.remove(); + if (!superseded) runtimeError = err instanceof Error ? err.message : String(err); + return; + } finally { + URL.revokeObjectURL(url); + } + if (superseded) return dispose(next); - import(/* @vite-ignore */ url) - .then((mod) => { - URL.revokeObjectURL(url); - if (disposed) return; + dispose(current); + layer.style.cssText = ''; + current = next; + instance = next.component; runtimeError = null; - mounted = mount(mod.default, { target: el as HTMLElement }); - instance = mounted; - }) - .catch((err) => { - URL.revokeObjectURL(url); - if (!disposed) runtimeError = err instanceof Error ? err.message : String(err); - }); + showing = true; + })(); + + return () => { + superseded = true; + }; + }); return () => { - disposed = true; - if (mounted) { - unmount(mounted); - if (instance === mounted) instance = null; - } + dispose(current); + current = null; + instance = null; + showing = false; }; }; @@ -223,6 +257,9 @@ export function createSandbox( get instance() { return instance; }, + get showing() { + return showing; + }, get dirty() { return editorValue !== original; }, @@ -243,3 +280,23 @@ export function createSandbox( } export type Sandbox = ReturnType; + +type Mounted = { layer: HTMLElement; component: Record }; + +/** Laid out at the preview's width so charts measure correctly, but not seen or hit. */ +const HIDDEN_LAYER = 'position:absolute;inset-inline:0;top:0;visibility:hidden;pointer-events:none'; + +function dispose(mounted: Mounted | null) { + if (!mounted) return; + unmount(mounted.component); + mounted.layer.remove(); +} + +const delay = (ms: number) => new Promise((done) => setTimeout(done, ms)); + +function frames(count: number) { + return new Promise((done) => { + const step = (left: number) => (left ? requestAnimationFrame(() => step(left - 1)) : done()); + step(count); + }); +} From 57ac1089ad73e76e6356114eb9b0ac3a89988c38 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Tue, 13 Oct 2026 11:48:05 -0400 Subject: [PATCH 10/15] Add split-pane layout for documentation examples --- docs/package.json | 1 + docs/src/lib/components/Example.svelte | 210 +++++++++++++++---------- docs/src/lib/sandbox/CodePanel.svelte | 204 +++++++++++++----------- pnpm-lock.yaml | 51 +++++- 4 files changed, 297 insertions(+), 169 deletions(-) diff --git a/docs/package.json b/docs/package.json index b249a9a831..778a8d51b4 100644 --- a/docs/package.json +++ b/docs/package.json @@ -124,6 +124,7 @@ "@stackblitz/sdk": "^1.11.0", "d3-geo-projection": "^4.0.0", "es-module-lexer": "^2.1.0", + "paneforge": "^1.0.2", "satori": "^0.26.0", "satori-html": "^0.3.2" } diff --git a/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte index 0ffce2d74a..8e7f2ca8e1 100644 --- a/docs/src/lib/components/Example.svelte +++ b/docs/src/lib/components/Example.svelte @@ -20,6 +20,8 @@ import { resolveExamplePath } from '@layerstack/docs/content'; import { exampleViewTransitionName } from '@layerstack/docs/utils'; import { untrack } from 'svelte'; + import { MediaQuery } from 'svelte/reactivity'; + import { Pane, PaneGroup, PaneResizer } from 'paneforge'; import { Json } from '@layerstack/docs/components'; import CodePanel from '$lib/sandbox/CodePanel.svelte'; import PreviewError from '$lib/sandbox/PreviewError.svelte'; @@ -103,6 +105,15 @@ }); }); + /** + * Code beside the preview rather than below it. Only offered with room for both, and + * only while the code is showing; the toggle lives in the code panel's toolbar. + */ + let splitPreferred = $state(false); + const wide = new MediaQuery('min-width: 768px'); + const canSplit = $derived(wide.current); + const split = $derived(splitPreferred && showCode && canSplit); + let containerEl = $state(null); let containerWidth = $state(undefined); const minWidth = 200; @@ -267,94 +278,133 @@
{#if example} -
+ {#snippet previewBlock()}
- {#if isVisible} - - {#if sandbox.live} - -
- {/if} - {#if !sandbox.showing} - - {/if} - {#snippet failed(error, reset)} -
-
- Example error{#if component && name}: {component}/{name}{/if} +
+ {#if isVisible} + + {#if sandbox.live} + +
+ {/if} + {#if !sandbox.showing && example} + + {/if} + {#snippet failed(error, reset)} +
+
+ Example error{#if component && name}: {component}/{name}{/if} +
+
{error}
+
-
{error}
- -
- {/snippet} - {#snippet pending()} -
- Loading... -
- {/snippet} - - {:else} -
- {/if} - - {#if canResize} -
{ - const newWidth = (containerWidth ?? containerEl?.offsetWidth ?? 0) + e.detail.dx; - if (newWidth >= minWidth) { - containerWidth = newWidth; + {/snippet} + {#snippet pending()} +
+ Loading... +
+ {/snippet} + + {:else} +
+ {/if} + + + {#if canResize && !split} +
{ + const newWidth = (containerWidth ?? containerEl?.offsetWidth ?? 0) + e.detail.dx; + if (newWidth >= minWidth) { + containerWidth = newWidth; + } } - } - }} - > - -
- {/if} - - {#if sandbox.error} - - {/if} + }} + > + +
+ {/if} + + {#if sandbox.error} + + {/if} +
-
- - {#if showCode} -
- openInStackBlitz(component, name, sandbox.dirty ? sandbox.source : undefined) - : undefined} + {/snippet} + + {#snippet codeBlock()} + openInStackBlitz(component, name, sandbox.dirty ? sandbox.source : undefined) + : undefined} + {split} + onsplitchange={canSplit ? (next) => (splitPreferred = next) : undefined} + /> + {/snippet} + + {#if split} + + + +
+ {@render codeBlock()} +
+
+ -
+ + {@render previewBlock()} + + + {:else} + {@render previewBlock()} + + {#if showCode} +
+ {@render codeBlock()} +
+ {/if} {/if} {#if variant === 'default'} diff --git a/docs/src/lib/sandbox/CodePanel.svelte b/docs/src/lib/sandbox/CodePanel.svelte index cf63b90e28..d7d00b2d11 100644 --- a/docs/src/lib/sandbox/CodePanel.svelte +++ b/docs/src/lib/sandbox/CodePanel.svelte @@ -13,11 +13,13 @@ } from 'svelte-ux'; import { cls } from '@layerstack/tailwind'; import LucideCode from '~icons/lucide/code'; + import LucideColumns2 from '~icons/lucide/columns-2'; import LucideEllipsisVertical from '~icons/lucide/ellipsis-vertical'; import LucideFilePen from '~icons/lucide/file-pen'; import LucideListOrdered from '~icons/lucide/list-ordered'; import LucideLoaderCircle from '~icons/lucide/loader-circle'; import LucideRotateCcw from '~icons/lucide/rotate-ccw'; + import LucideRows2 from '~icons/lucide/rows-2'; import SimpleIconsStackblitz from '~icons/simple-icons/stackblitz'; import type { Sandbox } from './state.svelte'; @@ -26,6 +28,8 @@ showLineNumbers = false, highlight, onopenstackblitz, + split = false, + onsplitchange, class: className }: { sandbox: Sandbox; @@ -33,6 +37,10 @@ highlight?: string; /** Adds "Open in StackBlitz" to the menu when set. */ onopenstackblitz?: () => Promise; + /** Whether the host shows this beside the preview rather than below it. */ + split?: boolean; + /** Shows the layout toggle when set. */ + onsplitchange?: (split: boolean) => void; class?: string; } = $props(); @@ -62,105 +70,125 @@ Edit anywhere the host didn't happen to supply one. -->
- {#if editing && sandbox.module} - - {:else} - - - {/if} - -
sandbox.load()} + class="screenshot-hidden pointer-events-none sticky top-[var(--code-toolbar-top,4rem)] z-10 flex h-9 justify-end" > - {#if sandbox.dirty} - - - + Edit + + + + + + + +
+
+
+ {#if editing && sandbox.module} + + {:else} + + + {/if}
{#if sandbox.loadError} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 67b6c89dc3..20055a7da3 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -98,6 +98,9 @@ importers: es-module-lexer: specifier: ^2.1.0 version: 2.1.0 + paneforge: + specifier: ^1.0.2 + version: 1.0.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)) satori: specifier: ^0.26.0 version: 0.26.0 @@ -311,7 +314,7 @@ importers: version: 5.56.1(@typescript-eslint/types@8.60.1) svelte-check: specifier: ^4.5.0 - version: 4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) + version: 4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) svelte-ux: specifier: 2.0.0-next.22 version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0))(postcss@8.5.15)(svelte@5.56.1(@typescript-eslint/types@8.60.1)) @@ -5053,6 +5056,11 @@ packages: pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + paneforge@1.0.2: + resolution: {integrity: sha512-KzmIXQH1wCfwZ4RsMohD/IUtEjVhteR+c+ulb/CHYJHX8SuDXoJmChtsc/Xs5Wl8NHS4L5Q7cxL8MG40gSU1bA==} + peerDependencies: + svelte: ^5.29.0 + parse-css-color@0.2.1: resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==} @@ -5459,6 +5467,11 @@ packages: peerDependencies: svelte: ^5.7.0 + runed@0.29.2: + resolution: {integrity: sha512-0cq6cA6sYGZwl/FvVqjx9YN+1xEBu9sDDyuWdDW1yWX7JF2wmvmVKfH+hVCZs+csW+P3ARH92MjI3H9QTagOQA==} + peerDependencies: + svelte: ^5.7.0 + runed@0.35.1: resolution: {integrity: sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==} peerDependencies: @@ -5701,6 +5714,12 @@ packages: peerDependencies: svelte: ^5.0.0 + svelte-toolbelt@0.9.3: + resolution: {integrity: sha512-HCSWxCtVmv+c6g1ACb8LTwHVbDqLKJvHpo6J8TaqwUme2hj9ATJCpjCPNISR1OCq2Q4U1KT41if9ON0isINQZw==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.30.2 + svelte-ux@2.0.0-next.19: resolution: {integrity: sha512-d6a4MdNgwdLod9GrrFPrw76MufHD+nx5siSoHlsKuRVur3z2wCY8O15R7dL461h/DBGOn78an4zLJIk/E8LFzw==} peerDependencies: @@ -10976,6 +10995,12 @@ snapshots: pako@0.2.9: {} + paneforge@1.0.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)): + dependencies: + runed: 0.23.4(svelte@5.56.1(@typescript-eslint/types@8.60.1)) + svelte: 5.56.1(@typescript-eslint/types@8.60.1) + svelte-toolbelt: 0.9.3(svelte@5.56.1(@typescript-eslint/types@8.60.1)) + parse-css-color@0.2.1: dependencies: color-name: 1.1.4 @@ -11402,6 +11427,11 @@ snapshots: esm-env: 1.2.2 svelte: 5.56.1(@typescript-eslint/types@8.60.1) + runed@0.29.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)): + dependencies: + esm-env: 1.2.2 + svelte: 5.56.1(@typescript-eslint/types@8.60.1) + runed@0.35.1(@sveltejs/kit@2.62.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@7.1.2(svelte@5.56.1(@typescript-eslint/types@8.60.1))(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3)(vite@8.0.16(@types/node@25.9.1)(esbuild@0.28.0)(jiti@2.7.0)(tsx@4.22.4)(yaml@2.9.0)))(svelte@5.56.1(@typescript-eslint/types@8.60.1)): dependencies: dequal: 2.0.3 @@ -11614,6 +11644,18 @@ snapshots: - stylus - sugarss + svelte-check@4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + chokidar: 4.0.3 + fdir: 6.5.0(picomatch@4.0.4) + picocolors: 1.1.1 + sade: 1.8.1 + svelte: 5.56.1(@typescript-eslint/types@8.60.1) + typescript: 6.0.3 + transitivePeerDependencies: + - picomatch + svelte-check@4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 @@ -11662,6 +11704,13 @@ snapshots: style-to-object: 1.0.14 svelte: 5.56.1(@typescript-eslint/types@8.60.1) + svelte-toolbelt@0.9.3(svelte@5.56.1(@typescript-eslint/types@8.60.1)): + dependencies: + clsx: 2.1.1 + runed: 0.29.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)) + style-to-object: 1.0.14 + svelte: 5.56.1(@typescript-eslint/types@8.60.1) + svelte-ux@2.0.0-next.19(postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0))(postcss@8.5.15)(svelte@5.56.1(@typescript-eslint/types@8.60.1)): dependencies: '@floating-ui/dom': 1.7.4 From 09f8e604d77d172080639bbc5c7335898c6ac902 Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Thu, 15 Oct 2026 18:55:38 -0400 Subject: [PATCH 11/15] Improve sandbox module loading and error handling --- docs/package.json | 2 +- docs/src/lib/components/Example.svelte | 45 +++----- docs/src/lib/sandbox/CodeEditor.svelte | 21 +--- docs/src/lib/sandbox/CodePanel.svelte | 39 ++----- docs/src/lib/sandbox/PreviewError.svelte | 9 +- docs/src/lib/sandbox/SplitLayout.svelte | 32 ++++++ docs/src/lib/sandbox/compile.ts | 10 +- docs/src/lib/sandbox/registry-plugin.ts | 127 +++++++++++++++-------- docs/src/lib/sandbox/registry.ts | 42 ++------ docs/src/lib/sandbox/state.svelte.ts | 60 +++++------ pnpm-lock.yaml | 20 +--- 11 files changed, 201 insertions(+), 206 deletions(-) create mode 100644 docs/src/lib/sandbox/SplitLayout.svelte diff --git a/docs/package.json b/docs/package.json index 778a8d51b4..975644601c 100644 --- a/docs/package.json +++ b/docs/package.json @@ -85,6 +85,7 @@ "layerchart": "workspace:*", "mathjs": "^15.2.0", "mdsx": "^0.0.7", + "paneforge": "^1.0.2", "playwright": "^1.60.0", "posthog-js": "^1.379.0", "prettier": "^3.8.3", @@ -124,7 +125,6 @@ "@stackblitz/sdk": "^1.11.0", "d3-geo-projection": "^4.0.0", "es-module-lexer": "^2.1.0", - "paneforge": "^1.0.2", "satori": "^0.26.0", "satori-html": "^0.3.2" } diff --git a/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte index 8e7f2ca8e1..fad5b5d3bd 100644 --- a/docs/src/lib/components/Example.svelte +++ b/docs/src/lib/components/Example.svelte @@ -21,7 +21,6 @@ import { exampleViewTransitionName } from '@layerstack/docs/utils'; import { untrack } from 'svelte'; import { MediaQuery } from 'svelte/reactivity'; - import { Pane, PaneGroup, PaneResizer } from 'paneforge'; import { Json } from '@layerstack/docs/components'; import CodePanel from '$lib/sandbox/CodePanel.svelte'; import PreviewError from '$lib/sandbox/PreviewError.svelte'; @@ -107,12 +106,21 @@ /** * Code beside the preview rather than below it. Only offered with room for both, and - * only while the code is showing; the toggle lives in the code panel's toolbar. + * only while the code is showing; the toggle is in the code panel's menu. */ let splitPreferred = $state(false); const wide = new MediaQuery('min-width: 768px'); - const canSplit = $derived(wide.current); - const split = $derived(splitPreferred && showCode && canSplit); + const split = $derived(splitPreferred && showCode && wide.current); + + /** Loaded on first use, and only then switched to, so there's no half-loaded state. */ + let SplitLayout = $state(null); + async function setSplit(next: boolean) { + if (next) SplitLayout ??= (await import('$lib/sandbox/SplitLayout.svelte')).default; + splitPreferred = next; + } + + /** Kept here, not in `CodePanel`, so it survives the panel remounting on a layout change. */ + let lineNumbers = $state(untrack(() => showLineNumbers)); let containerEl = $state(null); let containerWidth = $state(undefined); @@ -364,39 +372,18 @@ {#snippet codeBlock()} openInStackBlitz(component, name, sandbox.dirty ? sandbox.source : undefined) : undefined} {split} - onsplitchange={canSplit ? (next) => (splitPreferred = next) : undefined} + onsplitchange={wide.current ? setSplit : undefined} /> {/snippet} - {#if split} - - - -
- {@render codeBlock()} -
-
- - - {@render previewBlock()} - -
+ {#if split && SplitLayout} + {:else} {@render previewBlock()} diff --git a/docs/src/lib/sandbox/CodeEditor.svelte b/docs/src/lib/sandbox/CodeEditor.svelte index 11a8334299..c6922e0e4f 100644 --- a/docs/src/lib/sandbox/CodeEditor.svelte +++ b/docs/src/lib/sandbox/CodeEditor.svelte @@ -35,16 +35,12 @@ * exactly when it was in View — adding or dropping one shifts every line sideways. * Reactive, so it can be toggled without rebuilding the editor. */ - lineNumbers = false, - oninput, - class: className + lineNumbers = false }: { value?: string; diagnostics?: Diagnostic[]; autofocus?: boolean; lineNumbers?: boolean; - oninput?: (value: string) => void; - class?: string; } = $props(); let container = $state(null); @@ -172,11 +168,6 @@ * These are hand-copied from `Code`, so they need re-checking if its highlighter changes. */ const appearance = EditorView.theme({ - // `!important` because the github theme sets its own `&` background and CodeMirror - // injects the two style modules at equal specificity — the panel must win, or the - // editor paints a different colour than the `Code` block it replaces. - '&': { height: '100%', backgroundColor: 'transparent !important' }, - '.cm-scroller, .cm-content': { backgroundColor: 'transparent !important' }, '&.cm-focused': { outline: 'none' }, '.cm-scroller': { overflow: 'auto', @@ -188,6 +179,8 @@ '.cm-content': { padding: '1rem', tabSize: '2' }, '.cm-line': { padding: '0' }, '.cm-gutters': { + // CodeMirror's base theme paints the gutter (`#f5f5f5` / `#333338`) at the same + // specificity; the panel has to show through, as it does behind `Code`'s numbers. backgroundColor: 'transparent !important', border: 'none', paddingLeft: '1rem', @@ -242,11 +235,7 @@ gutterCompartment.of(gutter(untrack(() => lineNumbers))), appearance, EditorView.updateListener.of((update) => { - if (update.docChanged) { - const next = update.state.doc.toString(); - value = next; - oninput?.(next); - } + if (update.docChanged) value = update.state.doc.toString(); }) ] }) @@ -297,4 +286,4 @@ }); -
+
diff --git a/docs/src/lib/sandbox/CodePanel.svelte b/docs/src/lib/sandbox/CodePanel.svelte index d7d00b2d11..258eae7ee4 100644 --- a/docs/src/lib/sandbox/CodePanel.svelte +++ b/docs/src/lib/sandbox/CodePanel.svelte @@ -1,5 +1,4 @@ @@ -23,7 +24,7 @@ role="alert" >
- Error compiling {filename} + Error {kind === 'compile' ? 'compiling' : 'running'} Example.svelte
+	import type { Snippet } from 'svelte';
+	import { Pane, PaneGroup, PaneResizer } from 'paneforge';
+
+	let { code, preview }: { code: Snippet; preview: Snippet } = $props();
+
+
+
+
+	
+		
+ {@render code()} +
+
+ + + {@render preview()} + +
diff --git a/docs/src/lib/sandbox/compile.ts b/docs/src/lib/sandbox/compile.ts index 1ecd3c8943..de53a166f1 100644 --- a/docs/src/lib/sandbox/compile.ts +++ b/docs/src/lib/sandbox/compile.ts @@ -16,8 +16,6 @@ export type CompileResult = { /** Blob URL of the linked module, or `null` when compilation failed. */ url: string | null; diagnostics: Diagnostic[]; - /** Time spent compiling + linking, in ms. */ - elapsed: number; }; /** Strip the trailing `https://svelte.dev/e/...` docs link the compiler appends. */ @@ -30,7 +28,6 @@ export async function compileSource( source: string, { base }: { base?: string } = {} ): Promise { - const started = performance.now(); const diagnostics: Diagnostic[] = []; let js: string; @@ -55,8 +52,7 @@ export async function compileSource( line: err.start?.line, column: err.start?.column != null ? err.start.column + 1 : undefined } - ], - elapsed: performance.now() - started + ] }; } @@ -102,8 +98,8 @@ export async function compileSource( message }); } - return { url: null, diagnostics, elapsed: performance.now() - started }; + return { url: null, diagnostics }; } - return { url: linked.url, diagnostics, elapsed: performance.now() - started }; + return { url: linked.url, diagnostics }; } diff --git a/docs/src/lib/sandbox/registry-plugin.ts b/docs/src/lib/sandbox/registry-plugin.ts index b9b539665e..c9e3c62c27 100644 --- a/docs/src/lib/sandbox/registry-plugin.ts +++ b/docs/src/lib/sandbox/registry-plugin.ts @@ -1,14 +1,15 @@ -import { globSync, readFileSync } from 'node:fs'; -import { join, relative, resolve } from 'node:path'; +import { existsSync, globSync, readFileSync } from 'node:fs'; +import { dirname, join, posix, relative, resolve } from 'node:path'; import { compile, parse } from 'svelte/compiler'; import type { Plugin } from 'vite'; import { exposeData } from '../utils/exampleSource'; import { compileOptions } from './compile-options'; /** - * Generates `virtual:sandbox-registry`: the packages edited examples may import, as loaders. + * Generates `virtual:sandbox-registry`: everything edited examples may import, as loaders + * — packages, `$lib` modules, and the helper files that sit next to an example. * - * Each package is offered with only the names some example imports, through a small + * Each module is offered with only the names some example imports, through a small * re-export module, not as its whole namespace. Exposing a whole namespace (`import('layerchart')`) * stops the bundler dropping unused exports, and the extra code lands in chunks every docs * page loads. Names an example already imports are already in the build, so offering @@ -24,41 +25,70 @@ import { compileOptions } from './compile-options'; const REGISTRY_ID = 'virtual:sandbox-registry'; const EXPORTS_PREFIX = 'virtual:sandbox-exports/'; + +/** + * The key in a virtual id, in base64url. Written plainly, `$lib/…/Controls.svelte` or + * `$lib/geo.remote.js` would end the id with that extension, and the Svelte and SvelteKit + * plugins would pick the re-export module up as a component or a remote-functions file. + */ +const toId = (key: string) => EXPORTS_PREFIX + Buffer.from(key).toString('base64url'); +const fromId = (id: string) => + Buffer.from(id.slice(EXPORTS_PREFIX.length + 1), 'base64url').toString(); const RUNTIME = 'svelte/internal/client'; /** - * Specifiers this plugin doesn't offer: `registry.ts` finds `$lib` and sibling files by - * glob, and the runtime's side-effect-only modules by hand. The runtime itself is - * gathered from compiled output below. + * Compiled output's own runtime imports: `svelte/internal/client` is gathered from compiled + * examples below, and its side-effect-only siblings are listed by hand in `registry.ts`. */ -const handledElsewhere = (specifier: string) => - specifier.startsWith('$lib/') || - specifier.startsWith('.') || - specifier.startsWith('/') || - specifier === 'svelte/internal' || - specifier.startsWith('svelte/internal/'); +const isRuntime = (specifier: string) => + specifier === 'svelte/internal' || specifier.startsWith('svelte/internal/'); -type Usage = { names: Set; whole: boolean }; +/** `target` is what the generated loader imports; it differs from the key for sibling files. */ +type Usage = { names: Set; whole: boolean; target: string }; + +type Example = { dir: string; source: string }; /** Compiled output imports the runtime as `import * as $ from 'svelte/internal/client'`. */ const RUNTIME_MEMBER = /(? - readFileSync(join(examplesDir, path), 'utf8') - ); +/** `dir` is the example's folder as the app sees it (`/src/examples/components/GeoPath/`). */ +function readExamples(root: string, examplesDir: string): Example[] { + return globSync('**/*.svelte', { cwd: examplesDir }).map((path) => { + const file = join(examplesDir, path); + const dir = '/' + relative(root, dirname(file)).split('\\').join('/') + '/'; + return { dir, source: readFileSync(file, 'utf8') }; + }); } -/** Every package import across the examples, with the names each one uses. */ -function scanImports(sources: string[]) { +/** + * The registry key and loader target for an import. Packages and `$lib` modules are keyed + * as written. A relative import is keyed by the path it points to (what `registry.ts` + * rebuilds from the example's folder), and targets the file that's actually there, since + * examples write `./timings.js` for a `.ts` file. + */ +function locate(root: string, dir: string, specifier: string) { + if (!/^\.\.?\//.test(specifier)) return { key: specifier, target: specifier }; + const key = posix.join(dir, specifier); + const candidates = [key, key.replace(/\.js$/, '.ts'), `${key}.ts`, `${key}.js`]; + const target = candidates.find((candidate) => existsSync(join(root, candidate))); + return target ? { key, target } : undefined; +} + +/** Every import across the examples, with the names each one uses. */ +function scanImports(root: string, examples: Example[]) { const usage = new Map(); - const use = (specifier: string) => { - let entry = usage.get(specifier); - if (!entry) usage.set(specifier, (entry = { names: new Set(), whole: false })); + const use = (dir: string, specifier: string) => { + const located = locate(root, dir, specifier); + if (!located) return; // a missing file fails that example's own build + let entry = usage.get(located.key); + if (!entry) { + entry = { names: new Set(), whole: false, target: located.target }; + usage.set(located.key, entry); + } return entry; }; - for (const source of sources) { + for (const { dir, source } of examples) { let ast; try { ast = parse(source, { modern: true }); @@ -71,8 +101,9 @@ function scanImports(sources: string[]) { for (const node of script.content.body as any[]) { if (node.type !== 'ImportDeclaration' || node.importKind === 'type') continue; const specifier: string = node.source.value; - if (handledElsewhere(specifier)) continue; - const entry = use(specifier); + if (isRuntime(specifier)) continue; + const entry = use(dir, specifier); + if (!entry) continue; for (const spec of node.specifiers) { if (spec.importKind === 'type') continue; if (spec.type === 'ImportNamespaceSpecifier') entry.whole = true; @@ -84,7 +115,8 @@ function scanImports(sources: string[]) { // `import('pkg')` hands back the whole namespace. const text = source.slice(script.start, script.end); for (const match of text.matchAll(/\bimport\(\s*(['"])([^'"]+)\1\s*\)/g)) { - if (!handledElsewhere(match[2])) use(match[2]).whole = true; + const entry = isRuntime(match[2]) ? undefined : use(dir, match[2]); + if (entry) entry.whole = true; } } } @@ -92,9 +124,9 @@ function scanImports(sources: string[]) { } /** The runtime functions compiled examples call. Compiles every example, so only on demand. */ -function scanRuntime(sources: string[]) { +function scanRuntime(examples: Example[]) { const names = new Set(); - for (const source of sources) { + for (const { source } of examples) { try { // Compiled exactly as the sandbox compiles, so these are the calls it makes. const { js } = compile(exposeData(source), compileOptions); @@ -121,24 +153,27 @@ const EDITOR_DEPS = [ ]; export function sandboxRegistry(): Plugin { + let root = ''; let examplesDir = ''; - let sources: string[] | null = null; + let read: Example[] | null = null; let usage: Map | null = null; let runtime: Set | null = null; - const examples = () => (sources ??= readExamples(examplesDir)); - const imports = () => (usage ??= scanImports(examples())); + const examples = () => (read ??= readExamples(root, examplesDir)); + const imports = () => (usage ??= scanImports(root, examples())); const runtimeNames = () => (runtime ??= scanRuntime(examples())); return { name: 'layerchart-docs:sandbox-registry', config(config, { command }) { - examplesDir = resolve(config.root ?? '', 'src/examples/components'); + root = resolve(config.root ?? ''); + examplesDir = join(root, 'src/examples/components'); if (command !== 'serve') return; // Everything here loads lazily on first edit. Undiscovered, each one makes the dev - // server re-optimize and reload the page in the middle of that edit. + // server re-optimize and reload the page in the middle of that edit. Only npm + // packages can be pre-bundled; the workspace `layerchart` and `svelte` never are. const packages = [...imports().keys()].filter( - (specifier) => !/^(\$|~|svelte(\/|$)|layerchart(\/|$))/.test(specifier) + (specifier) => !/^(\$|~|\/|svelte(\/|$)|layerchart(\/|$))/.test(specifier) ); return { optimizeDeps: { include: [...EDITOR_DEPS, ...packages] } }; }, @@ -149,20 +184,24 @@ export function sandboxRegistry(): Plugin { async load(id) { if (id === '\0' + REGISTRY_ID) { - const entries = [...imports(), [RUNTIME, { names: new Set(), whole: false }] as const]; + const entries: [string, Usage][] = [ + ...imports(), + [RUNTIME, { names: new Set(), whole: false, target: RUNTIME }] + ]; const lines = entries .sort(([a], [b]) => a.localeCompare(b)) - .map(([specifier, { whole }]) => { - const target = whole ? specifier : EXPORTS_PREFIX + encodeURIComponent(specifier); - return `\t${JSON.stringify(specifier)}: () => import(${JSON.stringify(target)}),`; + .map(([key, { whole, target }]) => { + const source = whole ? target : toId(key); + return `\t${JSON.stringify(key)}: () => import(${JSON.stringify(source)}),`; }); return `export default {\n${lines.join('\n')}\n};\n`; } if (id.startsWith('\0' + EXPORTS_PREFIX)) { - const specifier = decodeURIComponent(id.slice(EXPORTS_PREFIX.length + 1)); - let names = [...(imports().get(specifier)?.names ?? [])]; - if (specifier === RUNTIME) { + const key = fromId(id); + const entry = imports().get(key); + let names = [...(entry?.names ?? [])]; + if (key === RUNTIME) { // `$.` read off compiled output; drop anything that only looked like a call. // @ts-expect-error - no declarations for 'svelte/internal/client' const exported = await import('svelte/internal/client'); // eslint-disable-line svelte/no-svelte-internal -- reads what it exports @@ -173,14 +212,14 @@ export function sandboxRegistry(): Plugin { .map((name) => /^[\p{ID_Start}$_][\p{ID_Continue}$]*$/u.test(name) ? name : JSON.stringify(name) ); - return `export { ${names.join(', ')} } from ${JSON.stringify(specifier)};\n`; + return `export { ${names.join(', ')} } from ${JSON.stringify(entry?.target ?? key)};\n`; } }, // An edited, added or removed example can change what's offered. hotUpdate({ file }) { if (!file.endsWith('.svelte') || relative(examplesDir, file).startsWith('..')) return; - sources = usage = runtime = null; + read = usage = runtime = null; for (const id of this.environment.moduleGraph.idToModuleMap.keys()) { if (id === '\0' + REGISTRY_ID || id.startsWith('\0' + EXPORTS_PREFIX)) { const module = this.environment.moduleGraph.getModuleById(id); diff --git a/docs/src/lib/sandbox/registry.ts b/docs/src/lib/sandbox/registry.ts index 3639816638..539b75ce8a 100644 --- a/docs/src/lib/sandbox/registry.ts +++ b/docs/src/lib/sandbox/registry.ts @@ -5,9 +5,10 @@ * example runs against the workspace build of `layerchart` (not a published copy * fetched from a CDN) and shares a single Svelte runtime with the host page. * - * Every entry is a loader, so an edit only fetches what that example imports. Packages - * come from `virtual:sandbox-registry` (see `registry-plugin.ts`), which offers only the - * names the examples use, so the sandbox doesn't make docs pages load more. + * Every entry is a loader, so an edit only fetches what that example imports. They come + * from `virtual:sandbox-registry` (see `registry-plugin.ts`), generated from the + * examples' own imports: packages, `$lib` modules and sibling files, each offering only + * the names the examples use, so the sandbox doesn't make docs pages load more. * `registry.test.ts` checks every example's imports resolve here. */ import generated from 'virtual:sandbox-registry'; @@ -18,7 +19,7 @@ type Loader = () => Promise; /** Side-effect-only imports in compiled output — the host runtime has already run them. */ const empty: Loader = async () => ({}); -const packages: Record = { +const modules: Record = { ...generated, // Side-effect-only modules compiled components import. `svelte/internal/client` itself // is generated, with only the functions compiled examples call. @@ -27,36 +28,13 @@ const packages: Record = { 'svelte/internal/flags/legacy': empty }; -/** The `$lib` modules examples import: data loaders, controls and small helpers. */ -const lib = import.meta.glob([ - '/src/lib/{data,geo,graph}.remote.ts', - '/src/lib/utils/*.ts', - '!/src/lib/utils/*.test.ts', - '/src/lib/actions/*.ts', - '/src/lib/attachments/*.ts', - '/src/lib/components/controls/**/*.svelte' -]); - -/** Helper modules that sit next to an example and are imported relatively. */ -const exampleModules = import.meta.glob('/src/examples/components/**/*.{js,ts}'); - -/** Imports are written with `.js`, with no extension, or with the real one. */ -function fromFiles(files: Record, path: string) { - const candidates = [path, path.replace(/\.js$/, '.ts'), `${path}.ts`, `${path}.js`]; - const id = candidates.find((candidate) => candidate in files); - return id ? { id, load: files[id] } : undefined; -} - /** * Finds the module for an import specifier. `base` is the example's directory - * (`/src/examples/components/GeoPath/`), needed only for relative imports. `id` is - * stable across examples, so callers can cache per module rather than per spelling. + * (`/src/examples/components/GeoPath/`), which turns a relative import into the path the + * registry keys it by. `id` is stable across examples, so callers can cache per module. */ export function resolve(specifier: string, base?: string) { - if (Object.hasOwn(packages, specifier)) return { id: specifier, load: packages[specifier] }; - if (specifier.startsWith('$lib/')) return fromFiles(lib, `/src/lib/${specifier.slice(5)}`); - if (base && /^\.\.?\//.test(specifier)) { - return fromFiles(exampleModules, new URL(specifier, `file://${base}`).pathname); - } - return undefined; + const id = + base && /^\.\.?\//.test(specifier) ? new URL(specifier, `file://${base}`).pathname : specifier; + return Object.hasOwn(modules, id) ? { id, load: modules[id] } : undefined; } diff --git a/docs/src/lib/sandbox/state.svelte.ts b/docs/src/lib/sandbox/state.svelte.ts index f4266a0cf3..472046aed4 100644 --- a/docs/src/lib/sandbox/state.svelte.ts +++ b/docs/src/lib/sandbox/state.svelte.ts @@ -23,7 +23,6 @@ export function createSandbox( } = {} ) { let module = $state(null); - let loading = $state(false); let pending = $state(false); let loadError = $state(null); @@ -37,12 +36,12 @@ export function createSandbox( * doesn't have. */ const seed = () => normalizeSource(getSource()); - let original = $state(untrack(seed)); - let editorValue = $state(untrack(seed)); - let debounced = $state(untrack(seed)); + const initial = untrack(seed); + let original = $state(initial); + let editorValue = $state(initial); + let debounced = $state(initial); let diagnostics = $state([]); - let elapsed = $state(0); let runtimeError = $state(null); /** * `$state.raw` — `mount()` returns an exports object whose properties are getters onto @@ -98,26 +97,20 @@ export function createSandbox( // every package an edit can import into the Cloudflare Worker. if (import.meta.env.SSR) return Promise.resolve(); if (module) return Promise.resolve(); - if (!inFlight) { - loading = true; - inFlight = import('./lazy') - .then((m) => { - module = m; - }) - .catch((err) => { - loadError = err instanceof Error ? err.message : String(err); - }) - .finally(() => { - loading = false; - }); - } + inFlight ??= import('./lazy') + .then((m) => { + module = m; + }) + .catch((err) => { + loadError = err instanceof Error ? err.message : String(err); + }); return inFlight; } async function setMode(next: 'view' | 'edit') { if (next === 'edit' && !module) { - // `pending` is distinct from `loading`: the hover prefetch sets `loading` too, and - // showing progress for a speculative fetch the user never asked for is just noise. + // Only for a load the user asked for: the hover prefetch shows no progress, since + // a spinner for a fetch nobody requested is just noise. pending = true; await load(); pending = false; @@ -144,9 +137,11 @@ export function createSandbox( // newer one — drop it rather than let it replace what the user typed since. let stale = false; sb.compileSource(transform ? transform(src) : src, { base: base?.() }).then((result) => { - if (stale) return; + if (stale) { + if (result.url) URL.revokeObjectURL(result.url); + return; + } diagnostics = result.diagnostics; - elapsed = Math.round(result.elapsed); if (result.url) { build = result.url; runtimeError = null; @@ -223,11 +218,22 @@ export function createSandbox( const errors = $derived(diagnostics.filter((d) => d.severity === 'error')); - /** The one thing worth surfacing over the preview, or `null` when the build is good. */ + /** + * The one thing worth surfacing over the preview, or `null` when the build is good. A + * compile error wins: it's about the source as typed now, while a runtime error belongs + * to the last build that compiled. + */ const error = $derived.by(() => { - if (runtimeError) return { message: runtimeError, line: undefined, column: undefined }; const first = errors[0]; - return first ? { message: first.message, line: first.line, column: first.column } : null; + if (first) { + return { + kind: 'compile' as const, + message: first.message, + line: first.line, + column: first.column + }; + } + return runtimeError ? { kind: 'runtime' as const, message: runtimeError } : null; }); return { @@ -271,10 +277,6 @@ export function createSandbox( }, get error() { return error; - }, - /** Compile timing, or `null` until the user has edited. */ - get status() { - return live ? `${elapsed}ms` : null; } }; } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 20055a7da3..0ab9be2034 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -98,9 +98,6 @@ importers: es-module-lexer: specifier: ^2.1.0 version: 2.1.0 - paneforge: - specifier: ^1.0.2 - version: 1.0.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)) satori: specifier: ^0.26.0 version: 0.26.0 @@ -288,6 +285,9 @@ importers: mdsx: specifier: ^0.0.7 version: 0.0.7(svelte@5.56.1(@typescript-eslint/types@8.60.1)) + paneforge: + specifier: ^1.0.2 + version: 1.0.2(svelte@5.56.1(@typescript-eslint/types@8.60.1)) playwright: specifier: ^1.60.0 version: 1.60.0 @@ -314,7 +314,7 @@ importers: version: 5.56.1(@typescript-eslint/types@8.60.1) svelte-check: specifier: ^4.5.0 - version: 4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) + version: 4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3) svelte-ux: specifier: 2.0.0-next.22 version: 2.0.0-next.22(postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0))(postcss@8.5.15)(svelte@5.56.1(@typescript-eslint/types@8.60.1)) @@ -11644,18 +11644,6 @@ snapshots: - stylus - sugarss - svelte-check@4.5.0(picomatch@4.0.4)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - chokidar: 4.0.3 - fdir: 6.5.0(picomatch@4.0.4) - picocolors: 1.1.1 - sade: 1.8.1 - svelte: 5.56.1(@typescript-eslint/types@8.60.1) - typescript: 6.0.3 - transitivePeerDependencies: - - picomatch - svelte-check@4.5.0(picomatch@4.0.5)(svelte@5.56.1(@typescript-eslint/types@8.60.1))(typescript@6.0.3): dependencies: '@jridgewell/trace-mapping': 0.3.31 From 5587efd05f9453794284ca832c858fc2177d418a Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Thu, 15 Oct 2026 19:01:26 -0400 Subject: [PATCH 12/15] Toggle to edit mode when clicking view source and maintain cursor position --- docs/src/lib/sandbox/CodeEditor.svelte | 15 ++++++++++- docs/src/lib/sandbox/CodePanel.svelte | 36 ++++++++++++++++++++++++-- 2 files changed, 48 insertions(+), 3 deletions(-) diff --git a/docs/src/lib/sandbox/CodeEditor.svelte b/docs/src/lib/sandbox/CodeEditor.svelte index c6922e0e4f..faedeefac5 100644 --- a/docs/src/lib/sandbox/CodeEditor.svelte +++ b/docs/src/lib/sandbox/CodeEditor.svelte @@ -35,12 +35,19 @@ * exactly when it was in View — adding or dropping one shifts every line sideways. * Reactive, so it can be toggled without rebuilding the editor. */ - lineNumbers = false + lineNumbers = false, + caretAt = null }: { value?: string; diagnostics?: Diagnostic[]; autofocus?: boolean; lineNumbers?: boolean; + /** + * Where to put the caret when the editor opens, relative to its top-left corner (ex. + * where the read-only code was clicked — it lays out identically, so the same point + * lands on the same character). + */ + caretAt?: { x: number; y: number } | null; } = $props(); let container = $state(null); @@ -242,6 +249,12 @@ }); view = instance; + const at = untrack(() => caretAt); + if (at) { + const rect = parent.getBoundingClientRect(); + const pos = instance.posAtCoords({ x: rect.left + at.x, y: rect.top + at.y }); + if (pos != null) instance.dispatch({ selection: { anchor: pos } }); + } if (untrack(() => autofocus)) instance.focus(); return () => { diff --git a/docs/src/lib/sandbox/CodePanel.svelte b/docs/src/lib/sandbox/CodePanel.svelte index 258eae7ee4..977c89bdba 100644 --- a/docs/src/lib/sandbox/CodePanel.svelte +++ b/docs/src/lib/sandbox/CodePanel.svelte @@ -52,6 +52,32 @@ const iconButton = 'text-surface-content/70 hover:text-surface-content hover:bg-surface-content/10 p-0.5'; + /** + * Clicking into the read-only code switches to Edit, with the caret where you clicked. + * Only a real click counts: a drag that moved the pointer or selected text stays in + * View (so code can still be copied), and a touch scroll never produces a click at all. + */ + let down: { x: number; y: number } | null = null; + let caret = $state<{ x: number; y: number } | null>(null); + + function onpointerdown(e: PointerEvent) { + if (sandbox.mode === 'edit' || e.button !== 0) return; + down = { x: e.clientX, y: e.clientY }; + // Start fetching the editor as the click begins. Not for touch, where this is as + // likely the start of a scroll. + if (e.pointerType === 'mouse') sandbox.load(); + } + + function onclick(e: MouseEvent) { + if (sandbox.mode === 'edit' || !down) return; + const moved = Math.hypot(e.clientX - down.x, e.clientY - down.y) > 4; + down = null; + if (moved || !getSelection()?.isCollapsed) return; + const rect = (e.currentTarget as HTMLElement).getBoundingClientRect(); + caret = { x: e.clientX - rect.left, y: e.clientY - rect.top }; + sandbox.setMode('edit'); + } + async function openStackBlitz() { opening = true; await onopenstackblitz?.().finally(() => (opening = false)); @@ -110,7 +136,10 @@ variant="outline" size="xs" inset - on:change={(e) => sandbox.setMode(e.detail.value)} + on:change={(e) => { + caret = null; + sandbox.setMode(e.detail.value); + }} classes={{ root: 'ml-1.5', option: 'px-1.5 py-0 leading-5 flex items-center gap-1' }} > @@ -165,12 +194,15 @@
-
+ + +
(down = null)} {onclick}> {#if sandbox.mode === 'edit' && sandbox.module} {:else} From 73aa322693511433fd14385df803261b9eabf24c Mon Sep 17 00:00:00 2001 From: Sean Lynch Date: Fri, 16 Oct 2026 12:30:39 -0400 Subject: [PATCH 13/15] Add date sorting to example catalog (leveraging upstream @layerstack/docs changes) --- docs/package.json | 2 +- docs/src/examples/catalog/AnnotationLine.json | 100 +++- .../src/examples/catalog/AnnotationPoint.json | 77 ++- .../src/examples/catalog/AnnotationRange.json | 85 +++- docs/src/examples/catalog/Arc.json | 52 +- docs/src/examples/catalog/ArcChart.json | 64 ++- docs/src/examples/catalog/Area.json | 118 +++-- docs/src/examples/catalog/AreaChart.json | 176 +++++-- docs/src/examples/catalog/Axis.json | 245 ++++++--- docs/src/examples/catalog/BarChart.json | 471 +++++++++++++----- docs/src/examples/catalog/Bars.json | 280 ++++++++--- docs/src/examples/catalog/BoxPlot.json | 24 +- docs/src/examples/catalog/Brush.json | 24 +- docs/src/examples/catalog/BrushContext.json | 84 +++- docs/src/examples/catalog/Calendar.json | 36 +- docs/src/examples/catalog/Cell.json | 20 +- docs/src/examples/catalog/Chart.json | 239 ++++++--- docs/src/examples/catalog/ChartGroup.json | 59 ++- docs/src/examples/catalog/Chord.json | 20 +- docs/src/examples/catalog/Circle.json | 40 +- docs/src/examples/catalog/CircleLegend.json | 12 +- docs/src/examples/catalog/ClipPath.json | 16 +- docs/src/examples/catalog/ColorRamp.json | 12 +- docs/src/examples/catalog/Contour.json | 24 +- .../examples/catalog/CustomMarksChart.json | 6 + docs/src/examples/catalog/Dagre.json | 16 +- docs/src/examples/catalog/Density.json | 24 +- docs/src/examples/catalog/Dodge.json | 52 +- docs/src/examples/catalog/Ellipse.json | 24 +- .../src/examples/catalog/ForceSimulation.json | 44 +- docs/src/examples/catalog/Frame.json | 16 +- docs/src/examples/catalog/GeoCircle.json | 8 +- docs/src/examples/catalog/GeoClipPath.json | 4 +- docs/src/examples/catalog/GeoLegend.json | 24 +- docs/src/examples/catalog/GeoPath.json | 96 +++- docs/src/examples/catalog/GeoPoint.json | 20 +- docs/src/examples/catalog/GeoProjection.json | 28 +- docs/src/examples/catalog/GeoRaster.json | 20 +- docs/src/examples/catalog/GeoSpline.json | 8 +- docs/src/examples/catalog/GeoTile.json | 20 +- docs/src/examples/catalog/Graticule.json | 4 +- docs/src/examples/catalog/Grid.json | 56 ++- docs/src/examples/catalog/Group.json | 12 +- docs/src/examples/catalog/Highlight.json | 12 +- docs/src/examples/catalog/Hull.json | 8 +- docs/src/examples/catalog/Image.json | 24 +- docs/src/examples/catalog/Labels.json | 8 +- docs/src/examples/catalog/Layer.json | 28 +- docs/src/examples/catalog/Legend.json | 76 ++- docs/src/examples/catalog/Line.json | 40 +- docs/src/examples/catalog/LineChart.json | 306 +++++++++--- docs/src/examples/catalog/LinearGradient.json | 16 +- docs/src/examples/catalog/Link.json | 16 +- docs/src/examples/catalog/Marker.json | 20 +- docs/src/examples/catalog/Month.json | 24 +- docs/src/examples/catalog/MotionPath.json | 12 +- docs/src/examples/catalog/Pack.json | 4 +- docs/src/examples/catalog/Partition.json | 20 +- docs/src/examples/catalog/Path.json | 4 +- docs/src/examples/catalog/Pattern.json | 32 +- docs/src/examples/catalog/Pie.json | 108 +++- docs/src/examples/catalog/PieChart.json | 124 +++-- docs/src/examples/catalog/Point.json | 4 +- docs/src/examples/catalog/Points.json | 28 +- docs/src/examples/catalog/Polygon.json | 96 +++- docs/src/examples/catalog/RadialGradient.json | 16 +- docs/src/examples/catalog/Raster.json | 24 +- docs/src/examples/catalog/Rect.json | 28 +- docs/src/examples/catalog/Rule.json | 56 ++- docs/src/examples/catalog/Sankey.json | 20 +- docs/src/examples/catalog/ScatterChart.json | 104 +++- docs/src/examples/catalog/Spline.json | 150 ++++-- docs/src/examples/catalog/Text.json | 32 +- docs/src/examples/catalog/Threshold.json | 12 +- docs/src/examples/catalog/Tooltip.json | 236 ++++++--- docs/src/examples/catalog/Trail.json | 16 +- .../examples/catalog/TransformContext.json | 24 +- docs/src/examples/catalog/Tree.json | 16 +- docs/src/examples/catalog/Treemap.json | 24 +- docs/src/examples/catalog/Vector.json | 24 +- docs/src/examples/catalog/Violin.json | 16 +- docs/src/examples/catalog/Voronoi.json | 4 +- docs/src/examples/catalog/Waffle.json | 56 ++- docs/src/lib/components/Example.svelte | 5 +- docs/src/routes/docs/examples/+page.server.ts | 5 +- docs/src/routes/docs/examples/+page.svelte | 73 ++- pnpm-lock.yaml | 46 +- 87 files changed, 3590 insertions(+), 1169 deletions(-) create mode 100644 docs/src/examples/catalog/CustomMarksChart.json diff --git a/docs/package.json b/docs/package.json index 975644601c..b22350faa1 100644 --- a/docs/package.json +++ b/docs/package.json @@ -33,7 +33,7 @@ "@iconify-json/lucide": "^1.2.111", "@iconify-json/simple-icons": "^1.2.85", "@iconify-json/vscode-icons": "^1.2.53", - "@layerstack/docs": "1.0.0-next.4", + "@layerstack/docs": "1.0.0-next.6", "@layerstack/svelte-actions": "1.0.1-next.20", "@layerstack/svelte-state": "0.1.0-next.25", "@layerstack/svelte-table": "1.0.1-next.20", diff --git a/docs/src/examples/catalog/AnnotationLine.json b/docs/src/examples/catalog/AnnotationLine.json index 695204be73..8fb9aaab49 100644 --- a/docs/src/examples/catalog/AnnotationLine.json +++ b/docs/src/examples/catalog/AnnotationLine.json @@ -16,7 +16,57 @@ "lineNumber": 18, "line": "" + }, + { + "component": "Layer", + "lineNumber": 14, + "line": "" + }, + { + "component": "AnnotationLine", + "lineNumber": 15, + "line": "" + }, + { + "component": "AnnotationLine", + "lineNumber": 14, + "line": "" + }, + { + "component": "Line", + "lineNumber": 17, + "line": "" + } + ], + "createdAt": "2026-10-13T12:30:26.000Z", + "updatedAt": "2026-10-13T12:30:26.000Z" }, { "name": "horizontal", @@ -33,7 +83,9 @@ "lineNumber": 14, "line": "" + }, { "example": "horizontal", "component": "AnnotationLine", @@ -349,5 +429,5 @@ "line": "" + }, + { + "component": "AnnotationPoint", + "lineNumber": 23, + "line": "" + } + ], + "createdAt": "2026-10-13T12:30:26.000Z", + "updatedAt": "2026-10-13T12:30:26.000Z" }, { "name": "line-to-point", @@ -75,7 +103,9 @@ "lineNumber": 82, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "link-callouts", @@ -92,7 +122,9 @@ "lineNumber": 59, "line": "" } - ] + ], + "createdAt": "2026-04-20T20:21:36.000Z", + "updatedAt": "2026-08-04T17:36:56.000Z" }, { "name": "on-axis-with-tooltip", @@ -119,7 +151,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "on-series-with-line-and-tooltip", @@ -151,7 +185,9 @@ "lineNumber": 56, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "on-series-with-tooltip", @@ -178,7 +214,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "playground", @@ -200,7 +238,9 @@ "lineNumber": 246, "line": "" } - ] + ], + "createdAt": "2026-04-21T11:18:12.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "world-landmarks", @@ -271,7 +315,9 @@ "lineNumber": 116, "line": "" } - ] + ], + "createdAt": "2026-04-21T11:18:12.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ @@ -289,6 +335,13 @@ "lineNumber": 19, "line": "" + }, + { + "component": "AnnotationRange", + "lineNumber": 21, + "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "horizontal-with-pattern-lower-bound", @@ -101,7 +135,9 @@ "lineNumber": 20, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "concentric", @@ -85,7 +89,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-04-01T05:14:50.000Z", + "updatedAt": "2026-04-01T13:14:47.000Z" }, { "name": "label-direction", @@ -233,7 +245,9 @@ "lineNumber": 67, "line": "" } - ] + ], + "createdAt": "2026-04-01T04:29:26.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "tween-value-on-mount", @@ -425,7 +449,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "clip-tween-on-mount", @@ -58,7 +60,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "clipped-area-on-tooltip", @@ -105,7 +109,9 @@ "lineNumber": 52, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "fade-mask", @@ -174,7 +182,9 @@ "lineNumber": 28, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "gradient-separate-stroke", @@ -238,7 +250,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "highlight-color-based-on-value-using-color-scale", @@ -285,7 +299,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "highlight-color-based-on-value-using-tooltip-slot-prop", @@ -332,7 +348,9 @@ "lineNumber": 58, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "multiple-series", @@ -384,7 +402,9 @@ "lineNumber": 78, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-series-highlight-on-hover", @@ -436,7 +456,9 @@ "lineNumber": 82, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-series-tweened", @@ -463,7 +485,9 @@ "lineNumber": 51, "line": "" } - ] + ], + "createdAt": "2026-09-03T19:08:33.000Z", + "updatedAt": "2026-09-03T19:08:33.000Z" }, { "name": "multiple-series-using-overrides", @@ -500,7 +524,9 @@ "lineNumber": 67, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-series-with-labels", @@ -542,7 +568,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "oscilloscope-ridgeline", @@ -569,7 +597,9 @@ "lineNumber": 151, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "ridgeline", @@ -660,7 +694,9 @@ "lineNumber": 105, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "ridgeline-kde", @@ -697,7 +733,9 @@ "lineNumber": 195, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "stack", @@ -734,7 +772,9 @@ "lineNumber": 74, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "stack-with-gradient", @@ -766,7 +806,9 @@ "lineNumber": 56, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "threshold-with-lineargradient-over-under", @@ -840,7 +884,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "threshold-with-rectclippath-over-under", @@ -914,7 +962,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "tween-on-mount", @@ -941,7 +991,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "with-labels", @@ -973,7 +1025,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "with-tooltip-and-highlight", @@ -1010,7 +1064,9 @@ "lineNumber": 26, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" } ], "usage": [ @@ -1522,8 +1578,8 @@ "example": "compound-common-scale-with-extra-marks", "component": "Chart", "path": "/docs/components/Chart/compound-common-scale-with-extra-marks", - "lineNumber": 29, - "line": "" + "lineNumber": 31, + "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "band-scale", @@ -23,7 +25,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "brush", @@ -47,7 +53,9 @@ "lineNumber": 11, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "custom-tooltip", @@ -125,7 +139,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "funnel", @@ -164,7 +182,9 @@ "lineNumber": 82, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "labels", @@ -198,7 +220,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-07-01T13:37:08.000Z" }, { "name": "motion-tween", @@ -249,7 +277,9 @@ "lineNumber": 16, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "point-scale", @@ -290,7 +324,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "range-annotation", @@ -331,7 +371,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "series-overlap", @@ -382,7 +428,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-08-19T14:08:02.000Z" }, { "name": "series-stack-legend", @@ -488,7 +550,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "threshold-gradient", @@ -636,7 +716,9 @@ "lineNumber": 52, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tooltip-external", @@ -648,7 +730,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "tooltip-locking", @@ -682,7 +768,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Axis.json b/docs/src/examples/catalog/Axis.json index 2137f84d11..c6a20ce635 100644 --- a/docs/src/examples/catalog/Axis.json +++ b/docs/src/examples/catalog/Axis.json @@ -21,7 +21,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "axis-label-placement-left-right", @@ -43,7 +45,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "axis-label-placement-top-bottom", @@ -65,7 +69,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "barchart-tickspacing", @@ -77,7 +83,9 @@ "lineNumber": 76, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "extent-ticks-only", @@ -138,7 +150,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "grid", @@ -160,7 +174,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "grid-dashed", @@ -182,7 +198,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-14T17:26:37.000Z" }, { "name": "hide-zero-filter", @@ -204,7 +222,9 @@ "lineNumber": 7, "line": " scale.ticks?.().filter((d) => d !== 0)} />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "hide-zero-format", @@ -226,7 +246,9 @@ "lineNumber": 7, "line": " v || ''} />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "inject-ticks", @@ -248,7 +270,9 @@ "lineNumber": 7, "line": " [45, ...(scale.ticks?.() ?? [])]} />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "integer-only-filter", @@ -270,7 +294,9 @@ "lineNumber": 7, "line": " scale.ticks?.().filter(Number.isInteger)} />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "integer-only-format", @@ -292,7 +318,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "labels-next-hash", @@ -314,7 +342,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "multiline-tick-labels", @@ -370,7 +404,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "multiple-axis-grid-and-rules-separate-grid", @@ -424,7 +462,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "multiple-axis-grid-with-single-rule", @@ -446,7 +486,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "multiple-axis-same-placement-bottom", @@ -468,7 +510,9 @@ "lineNumber": 15, "line": "" }, { "component": "Layer", - "lineNumber": 9, + "lineNumber": 7, "line": "" }, { "component": "Axis", - "lineNumber": 10, - "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "override-axis-ticks-scale", @@ -512,7 +558,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement-bottom-left-rule", @@ -556,7 +606,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement-top-right", @@ -578,7 +630,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement-top-right-rule", @@ -600,7 +654,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "radial-grid", @@ -622,7 +678,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "radial-rule", @@ -644,7 +702,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "remove-tick-marks", @@ -666,7 +726,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "rotate-labels", @@ -688,7 +750,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tick-label-styling", @@ -732,7 +798,9 @@ "lineNumber": 11, "line": "" } - ] + ], + "createdAt": "2026-09-03T14:19:28.000Z", + "updatedAt": "2026-09-03T14:19:28.000Z" }, { "name": "tick-occlusion-priority", @@ -798,7 +870,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-09-03T14:19:28.000Z", + "updatedAt": "2026-09-03T14:19:28.000Z" }, { "name": "tick-occlusion-rotated", @@ -810,7 +884,9 @@ "lineNumber": 33, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "time-scale-auto", @@ -866,7 +946,9 @@ "lineNumber": 120, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "time-scale-auto-format-filtering", @@ -888,7 +970,9 @@ "lineNumber": 120, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "time-scale-auto-multiline", @@ -910,7 +994,9 @@ "lineNumber": 121, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "time-scale-brush", @@ -932,7 +1018,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "time-scale-brush-multiline", @@ -954,7 +1042,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "time-scale-explicit", @@ -976,7 +1066,9 @@ "lineNumber": 115, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "time-scale-explicit-multiline", @@ -998,7 +1090,9 @@ "lineNumber": 115, "line": "" } - ] + ], + "createdAt": "2026-08-11T20:14:44.000Z", + "updatedAt": "2026-08-11T20:14:44.000Z" } ], "usage": [ @@ -1644,14 +1740,14 @@ "example": "multiple-axis-same-placement-right", "component": "Axis", "path": "/docs/components/Axis/multiple-axis-same-placement-right", - "lineNumber": 10, - "line": "" }, { "example": "multiple-axis-same-placement-right", "component": "Axis", "path": "/docs/components/Axis/multiple-axis-same-placement-right", - "lineNumber": 17, + "lineNumber": 9, "line": "" }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 54, + "line": "" + }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 55, + "line": "" + }, { "example": "language-race", "component": "BarChart", @@ -3373,56 +3490,56 @@ "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 28, + "lineNumber": 27, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 24, + "lineNumber": 26, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 47, + "lineNumber": 49, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", - "lineNumber": 70, + "lineNumber": 71, "line": " 0} value=\"date\" class=\"text-sm fill-surface-300 stroke-none\" />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "both-axis-grid", @@ -40,7 +44,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "both-axis-grid-align-between", @@ -52,7 +58,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "brush", @@ -64,7 +72,9 @@ "lineNumber": 16, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "brush-band", @@ -76,7 +86,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-04-01T23:27:44.000Z", + "updatedAt": "2026-04-01T23:27:44.000Z" }, { "name": "brush-pan-zoom", @@ -88,7 +100,9 @@ "lineNumber": 16, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "color-per-value", @@ -124,7 +142,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "company-race", @@ -190,7 +214,9 @@ "lineNumber": 244, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "custom-tooltip", @@ -244,7 +272,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "duration", @@ -261,7 +291,9 @@ "lineNumber": 85, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "duration-bars", @@ -278,7 +310,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "duration-bars-color", @@ -295,7 +329,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "duration-bars-dense", @@ -312,7 +348,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "duration-bars-dense-lanes", @@ -329,7 +367,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "duration-bars-lanes", @@ -346,7 +386,9 @@ "lineNumber": 49, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "duration-civilization-timeline", @@ -363,7 +405,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "duration-civilization-timeline-dense", @@ -380,7 +424,9 @@ "lineNumber": 48, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "duration-labels", @@ -397,7 +443,9 @@ "lineNumber": 100, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "duration-points", @@ -424,7 +472,9 @@ "lineNumber": 48, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "duration-points-color", @@ -451,7 +501,9 @@ "lineNumber": 55, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "dynamic-height", @@ -463,7 +515,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "group-long-data", @@ -509,7 +567,9 @@ "lineNumber": 13, "line": "" + }, + { + "component": "Tooltip", + "lineNumber": 67, + "line": "" + } + ], + "createdAt": "2026-10-12T02:24:42.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "group-series-horizontal", @@ -545,7 +633,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "histogram-date-time-count", @@ -644,7 +746,9 @@ "lineNumber": 53, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "histogram-date-time-interval", @@ -666,7 +770,9 @@ "lineNumber": 60, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "histogram-horizontal", @@ -688,7 +794,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "histogram-random-distribution", @@ -710,7 +818,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "histogram-vertical", @@ -732,7 +842,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "horizontal", @@ -744,7 +856,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "labels-inside-placement", @@ -768,7 +884,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "labels-placement", @@ -780,7 +898,9 @@ "lineNumber": 35, "line": "" } - ] + ], + "createdAt": "2026-04-07T19:59:54.000Z", + "updatedAt": "2026-04-07T19:59:54.000Z" }, { "name": "language-race", @@ -827,7 +947,9 @@ "lineNumber": 247, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "override-axis-ticks-with-custom-scale", @@ -933,7 +1069,9 @@ "lineNumber": 16, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "scale-override", @@ -1149,7 +1321,9 @@ "lineNumber": 16, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "series-horizontal-diverging-as-percent", @@ -1231,7 +1415,9 @@ "lineNumber": 57, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "series-horizontal-diverging-label-gap", @@ -1268,7 +1454,9 @@ "lineNumber": 83, "line": "" } - ] + ], + "createdAt": "2026-07-22T16:51:29.000Z", + "updatedAt": "2026-07-22T16:51:29.000Z" }, { "name": "series-horizontal-diverging-split-scale", @@ -1295,7 +1483,9 @@ "lineNumber": 118, "line": "" } - ] + ], + "createdAt": "2026-07-22T16:51:29.000Z", + "updatedAt": "2026-07-22T16:51:29.000Z" }, { "name": "series-horizontal-labels", @@ -1307,7 +1497,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "single-axis-y", @@ -1343,7 +1539,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-05-06T16:36:52.000Z" }, { "name": "single-stack-with-indicator", @@ -1395,7 +1595,9 @@ ], "tags": [ "gauge" - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-19T13:24:57.000Z" }, { "name": "sparkbar", @@ -1407,7 +1609,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "stack-long-data", @@ -1477,7 +1689,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-fixed-width", @@ -1609,7 +1843,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "waterfall", @@ -1636,7 +1872,9 @@ "lineNumber": 110, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-calculated-value-domain-negative", @@ -90,7 +94,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-calculated-value-domain-positive", @@ -117,7 +123,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-candlestick-bars", @@ -154,7 +162,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "horizontal-click-handler", @@ -186,7 +196,9 @@ "lineNumber": 37, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-customize-individual-styles", @@ -218,7 +230,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-grouped", @@ -287,7 +303,9 @@ "lineNumber": 53, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-grouped-and-stacked", @@ -324,7 +342,9 @@ "lineNumber": 58, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-grouped-stacked-or-both-transition", @@ -361,7 +381,9 @@ "lineNumber": 118, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-highlight-individual-bar", @@ -398,7 +420,9 @@ "lineNumber": 39, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-highlight-individual-bar-line", @@ -430,7 +454,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-limit-ticks-count", @@ -494,7 +522,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-limit-ticks-second-scale", @@ -521,7 +551,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-multiple-diverging", @@ -563,7 +595,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-multiple-overlapping", @@ -600,7 +634,9 @@ "lineNumber": 35, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-outside-labels-default", @@ -637,7 +673,9 @@ "lineNumber": 26, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-rounded-right-only", @@ -664,7 +702,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-stacked", @@ -701,7 +741,9 @@ "lineNumber": 50, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-stacked-percent", @@ -738,7 +780,9 @@ "lineNumber": 55, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-stagger-tween-on-mount", @@ -765,7 +809,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-time-scale-with-interval", @@ -819,7 +867,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-time-scale-with-missing-data", @@ -846,7 +896,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-tooltip-and-bar-highlight", @@ -883,7 +935,9 @@ "lineNumber": 35, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-tooltip-and-click-handlers-for-individual-stack-grouped-bar", @@ -915,7 +969,9 @@ "lineNumber": 121, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-tooltip-and-clipped-highlight", @@ -957,7 +1013,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-tooltip-and-highlight", @@ -994,7 +1052,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal-tween-on-mount", @@ -1021,7 +1081,9 @@ "lineNumber": 37, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "horizontal-with-grid-on-top-mix-blend", @@ -1075,7 +1139,9 @@ "lineNumber": 29, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-average-annotation-rule", @@ -1112,7 +1178,9 @@ "lineNumber": 39, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-calculated-value-domain-negative", @@ -1166,7 +1236,9 @@ "lineNumber": 26, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-calculated-value-domain-positive", @@ -1193,7 +1265,9 @@ "lineNumber": 26, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-click-handler", @@ -1225,7 +1299,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-customize-individual-styles", @@ -1257,7 +1333,9 @@ "lineNumber": 29, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-gradient", @@ -1316,7 +1396,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-grouped", @@ -1353,7 +1435,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-grouped-and-stacked", @@ -1390,7 +1474,9 @@ "lineNumber": 49, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-grouped-stacked-or-both-transition", @@ -1427,7 +1513,9 @@ "lineNumber": 113, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-highlight-individual-bar", @@ -1464,7 +1552,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-highlight-individual-bar-line", @@ -1496,7 +1586,9 @@ "lineNumber": 24, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-limit-ticks-count", @@ -1560,7 +1654,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-limit-ticks-second-scale", @@ -1587,7 +1683,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-multiple-diverging", @@ -1629,7 +1727,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-multiple-diverging-rounded-specific", @@ -1671,7 +1771,9 @@ "lineNumber": 46, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-multiple-overlapping", @@ -1708,7 +1810,9 @@ "lineNumber": 33, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-outside-labels-default", @@ -1745,7 +1849,9 @@ "lineNumber": 26, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-rounded-top-only", @@ -1772,7 +1878,9 @@ "lineNumber": 28, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-stacked", @@ -1809,7 +1917,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-stacked-percent", @@ -1846,7 +1956,9 @@ "lineNumber": 45, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-stagger-tween-on-mount", @@ -1873,7 +1985,9 @@ "lineNumber": 35, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-time-scale-with-interval", @@ -1954,7 +2072,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-time-scale-with-interval-months", @@ -1981,7 +2101,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-time-scale-with-missing-data", @@ -2008,7 +2130,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-tooltip-and-bar-highlight", @@ -2045,7 +2169,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-tooltip-and-click-handlers-for-individual-stack-grouped-bar", @@ -2077,7 +2203,9 @@ "lineNumber": 121, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-tooltip-and-clipped-highlight", @@ -2119,7 +2247,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-tooltip-and-highlight", @@ -2156,7 +2286,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "vertical-tween-on-mount", @@ -2183,7 +2315,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "vertical-with-grid-on-top-mix-blend", @@ -2264,7 +2402,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/BoxPlot.json b/docs/src/examples/catalog/BoxPlot.json index a967456460..668a8ecb64 100644 --- a/docs/src/examples/catalog/BoxPlot.json +++ b/docs/src/examples/catalog/BoxPlot.json @@ -26,7 +26,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "horizontal", @@ -53,7 +55,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "pre-computed", @@ -80,7 +84,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "with-violin", @@ -186,7 +196,9 @@ "lineNumber": 95, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Brush.json b/docs/src/examples/catalog/Brush.json index 67e252d394..636593ab61 100644 --- a/docs/src/examples/catalog/Brush.json +++ b/docs/src/examples/catalog/Brush.json @@ -31,7 +31,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-08-17T18:59:37.000Z", + "updatedAt": "2026-08-17T18:59:37.000Z" }, { "name": "html", @@ -63,7 +65,9 @@ "lineNumber": 48, "line": "" } - ] + ], + "createdAt": "2026-08-17T18:59:37.000Z", + "updatedAt": "2026-08-17T18:59:37.000Z" }, { "name": "programmatic", @@ -95,7 +99,9 @@ "lineNumber": 52, "line": "" } - ] + ], + "createdAt": "2026-08-17T18:59:37.000Z", + "updatedAt": "2026-08-17T18:59:37.000Z" }, { "name": "region", @@ -127,7 +133,9 @@ "lineNumber": 53, "line": "" } - ] + ], + "createdAt": "2026-08-17T18:59:37.000Z", + "updatedAt": "2026-08-17T18:59:37.000Z" }, { "name": "vertical", @@ -196,7 +206,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-08-17T18:59:37.000Z", + "updatedAt": "2026-08-17T18:59:37.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/BrushContext.json b/docs/src/examples/catalog/BrushContext.json index 89d2a7ab60..01e5af8b8b 100644 --- a/docs/src/examples/catalog/BrushContext.json +++ b/docs/src/examples/catalog/BrushContext.json @@ -21,7 +21,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "constant-labels", @@ -48,7 +50,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-07-21T18:21:59.000Z", + "updatedAt": "2026-07-21T18:21:59.000Z" }, { "name": "handle-arrows", @@ -127,7 +133,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "integrated-brush-(x-axis)", @@ -228,7 +240,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "integrated-brush-(y-axis)", @@ -265,7 +279,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "max-window", @@ -297,7 +313,9 @@ "lineNumber": 52, "line": "" } - ] + ], + "createdAt": "2026-07-01T16:26:01.000Z", + "updatedAt": "2026-07-01T16:26:01.000Z" }, { "name": "min-max-extent", @@ -324,7 +342,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-07-01T16:26:01.000Z", + "updatedAt": "2026-07-01T16:26:01.000Z" }, { "name": "minimap", @@ -361,7 +381,9 @@ "lineNumber": 89, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "selection", @@ -420,7 +444,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "separate-chart-(clip-data)", @@ -494,7 +522,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "separate-chart-(filter-data)", @@ -526,7 +556,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "snap-to-month", @@ -575,7 +609,9 @@ "lineNumber": 54, "line": "" } - ] + ], + "createdAt": "2026-07-01T16:26:01.000Z", + "updatedAt": "2026-07-01T16:26:01.000Z" }, { "name": "striped-background", @@ -597,7 +633,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "synced-brushes", @@ -639,7 +677,9 @@ "lineNumber": 71, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-08-27T02:37:19.000Z" }, { "name": "tooltip-interop", @@ -686,7 +726,9 @@ "lineNumber": 56, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "basic", @@ -48,7 +50,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "fixed-cell-size", @@ -75,7 +79,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "html-with-padding", @@ -102,7 +108,9 @@ "lineNumber": 63, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "isometric", @@ -129,7 +137,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "last-month", @@ -156,7 +166,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-years", @@ -193,7 +205,9 @@ "lineNumber": 54, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "responsive-cell-size-default", @@ -220,7 +234,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "rounded-cells", @@ -252,7 +268,9 @@ "lineNumber": 60, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Cell.json b/docs/src/examples/catalog/Cell.json index c9bcbc0829..cf232cf392 100644 --- a/docs/src/examples/catalog/Cell.json +++ b/docs/src/examples/catalog/Cell.json @@ -26,7 +26,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "circle", @@ -53,7 +55,9 @@ "lineNumber": 42, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "color-scale", @@ -80,7 +84,9 @@ "lineNumber": 42, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "punchcard", @@ -112,7 +118,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Chart.json b/docs/src/examples/catalog/Chart.json index 06af049852..5ec2e8f6d5 100644 --- a/docs/src/examples/catalog/Chart.json +++ b/docs/src/examples/catalog/Chart.json @@ -8,20 +8,22 @@ "components": [ { "component": "BarChart", - "lineNumber": 19, + "lineNumber": 20, "line": "" + "lineNumber": 31, + "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "compound-dual-axis-with-single-chart-using-remapped-scale", @@ -30,116 +32,139 @@ "components": [ { "component": "Chart", - "lineNumber": 14, + "lineNumber": 13, "line": "" }, { "component": "Axis", - "lineNumber": 28, + "lineNumber": 27, "line": "" }, { "component": "Highlight", - "lineNumber": 48, + "lineNumber": 47, "line": "" }, { "component": "Tooltip", - "lineNumber": 52, + "lineNumber": 51, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "compound-dual-axis-with-stacked-charts", "title": "compound dual axis with stacked charts", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", "components": [ + { + "component": "ChartGroup", + "lineNumber": 13, + "line": "" + }, { "component": "Chart", - "lineNumber": 14, + "lineNumber": 16, "line": "" }, { "component": "Axis", - "lineNumber": 24, + "lineNumber": 26, "line": "" }, { "component": "Highlight", - "lineNumber": 34, + "lineNumber": 36, "line": "" }, { "component": "Tooltip", - "lineNumber": 59, + "lineNumber": 60, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "title": "compound separate scales with stacked charts and overridden marks", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", "components": [ + { + "component": "ChartGroup", + "lineNumber": 18, + "line": "" + }, { "component": "BarChart", - "lineNumber": 14, + "lineNumber": 21, "line": "" + "lineNumber": 54, + "line": "" }, { "component": "Tooltip", - "lineNumber": 48, + "lineNumber": 59, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "title": "compound separate scales with stacked charts with inverted range top down", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "components": [ + { + "component": "ChartGroup", + "lineNumber": 15, + "line": "" + }, { "component": "BarChart", - "lineNumber": 17, + "lineNumber": 18, "line": "" }, { "component": "Tooltip", - "lineNumber": 83, + "lineNumber": 84, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "data-chart-multi", @@ -156,7 +181,9 @@ "lineNumber": 16, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "data-chart-single", @@ -173,7 +200,9 @@ "lineNumber": 16, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "data-mark-data", @@ -190,7 +219,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "data-primitive-data", @@ -212,7 +243,9 @@ "lineNumber": 26, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "data-series-chart-data", @@ -229,7 +262,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-08-19T14:08:02.000Z" }, { "name": "data-series-separate-data", @@ -246,7 +281,9 @@ "lineNumber": 33, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "facet-annotation", @@ -268,7 +305,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-08-20T12:46:36.000Z", + "updatedAt": "2026-08-20T12:46:36.000Z" }, { "name": "facet-brush-summary", @@ -378,7 +425,9 @@ "lineNumber": 84, "line": "" } - ] + ], + "createdAt": "2026-08-16T02:01:54.000Z", + "updatedAt": "2026-08-16T14:55:58.000Z" }, { "name": "facet-composed", @@ -488,7 +545,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-08-15T17:24:19.000Z", + "updatedAt": "2026-08-16T14:55:58.000Z" }, { "name": "facet-non-faceted-marks", @@ -544,7 +607,9 @@ "lineNumber": 29, "line": "" } - ] + ], + "createdAt": "2026-08-16T02:01:54.000Z", + "updatedAt": "2026-08-26T18:20:53.000Z" }, { "name": "facet-two-dimensional", @@ -630,7 +699,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "isometric-playground", @@ -866,7 +951,9 @@ "lineNumber": 116, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "isometric-scatter", @@ -878,7 +965,9 @@ "lineNumber": 13, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "isometric-scatter-3d", @@ -925,7 +1014,9 @@ "lineNumber": 83, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "isometric-stacked-columns", @@ -977,7 +1068,9 @@ "lineNumber": 62, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "isometric-treemap", @@ -1014,7 +1107,9 @@ "lineNumber": 138, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "mixed-marks-with-stack", @@ -1061,7 +1156,9 @@ "lineNumber": 57, "line": "" } - ] + ], + "createdAt": "2026-08-20T03:04:59.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "mixed-marks-with-stack-long-data", @@ -1108,7 +1205,9 @@ "lineNumber": 76, "line": "" } - ] + ], + "createdAt": "2026-08-20T03:04:59.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" } ], "usage": [ @@ -1550,7 +1649,7 @@ "example": "multiple-axis-same-placement-right", "component": "Axis", "path": "/docs/components/Axis/multiple-axis-same-placement-right", - "lineNumber": 7, + "lineNumber": 6, "line": "" }, { @@ -2656,21 +2755,21 @@ "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 14, + "lineNumber": 13, "line": "" } - ] + ], + "createdAt": "2026-08-18T18:09:40.000Z", + "updatedAt": "2026-08-18T18:09:40.000Z" }, { "name": "faceted-group", @@ -70,7 +74,9 @@ "lineNumber": 58, "line": "" } - ] + ], + "createdAt": "2026-08-16T14:55:58.000Z", + "updatedAt": "2026-08-20T12:46:36.000Z" }, { "name": "highlight-only", @@ -87,7 +93,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-08-14T04:35:33.000Z", + "updatedAt": "2026-08-27T02:37:19.000Z" }, { "name": "synced-legend", @@ -210,7 +224,9 @@ "lineNumber": 26, "line": "" } - ] + ], + "createdAt": "2026-08-14T17:22:22.000Z", + "updatedAt": "2026-08-19T14:08:02.000Z" }, { "name": "synced-zoom", @@ -227,10 +243,33 @@ "lineNumber": 32, "line": "" + }, + { + "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", + "component": "Chart", + "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", + "lineNumber": 18, + "line": "" + }, + { + "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", + "component": "Chart", + "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", + "lineNumber": 15, + "line": "" + }, { "example": "facet-brush-overview", "component": "Chart", @@ -302,5 +341,5 @@ "line": "" } ], - "updatedAt": "2026-09-03T20:00:06.232Z" + "updatedAt": "2026-10-16T16:15:13.253Z" } \ No newline at end of file diff --git a/docs/src/examples/catalog/Chord.json b/docs/src/examples/catalog/Chord.json index 555cd80076..b75ae32668 100644 --- a/docs/src/examples/catalog/Chord.json +++ b/docs/src/examples/catalog/Chord.json @@ -36,7 +36,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "hover", @@ -162,7 +168,9 @@ "lineNumber": 145, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "ticks", @@ -204,7 +212,9 @@ "lineNumber": 69, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "color-via-threshold-scale", @@ -58,7 +60,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "data-mode", @@ -85,7 +89,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "styling-using-attributes", @@ -112,7 +118,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-classes", @@ -139,7 +147,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-css-variables", @@ -166,7 +176,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ @@ -184,6 +196,20 @@ "lineNumber": 121, "line": "" + }, + { + "example": "custom-marker", + "component": "AnnotationPoint", + "path": "/docs/components/AnnotationPoint/custom-marker", + "lineNumber": 38, + "line": "" + }, { "example": "playground", "component": "AnnotationPoint", @@ -1242,5 +1268,5 @@ "line": "" } ], - "updatedAt": "2026-10-08T16:54:43.257Z" + "updatedAt": "2026-10-16T16:15:13.291Z" } \ No newline at end of file diff --git a/docs/src/examples/catalog/CircleLegend.json b/docs/src/examples/catalog/CircleLegend.json index 5e9de9f1c9..4c9a14f85e 100644 --- a/docs/src/examples/catalog/CircleLegend.json +++ b/docs/src/examples/catalog/CircleLegend.json @@ -16,7 +16,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-08T22:40:53.000Z" }, { "name": "label-placement", @@ -28,7 +30,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-08T22:40:53.000Z" }, { "name": "scale-types", @@ -40,7 +44,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-08T22:40:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/ClipPath.json b/docs/src/examples/catalog/ClipPath.json index dccae10b92..b6574c72b3 100644 --- a/docs/src/examples/catalog/ClipPath.json +++ b/docs/src/examples/catalog/ClipPath.json @@ -31,7 +31,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-04-14T21:40:56.000Z", + "updatedAt": "2026-04-14T21:40:56.000Z" }, { "name": "clip-snippet", @@ -73,7 +75,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-04-15T15:23:20.000Z", + "updatedAt": "2026-04-15T15:23:20.000Z" }, { "name": "inverted", @@ -105,7 +109,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-04-14T21:40:56.000Z", + "updatedAt": "2026-04-14T21:40:56.000Z" }, { "name": "use-id", @@ -142,7 +148,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-04-15T15:23:20.000Z", + "updatedAt": "2026-04-15T15:23:20.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/ColorRamp.json b/docs/src/examples/catalog/ColorRamp.json index 278736fe9e..eb7bcb352f 100644 --- a/docs/src/examples/catalog/ColorRamp.json +++ b/docs/src/examples/catalog/ColorRamp.json @@ -16,7 +16,9 @@ "lineNumber": 24, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "pixelated", @@ -33,7 +35,9 @@ "lineNumber": 28, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "schemes", @@ -50,7 +54,9 @@ "lineNumber": 21, "line": " Math.sin(x) * Math.cos(y)} thresholds={20} />" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "sampled-interactive", @@ -53,7 +55,9 @@ "lineNumber": 26, "line": " Math.sin(x) * Math.cos(y)} {thresholds} {blur} />" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "volcano-filled", @@ -80,7 +84,9 @@ "lineNumber": 20, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "volcano-filled-interactive", @@ -107,7 +113,9 @@ "lineNumber": 29, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "basic", @@ -63,7 +65,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "stroke-only", @@ -95,7 +99,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "thresholds", @@ -127,7 +133,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "walmart", @@ -164,7 +172,9 @@ "lineNumber": 74, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "weighted", @@ -201,7 +211,9 @@ "lineNumber": 37, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "beeswarm", @@ -85,7 +89,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "duration-bars-dense-lanes", @@ -112,7 +118,9 @@ "lineNumber": 57, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "grouped-horizontal", @@ -139,7 +147,9 @@ "lineNumber": 68, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "grouped-vertical", @@ -166,7 +176,9 @@ "lineNumber": 67, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "image-beeswarm", @@ -193,7 +205,9 @@ "lineNumber": 39, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "penguins", @@ -220,7 +234,9 @@ "lineNumber": 55, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "tech-layoffs", @@ -252,7 +268,9 @@ "lineNumber": 63, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "text-beeswarm", @@ -279,7 +297,9 @@ "lineNumber": 60, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "timeline", @@ -316,7 +336,9 @@ "lineNumber": 81, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Ellipse.json b/docs/src/examples/catalog/Ellipse.json index 886b91d533..0411c5d948 100644 --- a/docs/src/examples/catalog/Ellipse.json +++ b/docs/src/examples/catalog/Ellipse.json @@ -26,7 +26,9 @@ "lineNumber": 29, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "color-via-threshold-scale", @@ -58,7 +60,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "data-mode", @@ -85,7 +89,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "styling-using-attributes", @@ -112,7 +118,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-classes", @@ -139,7 +147,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-css-variables", @@ -166,7 +176,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/ForceSimulation.json b/docs/src/examples/catalog/ForceSimulation.json index ec4307c5b8..e96f33e4f6 100644 --- a/docs/src/examples/catalog/ForceSimulation.json +++ b/docs/src/examples/catalog/ForceSimulation.json @@ -36,7 +36,9 @@ "lineNumber": 60, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "collision-detection", @@ -68,7 +70,9 @@ "lineNumber": 60, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "games-industry-layoffs", @@ -142,7 +148,9 @@ "lineNumber": 86, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "graph-drag", @@ -179,7 +187,9 @@ "lineNumber": 141, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "graph-playground", @@ -216,7 +226,9 @@ "lineNumber": 196, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "group", @@ -243,7 +255,9 @@ "lineNumber": 73, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "layoffs-by-industry", @@ -312,7 +328,9 @@ "lineNumber": 132, "line": "" } - ] + ], + "createdAt": "2026-05-05T17:25:23.000Z", + "updatedAt": "2026-05-05T17:51:04.000Z" }, { "name": "text", @@ -339,7 +357,9 @@ "lineNumber": 104, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "tree", @@ -376,7 +396,9 @@ "lineNumber": 68, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Frame.json b/docs/src/examples/catalog/Frame.json index 02e4ae2a16..47740bf9bb 100644 --- a/docs/src/examples/catalog/Frame.json +++ b/docs/src/examples/catalog/Frame.json @@ -26,7 +26,9 @@ "lineNumber": 13, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "border", @@ -53,7 +55,9 @@ "lineNumber": 13, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "full", @@ -80,7 +84,9 @@ "lineNumber": 13, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "gradient", @@ -112,7 +118,9 @@ "lineNumber": 17, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/GeoCircle.json b/docs/src/examples/catalog/GeoCircle.json index b9b0a81498..9ab7f13a59 100644 --- a/docs/src/examples/catalog/GeoCircle.json +++ b/docs/src/examples/catalog/GeoCircle.json @@ -36,7 +36,9 @@ "lineNumber": 83, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "playground", @@ -68,7 +70,9 @@ "lineNumber": 78, "line": "" } - ] + ], + "createdAt": "2026-04-12T22:42:54.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/GeoLegend.json b/docs/src/examples/catalog/GeoLegend.json index dd324e1316..8e5136c8e9 100644 --- a/docs/src/examples/catalog/GeoLegend.json +++ b/docs/src/examples/catalog/GeoLegend.json @@ -26,7 +26,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "canvas-mode", @@ -53,7 +55,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "stacked-units", @@ -80,7 +84,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "tick-format", @@ -107,7 +113,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "ticks", @@ -134,7 +142,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "variants", @@ -161,7 +171,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-04-08T22:40:53.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/GeoPath.json b/docs/src/examples/catalog/GeoPath.json index 0fd6bfb4f4..de8f8e9ebd 100644 --- a/docs/src/examples/catalog/GeoPath.json +++ b/docs/src/examples/catalog/GeoPath.json @@ -36,7 +36,9 @@ "lineNumber": 161, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "bubble-map", @@ -83,7 +85,9 @@ "lineNumber": 142, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "choropleth", @@ -115,7 +119,9 @@ "lineNumber": 109, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "eclipses-globe", @@ -152,7 +158,9 @@ "lineNumber": 94, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "election-isometric", @@ -179,7 +187,9 @@ "lineNumber": 81, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "interpolating-projections", @@ -206,7 +216,9 @@ "lineNumber": 183, "line": "" } - ] + ], + "createdAt": "2026-04-03T05:11:09.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "paint-brush-selection", @@ -243,7 +255,9 @@ "lineNumber": 451, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "spike-map", @@ -302,7 +318,9 @@ "lineNumber": 119, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "submarine-cables-globe", @@ -344,7 +362,9 @@ "lineNumber": 96, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "timezones", @@ -391,7 +411,9 @@ "lineNumber": 137, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "tooltip", @@ -423,7 +445,9 @@ "lineNumber": 48, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "transform-canvas", @@ -450,7 +474,9 @@ "lineNumber": 126, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "transform-canvas-scale-extent", @@ -472,7 +498,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "transform-globe-inertia", @@ -526,7 +556,9 @@ "lineNumber": 53, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "transform-projection", @@ -553,7 +585,9 @@ "lineNumber": 124, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "transform-world-canvas", @@ -585,7 +619,9 @@ "lineNumber": 117, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "transform-world-projection", @@ -617,7 +653,9 @@ "lineNumber": 127, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "translucent-globe", @@ -654,7 +692,9 @@ "lineNumber": 80, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "us-country-map", @@ -681,7 +721,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "us-state-with-counties", @@ -730,7 +774,9 @@ "lineNumber": 66, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "us-state-with-surrounding-states", @@ -762,7 +808,9 @@ "lineNumber": 71, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/GeoPoint.json b/docs/src/examples/catalog/GeoPoint.json index f22c2a936f..76c2acd089 100644 --- a/docs/src/examples/catalog/GeoPoint.json +++ b/docs/src/examples/catalog/GeoPoint.json @@ -41,7 +41,9 @@ "lineNumber": 58, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "us-airports", @@ -73,7 +75,9 @@ "lineNumber": 64, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "us-state-capitals", @@ -110,7 +114,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "world-capitals", @@ -179,7 +187,9 @@ "lineNumber": 68, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-07-01T13:37:08.000Z" }, { "name": "projection-playground", @@ -63,7 +65,9 @@ "lineNumber": 85, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "satellite", @@ -90,7 +94,9 @@ "lineNumber": 57, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "shapefile-preview", @@ -112,7 +118,9 @@ "lineNumber": 125, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-08-06T14:51:07.000Z" }, { "name": "topojson-preview", @@ -144,7 +152,9 @@ "lineNumber": 134, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-07-01T13:37:08.000Z" }, { "name": "true-size", @@ -171,7 +181,9 @@ "lineNumber": 292, "line": "" } - ] + ], + "createdAt": "2026-04-02T13:05:35.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "true-size-globe", @@ -208,7 +220,9 @@ "lineNumber": 422, "line": "" } - ] + ], + "createdAt": "2026-04-07T16:43:26.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "planets", @@ -63,7 +65,9 @@ "lineNumber": 96, "line": "" } - ] + ], + "createdAt": "2026-04-07T16:43:26.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "projections", @@ -95,7 +99,9 @@ "lineNumber": 62, "line": "" } - ] + ], + "createdAt": "2026-04-07T16:43:26.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "textures", @@ -127,7 +133,9 @@ "lineNumber": 173, "line": "" } - ] + ], + "createdAt": "2026-04-07T16:43:26.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "tiles-globe", @@ -159,7 +167,9 @@ "lineNumber": 113, "line": "" } - ] + ], + "createdAt": "2026-04-07T16:43:26.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/GeoSpline.json b/docs/src/examples/catalog/GeoSpline.json index 0eed21f705..98078e1e9a 100644 --- a/docs/src/examples/catalog/GeoSpline.json +++ b/docs/src/examples/catalog/GeoSpline.json @@ -41,7 +41,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "world-map", @@ -78,7 +80,9 @@ "lineNumber": 48, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/GeoTile.json b/docs/src/examples/catalog/GeoTile.json index 23e6b2749e..3e62f7c5c1 100644 --- a/docs/src/examples/catalog/GeoTile.json +++ b/docs/src/examples/catalog/GeoTile.json @@ -31,7 +31,9 @@ "lineNumber": 59, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "clipped", @@ -68,7 +70,9 @@ "lineNumber": 58, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "zoomable", @@ -100,7 +104,9 @@ "lineNumber": 82, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "zoomable-seamless-layers", @@ -132,7 +138,9 @@ "lineNumber": 89, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "zoomable-with-padding", @@ -164,7 +172,9 @@ "lineNumber": 88, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Graticule.json b/docs/src/examples/catalog/Graticule.json index 51b3eeef32..e1291c6e71 100644 --- a/docs/src/examples/catalog/Graticule.json +++ b/docs/src/examples/catalog/Graticule.json @@ -31,7 +31,9 @@ "lineNumber": 71, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Grid.json b/docs/src/examples/catalog/Grid.json index bbb9ee377d..ce899f86e2 100644 --- a/docs/src/examples/catalog/Grid.json +++ b/docs/src/examples/catalog/Grid.json @@ -26,7 +26,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "band-scale-default", @@ -53,7 +55,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "basic", @@ -75,7 +79,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "dashed-lines", @@ -97,7 +103,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-14T17:26:37.000Z" }, { "name": "explicit-ticks", @@ -124,7 +132,9 @@ "lineNumber": 8, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "inject-tick-value", @@ -151,7 +161,9 @@ "lineNumber": 8, "line": " [45, ...(scale.ticks?.() ?? [])]} />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "integer-only", @@ -178,7 +190,9 @@ "lineNumber": 8, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "radial", @@ -222,7 +238,9 @@ "lineNumber": 7, "line": " scale.ticks?.().splice(1)} y />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "radial-linear", @@ -244,7 +262,9 @@ "lineNumber": 7, "line": " scale.ticks?.().splice(1)} y radialY=\"linear\" />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tick-count", @@ -271,7 +291,9 @@ "lineNumber": 8, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tick-count-null", @@ -298,7 +320,9 @@ "lineNumber": 8, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "x-only", @@ -320,7 +344,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "y-only", @@ -342,7 +368,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Group.json b/docs/src/examples/catalog/Group.json index cc1ef6b52b..4c39d3b875 100644 --- a/docs/src/examples/catalog/Group.json +++ b/docs/src/examples/catalog/Group.json @@ -36,7 +36,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "data-mode", @@ -73,7 +75,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-08-06T12:20:24.000Z" }, { "name": "series-state", @@ -100,7 +104,9 @@ "lineNumber": 35, "line": "" } - ] + ], + "createdAt": "2026-09-09T14:47:19.000Z", + "updatedAt": "2026-09-09T14:47:19.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Highlight.json b/docs/src/examples/catalog/Highlight.json index dbe1c74216..94985a5a8f 100644 --- a/docs/src/examples/catalog/Highlight.json +++ b/docs/src/examples/catalog/Highlight.json @@ -342,29 +342,29 @@ "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 48, + "lineNumber": 47, "line": "" }, { "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 49, + "lineNumber": 48, "line": " context.y1Scale?.(d.efficiency)} />" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 34, + "lineNumber": 36, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 56, - "line": "" + "lineNumber": 57, + "line": "" }, { "example": "facet-tooltip", @@ -703,5 +703,5 @@ "line": "" } ], - "updatedAt": "2026-10-08T16:54:43.721Z" + "updatedAt": "2026-10-16T16:15:13.997Z" } \ No newline at end of file diff --git a/docs/src/examples/catalog/Hull.json b/docs/src/examples/catalog/Hull.json index e5669ccac5..7273a10d2f 100644 --- a/docs/src/examples/catalog/Hull.json +++ b/docs/src/examples/catalog/Hull.json @@ -41,7 +41,9 @@ "lineNumber": 49, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "country-flags", @@ -63,7 +65,9 @@ "lineNumber": 29, "line": "" + }, { "example": "band-scale-on-axis", "component": "AnnotationPoint", @@ -79,6 +88,13 @@ "lineNumber": 110, "line": "" }, + { + "example": "custom-label", + "component": "AnnotationRange", + "path": "/docs/components/AnnotationRange/custom-label", + "lineNumber": 20, + "line": "" + }, { "example": "clock", "component": "Arc", @@ -517,7 +533,7 @@ "example": "multiple-axis-same-placement-right", "component": "Axis", "path": "/docs/components/Axis/multiple-axis-same-placement-right", - "lineNumber": 9, + "lineNumber": 7, "line": "" }, { @@ -1595,21 +1611,21 @@ "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 27, + "lineNumber": 26, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 23, + "lineNumber": 25, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 46, + "lineNumber": 48, "line": "" }, { @@ -4546,5 +4562,5 @@ "line": "" } ], - "updatedAt": "2026-10-08T16:54:43.809Z" + "updatedAt": "2026-10-16T16:15:14.129Z" } \ No newline at end of file diff --git a/docs/src/examples/catalog/Legend.json b/docs/src/examples/catalog/Legend.json index 386e3d30ff..59406617d4 100644 --- a/docs/src/examples/catalog/Legend.json +++ b/docs/src/examples/catalog/Legend.json @@ -16,7 +16,9 @@ "lineNumber": 13, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "chart-placement", @@ -33,7 +35,9 @@ "lineNumber": 13, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "children-override", @@ -45,7 +49,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "responsive-swatches", @@ -129,7 +147,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "sequential-log", @@ -153,7 +175,9 @@ "lineNumber": 8, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "sqrt", @@ -189,7 +217,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "square-swatch", @@ -201,7 +231,9 @@ "lineNumber": 8, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "color-via-threshold-scale", @@ -68,7 +70,9 @@ "lineNumber": 45, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "data-mode", @@ -100,7 +104,9 @@ "lineNumber": 29, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "styling-using-attributes", @@ -127,7 +133,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-classes", @@ -154,7 +162,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-css-variables", @@ -181,10 +191,26 @@ "lineNumber": 14, "line": "" + }, + { + "example": "custom-line", + "component": "AnnotationLine", + "path": "/docs/components/AnnotationLine/custom-line", + "lineNumber": 18, + "line": "" + }, { "example": "clock", "component": "Arc", @@ -473,5 +499,5 @@ "line": "" } ], - "updatedAt": "2026-05-05T17:36:02.034Z" + "updatedAt": "2026-10-16T16:15:14.178Z" } \ No newline at end of file diff --git a/docs/src/examples/catalog/LineChart.json b/docs/src/examples/catalog/LineChart.json index b0b7901ee7..314b77cc8c 100644 --- a/docs/src/examples/catalog/LineChart.json +++ b/docs/src/examples/catalog/LineChart.json @@ -11,7 +11,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "brush", @@ -35,7 +39,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "custom-tooltip", @@ -155,7 +169,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "draw", @@ -179,7 +197,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "gradient-threshold", @@ -245,7 +269,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "labels", @@ -257,7 +283,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "override-color", @@ -426,7 +476,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "perf-dimension-arrays", @@ -513,7 +575,9 @@ "lineNumber": 55, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-07-01T13:37:08.000Z" }, { "name": "perf-streaming", @@ -549,7 +617,9 @@ "lineNumber": 131, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "perf-wide-data", @@ -561,7 +631,9 @@ "lineNumber": 54, "line": " 100 - d.idl} props={chartProps} brush profile />" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-07-01T13:37:08.000Z" }, { "name": "perf-wide-data-processed", @@ -573,7 +645,9 @@ "lineNumber": 61, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-07-01T13:37:08.000Z" }, { "name": "persist-brush-zoom", @@ -600,7 +674,9 @@ "lineNumber": 86, "line": "" } - ] + ], + "createdAt": "2026-04-09T04:27:28.000Z", + "updatedAt": "2026-08-17T18:59:37.000Z" }, { "name": "persist-series", @@ -612,7 +688,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" }, { "name": "points", @@ -641,7 +721,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "series-labels-hover", @@ -769,7 +867,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "series-point-annotations", @@ -781,7 +881,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "sparkline-zero-axis", @@ -964,7 +1092,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tooltip-click", @@ -1030,7 +1164,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ + { + "example": "custom-label", + "component": "AnnotationLine", + "path": "/docs/components/AnnotationLine/custom-label", + "lineNumber": 12, + "line": "" + }, + { + "example": "custom-line", + "component": "AnnotationLine", + "path": "/docs/components/AnnotationLine/custom-line", + "lineNumber": 12, + "line": "" + }, { "example": "horizontal", "component": "AnnotationLine", @@ -1102,6 +1254,13 @@ "lineNumber": 12, "line": "" }, + { + "example": "custom-marker", + "component": "AnnotationPoint", + "path": "/docs/components/AnnotationPoint/custom-marker", + "lineNumber": 20, + "line": "" + }, { "example": "line-to-point", "component": "AnnotationPoint", @@ -1144,6 +1303,13 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "explicit-offsets", @@ -53,7 +55,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tailwind-colors", @@ -80,7 +84,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "units", @@ -107,7 +113,9 @@ "lineNumber": 11, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Link.json b/docs/src/examples/catalog/Link.json index 7ad7903c70..f28e7d1760 100644 --- a/docs/src/examples/catalog/Link.json +++ b/docs/src/examples/catalog/Link.json @@ -36,7 +36,9 @@ "lineNumber": 74, "line": "" } ], - "description": "When " + "description": "When ", + "createdAt": "2026-04-19T23:06:20.000Z", + "updatedAt": "2026-04-20T20:21:36.000Z" }, { "name": "playground", @@ -91,7 +95,9 @@ "lineNumber": 77, "line": "" } ], - "description": "Link supports several path types across cartesian and radial orientations." + "description": "Link supports several path types across cartesian and radial orientations.", + "createdAt": "2026-04-19T23:06:20.000Z", + "updatedAt": "2026-04-20T20:21:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Marker.json b/docs/src/examples/catalog/Marker.json index 83e6ebb9f7..7923df527b 100644 --- a/docs/src/examples/catalog/Marker.json +++ b/docs/src/examples/catalog/Marker.json @@ -21,7 +21,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-04-01T17:24:28.000Z", + "updatedAt": "2026-04-01T17:24:28.000Z" }, { "name": "basic", @@ -53,7 +55,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-04-01T17:24:28.000Z", + "updatedAt": "2026-04-01T17:24:28.000Z" }, { "name": "custom-cell-size", @@ -80,7 +84,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-04-01T17:24:28.000Z", + "updatedAt": "2026-04-01T17:24:28.000Z" }, { "name": "multiple-years", @@ -107,7 +113,9 @@ "lineNumber": 41, "line": "" } - ] + ], + "createdAt": "2026-04-01T17:24:28.000Z", + "updatedAt": "2026-04-01T17:24:28.000Z" }, { "name": "without-day-numbers", @@ -134,7 +142,9 @@ "lineNumber": 42, "line": "" } - ] + ], + "createdAt": "2026-04-01T17:24:28.000Z", + "updatedAt": "2026-04-01T17:24:28.000Z" }, { "name": "without-month-labels", @@ -161,7 +171,9 @@ "lineNumber": 42, "line": "" } - ] + ], + "createdAt": "2026-04-01T17:24:28.000Z", + "updatedAt": "2026-04-01T17:24:28.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/MotionPath.json b/docs/src/examples/catalog/MotionPath.json index 569fd4706b..c50b7b9cbb 100644 --- a/docs/src/examples/catalog/MotionPath.json +++ b/docs/src/examples/catalog/MotionPath.json @@ -36,7 +36,9 @@ "lineNumber": 48, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Pack.json b/docs/src/examples/catalog/Pack.json index c7f8f37206..d85f5a45c3 100644 --- a/docs/src/examples/catalog/Pack.json +++ b/docs/src/examples/catalog/Pack.json @@ -36,7 +36,9 @@ "lineNumber": 134, "line": "" } - ] + ], + "createdAt": "2026-07-21T18:21:59.000Z", + "updatedAt": "2026-07-21T18:23:36.000Z" }, { "name": "horizontal", @@ -160,7 +164,9 @@ "lineNumber": 123, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "vertical", @@ -259,7 +267,9 @@ "lineNumber": 123, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Pattern.json b/docs/src/examples/catalog/Pattern.json index 792d6f2fbd..a570c2e307 100644 --- a/docs/src/examples/catalog/Pattern.json +++ b/docs/src/examples/catalog/Pattern.json @@ -26,7 +26,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "lines", @@ -117,7 +123,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "with-lineargradient", @@ -235,7 +249,9 @@ "lineNumber": 11, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Pie.json b/docs/src/examples/catalog/Pie.json index 0439509500..2606121803 100644 --- a/docs/src/examples/catalog/Pie.json +++ b/docs/src/examples/catalog/Pie.json @@ -21,7 +21,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "default-slot-render-each-arc", @@ -48,7 +50,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "inner-radius-negative", @@ -92,7 +98,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "inner-radius-positive", @@ -114,7 +122,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "inner-radius-zero-one", @@ -136,7 +146,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "isometric", @@ -173,7 +185,9 @@ "lineNumber": 104, "line": "" } - ] + ], + "createdAt": "2026-10-08T16:43:08.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "labels", @@ -205,7 +219,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "offset", @@ -409,7 +437,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "outer-radius", @@ -431,7 +461,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "pad-angle", @@ -453,7 +485,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "pad-angle-with-inner-radius", @@ -475,7 +509,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "partial-range-chart-xrange", @@ -497,7 +533,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "partial-range-range-prop", @@ -519,7 +557,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement", @@ -541,7 +581,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement-center", @@ -563,7 +605,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement-left", @@ -590,7 +634,9 @@ "lineNumber": 21, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement-right", @@ -617,7 +663,9 @@ "lineNumber": 21, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tooltip", @@ -644,7 +692,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "tooltip-with-arcs-slot", @@ -686,7 +736,9 @@ "lineNumber": 69, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "tweened", @@ -708,7 +760,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/PieChart.json b/docs/src/examples/catalog/PieChart.json index 78f9f35739..75500e347e 100644 --- a/docs/src/examples/catalog/PieChart.json +++ b/docs/src/examples/catalog/PieChart.json @@ -11,7 +11,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "colors-data-prop", @@ -47,7 +53,9 @@ "lineNumber": 21, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "colors-interpolator", @@ -59,7 +67,9 @@ "lineNumber": 11, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "colors-scheme", @@ -71,7 +81,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "colors-variables", @@ -83,7 +95,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "donut", @@ -95,7 +109,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "legend-custom-label", @@ -160,7 +184,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "legend-programmatic-control", @@ -184,7 +212,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "placement-custom", @@ -261,7 +301,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "radius-offset", @@ -309,7 +357,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "radius-percent", @@ -321,7 +371,9 @@ "lineNumber": 10, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "segments", @@ -338,7 +390,9 @@ "lineNumber": 37, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Points.json b/docs/src/examples/catalog/Points.json index f479a97143..de6966b2ba 100644 --- a/docs/src/examples/catalog/Points.json +++ b/docs/src/examples/catalog/Points.json @@ -26,7 +26,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "color-via-class", @@ -53,7 +55,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "color-via-fill", @@ -80,7 +84,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "color-via-ordinal-scale", @@ -112,7 +118,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "color-via-threshold-scale", @@ -144,7 +152,9 @@ "lineNumber": 39, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-14T17:26:37.000Z" }, { "name": "with-labels", @@ -176,7 +186,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "with-tooltip-and-highlight", @@ -213,7 +225,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Polygon.json b/docs/src/examples/catalog/Polygon.json index 922e55a462..ded926697c 100644 --- a/docs/src/examples/catalog/Polygon.json +++ b/docs/src/examples/catalog/Polygon.json @@ -21,7 +21,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "color-via-threshold-scale", @@ -261,7 +281,9 @@ "lineNumber": 42, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "cross", @@ -288,7 +310,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "diamond", @@ -337,7 +363,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "rectangle", @@ -469,7 +507,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "spreadmethod", @@ -53,7 +55,9 @@ "lineNumber": 11, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "tailwind-colors", @@ -80,7 +84,9 @@ "lineNumber": 19, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Raster.json b/docs/src/examples/catalog/Raster.json index 3b1d4da48f..5645c41a0b 100644 --- a/docs/src/examples/catalog/Raster.json +++ b/docs/src/examples/catalog/Raster.json @@ -26,7 +26,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "math-functions", @@ -58,7 +60,9 @@ "lineNumber": 112, "line": " Math.sin(x) * Math.cos(y)} />" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "us-water-vapor", @@ -127,7 +133,9 @@ "lineNumber": 66, "line": "" } - ] + ], + "createdAt": "2026-04-01T03:22:51.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "volcano", @@ -154,7 +162,9 @@ "lineNumber": 20, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "with-contour-overlay", @@ -186,7 +196,9 @@ "lineNumber": 21, "line": " 0} x1=\"x1\" y1=\"count\" insets={{ x: 1 }} fill=\"group\" />" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "color-via-threshold-scale", @@ -58,7 +60,9 @@ "lineNumber": 47, "line": " 0} x1=\"x1\" y1=\"count\" insets={{ x: 1 }} fill=\"count\" />" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "data-mode-edge", @@ -85,7 +89,9 @@ "lineNumber": 30, "line": " 0} x1=\"x1\" y1=\"count\" insets={{ x: 1 }} class=\"fill-primary\" />" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "playground", @@ -112,7 +118,9 @@ "lineNumber": 151, "line": "" } - ] + ], + "createdAt": "2026-05-09T15:35:17.000Z", + "updatedAt": "2026-05-09T15:35:17.000Z" }, { "name": "styling-using-attributes", @@ -139,7 +147,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-classes", @@ -166,7 +176,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "styling-using-css-variables", @@ -193,7 +205,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Rule.json b/docs/src/examples/catalog/Rule.json index eab7615198..7f76002596 100644 --- a/docs/src/examples/catalog/Rule.json +++ b/docs/src/examples/catalog/Rule.json @@ -26,7 +26,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "baseline-x-negative", @@ -107,7 +113,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "baseline-x-y", @@ -134,7 +142,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "baseline-y-negative", @@ -161,7 +171,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "candlestick", @@ -198,7 +210,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "candlestick-open-close-line-color", @@ -235,7 +249,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "candlestick-with-brushing", @@ -277,7 +293,9 @@ "lineNumber": 70, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "data-x-band", @@ -304,7 +322,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "data-x-date", @@ -331,7 +351,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "data-x-range", @@ -358,7 +380,9 @@ "lineNumber": 20, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "data-y-range", @@ -385,7 +409,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "lollipop", @@ -427,7 +453,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-12T21:37:32.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Sankey.json b/docs/src/examples/catalog/Sankey.json index 5aab5d0149..488a0c9914 100644 --- a/docs/src/examples/catalog/Sankey.json +++ b/docs/src/examples/catalog/Sankey.json @@ -46,7 +46,9 @@ "lineNumber": 125, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "hierarchy", @@ -88,7 +90,9 @@ "lineNumber": 108, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/ScatterChart.json b/docs/src/examples/catalog/ScatterChart.json index 9cdee64145..806a9502fc 100644 --- a/docs/src/examples/catalog/ScatterChart.json +++ b/docs/src/examples/catalog/ScatterChart.json @@ -11,7 +11,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "brush", @@ -23,7 +25,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "custom-tooltip", @@ -77,7 +83,9 @@ "lineNumber": 12, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "domain-nice", @@ -113,7 +125,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "domain-padding", @@ -125,7 +139,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "line-annotation", @@ -149,7 +167,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "radius-scale", @@ -195,7 +219,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "single-axis-y", @@ -315,7 +359,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "single-dimension", @@ -332,7 +378,9 @@ "lineNumber": 24, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "tooltip-click", @@ -344,7 +392,9 @@ "lineNumber": 9, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Spline.json b/docs/src/examples/catalog/Spline.json index dda5ca0db1..4f71f80c7a 100644 --- a/docs/src/examples/catalog/Spline.json +++ b/docs/src/examples/catalog/Spline.json @@ -26,7 +26,9 @@ "lineNumber": 14, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "basic-start-and-end-snippets", @@ -58,7 +60,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "draw", @@ -85,7 +89,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "end-slot-with-draw-with-value", @@ -122,7 +128,9 @@ "lineNumber": 45, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "geo-routes", @@ -186,7 +196,9 @@ "lineNumber": 34, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "label-using-start-end-snippets", @@ -292,7 +308,9 @@ "lineNumber": 39, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "markers-arrows", @@ -319,7 +337,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-04-13T12:45:20.000Z", + "updatedAt": "2026-04-13T13:08:22.000Z" }, { "name": "missing-data-dashed", @@ -378,7 +400,9 @@ "lineNumber": 77, "line": "" } - ] + ], + "createdAt": "2026-09-08T14:15:24.000Z", + "updatedAt": "2026-09-08T14:15:24.000Z" }, { "name": "missing-data-with-markers", @@ -415,7 +439,9 @@ "lineNumber": 65, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-series-highlight-on-hover", @@ -509,7 +537,9 @@ "lineNumber": 75, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-series-tweened", @@ -536,7 +566,9 @@ "lineNumber": 51, "line": "" } - ] + ], + "createdAt": "2026-09-03T19:08:33.000Z", + "updatedAt": "2026-09-03T19:08:33.000Z" }, { "name": "multiple-series-using-overrides", @@ -573,7 +605,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-series-with-labels", @@ -615,7 +649,9 @@ "lineNumber": 44, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-08-20T03:04:59.000Z" }, { "name": "parallel-coordinates", @@ -652,7 +688,9 @@ "lineNumber": 81, "line": "" } - ] + ], + "createdAt": "2026-08-15T17:38:38.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "parallel-coordinates-mixed", @@ -748,7 +790,9 @@ "lineNumber": 114, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "radial-multi-year-lines", @@ -839,7 +887,9 @@ "lineNumber": 40, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-10-08T16:43:08.000Z" }, { "name": "radial-radar", @@ -871,7 +921,9 @@ "lineNumber": 39, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "stroke-grouping", @@ -898,7 +950,9 @@ "lineNumber": 21, "line": " yearColor(d.date.getFullYear())} class=\"stroke-2\" />" } - ] + ], + "createdAt": "2026-04-02T19:13:52.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "stroke-grouping-with-legend", @@ -930,7 +984,9 @@ "lineNumber": 42, "line": "" } - ] + ], + "createdAt": "2026-08-20T07:11:37.000Z", + "updatedAt": "2026-08-20T07:11:37.000Z" }, { "name": "tween-on-mount", @@ -957,7 +1013,9 @@ "lineNumber": 18, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "tweened", @@ -984,7 +1042,9 @@ "lineNumber": 36, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-13T12:19:51.000Z" }, { "name": "vertical", @@ -1021,7 +1081,9 @@ "lineNumber": 28, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "with-labels", @@ -1053,7 +1115,9 @@ "lineNumber": 15, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "with-tooltip-and-highlight", @@ -1090,7 +1154,9 @@ "lineNumber": 27, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" } ], "usage": [ @@ -1133,43 +1199,43 @@ "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 46, + "lineNumber": 45, "line": "" }, { "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 47, + "lineNumber": 46, "line": " context.y1Scale?.(d.efficiency)} class=\"stroke-2 stroke-secondary\" />" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 33, + "lineNumber": 35, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 54, + "lineNumber": 56, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 43, - "line": "" + "lineNumber": 54, + "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 44, - "line": "" + "lineNumber": 55, + "line": "" }, { "example": "data-chart-multi", @@ -1753,5 +1819,5 @@ "line": "" } ], - "updatedAt": "2026-10-05T16:56:46.250Z" + "updatedAt": "2026-10-16T16:15:15.002Z" } \ No newline at end of file diff --git a/docs/src/examples/catalog/Text.json b/docs/src/examples/catalog/Text.json index d48442954f..072589a617 100644 --- a/docs/src/examples/catalog/Text.json +++ b/docs/src/examples/catalog/Text.json @@ -31,7 +31,9 @@ "lineNumber": 28, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" }, { "name": "segments", @@ -149,7 +157,9 @@ "lineNumber": 7, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Threshold.json b/docs/src/examples/catalog/Threshold.json index bcbcdef3f4..75c9b16e79 100644 --- a/docs/src/examples/catalog/Threshold.json +++ b/docs/src/examples/catalog/Threshold.json @@ -26,7 +26,9 @@ "lineNumber": 37, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "with-labels", @@ -53,7 +55,9 @@ "lineNumber": 42, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "with-tooltip-and-highlight", @@ -85,7 +89,9 @@ "lineNumber": 51, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Tooltip.json b/docs/src/examples/catalog/Tooltip.json index a7ccc14cc3..26136c3d3b 100644 --- a/docs/src/examples/catalog/Tooltip.json +++ b/docs/src/examples/catalog/Tooltip.json @@ -36,7 +36,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "color-swatch", @@ -147,7 +153,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "color-swatch-using-theme", @@ -184,7 +192,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "custom-content", @@ -221,7 +231,9 @@ "lineNumber": 32, "line": "Anything can go here test" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "data-snapping", @@ -258,7 +270,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "default-mouse-position-with-offset", @@ -295,7 +309,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "disable-motion", @@ -332,7 +348,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "duration", @@ -374,7 +392,9 @@ "lineNumber": 62, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "invert-variant", @@ -448,7 +470,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-03-31T15:09:10.000Z" }, { "name": "multiple-overlapping-bars", @@ -485,7 +509,9 @@ "lineNumber": 60, "line": "" } - ] + ], + "createdAt": "2026-04-13T14:38:57.000Z", + "updatedAt": "2026-04-13T14:38:57.000Z" }, { "name": "programmatic-control", @@ -650,7 +684,9 @@ "lineNumber": 70, "line": "" }, { "example": "tooltip-locking", @@ -1409,13 +1453,13 @@ "component": "AreaChart", "path": "/docs/components/AreaChart/tooltip-locking", "lineNumber": 48, - "line": "" }, { "example": "tooltip-locking", "component": "AreaChart", "path": "/docs/components/AreaChart/tooltip-locking", - "lineNumber": 72, + "lineNumber": 67, "line": "" }, { @@ -2013,6 +2057,48 @@ "lineNumber": 70, "line": "" }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 67, + "line": "" + }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 69, + "line": "" + }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 70, + "line": "" + }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 71, + "line": "" + }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 72, + "line": "" + }, + { + "example": "group-series-dual-axis", + "component": "BarChart", + "path": "/docs/components/BarChart/group-series-dual-axis", + "lineNumber": 74, + "line": "" + }, { "example": "histogram-date-time-count", "component": "BarChart", @@ -2249,7 +2335,7 @@ "component": "BarChart", "path": "/docs/components/BarChart/series-horizontal-diverging", "lineNumber": 63, - "line": "" + "line": "" }, { "example": "series-horizontal-diverging-as-percent", @@ -2277,7 +2363,7 @@ "component": "BarChart", "path": "/docs/components/BarChart/series-horizontal-diverging-as-percent", "lineNumber": 64, - "line": "" + "line": "" }, { "example": "series-horizontal-diverging-label-gap", @@ -3760,210 +3846,210 @@ "example": "compound-common-scale-with-extra-marks", "component": "Chart", "path": "/docs/components/Chart/compound-common-scale-with-extra-marks", - "lineNumber": 33, + "lineNumber": 40, "line": "" }, { "example": "compound-common-scale-with-extra-marks", "component": "Chart", "path": "/docs/components/Chart/compound-common-scale-with-extra-marks", - "lineNumber": 35, + "lineNumber": 42, "line": "" }, { "example": "compound-common-scale-with-extra-marks", "component": "Chart", "path": "/docs/components/Chart/compound-common-scale-with-extra-marks", - "lineNumber": 36, + "lineNumber": 43, "line": "" }, { "example": "compound-common-scale-with-extra-marks", "component": "Chart", "path": "/docs/components/Chart/compound-common-scale-with-extra-marks", - "lineNumber": 37, + "lineNumber": 44, "line": "" }, { "example": "compound-common-scale-with-extra-marks", "component": "Chart", "path": "/docs/components/Chart/compound-common-scale-with-extra-marks", - "lineNumber": 38, + "lineNumber": 45, "line": "" }, { "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 52, + "lineNumber": 51, "line": "" }, { "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 54, + "lineNumber": 53, "line": "{data.year}" }, { "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 55, + "lineNumber": 54, "line": "" }, { "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 56, + "lineNumber": 55, "line": "" }, { "example": "compound-dual-axis-with-single-chart-using-remapped-scale", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-single-chart-using-remapped-scale", - "lineNumber": 57, + "lineNumber": 56, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 59, + "lineNumber": 60, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 61, + "lineNumber": 62, "line": "{data.year}" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 62, + "lineNumber": 63, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 63, + "lineNumber": 64, "line": "" }, { "example": "compound-dual-axis-with-stacked-charts", "component": "Chart", "path": "/docs/components/Chart/compound-dual-axis-with-stacked-charts", - "lineNumber": 64, + "lineNumber": 65, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 48, + "lineNumber": 59, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 50, - "line": "" + "lineNumber": 61, + "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 51, + "lineNumber": 62, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 52, + "lineNumber": 63, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 53, + "lineNumber": 64, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 54, + "lineNumber": 65, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 55, + "lineNumber": 66, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-and-overridden-marks", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-and-overridden-marks", - "lineNumber": 56, + "lineNumber": 67, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", - "lineNumber": 83, + "lineNumber": 84, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", - "lineNumber": 85, + "lineNumber": 86, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", - "lineNumber": 86, + "lineNumber": 87, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", - "lineNumber": 87, + "lineNumber": 88, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", - "lineNumber": 88, + "lineNumber": 89, "line": "" }, { "example": "compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", "component": "Chart", "path": "/docs/components/Chart/compound-separate-scales-with-stacked-charts-with-inverted-range-top-down", - "lineNumber": 94, + "lineNumber": 95, "line": "" }, { "example": "mixed-marks-with-stack", "component": "Chart", "path": "/docs/components/Chart/mixed-marks-with-stack", - "lineNumber": 71, + "lineNumber": 65, "line": "" }, { "example": "mixed-marks-with-stack", "component": "Chart", "path": "/docs/components/Chart/mixed-marks-with-stack", - "lineNumber": 73, + "lineNumber": 67, "line": "" }, { @@ -7926,20 +8012,20 @@ "component": "Waffle", "path": "/docs/components/Waffle/custom-symbol", "lineNumber": 68, - "line": "" }, { "example": "custom-symbol", "component": "Waffle", "path": "/docs/components/Waffle/custom-symbol", - "lineNumber": 76, + "lineNumber": 70, "line": "" }, { "example": "custom-symbol", "component": "Waffle", "path": "/docs/components/Waffle/custom-symbol", - "lineNumber": 77, + "lineNumber": 71, "line": "" }, { "example": "olympians-weight-by-sex", "component": "Waffle", "path": "/docs/components/Waffle/olympians-weight-by-sex", - "lineNumber": 64, + "lineNumber": 58, "line": "" }, { "example": "olympians-weight-by-sex", "component": "Waffle", "path": "/docs/components/Waffle/olympians-weight-by-sex", - "lineNumber": 65, + "lineNumber": 59, "line": "" }, { "example": "penguins", "component": "Waffle", "path": "/docs/components/Waffle/penguins", - "lineNumber": 63, + "lineNumber": 57, "line": "" }, { "example": "penguins", "component": "Waffle", "path": "/docs/components/Waffle/penguins", - "lineNumber": 64, + "lineNumber": 58, "line": "" }, { "example": "stacked", "component": "Waffle", "path": "/docs/components/Waffle/stacked", - "lineNumber": 56, + "lineNumber": 50, "line": "" }, { "example": "stacked", "component": "Waffle", "path": "/docs/components/Waffle/stacked", - "lineNumber": 57, + "lineNumber": 51, "line": "" } ], - "updatedAt": "2026-10-08T16:54:44.376Z" + "updatedAt": "2026-10-16T16:15:15.158Z" } \ No newline at end of file diff --git a/docs/src/examples/catalog/Trail.json b/docs/src/examples/catalog/Trail.json index eed94711bb..67f9784321 100644 --- a/docs/src/examples/catalog/Trail.json +++ b/docs/src/examples/catalog/Trail.json @@ -26,7 +26,9 @@ "lineNumber": 25, "line": "" } - ] + ], + "createdAt": "2026-04-03T20:04:05.000Z", + "updatedAt": "2026-04-03T20:04:05.000Z" }, { "name": "curves", @@ -54,7 +56,9 @@ "line": "" } ], - "description": "The trail mark supports round and butt capping and different interpolation methods." + "description": "The trail mark supports round and butt capping and different interpolation methods.", + "createdAt": "2026-04-03T20:04:05.000Z", + "updatedAt": "2026-04-03T20:04:05.000Z" }, { "name": "playground", @@ -86,7 +90,9 @@ "lineNumber": 52, "line": "" } ], - "description": "Elevation profile of a Tour de France stage using trail width to encode elevation." + "description": "Elevation profile of a Tour de France stage using trail width to encode elevation.", + "createdAt": "2026-04-03T20:04:05.000Z", + "updatedAt": "2026-04-12T22:28:43.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/TransformContext.json b/docs/src/examples/catalog/TransformContext.json index ccac7528c2..0ccd418b1c 100644 --- a/docs/src/examples/catalog/TransformContext.json +++ b/docs/src/examples/catalog/TransformContext.json @@ -31,7 +31,9 @@ "lineNumber": 53, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-05-05T17:25:23.000Z" }, { "name": "playground", @@ -155,7 +163,9 @@ "lineNumber": 58, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "nested-filter", @@ -125,7 +129,9 @@ "lineNumber": 163, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "playground", @@ -229,7 +237,9 @@ "lineNumber": 194, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "stacked-zoom", @@ -281,7 +291,9 @@ "lineNumber": 115, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "basic", @@ -53,7 +55,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "data-mode", @@ -80,7 +84,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "shapes", @@ -154,7 +162,9 @@ "lineNumber": 81, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Violin.json b/docs/src/examples/catalog/Violin.json index 59841966f9..fcccd338f6 100644 --- a/docs/src/examples/catalog/Violin.json +++ b/docs/src/examples/catalog/Violin.json @@ -26,7 +26,9 @@ "lineNumber": 59, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "horizontal", @@ -80,7 +84,9 @@ "lineNumber": 53, "line": "" } - ] + ], + "createdAt": "2026-03-31T15:09:10.000Z", + "updatedAt": "2026-04-27T16:10:53.000Z" }, { "name": "with-box-median", @@ -107,7 +113,9 @@ "lineNumber": 52, "line": "" } - ] + ], + "createdAt": "2026-02-18T13:27:36.000Z", + "updatedAt": "2026-02-18T13:27:36.000Z" } ], "usage": [ diff --git a/docs/src/examples/catalog/Waffle.json b/docs/src/examples/catalog/Waffle.json index 5c37241fd7..fe98983be3 100644 --- a/docs/src/examples/catalog/Waffle.json +++ b/docs/src/examples/catalog/Waffle.json @@ -16,7 +16,9 @@ "lineNumber": 23, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "band-padding", @@ -38,7 +40,9 @@ "lineNumber": 54, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "basic", @@ -60,7 +64,9 @@ "lineNumber": 30, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "circular-cells", @@ -82,7 +88,9 @@ "lineNumber": 32, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "custom-symbol", @@ -124,7 +132,9 @@ "lineNumber": 63, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "horizontal", @@ -146,7 +156,9 @@ "lineNumber": 31, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "months", @@ -168,7 +180,9 @@ "lineNumber": 51, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "olympians-by-birth-year", @@ -190,7 +204,9 @@ "lineNumber": 63, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "olympians-by-sex", @@ -212,7 +228,9 @@ "lineNumber": 38, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" }, { "name": "olympians-weight-by-sex", @@ -239,7 +257,9 @@ "lineNumber": 51, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "penguins", @@ -266,7 +286,9 @@ "lineNumber": 50, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "stacked", @@ -288,7 +310,9 @@ "lineNumber": 43, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-10-12T02:24:42.000Z" }, { "name": "survey", @@ -315,7 +339,9 @@ "lineNumber": 47, "line": "" } - ] + ], + "createdAt": "2026-05-08T16:22:57.000Z", + "updatedAt": "2026-05-08T16:22:57.000Z" } ], "usage": [ diff --git a/docs/src/lib/components/Example.svelte b/docs/src/lib/components/Example.svelte index fad5b5d3bd..148f99204c 100644 --- a/docs/src/lib/components/Example.svelte +++ b/docs/src/lib/components/Example.svelte @@ -383,7 +383,10 @@ {/snippet} {#if split && SplitLayout} - + + {#snippet code()}{@render codeBlock()}{/snippet} + {#snippet preview()}{@render previewBlock()}{/snippet} + {:else} {@render previewBlock()} diff --git a/docs/src/routes/docs/examples/+page.server.ts b/docs/src/routes/docs/examples/+page.server.ts index ea8a1fd0da..d9fd162aa2 100644 --- a/docs/src/routes/docs/examples/+page.server.ts +++ b/docs/src/routes/docs/examples/+page.server.ts @@ -8,6 +8,8 @@ interface ExampleInfo { name: string; title: string; path: string; + /** The commit that first added the example's file (absent until it's committed) */ + createdAt?: string; }>; } @@ -34,7 +36,8 @@ export async function load() { examples: catalog.examples.map((example) => ({ name: example.name, title: example.title, - path: `/example/${catalog.component}/${example.name}` + path: `/example/${catalog.component}/${example.name}`, + createdAt: example.createdAt })) })) .sort((a, b) => a.component.localeCompare(b.component)); diff --git a/docs/src/routes/docs/examples/+page.svelte b/docs/src/routes/docs/examples/+page.svelte index 866f34200b..7011efda40 100644 --- a/docs/src/routes/docs/examples/+page.svelte +++ b/docs/src/routes/docs/examples/+page.svelte @@ -1,6 +1,6 @@