Conversation
built with Refined Cloudflare Pages Action⚡ Cloudflare Pages Deployment
|
commit: |
🦋 Changeset detectedLatest commit: 20e7a02 The changes in this PR will be included in the next version bump. This PR includes changesets to release 1 package
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Hey, @techniq. I have a question: When are you planning to merge this PR so we can finally get the Svelte 5 support? 🤗 |
|
Hey @HicaroD, thanks for the kind words 🫶. Sorry, I don't have a rough release date set yet. There are a good number of improvements I would like to include in With that said, you 100% can use it today via I could see pushing some items to Related: I also need to migrate Svelte UX fully over to Svelte 5 (it's Svelte 3-5 compat with Svelte 3/4 state/syntax). Both libraries have already been migrated to Tailwind 4, but the move to Svelte 5 state runes/snippets and regressions checking will take some concentrated efforts and time. I don't know how close I'll try to sync their release schedules though (and the benefit of having |
|
All the examples give 500 errors on https://next.layerchart.com/ |
@cycle4passion Odd... working here Maybe try a hard refresh? Which browser? |
|
mobile only, does not work in arc (chromium), native chrome, or Safari browser. |
The `{#await}` block doesn't anchor a remote `query` to SSR's hydratable serialization, so on hydration the client threw `hydratable_missing_but_required` looking for `getStats/`. Switch to the `query.loading`/`error`/`current` pattern, which is the supported path for remote queries and also avoids the async-mode `<svelte:boundary>` commit that triggered a "Batch has scheduled roots" invariant.
* Initialize bundle analyzer package * update bundle baseline
- Sum entry chunk + all chunks reachable via static imports (so the reported size reflects true up-front cost; lazy chunks excluded) - Add `--visualize` flag (and `bundle:visualize` script) that emits an interactive treemap HTML per scenario via `rollup-plugin-visualizer` - Regenerate `latest.json` baseline with the new methodology
* Initialize bundle analyzer package
* update bundle baseline
* Prepare ChartChildren and Chart for tree-shaking
- Add `"sideEffects": ["**/*.css"]` to layerchart/package.json so downstream bundlers can prune unused barrel re-exports
- Convert ChartChildren's value imports of components only referenced in `ComponentProps<typeof X>` to `import type` (Area, Arc, Bars, BrushContext, Group, Line, Pie, Spline, TooltipContext)
- Inline `geoFitObjectTransform` into Chart.svelte to drop the static import edge through `$lib/utils/geo.js` (which transitively imports d3-geo)
No visible change in the bundle analyzer (it already does aggressive treeshaking), but unlocks the dynamic-import refactor in the next commit and protects consumers whose bundlers tree-shake less aggressively.
* Lazy-load conditionally-rendered components in Chart
Convert statically-imported components to `{#await import(...)}` so they only ship to users who opt in via the corresponding prop:
- ChartChildren: ChartAnnotations (when annotations.length > 0), DefaultTooltip (tooltipContext truthy), Labels, Legend, Points
- TooltipContext: Voronoi (mode === 'voronoi'), Arc (radial bounds/band)
Voronoi alone removes d3-geo-voronoi and its transitive d3-geo from the always-loaded bundle.
Update the bundle analyzer to sum the entry chunk plus all chunks reachable via static imports (lazy chunks excluded), so the reported size reflects up-front cost rather than total feature surface.
Result: `core` (`Chart` + `Svg`) drops 154.94 → 109.95 KB gz (-29%). Comparable savings on every scenario except `all` (which exercises every lazy path).
* Add `pnpm bundle:visualize` to generate treemaps using rollup-plugin-visualizer
* Fix BarChart legend toggle test for lazy-loaded Legend
The test queried `.lc-legend-swatch-button` synchronously, but `Legend` is now dynamically imported inside `ChartChildren` and isn't in the DOM until the chunk resolves. Wrap the query in `vi.waitFor` so the test waits for the buttons to mount before clicking.
* Fix analyzer footgun: don't overwrite latest.json on filtered runs
A filtered run (e.g. `pnpm bundle:visualize -- core`) was overwriting `bundle-reports/latest.json` with just the filtered scenarios, causing the PR comparison comment to show "0 KB" for every scenario the filtered run didn't cover. Now `latest.json` is only updated when no `--components`, scenario, or component filters are passed; filtered runs still get a timestamped report. Also regenerate the full baseline against the current lazy-loaded code.
* Fix CI test failure by avoiding tooltip namespace barrel in DefaultTooltip
DefaultTooltip is dynamically imported from ChartChildren. It was using `import * as Tooltip from '../tooltip/index.js'`, which dragged the entire tooltip barrel — including TooltipContext.svelte (already in the static graph via Chart.svelte) — into its lazy chunk. Under CI's resource-constrained dev server this broke the DefaultTooltip browser test ("Failed to fetch dynamically imported module"). Replace the namespace import with explicit named imports of just the 5 components actually used (no Context). The local `const Tooltip = { Root, Header, List, Item, Separator }` keeps the existing template syntax (`<Tooltip.Root>`, etc.) unchanged. Bonus: tightens tree-shaking — `all` scenario drops ~3 KB gz.
* Revert DefaultTooltip lazy-load to fix vitest-browser CI test
The dynamic import of `DefaultTooltip` from `ChartChildren` caused a CI-only "Failed to fetch dynamically imported module" failure in `DefaultTooltip.svelte.test.ts`. Local tests passed; only the Linux/playwright runner reproduced. Switching the inner `import * as Tooltip` namespace to named imports (commit 7e5d6e7) didn't help. The savings were small (~5 KB gz on `core`) and not worth the test instability — the other lazy-loads (Voronoi, Arc, ChartAnnotations, Labels, Legend, Points) remain. Net Phase 2 gain on `core` is now -39 KB gz (-25%) instead of -45 KB gz (-29%).
* Revert ChartChildren lazy-loads; keep TooltipContext lazy-loads
The DefaultTooltip vitest-browser test still failed in CI ("Failed to fetch dynamically imported module") even after reverting just DefaultTooltip's lazy-load and after switching the inner namespace import to named imports. Rather than continue narrowing, revert all 4 ChartChildren lazy-loads (Labels, Legend, Points, ChartAnnotations). The TooltipContext lazy-loads (Voronoi, Arc) stay — they're the biggest win (~17 KB gz on core from removing d3-geo-voronoi + d3-geo from the static graph) and aren't in the test failure path. Net Phase 2 gain on `core` is now -17 KB gz (-11%).
* Switch ChartChildren lazy-loads from `{#await}` to `$effect`
The `{#await import('./X.svelte')}` template pattern broke `DefaultTooltip.svelte.test.ts` in CI ("Failed to fetch dynamically imported module" on the test file). Local tests passed; only the Linux/playwright runner reproduced. Move the dynamic imports back into `$effect` blocks (script-side `import()`), which Vite/vitest-browser appears to handle differently. Same chunks, same bundle savings, but the dynamic imports live in regular JS rather than Svelte template syntax. TooltipContext keeps `{#await}` for Voronoi/Arc — those weren't in the test failure path. Net Phase 2 gain on `core` recovered to -40 KB gz (-25%).
* Refactor lazy-loading to a `<Lazy>` wrapper with prop-spread + `then` snippet
Replace per-component `$state`/`$effect`/conditional-render boilerplate in ChartChildren with a generic `<Lazy>` component that takes a `load` factory and either spreads remaining props to the loaded component (single-render case: ChartAnnotations, Legend) or passes it via a `then` snippet (loop case: Points, Labels). Conditional gating uses standard `{#if}` outside `<Lazy>` rather than a `when` prop. The snippet is named `then` (not `children`) to avoid collisions with loaded components that have their own `children` prop. Same bundle behavior and CI-friendly `$effect`-under-the-hood as the previous explicit pattern; ~half the lines per lazy-load.
* Use `{#await import(...)}` for lazy-loads; remove `<Lazy>` wrapper
Now that `optimizeDeps.include: ['d3-interpolate']` prevents the mid-test Vite reload (the actual cause of the CI flake), the cleaner inline `{#await import('./X.svelte') then { default: X }}` pattern works fine in CI. Revert ChartChildren back to that pattern, matching what TooltipContext already does. Remove `Lazy.svelte` since it's no longer needed. Same chunks, same ~25% savings on `core` (115.60 KB gz).
* Add `build` script alias so CI's `build:packages` actually builds layerchart
The bundle analysis CI workflow runs `pnpm build:packages` (which calls `pnpm --filter './packages/*' build`) before `pnpm bundle:analyze`. layerchart only had a `package` script (svelte-package convention), no `build`, so the filter call did nothing in CI — the analyzer ran against an empty `dist/` and produced 0-byte sizes for every scenario. That's why the PR comment showed "0.00 KB" for "New". Add a `build` alias for `svelte-package` (kept alongside existing `package` for back-compat) so CI's existing build step now actually rebuilds layerchart's `dist/`.
* Add percentage change to bundle analysis PR comment
The script already computed `sizePercent` and `gzipSizePercent`; now display them inline in the Change column alongside the raw KB deltas (e.g. `-160.00 KB (-25.1%)`). Easier to scan relative impact across scenarios than raw byte counts alone. Same for the Individual Components table.
* Group bundle analysis scenarios in PR comment by category
Add a `group` field to scenarios (Foundation, Cartesian charts, Geo, Hierarchy, Graph / network, Worst case) and render the PR comment with one sub-table per group instead of one alphabetized list. Reorder `define-scenarios.ts` to put `core` first and scenarios within their category. Remove the alphabetical sort in `analyzeChanges` so the comment preserves the natural order.
* Move heavy-dep components into sub-path exports
Remove from root `layerchart`: `Geo*` + `Graticule` + `TileImage`, `Tree`/`Treemap`/`Pack`/`Partition`, `ForceSimulation`, `Dagre`/`Sankey`/`Chord`/`Ribbon`. Each group now lives in its own folder + sub-path entry: `layerchart/geo`, `layerchart/hierarchy`, `layerchart/force`, `layerchart/graph`.
Defends against bundlers that don't tree-shake the root barrel cleanly — `@dagrejs/dagre` (~22 KB), `d3-geo` (~15 KB), `d3-force` (~7 KB), `d3-hierarchy` (~6 KB), `d3-sankey` (~6 KB), and `d3-chord` (~2 KB) are now reachable only via opt-in imports. Per-scenario bundle sizes are unchanged for already-good consumers; the worst-case `all` scenario drops 241.8 → 235.5 KB gz.
`Voronoi`/`Hull` stay at root (already lazy via `TooltipContext`). `Contour`/`Density`/`Raster`/`BoxPlot`/`Violin`/`Threshold` also stay (not category-specific). High-level charts (`LineChart`, `BarChart`, etc.) remain at root.
Breaking: imports for the moved components must move to the new sub-paths.
* Lazy-load opt-in features in core path
Three components that everyone pays for in `core` today, but only some users actually need:
- `Spline` in `Grid` (radial linear grid lines only — non-radial users never render it)
- `Bar` in `Highlight` (only when user sets `bar` prop, default `false`)
- `BrushContext` in `Chart` (only when user sets `brush` prop, default `undefined`) — required splitting the inner `<TooltipContext>` tree across the brush/no-brush branches; brush tests now wait for the lazy chunk via a new `awaitBrushReady` helper
Saves ~4 KB gz on `core` (115.60 → 111.31 KB) and similar on every cartesian/geo/graph/hierarchy scenario. ~28% total reduction on `core` vs the pre-Phase-1 baseline.
Also switch `@layerstack/svelte-actions` imports from the barrel to sub-paths (`/styles`, `/portal`). No bundle effect since tree-shaking already stripped the unused `popover.js`, but it stops the Svelte REPL/CDN from eagerly fetching `@floating-ui/dom` (popover's transitive dep) when users load `layerchart` from a CDN.
* add changeset for lazy loading opt-in features (brush, radial spline, etc)
* lazy load d3-quadtree and DefaultTooltip based on usage
* Render chart subtree during BrushContext lazy load
The previous structure put `<TooltipContext>` + `<ChartChildren>` *inside* the `{#await import('./BrushContext.svelte')}` block, so on slow networks the entire chart was blocked on the chunk fetch (~300-1000ms on Fast 4G). Move the same subtree into the `{#await}`'s pending branch as well so the chart paints immediately; the `{:then}` branch then re-mounts it inside `BrushContext` once the chunk arrives.
Trade-off: brief one-time re-mount of `TooltipContext` + `ChartChildren` (~50ms) when the chunk lands. Acceptable because it happens before any user interaction (no tooltip/series state to lose) and brush is opt-in. Bundle savings preserved (core +0.1 KB from the duplicated template, since the actual modules are deduped).
The other lazy-load sites (`Voronoi`/`Arc` in `TooltipContext`, `DefaultTooltip`, `Bar`, `Points`/`Labels`/`Legend`/`ChartAnnotations` in `ChartChildren`, `Spline` in `Grid`) don't need the same treatment — none of them block visible chart content from rendering.
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* split Circle.svelte into 3 layer-specific components (Circle.svg.svelte, etc) along with CircleState (Circle.shared.svelte.ts). Keep Circle.svelte and delegate to underlying type
* split Text.svelte into 3 layer-specific components
* Organize into component directories
* split Rect, Line, and Path into 3 layer-specific components
* split Ellipse, Polygon, Group, Image, ClipPath, Pattern, LinearGradient, and RadialGradient into 3 layer-specific components
* Add changeset for per-layer primitive
* split Axis into 3 layer-specific components
* Add full-chart layer examples (to monitor progress)
* split Grid and Rule into 3 layer-specific components
* split Chart and ChartChildren into 3 layer-specific components, and alias Layer based on layer type (Layer within layerchart/svg => Svg)
* refine bundle scenarios
* refine bundle scenarios
* Add more foundation examples
Co-authored-by: Copilot <copilot@github.com>
* improve bundle comment
* split Highlight, ChartClipPath, RectClipPath into 3 layer-specific components
* split Arc, Area, and Spline into 3 layer-specific components
* split ArcLabel, Bar, Bars, Labels, Pie, and Points into 3 layer-specific components
* split Frame, Cell, Threshold, AnnotationLine, AnnotationPoint, and Trail into 3 layer-specific components
* split AnnotationRange, CircleClipPath, Vector, Link, Hull, Density, and Calendar into 3 layer-specific components
* split BoxPlot, Violin, Raster, Month, Contour, and Voronoi into 3 layer-specific components
* split geo components (GeoPath, GeoSpline, etc) into 3 layer-specific components
* split Ribbon into 3 layer-specific components. Re-export all layout/helper components
* split high-level charts (BarChart, LineChart, etc) into 3 layer-specific components. Re-export all layout/helper components
* update changeset and docs
* Update bundle size PR comment with collapsible sections
* Remove `Svg` from core (just Chart)
* Split `Foundation` scenarios into `Core (agnostic)` and `Core (layer-specific)`
* update bundle report
* Lazy load transform context (and only when used) similar to brush context
* Add ChartCore. Fix TransformContext test
* update bundle sizes in docs
* move core section above base
* Fix primitive fill/stroke for canvas primitives
* fix(Text): Render on `<Svg>` layer when only one of `x`/`y` is set
The static-mode render guard required both `x` and `y` to be explicit, so
`<Text y={-6}>` inside a positioned `<Group>` (e.g. tooltip labels in the
GeoPoint world-capitals example) was skipped on the Svg layer — Canvas
worked because it doesn't gate on coordinate validity.
Change `&&` to `||` so Text renders when either coordinate is set; the
missing one falls through to the existing `motionX`/`motionY` default of 0,
matching SVG's natural "missing coord = 0" behavior and the Canvas variant.
* fix components missing html impls (Calendar, Bars, Annotation*, etc)
* Fix Text within group
---------
Co-authored-by: Copilot <copilot@github.com>
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
* perf: Skip motion container allocation when `motion` prop is `undefined` * perf: Skip mark-info `$effect` for pixel-mode primitives * perf: Reduce per-tick reactive overhead in `Path` / `Link` (force-simulation graphs) * fix(Arc, RectClipPath, ChartClipPath): Restore on-mount tween animations * Force SVG for lattice example to verify delegation perf issue * Revert lattice svg force * Improve bundle size warnings * sort bundle scenarios by size desc * sort warnings by change desc * Revert "perf: Skip motion container allocation when `motion` prop is `undefined`" This reverts b45f47a. Empirical measurements on the lattice (n=20, 760 links) and tree force-simulation examples showed the call-site gating produced no measurable FPS difference vs. an unmodified `createMotion` — the fast path at `motion.svelte.ts:197-213` (passthrough returned when `motionProp === undefined`) already covers the no-motion case. | Example | Phase | Before | After (revert) | |----------|-------------|-----------|---------------:| | Lattice | steady sim | 6.46-6.53 | 6.52-6.58 | | Tree | active sim | 16.88-17.28 | 17.46-17.51 | The 728-line, 13-file diff added per-call-site gates and null-check fallbacks for an optimization that was already happening one layer down. Reverting restores the simpler unconditional construction. The Path.shared.svelte.ts merge keeps ee6b332's `#getPathData` hot-path getter (which is independent of the motion-alloc question) and switches the initial-pathData resolution to `resolvePathData()` to handle the polymorphic `string | () => string` form added by that commit. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com> * fix(SeriesState): Avoid `derived_inert` crash when chart unmounts under a `<svelte:boundary>` --------- Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <action@github.com>
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…s` is metadata-only
* feat(Dodge): Add Dodge component for deterministic non-overlapping layout * Simplify examples * fix(Image): Stop disabling pointer events by default. Add more examples * add timeline-bidirectional * add dense lanes example * update svelte-milestones to use relative pixel dx/dy instead of data-space values to look better when zooming * Improve svelte-milestones example * Replace `size` with `baseline` * Add text beeswarm example * feat(Text): Add `fontSize` prop with auto-derived `capHeight` * add more Dodge and ForceSimulation examples * Add dodge to layer-specific exports and add bundle scenario * Add more bundle scenarios includes Dodge * Improve examples and add note about sort order controlling stacking * Replace `rowHeight` with `rx/ry` to specify separate anchor/dodge axis values


No description provided.