npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@fundar/data-chart-telling

v0.0.64

Published

A Svelte 5 component library for building data visualisation charts, built on top of [svelteplot](https://svelteplot.dev). It provides low-level **plot** primitives (single graphs) and will grow to include higher-level **chart** compositions with titles,

Downloads

2,860

Readme

data-chart-telling

A Svelte 5 component library for building data visualisation charts, built on top of svelteplot. It provides low-level plot primitives (single graphs) and will grow to include higher-level chart compositions with titles, legends, facets, and timelines.


Build & publish

After making changes, rebuild the package distributable:

pnpm build

prepack runs svelte-package followed by publint automatically before packing, so a publish will always ship a clean build:

# dry-run — inspect what will be uploaded
pnpm pack

# publish to the npm registry
pnpm publish --access public

Bump version in package.json before each publish.


Tests

Unit tests (node)

Pure logic tests — no browser required.

pnpm test

This runs both the node unit project and the browser component project (Chromium via Playwright).

To run only the node unit tests:

pnpm vitest run --project=unit

To run only the browser component tests:

pnpm vitest run --project=browser

Storybook interaction tests

Run stories as Vitest tests (requires Storybook to boot internally):

pnpm test:stories

Storybook

Serve the component explorer locally:

pnpm storybook
# → http://localhost:6006

Build a static Storybook for deployment:

pnpm build-storybook

Chart types

Vocabulary: a plot is a single graph (axes + marks). A chart wraps a plot with a title, caption, legend, facets, and/or a timeline.

Charts

| Component | Import path | Description | | --- | --- | --- | | BarChart | $lib/charts/bar/Chart.svelte | Vertical bar chart with title/caption/legend/facet/timeline chrome. | | HeatmapChart | $lib/charts/heatmap/Chart.svelte | Grid of colour-coded cells. Colour domain is computed over the full dataset for cross-facet comparability. | | LineChart | $lib/charts/line/Chart.svelte | Line chart. Default timeline mode is upTo (cumulative reveal). | | PyramidChart | $lib/charts/pyramid/Chart.svelte | Population-pyramid-style diverging bar chart with a shared zero baseline. |

Plots

| Component | Import path | Description | | --- | --- | --- | | BarPlot | $lib/plots/bar/Plot.svelte | Vertical bar chart. Supports multiple series and per-series range segments. | | HeatmapPlot | $lib/plots/heatmap/Plot.svelte | Grid of colour-coded cells. | | LinePlot | $lib/plots/line/Plot.svelte | Line chart. Supports multiple series and per-series range segments with independent stroke styles. | | PyramidPlot | $lib/plots/pyramid/Plot.svelte | Diverging horizontal bar chart; each series is mirrored left or right of a shared zero baseline. | | GeoPlot | $lib/plots/geo/Plot.svelte | Geographic map rendered from GeoJSON/TopoJSON with optional choropleth styling and interactive markers. |

All components accept explicit width and height in pixels (svelteplot does not auto-size).


Plot props (BarPlot, LinePlot, HeatmapPlot, PyramidPlot)

Plots accept either series (pre-built Series[]) or the data + x/y/z flat-rows path — these are mutually exclusive.

| Prop | Type | Default | BarPlot | HeatmapPlot | LinePlot | PyramidPlot | | ---- | ---- | ------- | ------- | ----------- | -------- | ----------- | | width | number | — | ✅ | ✅ | ✅ | ✅ | | height | number | — | ✅ | ✅ | ✅ | ✅ | | series | Series[] | — | ✅ | ✅ | ✅ | ✅ | | data | TData[] | — | ✅ | ✅ | ✅ | ✅ | | x | Accessor | — | ✅ | ✅ | ✅ | ✅ | | y | Accessor | — | ✅ | ✅ | ✅ | ✅ | | z | Accessor | — | ✅ | ✅ | ✅ | ✅ | | segments | SegmentsConfig<TStyle> | [] | ✅ | ✅ | ✅ | ✅ | | markers | Marker[] | [] | ✅ | ✅ | ✅ | ✅ | | scales | AxisBasedScalesConfig | {} | ✅ | ✅ | ✅ | ✅ | | margins | MarginConfig | {} | ✅ | ✅ | ✅ | ✅ | | tooltip | TooltipConfig | | ✅ | ✅ | ✅ | ✅ | | styles | BasePlotStyles | | ✅ | ✅ | ✅ | ✅ |

GeoPlot props

Unlike x/y plots, GeoPlot uses GeoJSON/TopoJSON as its data source (no x/y/z axes). It accepts either a FeatureCollection, a Feature[], or a TopoJSON Topology (with the object key to specify which named object to extract).

| Prop | Type | Default | Description | | ---- | ---- | ------- | ----------- | | width | number | — | Plot width in pixels. | | height | number | — | Plot height in pixels. | | data | FeatureCollection \| Feature[] \| Topology | — | GeoJSON (FeatureCollection or Feature array) or TopoJSON Topology. | | object | string | — | Required when data is a TopoJSON Topology — the key under topology.objects to extract. | | featureId | Accessor<GeoFeature, string> | feature.id ?? feature.properties?.id ?? feature.properties?.name | Resolver for each feature's stable id (used for segments lookup and hover identification). | | value | (feature: GeoFeature) => number \| undefined | — | Optional continuous accessor for choropleth colouring (mirrors heatmap's z). | | excludeParts | (part: GeoGeometry, feature: GeoFeature) => boolean | — | Excludes matching geometry parts from rendering/hover (e.g. for inset markers). Return true to exclude. | | segments | SegmentsConfig<GeoSegmentStyle> | [] | Per-feature styling (keyed by featureId). | | markers | GeoMarker[] | [] | Array of markers: graticule, sphere, dot, vector, link, contour, inset, or custom component. | | scales | GeoScalesConfig | {} | Projection and colour scale config. | | margins | MarginConfig | {} | Top/right/bottom/left margin overrides. | | tooltip | TooltipConfig<GeoFeature> | — | Hover/click tooltip configuration. | | styles | GeoStyles<TProps> | — | Base map fill, choropleth ramp, tile layer, zoom, and click handlers. |

BasePlotStyles sub-properties (BarPlot, LinePlot, HeatmapPlot, PyramidPlot)

| Sub-prop | Type | BarPlot default | HeatmapPlot default | LinePlot default | PyramidPlot default | | -------- | ---- | --------------- | ------------------- | ---------------- | ------------------- | | styles.values.show | boolean | false | true | false (last point) | false | | styles.values.format | (v: number, seriesName: string) => string | v => \${v}`|v => `${v}`|(v, name) => `${name} - ${v}`|v => `${v}`| |styles.values.anchor|'outside' | 'start' | 'middle' | 'end'|'outside'| — |'start'|'outside'| |styles.values.dx|number| | | | | |styles.values.dy|number| | | | | |styles.values.textAnchor|'start' | 'end' | 'middle'| |'middle'| | | |styles.values.lineAnchor|'top' | 'bottom' | 'middle'| |'middle'| | | |styles.values.rotate|number| | | | | |styles.values.class|string| | | | | |styles.values.textClass|string| | | | | |styles.colors.min|string| — | cfgcontinuous.min| — | — | |styles.colors.max|string| — | cfgcontinuous.max| — | — | |styles.colors.left|string| — | — | — | palette index 0 | |styles.colors.right|string` | — | — | — | palette index 1 |

GeoStyles sub-properties (GeoPlot)

| Sub-prop | Type | Default | Description | | -------- | ---- | ------- | ----------- | | styles.fill | string | palette[0] | Base map fill for features not styled by segments or choropleth. | | styles.fillOpacity | number | 1 | Base map fill opacity. | | styles.stroke | string | cfg axis.color | Base map feature stroke colour. | | styles.strokeWidth | number | 0.5 | Base map feature stroke width. | | styles.colors.min | string | cfg continuous.min | Choropleth ramp minimum colour (when value is provided). | | styles.colors.max | string | cfg continuous.max | Choropleth ramp maximum colour (when value is provided). | | styles.tileLayer | GeoTileLayerConfig | — | XYZ raster basemap config (URL, opacity, zoom range). Mercator-family projections only. | | styles.zoom | boolean \| GeoZoomConfig | false | Enable/configure drag-pan + scroll-zoom (false = static map). | | styles.onFeatureClick | (feature: GeoFeature, event: Event) => void | — | Click handler for base-map features. |

Scales: AxisBasedScalesConfig (x/y plots) vs GeoScalesConfig (GeoPlot)

X/Y plots use AxisBasedScalesConfig with x, y, z axis configurations. GeoPlot uses GeoScalesConfig with projection and colour settings instead. ScalesConfig is the union of both (AxisBasedScalesConfig | GeoScalesConfig) — each plot kind's own scales prop narrows to whichever one applies to it.

| Prop | AxisBasedScalesConfig (BarPlot, LinePlot, HeatmapPlot, PyramidPlot) | GeoScalesConfig (GeoPlot) | | ---- | ------- | ------- | | x | ✅ (AxisScale) | ❌ | | y | ✅ (AxisScale) | ❌ | | z | ✅ (AxisScale) | ❌ | | projection | ❌ | ✅ (GeoProjectionConfig) | | color | ❌ | ✅ ({ domain?: [number, number] }) |

Props distribution across all plot kinds

| Prop | BarPlot | HeatmapPlot | LinePlot | PyramidPlot | GeoPlot | Notes | | ---- | ------- | ----------- | -------- | ----------- | ------- | ----- | | width | ✅ | ✅ | ✅ | ✅ | ✅ | Common to all plots. | | height | ✅ | ✅ | ✅ | ✅ | ✅ | Common to all plots. | | segments | ✅ | ✅ | ✅ | ✅ | ✅ | Common to all plots; GeoPlot uses SegmentsConfig<GeoSegmentStyle>, others use their own SegmentStyle type. | | markers | ✅ | ✅ | ✅ | ✅ | ✅ | Common to all plots; GeoPlot uses GeoMarker[], others use Marker[]. | | margins | ✅ | ✅ | ✅ | ✅ | ✅ | Common to all plots. | | tooltip | ✅ | ✅ | ✅ | ✅ | ✅ | Common to all plots; row type varies per plot. | | styles | ✅ | ✅ | ✅ | ✅ | ✅ | Common; type is BasePlotStyles for x/y plots, GeoStyles<TProps> for GeoPlot. | | scales | ✅ | ✅ | ✅ | ✅ | ✅ | Common; type is AxisBasedScalesConfig<TData> for x/y plots, GeoScalesConfig for GeoPlot. | | series | ✅ | ✅ | ✅ | ✅ | ❌ | X/Y plots only (mutually exclusive with data/x/y/z). | | data | ✅ (TData[]) | ✅ (TData[]) | ✅ (TData[]) | ✅ (TData[]) | ✅ (FeatureCollection | Feature[] | Topology) | Common; data shape differs — x/y plots use flat rows, GeoPlot uses geo features. | | x | ✅ | ✅ | ✅ | ✅ | ❌ | X/Y plots only. | | y | ✅ | ✅ | ✅ | ✅ | ❌ | X/Y plots only. | | z | ✅ | ✅ | ✅ | ✅ | ❌ | X/Y plots only (used as series selector in bar/line/pyramid, value accessor in heatmap). | | object | ❌ | ❌ | ❌ | ❌ | ✅ (optional) | GeoPlot only; required when data is a TopoJSON Topology. | | featureId | ❌ | ❌ | ❌ | ❌ | ✅ (optional) | GeoPlot only; resolves feature identity for segments lookup and hover. | | value | ❌ | ❌ | ❌ | ❌ | ✅ (optional) | GeoPlot only; drives choropleth colouring (analogous to heatmap's z). | | excludeParts | ❌ | ❌ | ❌ | ❌ | ✅ (optional) | GeoPlot only; filters geometry parts from rendering. |


Chart props

| Prop | Type | Default | BarChart | HeatmapChart | LineChart | PyramidChart | | ---- | ---- | ------- | -------- | ------------ | --------- | ------------ | | width | number | — | ✅ | ✅ | ✅ | ✅ | | height | number | — | ✅ | ✅ | ✅ | ✅ | | data | TRow[] | — | ✅ | ✅ | ✅ | ✅ | | x | Accessor | — | ✅ | ✅ | ✅ | ✅ | | y | Accessor | — | ✅ | ✅ | ✅ | ✅ | | z | Accessor | — | ✅ | ✅ | ✅ | ✅ | | title | string | | ✅ | ✅ | ✅ | ✅ | | subtitle | string | | ✅ | ✅ | ✅ | ✅ | | caption | string | | ✅ | ✅ | ✅ | ✅ | | header | Snippet | | ✅ | ✅ | ✅ | ✅ | | footer | Snippet | | ✅ | ✅ | ✅ | ✅ | | legend | LegendSection[] | | ✅ | ✅ | ✅ | ✅ | | segments | SegmentsConfig<TStyle> | [] | ✅ | ✅ | ✅ | ✅ | | markers | Marker[] | [] | ✅ | ✅ | ✅ | ✅ | | scales | AxisBasedScalesConfig | {} | ✅ | ✅ | ✅ | ✅ | | margins | MarginConfig | {} | ✅ | ✅ | ✅ | ✅ | | facet | FacetConfig | | ✅ | ✅ | ✅ | ✅ | | timeline | TimelineConfig | | ✅ | ✅ | ✅ | ✅ | | tooltip | TooltipProp | | ✅ | ✅ | ✅ | ✅ | | styles | BasePlotStyles | | ✅ | ✅ | ✅ | ✅ |

header and footer are Svelte 5 snippets that replace the string props when richer markup is needed (custom styles, logos, links, etc.). When header is provided it takes full precedence over title/subtitle; when footer is provided it takes full precedence over caption. Use the natural snippet syntax:

<LineChart ...>
  {#snippet header()}
    <div style="display:flex; justify-content:space-between">
      <h3 style="color:#2563eb">My Chart</h3>
      <img src="/logo.svg" alt="Logo" />
    </div>
  {/snippet}

  {#snippet footer()}
    <small>Source: <a href="...">Dataset</a> · Updated Q3 2024</small>
  {/snippet}
</LineChart>

See the BasePlotStyles sub-properties table above — charts accept the same styles shape and pass it through to their underlying plot.


Segments

The segments prop separates data ranges from visual styling. Every plot kind shares the same underlying types; the style shape (TStyle) differs per mark.

| Plot | segments type | Key structure | Lookup | | ---- | --------------- | ------------- | ------ | | LinePlot / LineChart | SegmentsConfig<LineSegmentStyle> | Named keys (series names) or 'default' | By series name (z accessor or series index). | | BarPlot / BarChart | SegmentsConfig<BarSegmentStyle> | Named keys (series names) or 'default' | By series name (z accessor or series index). | | PyramidPlot / PyramidChart | SegmentsConfig<BarSegmentStyle> | Named keys (series names) or 'default' | By series name (z accessor or series index). | | HeatmapPlot / HeatmapChart | SegmentsConfig<CellSegmentStyle> | 'default' key only | All cells (can be restricted by areas coordinates). | | GeoPlot | SegmentsConfig<GeoSegmentStyle> | Named keys (feature ids) or 'default' | By feature id (featureId accessor or derived from properties). |

Segment styles by plot:

| SegmentStyle type | Supports | Plot(s) | | --- | --- | --- | | LineSegmentStyle | stroke (line), dots (endpoint markers) | LinePlot / LineChart | | BarSegmentStyle | fill, fillOpacity | BarPlot / BarChart, PyramidPlot / PyramidChart | | CellSegmentStyle | fill, fillOpacity, stroke, strokeWidth | HeatmapPlot / HeatmapChart | | GeoSegmentStyle | fill, fillOpacity, stroke, strokeWidth | GeoPlot |

Core types

type Range           = { from?: AxisValue; to?: AxisValue };  // inclusive on both sides
type Area            = { x?: Range; y?: Range };              // 2-D rectangular region
type Segment<TStyle> = { areas?: Area[]; style?: TStyle };

A Segment matches a data point (or heatmap cell) when the point falls inside any of its areas. Omitting areas creates a catch-all that matches every data point — but catch-alls are always evaluated last, regardless of their position in the list, so area-specific segments always win. This lets a catch-all placed first act as a fallback baseline that highlighted ranges override.

An Area restricts by x, y, or both. Both bounds of a Range are inclusive. Omitting x or y leaves that axis unrestricted.

Segments structure

segments is always an array of groups. Each group is a plain object whose keys map to Segment[] lists:

// 'default' key — applies its segments to every series
type DefaultSegmentsMap<TStyle>     = { default: Segment<TStyle>[] };

// named keys — applies segments only to the named series
type SeriesAwareSegmentsMap<TStyle> = Record<string, Segment<TStyle>[]>;

// one element of the array — either form, or a mix of both key types
type SegmentsStyle<TStyle> = DefaultSegmentsMap<TStyle> | SeriesAwareSegmentsMap<TStyle>;

// the prop type: an ordered list of groups
type Segments<TStyle> = SegmentsStyle<TStyle>[];

Having multiple groups lets you organise segments by concern — for example one group for per-series stroke colours and a second for shared dot markers applied via 'default'. Groups are processed in order and their resolved segments are concatenated per series before evaluation.

Examples

Line chart — baseline colour with a highlighted range (catch-all as fallback):

<LinePlot
  {width} {height}
  series={[{ name: 'gdp', x: 'year', y: 'value', data: GDP }]}
  segments={[
    {
      gdp: [
        { style: { stroke: { stroke: '#94a3b8', strokeWidth: 1 } } },
        { areas: [{ x: { from: 2008, to: 2010 } }],
          style: { stroke: { stroke: '#ef4444', strokeWidth: 3 } } },
      ],
    },
  ]}
/>

Line chart — per-series baseline colours + shared dot markers (two-group approach):

<LinePlot
  {width} {height}
  data={LIFE_EXPECTANCY} x="year" y="value" z="sex"
  segments={[
    // Group 1: per-series catch-all stroke colours
    { female: [{ style: { stroke: { stroke: 'steelblue' } } }],
      male:   [{ style: { stroke: { stroke: 'tomato'    } } }] },
    // Group 2: dots for all series in a specific range
    { default: [
        { areas: [{ x: { from: 2010, to: 2012 } }],
          style: { dots: { dotRadius: 5, dotSymbol: 'circle' } } },
      ],
    },
  ]}
/>

Heatmap — highlight specific columns, rows, and individual cells:

<HeatmapChart
  {width} {height} {data} {x} {y} {z}
  segments={[
    {
      default: [
        { areas: [{ x: { from: 'Q1', to: 'Q1' } }, { x: { from: 'Q3', to: 'Q3' } }],
          style: { stroke: '#f59e0b', strokeWidth: 2 } },
        { areas: [{ x: { from: 'Q2', to: 'Q2' }, y: { from: 1, to: 2 } }],
          style: { fill: '#ef4444', fillOpacity: 0.8 } },
      ],
    },
  ]}
/>

GeoPlot — per-feature styling and catch-all fallback (note: GeoPlot keys are feature ids, not series names):

<GeoPlot
  {width} {height}
  data={COUNTRIES_GEOJSON}
  value={(f) => f.properties?.population}
  segments={[
    {
      // Catch-all baseline (always evaluated last)
      default: [
        { style: { fillOpacity: 0.7, stroke: '#94a3b8' } },
      ],
      // Per-feature overrides (matched by feature id)
      argentina: [
        { style: { fill: '#3b82f6', fillOpacity: 0.9 } },
      ],
      brazil: [
        { style: { fill: '#ef4444', fillOpacity: 0.9 } },
      ],
    },
  ]}
/>

Omitting segments (or passing []) renders every mark in its default palette colour.


Theming & configuration

The whole package reads its default styling — fonts, colours, spacing, legend/tooltip/axis chrome, plot geometry — from one global, reactive config store (src/lib/configuration/config.svelte.ts). Overriding it re-themes every chart on screen; nothing needs to be passed prop-by-prop to each component.

import { setConfiguration, getConfiguration, resetConfiguration } from '@fundar/data-chart-telling';

setConfiguration({
  font: '"Inter", sans-serif',
  palette: ['#4f46e5', '#e6580d', '#16a34a'],
  legend: { continuous: { label: { size: '0.8125rem', weight: 400 } } }
});

getConfiguration();   // read the live, merged config
resetConfiguration(); // restore shipped defaults
  • setConfiguration takes a deep-partial patch (ChartConfigInput) and deep-merges it into the current config — you only specify the leaves you want to change, everything else keeps its previous value. It's reactive ($state-backed), so applying it re-renders every mounted chart.
  • Call it once at app startup (or per-theme-switch); it's global, not per-chart. A single chart can still override specific visuals via its own props (styles, scales, a section's own format/color, etc.) — those always win over the global config.

How values reach the DOM

The config feeds two different consumers, and a field is one or the other, never both:

  1. CSS custom properties — configToCssVars flattens the relevant fields into --dct-* variables, which ChartContainer stamps on its own root element; every component's scoped <style> block reads them with a hardcoded fallback (e.g. font-size: var(--dct-continuous-label-size, 0.875rem)). These are the fields listed with a CSS variable below — you can also override them directly with plain CSS on a wrapping element instead of going through setConfiguration, if you only need a one-off, non-reactive tweak.
  2. Plain JS values — read directly by plot components as props svelteplot needs (numeric tick sizes, the categorical palette array, margins, gradient endpoints, hover geometry, per-mark defaults). These have no CSS variable — setConfiguration (or editing DEFAULT_CONFIG) is the only way to change them.

Reference

All types live in src/lib/types/configuration/styling.ts; all defaults in src/lib/configuration/config.svelte.ts. "CSS variable" is — for JS-only fields.

Base

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | font | string | 'inherit' | --dct-font | | color | string | 'currentColor' | --dct-fg | | background | string | 'transparent' | --dct-bg | | border | string | 'color-mix(in srgb, currentColor 15%, transparent)' | --dct-border |

Spacing

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | spacing.headerPadding | string | '0.75rem 0 1rem' | --dct-header-pad | | spacing.legendPadding | string | '0.75rem 0' | --dct-legend-pad | | spacing.captionPadding | string | '0.5rem 0' | --dct-caption-pad | | spacing.bleed | string | '12px' | --dct-bleed |

Text blocks: title, subtitle, caption

Each is a TextStyle — { font, size, weight, color, leading, spacing } — mapped to --dct-{title|subtitle|caption}-{font|size|weight|color|leading|spacing}. Shared base before per-block overrides: font: 'inherit', size: '1rem', weight: 400, color: 'inherit', leading: '1.3', spacing: 'normal'.

| Block | Overrides its own default | | ----- | -------------------------- | | title | size: '1.5rem', weight: 500, leading: '1.2' | | subtitle | size: '1rem', weight: 400, color: 'color-mix(in srgb, currentColor 85%, transparent)' | | caption | size: '0.75rem', color: 'color-mix(in srgb, currentColor 75%, transparent)' |

Legend

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | legend.font | string | 'inherit' | --dct-legend-font | | legend.size | string | '0.875rem' | --dct-legend-size | | legend.weight | number \| string | 400 | --dct-legend-weight | | legend.color | string | 'inherit' | --dct-legend-color | | legend.titleSize | string | '0.875rem' | --dct-legend-title-size | | legend.titleWeight | number \| string | 500 | --dct-legend-title-weight | | legend.gap | string (CSS gap shorthand) | '0.5rem 2rem' | --dct-legend-gap | | legend.swatchSize | string | '1.25rem' | --dct-legend-swatch | | legend.disabledOpacity | number | 0.12 | — (fallback for a legend-disabled series/value when a section doesn't set its own style) |

legend.navButton — prev/next arrows on an overflowing horizontal discrete section:

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | legend.navButton.background | string | 'transparent' | --dct-legend-nav-bg | | legend.navButton.color | string | 'currentColor' | --dct-legend-nav-color | | legend.navButton.size | string | '1.5rem' | --dct-legend-nav-size | | legend.navButton.fontSize | string | '1rem' | --dct-legend-nav-font-size | | legend.navButton.disabledOpacity | number | 0.3 | --dct-legend-nav-disabled-opacity |

legend.continuous — the gradient bar itself, its draggable handles, ticks, and labels:

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | legend.continuous.height | number (px) | 20 | — | | legend.continuous.barHeight | number (px) | 12 | — | | legend.continuous.barRadius | number (px) | 2 | — | | legend.continuous.handle.width | string | '6px' | --dct-continuous-handle-width | | legend.continuous.handle.height | string | '20px' | --dct-continuous-handle-height | | legend.continuous.handle.radius | string | '3px' | --dct-continuous-handle-radius | | legend.continuous.handle.fill | string | 'currentColor' | --dct-continuous-handle-fill | | legend.continuous.handle.stroke | string | 'var(--dct-bg, #fff)' | --dct-continuous-handle-stroke | | legend.continuous.handle.strokeWidth | string | '1.5px' | --dct-continuous-handle-stroke-width | | legend.continuous.tick.color | string | 'currentColor' | --dct-continuous-tick-color | | legend.continuous.tick.width | string | '1px' | --dct-continuous-tick-width | | legend.continuous.tick.length | string | '6px' | --dct-continuous-tick-length | | legend.continuous.label.rotate | string | '0deg' | --dct-continuous-label-rotate | | legend.continuous.label.size | string | '0.875rem' | --dct-continuous-label-size | | legend.continuous.label.weight | number \| string | 600 | --dct-continuous-label-weight |

legend.continuous.label.overlap — interactive mode only: once dragging brings the lo/hi handle labels too close to read side by side, both flip to read top-to-bottom instead of clipping or overlapping:

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | legend.continuous.label.overlap.enabled | boolean | true | — (false always keeps both labels horizontal, however close together) | | legend.continuous.label.overlap.margin | number (px) | 4 | — (horizontal slack the two labels need before they're considered overlapping) | | legend.continuous.label.overlap.rotate | string | '90deg' | --dct-continuous-label-overlap-rotate (lo rotates by this; hi by its negation, via calc(... * -1), so both still grow inward toward the bar) |

Axis

Consumed as plain numeric/boolean props by the underlying svelteplot axes — only color is also exposed as a CSS variable (used by non-plot axis-adjacent chrome).

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | axis.color | string | 'currentColor' | --dct-axis-color | | axis.fontSize | number | 14 | — | | axis.labelFontSize | number | 14 | — | | axis.titleFontSize | number | 14 | — | | axis.xTickSize | number | 5 | — | | axis.yTickSize | number | 5 | — | | axis.xTickPadding | number | 10 | — | | axis.yTickPadding | number | 10 | — | | axis.grid | boolean | false | — | | axis.locale | string | 'es-AR' | — | | axis.compactDisplay | 'short' \| 'long' | 'long' | — ('1 mil' vs '1 K') |

axis.locale/axis.compactDisplay feed svelteplot's own automatic tick formatter — the one it falls back to on any axis without its own explicit scales.x/scales.y.tickFormat. Whether a given axis abbreviates at all (vs. spelling every digit out) stays svelteplot's own per-axis call, based on that axis's value range; these two only change the wording once it decides to. axis.locale updates a chart already on screen; axis.compactDisplay is read once when a chart mounts (it goes through svelteplot's own setPlotDefaults context hook, not a per-instance prop) and needs a remount to pick up a later change.

Tooltip

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | tooltip.background | string | '#111827' | --dct-tooltip-bg | | tooltip.color | string | '#ffffff' | --dct-tooltip-color | | tooltip.fontSize | string | '0.8125rem' | --dct-tooltip-size | | tooltip.padding | string | '0.5rem 0.75rem' | --dct-tooltip-pad | | tooltip.radius | string | '0.375rem' | --dct-tooltip-radius | | tooltip.border | string | 'none' | --dct-tooltip-border |

Plot geometry & colour (all JS-only — no CSS variables)

| Field | Type | Default | | ----- | ---- | ------- | | margins.top/right/bottom/left | number \| 'auto' | 'auto' each — lets svelteplot size that side to fit whatever it actually renders there; a number pins it exactly | | palette | string[] | ['#4f46e5', '#e6580d', '#16a34a', '#dc2626', '#0891b2', '#9333ea', '#ca8a04', '#db2777'] — categorical series colours | | continuous.min / continuous.max | string | '#e0e7ff' / '#4f46e5' — heatmap/choropleth gradient endpoints | | continuous.labelColor | string | '#111827' — on-cell label colour | | line.strokeWidth | number | 3 | | line.dotRadius | number | 4 | | line.gap.stroke / line.gap.dots | StrokeStyle / DotStyle | { strokeOpacity: 0.6, strokeDasharray: '4 4' } / {} — fallback for LinePlot's styles.gaps | | line.valueLabels.elbowGap | number | 10 — shortest leader-line lane distance before it bends | | line.valueLabels.laneStep | number | 7 — extra distance each subsequent lane sits out | | line.valueLabels.labelGap | number | 6 — clearance between the outermost lane and its label | | line.valueLabels.connectorColor | string | '#94a3b8' | | line.valueLabels.connectorWidth | number | 0.5 | | bar.gap | AreaStyle | { fillOpacity: 0.5 } — fallback for BarPlot's styles.gaps | | bar.seriesPadding | number (0–1) | 0.2 — fallback scales.z.seriesPadding for grouped series | | bar.paddingInner | number (0–1) | 0.15 — gap between category groups | | bar.paddingOuter | number (0–1) | 0.15 — gap before the first / after the last group | | pyramid.gap | AreaStyle | { fillOpacity: 0.5 } — fallback for PyramidPlot's styles.gaps | | scatter.dotRadius | number | 5 | | timeline.thickness | number | 60 | | hover.rule | StrokeStyle | { stroke: '#e6580d', strokeOpacity: 0.35, strokeWidth: 1.5, strokeDasharray: '4 4' } — hover crosshair | | hover.dot | DotStyle | { dotRadius: 5, dotFill: 'currentColor' } | | hover.font | FontStyle | { fill: 'currentColor', fontSize: 12, dy: -18 } | | hover.area | AreaStyle | { fill: '#94a3b8', fillOpacity: 0.25 } — band highlight on a band scale |

timeline.axisColor / timeline.activeColor are the two exceptions in this group — they do have CSS variables (see below), since the timeline gutter is HTML chrome, not an SVG plot mark.

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | timeline.axisColor | string | 'currentColor' | --dct-timeline-axis | | timeline.activeColor | string | '#e6580d' | --dct-timeline-active |

Facet (small multiples)

| Field | Type | Default | CSS variable | | ----- | ---- | ------- | ------------- | | facet.indicator.background | string | '#111827' | --dct-facet-indicator-bg | | facet.indicator.color | string | '#ffffff' | --dct-facet-indicator-color | | facet.indicator.fontSize | string | '0.8125rem' | --dct-facet-indicator-size | | facet.indicator.padding | string | '0.125rem 0.5rem' | --dct-facet-indicator-pad | | facet.indicator.radius | string | '999px' | --dct-facet-indicator-radius | | facet.navButton.background | string | '#111827' | --dct-facet-nav-bg | | facet.navButton.color | string | '#ffffff' | --dct-facet-nav-color | | facet.navButton.size | string | '2rem' | --dct-facet-nav-btn-size | | facet.navButton.fontSize | string | '1.1rem' | --dct-facet-nav-font-size | | facet.navButton.disabledOpacity | number | 0.3 | --dct-facet-nav-disabled-opacity |


Public API

import {
  ...
} from '@fundar/data-chart-telling';