@vielzeug/codex 2.2.6 → 2.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/data/catalog.json +1693 -0
- package/data/llms-full.txt +27748 -0
- package/data/llms.txt +40 -0
- package/data/manifest.json +8 -0
- package/data/packages/arsenal.json +210 -0
- package/data/packages/assay.json +39 -0
- package/data/packages/clockwork.json +67 -0
- package/data/packages/codex.json +43 -0
- package/data/packages/coins.json +102 -0
- package/data/packages/conduit.json +60 -0
- package/data/packages/courier.json +58 -0
- package/data/packages/dnd.json +77 -0
- package/data/packages/familiar.json +40 -0
- package/data/packages/flux.json +93 -0
- package/data/packages/forge.json +84 -0
- package/data/packages/herald.json +108 -0
- package/data/packages/keymap.json +60 -0
- package/data/packages/ledger.json +57 -0
- package/data/packages/lingua.json +67 -0
- package/data/packages/necromancer.json +50 -0
- package/data/packages/orbit.json +99 -0
- package/data/packages/ore.json +73 -0
- package/data/packages/prism.json +66 -0
- package/data/packages/pulse.json +69 -0
- package/data/packages/refine.json +12 -0
- package/data/packages/ripple.json +83 -0
- package/data/packages/rune.json +79 -0
- package/data/packages/sandbox.json +40 -0
- package/data/packages/scout.json +60 -0
- package/data/packages/scroll.json +109 -0
- package/data/packages/sourcerer.json +72 -0
- package/data/packages/spell.json +133 -0
- package/data/packages/tempo.json +81 -0
- package/data/packages/vault.json +85 -0
- package/data/packages/ward.json +114 -0
- package/data/packages/wayfinder.json +110 -0
- package/data/refine.json +11926 -0
- package/data/search.json +1432 -0
- package/package.json +1 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiSource": "// Public API — all exports for @vielzeug/prism\n\nexport type { EasingFn } from './animation/easing';\nexport type { AnimationTarget } from './animation/transition';\n// Animation utilities (for plugin authors)\nexport { animate } from './animation/transition';\n// Chart factories\nexport { createAreaChart } from './charts/area';\nexport { createBarChart } from './charts/bar';\nexport { createLineChart } from './charts/line';\nexport { createPieChart } from './charts/pie';\nexport { createSparkline } from './charts/sparkline';\n// Error classes\nexport { PrismError, PrismRenderError } from './errors';\n// Interaction types (useful for plugin authors)\nexport type { LegendState } from './interaction/legend';\nexport type { TooltipState } from './interaction/tooltip';\n// Scale factories\nexport { bandScale } from './scales/band';\nexport { linearScale } from './scales/linear';\nexport { timeScale } from './scales/time';\n// SVG primitives (for plugin authors)\nexport type { Point } from './svg/path';\n// Theme utilities\nexport { resetTheme, seriesColor, setTheme } from './theme';\nexport type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';\n",
|
|
3
|
+
"docs": {
|
|
4
|
+
"index": "---\ntitle: Prism — Reactive SVG data visualization\ndescription: Reactive SVG charting library — line, bar, and area charts. Signal-driven updates, CSS-themeable, accessible.\npackage: prism\ncategory: ui\nkeywords: [chart, svg, visualization, reactive, line-chart, bar-chart, area-chart, signals, typescript]\nrelated: [ripple, refine, orbit]\nexports:\n [\n createLineChart,\n createBarChart,\n createAreaChart,\n createPieChart,\n createSparkline,\n linearScale,\n timeScale,\n bandScale,\n seriesColor,\n setTheme,\n resetTheme,\n animate,\n PrismError,\n ChartA11y,\n AnimationTarget,\n EasingFn,\n LegendState,\n TooltipState,\n ChartPluginContext,\n Point,\n ScaffoldContext,\n ScaffoldGroups,\n ChartEventHandlers,\n StackSegment,\n ]\nenvironments: [browser]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"prism\" />\n\n## Why Prism?\n\nCharting libraries typically require a framework binding, bundle heavy dependencies, or force canvas rendering that can't be styled with CSS. Prism takes a different approach:\n\n```ts\n// Before — Chart.js, imperative setup with a canvas you can't CSS-theme\nimport Chart from 'chart.js/auto';\nconst ctx = document.getElementById('myChart') as HTMLCanvasElement;\nnew Chart(ctx, {\n type: 'line',\n data: { labels, datasets: [{ data: values }] },\n // re-render manually when data changes, no signals, canvas not CSS-styleable\n});\n\n// After — Prism, declarative SVG chart driven by a signal\nimport { createLineChart } from '@vielzeug/prism';\nimport { signal } from '@vielzeug/ripple';\n\nconst data = signal([\n { key: 1, value: 12 },\n { key: 2, value: 40 },\n { key: 3, value: 28 },\n]);\nconst chart = createLineChart(document.getElementById('chart')!, {\n a11y: { ariaLabel: 'Users by day' },\n series: [{ name: 'Users', data }],\n tooltip: true,\n});\n// chart auto-updates when data.value changes — no manual re-render\ndata.value = [...data.value, { key: 4, value: 65 }];\n```\n\n| Feature | Prism | Chart.js | Lightweight Charts | D3 |\n| ------------------ | -------------------------------------------- | ---------------------------------------- | -------------------------------------------- | -------------------------------------------- |\n| Bundle size | <PackageInfo package=\"prism\" type=\"size\" /> | ~60 kB | ~45 kB | ~30 kB (core) |\n| Renderer | SVG | Canvas | Canvas | SVG/Canvas |\n| Reactive data model | Ripple signals | Plugin-specific | Plugin-specific | Manual |\n| CSS themeable | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | Limited | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n| Reactive (signals) | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Accessible SVG | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | Manual |\n| TypeScript-first | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Partial | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Types available |\n\n<div class=\"decision-callout\">\n\n**Use Prism when** you need lightweight, reactive charts that integrate with signal-based state and can be styled purely with CSS. Ideal for dashboards, admin panels, and data-heavy applications using Vielzeug.\n\n**Consider alternatives when** you need 50+ chart types (ECharts), financial trading charts (Lightweight Charts), or low-level visualization grammar (D3).\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/prism\n```\n\n```sh [npm]\nnpm install @vielzeug/prism\n```\n\n```sh [yarn]\nyarn add @vielzeug/prism\n```\n\n:::\n\n## Quick Start\n\n```ts\nimport { createLineChart } from '@vielzeug/prism';\nimport { signal } from '@vielzeug/ripple';\nimport '@vielzeug/prism/theme';\n\nconst data = signal([\n { key: 1, value: 10 },\n { key: 2, value: 25 },\n { key: 3, value: 18 },\n { key: 4, value: 32 },\n]);\n\nconst chart = createLineChart(document.getElementById('chart')!, {\n a11y: { ariaLabel: 'Revenue by month' },\n series: [{ name: 'Revenue', data, color: '#3b82f6' }],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n crosshair: true,\n onHover: (event) => console.log(event?.datum),\n});\n\n// Update data → chart re-renders automatically\ndata.value = [...data.value, { key: 5, value: 28 }];\n\n// Cleanup when done\nchart.dispose();\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- **`createLineChart(container, config)`** — line chart with linear, monotone, or step interpolation\n- **`createBarChart(container, config)`** — bar chart with four layout variants: grouped, stacked, grouped-horizontal, stacked-horizontal\n- **`createAreaChart(container, config)`** — filled area with configurable opacity\n- **`createSparkline(container, config)`** — minimal inline sparkline (line, area, or bar variant)\n- **`createPieChart(container, config)`** — pie, donut, or semi-circle donut chart\n- **`linearScale(config)`** — continuous numeric scale with nice tick generation\n- **`timeScale(config)`** — date/time scale with interval-based ticks\n- **`bandScale(config)`** — categorical scale for bar charts\n- **`MaybeSignal<T>`** — pass plain values or `@vielzeug/ripple` signals; both work seamlessly\n- **`seriesColor(index, override?)`** — resolve CSS palette color by series index\n- **`setTheme(theme)` / `resetTheme()`** — apply or clear custom colors, font, and grid tokens at runtime\n- **Event hooks** — `onClick` and `onHover` callbacks on every chart\n- **Plugin system** — extend charts with `ChartPlugin` (`install()`/`dispose()` lifecycle, each isolated from the other's failures); supported by all chart types including `createPieChart`\n- **Devtools** — `debugChart()` from `@vielzeug/prism/devtools` logs mount/resize/dispose to `console.debug`; tree-shaken from production unless imported\n- **CSS custom properties** — full theme control via `--prism-*` tokens\n- **Responsive** — auto-resizes via `ResizeObserver`\n- **Accessible** — ARIA labels and semantic SVG structure\n- **`Symbol.dispose`** — explicit resource management following TC39 proposal\n\n</div>\n\n## Sub-paths\n\n| Import | Purpose |\n| -------------------------- | ------------------------------------------------------------------------------------ |\n| `@vielzeug/prism` | All chart factories, scales, and types |\n| `@vielzeug/prism/theme` | Default CSS (custom properties + dark mode) |\n| `@vielzeug/prism/devtools` | `debugChart()` — opt-in `console.debug` lifecycle logging, tree-shaken in production |\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Ripple](/ripple/) — reactive signals that power Prism's auto-updating charts\n- [Refine](/refine/) — accessible web components that pair well with Prism for dashboards\n- [Orbit](/orbit/) — floating element positioning for chart tooltips and popovers\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
|
|
5
|
+
"api": "---\ntitle: Prism — API Reference\ndescription: Complete type signatures, parameter docs, and return values for every export in @vielzeug/prism.\n---\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| -------------------- | ----------------------------------------------------- | -------------- | -------------------------------------------------------------------------- |\n| `createLineChart()` | Reactive line chart with curves and interpolation | Sync | Container must have explicit dimensions before mount |\n| `createBarChart()` | Bar chart: grouped, stacked, horizontal variants | Sync | Use `variant` to switch layout; default is `'grouped'` |\n| `createAreaChart()` | Filled area chart | Sync | Container must have explicit dimensions before mount |\n| `linearScale()` | Continuous numeric → pixel scale | Sync | Config is not `MaybeSignal` — call again if domain/range changes |\n| `timeScale()` | Date → pixel scale | Sync | Config is not `MaybeSignal` — call again if domain/range changes |\n| `bandScale()` | Categorical → pixel band scale | Sync | Config is not `MaybeSignal` — call again if domain/range changes |\n| `createSparkline()` | Minimal inline sparkline (line/area/bar) | Sync | Defaults to decorative (`aria-hidden=\"true\"`); set `a11y` to label |\n| `createPieChart()` | Pie, donut, or semi-circle donut chart | Sync | `onClick`/`onHover` use slice signatures, not `ChartEvent` |\n| `seriesColor()` | CSS variable color for series index | Sync | Wraps at 8 colors; pass `override` to bypass the palette |\n| `setTheme()` | Apply custom palette / CSS tokens at runtime | Sync | Call before mounting charts; clears unset color slots from prior theme |\n| `resetTheme()` | Clear all custom theme overrides back to defaults | Sync | Use in test teardown or theme-switcher reset |\n| `animate()` | Animate SVG element attributes via RAF | Async (RAF) | Returns a cancel function; `duration: 0` sets attributes synchronously |\n| `debugChart()` | Wrap a `ChartHandle` with lifecycle logging | Sync | Import from `@vielzeug/prism/devtools`; tree-shaken in production |\n| `PrismError` | Base class for all prism-originated errors | — | Use `instanceof PrismError` to catch any prism error |\n| `ChartA11y` | Accessibility intent (labelled or decorative) | — | Omitting `a11y` defaults to `role=\"img\"` (scaffolded) or decorative (sparkline) |\n| `LegendState` | Live legend state object (plugin API) | — | `el` is `null` when no legend is configured |\n| `TooltipState` | Live tooltip state object (plugin API) | — | `el` is `null` when no tooltip is configured |\n| `ChartPluginContext` | Context object passed to `ChartPlugin.install()` | — | Use `disposalSignal` for plugin cleanup instead of overriding `dispose()` |\n\n## Package Entry Points\n\n| Import | Purpose |\n| -------------------------- | --------------------------------------------------------------------------- |\n| `@vielzeug/prism` | All chart factories, scales, types, and utilities |\n| `@vielzeug/prism/theme` | Default CSS custom properties (light + dark) |\n| `@vielzeug/prism/devtools` | `debugChart()` — opt-in `console.debug` lifecycle logging, tree-shaken in production |\n\n---\n\n## Chart Factories\n\n### `createLineChart`\n\n```ts\nfunction createLineChart(container: HTMLElement, config: LineChartConfig): ChartHandle;\n```\n\nCreates a reactive line chart. Supports multiple series, curve interpolation, tooltips, crosshair, and event hooks.\n\n| Parameter | Type | Description |\n| ----------- | ----------------- | --------------------------------------------------- |\n| `container` | `HTMLElement` | DOM element to render into (must have width/height) |\n| `config` | `LineChartConfig` | Chart configuration |\n\n**Returns** — [`ChartHandle`](#charthandle)\n\n---\n\n### `createBarChart`\n\n```ts\nfunction createBarChart(container: HTMLElement, config: BarChartConfig): ChartHandle;\n```\n\nCreates a reactive bar chart. Use `variant` to switch between grouped, stacked, horizontal variants.\n\n| Parameter | Type | Description |\n| ----------- | ---------------- | -------------------------- |\n| `container` | `HTMLElement` | DOM element to render into |\n| `config` | `BarChartConfig` | Chart configuration |\n\n**Returns** — [`ChartHandle`](#charthandle)\n\n---\n\n### `createAreaChart`\n\n```ts\nfunction createAreaChart(container: HTMLElement, config: AreaChartConfig): ChartHandle;\n```\n\nCreates a reactive filled area chart with configurable opacity, curve, and event hooks.\n\n| Parameter | Type | Description |\n| ----------- | ----------------- | -------------------------- |\n| `container` | `HTMLElement` | DOM element to render into |\n| `config` | `AreaChartConfig` | Chart configuration |\n\n**Returns** — [`ChartHandle`](#charthandle)\n\n---\n\n### `createPieChart`\n\n```ts\nfunction createPieChart(container: HTMLElement, config: PieChartConfig): ChartHandle;\n```\n\nCreates a pie, donut, or semi-circle donut chart. All three variants share the same `PieChartConfig` — select via `variant`.\n\n| Parameter | Type | Description |\n| ----------- | ---------------- | ----------------------------------------- |\n| `container` | `HTMLElement` | DOM element to render into (sized by CSS) |\n| `config` | `PieChartConfig` | Chart configuration |\n\n**Returns** — [`ChartHandle`](#charthandle)\n\n---\n\n### `createSparkline`\n\n```ts\nfunction createSparkline(container: HTMLElement, config: SparklineConfig): ChartHandle;\n```\n\nCreates a minimal inline chart with no axes, no legend, and no margin. Designed for use in tables, cards, and inline data contexts.\n\n| Parameter | Type | Description |\n| ----------- | ----------------- | ----------------------------------------- |\n| `container` | `HTMLElement` | DOM element to render into (sized by CSS) |\n| `config` | `SparklineConfig` | Sparkline configuration |\n\n**Returns** — [`ChartHandle`](#charthandle)\n\n---\n\n## Scale Factories\n\n### `linearScale`\n\n```ts\nfunction linearScale(config: LinearScaleConfig): Scale<number>;\n```\n\nContinuous linear scale mapping a numeric domain to a pixel range. Unlike chart config fields, scale factory config is not `MaybeSignal` — pass plain values and call `linearScale()` again if the domain/range changes.\n\n| Field | Type | Default | Description |\n| --------------- | ------------------ | ------- | ----------------------------------------------------------------- |\n| `config.domain` | `[number, number]` | — | Input data range `[min, max]`. A reversed domain (`min > max`) is supported for inverted axes. |\n| `config.range` | `[number, number]` | — | Output pixel range `[min, max]` |\n| `config.nice` | `boolean` | `true` | Extend domain to nice round numbers |\n| `config.clamp` | `boolean` | `false` | Clamp output to range bounds |\n\n---\n\n### `timeScale`\n\n```ts\nfunction timeScale(config: TimeScaleConfig): Scale<Date>;\n```\n\nTime scale mapping `Date` values to pixels. Automatically selects tick intervals (seconds → years).\n\n| Field | Type | Default | Description |\n| --------------- | ----------------- | ------- | -------------------------------- |\n| `config.domain` | `[Date, Date]` | — | Input date range `[start, end]` |\n| `config.range` | `[number, number]` | — | Output pixel range |\n| `config.nice` | `boolean` | `true` | Extend domain to nice boundaries |\n\n---\n\n### `bandScale`\n\n```ts\nfunction bandScale(config: BandScaleConfig): BandScale;\n```\n\nCategorical scale dividing the range into equal bands with configurable padding.\n\n| Field | Type | Default | Description |\n| --------------------- | ------------------ | ----------------- | ------------------------- |\n| `config.domain` | `string[]` | — | Category names |\n| `config.range` | `[number, number]` | — | Output pixel range |\n| `config.padding` | `number` | `0.1` | Inner padding ratio (0–1) |\n| `config.paddingOuter` | `number` | same as `padding` | Outer edge padding ratio |\n\n---\n\n## Types\n\n### `ChartA11y`\n\nAccessibility intent for a chart's root `<svg>` element. Discriminated union: either explicitly decorative, or labelled with an accessible name.\n\n```ts\ntype ChartA11y =\n | { readonly decorative: true }\n | {\n readonly ariaLabel: string;\n readonly decorative?: false;\n readonly description?: string;\n };\n```\n\n| Variant | Field | Type | Description |\n| ---------------------- | ------------- | -------- | ------------------------------------------------------------------------------------------------- |\n| Decorative | `decorative` | `true` | Marks the SVG `aria-hidden=\"true\"` — excluded from the accessibility tree |\n| Labelled | `ariaLabel` | `string` | Sets `role=\"img\"` + `aria-label` on the SVG; exposes the chart to assistive technology |\n| Labelled | `description` | `string` | Optional longer description; sets `aria-description` if supported |\n\n> **Default:** When `a11y` is omitted entirely, scaffolded charts (line/bar/area/pie) render with `role=\"img\"` but no `aria-label`; sparklines render as `aria-hidden=\"true\"` (decorative). Set `a11y: { ariaLabel: '…' }` to label a chart, or `a11y: { decorative: true }` to explicitly mark it decorative.\n\n---\n\n### `ChartHandle`\n\nReturned by all chart factories.\n\n```ts\ninterface ChartHandle {\n readonly disposalSignal: AbortSignal;\n readonly disposed: boolean;\n readonly el: SVGSVGElement;\n dispose(): void;\n [Symbol.dispose](): void;\n}\n```\n\n| Member | Description |\n| -------------------- | ----------------------------------------------------------------------------------------------- |\n| `el` | The root `SVGSVGElement` (for styling or external manipulation) |\n| `disposed` | `true` once `dispose()` has run; useful for guarding late callbacks |\n| `disposalSignal` | Aborted when the chart is disposed — tie your own cleanup (RAF loops, observers) to this instead of overriding `dispose()` |\n| `dispose()` | Tear down all effects, observers, DOM nodes, tooltip, and legend. Calling it more than once is a no-op |\n| `[Symbol.dispose]()` | Same as `dispose()` — for TC39 `using` declarations |\n\n> **Note:** Charts re-render automatically when signal data changes. There is no `update()` method — reactivity is fully automatic.\n\n---\n\n### `ChartEvent`\n\nPassed to `onClick` and `onHover` callbacks.\n\n```ts\ninterface ChartEvent {\n datum: Datum;\n originalEvent: Event;\n series: Series;\n}\n```\n\n---\n\n### `ChartPlugin`\n\nInterface for extending charts with custom behavior. Plugins are installed after the chart is mounted and torn down on `dispose()`.\n\n```ts\ninterface ChartPlugin {\n install(ctx: ChartPluginContext): void;\n dispose(): void;\n}\n```\n\nSee [`ChartPluginContext`](#chartplugincontext) for the object passed to `install()`.\n\n---\n\n### `BaseChartConfig`\n\nShared configuration inherited by all chart config types.\n\n```ts\ninterface BaseChartConfig {\n a11y?: ChartA11y;\n legend?: boolean | LegendConfig;\n margin?: Partial<ChartMargin>;\n onClick?: (event: ChartEvent) => void;\n onHover?: (event: ChartEvent | null) => void;\n plugins?: ChartPlugin[];\n tooltip?: boolean | TooltipConfig;\n transition?: TransitionConfig;\n xAxis?: AxisConfig;\n yAxis?: AxisConfig;\n}\n```\n\n| Field | Type | Description |\n| ------------ | ------------------------------------- | --------------------------------------- |\n| `a11y` | `ChartA11y` | Accessibility intent — labelled (`{ ariaLabel: '…' }`) or decorative (`{ decorative: true }`) |\n| `legend` | `boolean \\| LegendConfig` | Show a series legend |\n| `margin` | `Partial<ChartMargin>` | Override chart margins |\n| `onClick` | `(event: ChartEvent) => void` | Fired when a data point is clicked |\n| `onHover` | `(event: ChartEvent \\| null) => void` | Fired on mousemove (null on mouseleave) |\n| `plugins` | `ChartPlugin[]` | Extension plugins installed at mount |\n| `tooltip` | `boolean \\| TooltipConfig` | Hover tooltip |\n| `transition` | `TransitionConfig` | Enter/update animation |\n| `xAxis` | `AxisConfig` | X-axis configuration |\n| `yAxis` | `AxisConfig` | Y-axis configuration |\n\n---\n\n### `MaybeSignal<T>`\n\n```ts\ntype MaybeSignal<T> = Readable<T> | T;\n```\n\nAccepts either a plain value or a `@vielzeug/ripple` `Readable<T>` signal (e.g. one created with `signal()`). Used for `series`/`data` fields on chart configs — when a signal is passed, the chart re-renders automatically on `.value` changes. Not used by the scale factories (`linearScale`/`timeScale`/`bandScale`), whose config fields are always plain values.\n\n---\n\n### `Scale<T>`\n\n```ts\ninterface Scale<T> {\n readonly domain: readonly [T, T];\n readonly range: readonly [number, number];\n map(value: T): number;\n invert(pixel: number): T;\n ticks(count?: number): T[];\n}\n```\n\n| Member | Description |\n| --------------- | --------------------------------------------------- |\n| `domain` | Input domain `[min, max]` — readonly computed tuple |\n| `range` | Output pixel range — readonly computed tuple |\n| `map(value)` | Domain value → pixel position |\n| `invert(pixel)` | Pixel position → domain value |\n| `ticks(count?)` | Nicely-spaced tick values (default: 10) |\n\n---\n\n### `BandScale`\n\n```ts\ninterface BandScale {\n readonly domain: readonly string[];\n readonly range: readonly [number, number];\n map(value: string): number;\n bandwidth(): number;\n gap(): number;\n ticks(count?: number): string[];\n}\n```\n\n| Member | Description |\n| --------------- | --------------------------------------------------------------- |\n| `map(value)` | Left edge pixel position of a category's band |\n| `bandwidth()` | Width of each band in pixels |\n| `gap()` | Pixel gap between adjacent bands (`bandwidth × padding`) |\n| `ticks(count?)` | All domain categories, or at most `count` evenly sampled values |\n\n---\n\n### `Point`\n\n```ts\ninterface Point {\n x: number;\n y: number;\n}\n```\n\nA pixel-space 2D point used by path builders and area renderers. Exported for plugin authors who build custom SVG paths.\n\n---\n\n### `Datum`\n\nA single data point in a cartesian chart series.\n\n```ts\ninterface Datum {\n key: Date | number | string;\n value: number;\n meta?: Record<string, unknown>;\n}\n```\n\n| Field | Type | Description |\n| ------- | -------------------------- | ----------------------------------------------------------------------------------------- |\n| `key` | `Date \\| number \\| string` | X-axis identity. Use `number` or `Date` for line/area charts; `string` for bar categories |\n| `value` | `number` | Y-axis measured quantity |\n| `meta` | `Record<string, unknown>` | Optional arbitrary metadata (available in tooltip `render` callbacks) |\n\n---\n\n### `Series`\n\n```ts\ninterface Series {\n name: string;\n data: MaybeSignal<Datum[]>;\n color?: string;\n}\n```\n\n---\n\n### `AnimationTarget`\n\n```ts\ninterface AnimationTarget {\n attrs: Record<string, { from: number; to: number }>;\n el: SVGElement;\n}\n```\n\nOne element + attribute map for use with `animate()`. Each attribute entry specifies the start (`from`) and end (`to`) pixel value.\n\n---\n\n## Pie / Donut Types\n\n### `PieChartConfig`\n\nExtends [`BaseChartConfig`](#basechartconfig) (inherits `a11y`, `legend`, `plugins`, `tooltip`, `transition`). Overrides `onClick`/`onHover` with pie-specific slice signatures and omits `margin`/`xAxis`/`yAxis` (not applicable to radial charts).\n\n```ts\ninterface PieChartConfig extends Omit<BaseChartConfig, 'margin' | 'onClick' | 'onHover' | 'xAxis' | 'yAxis'> {\n cornerRadius?: number;\n data: MaybeSignal<PieSliceConfig[]>;\n innerRadius?: number;\n onClick?: (slice: PieSliceConfig, index: number) => void;\n onHover?: (slice: PieSliceConfig | null, index: number | null) => void;\n padPixels?: number;\n variant?: PieVariant;\n}\n```\n\n| Field | Type | Default | Description |\n| -------------- | ------------------------------------ | -------------------------------------- | ------------------------------------------------------- |\n| `data` | `MaybeSignal<PieSliceConfig[]>` | — | Slice definitions |\n| `variant` | `PieVariant` | `'pie'` | Chart style: `'pie'`, `'donut'`, or `'semi'` |\n| `innerRadius` | `number` | `55%` of outer (donut/semi), `0` (pie) | Inner hole radius in pixels |\n| `padPixels` | `number` | `0` (pie), `8` (donut/semi) | Pixel gap between slices (uniform across arc thickness) |\n| `cornerRadius` | `number` | `0` (pie), `8` (donut/semi) | Rounded arc corners (pixels) |\n| `onClick` | `(slice, index) => void` | — | Fired on slice click |\n| `onHover` | `(slice\\|null, index\\|null) => void` | — | Fired on hover; `null` on mouseleave |\n\n> Inherited `BaseChartConfig` fields (`tooltip`, `transition`, `legend`, `a11y`, `plugins`) behave identically to other chart types. `margin`, `xAxis`, and `yAxis` are omitted (not applicable to radial charts).\n\n### `PieSliceConfig`\n\n```ts\ninterface PieSliceConfig {\n color?: string;\n label?: string;\n value: number;\n}\n```\n\n| Field | Type | Description |\n| ------- | -------- | ------------------------------------------------- |\n| `value` | `number` | Numeric weight of the slice |\n| `color` | `string` | Slice fill color; defaults to `--prism-color-{n}` |\n| `label` | `string` | Optional text rendered at the arc centroid |\n\n### `PieVariant`\n\n```ts\ntype PieVariant = 'donut' | 'pie' | 'semi';\n```\n\n- **`pie`** — full circle, no hole\n- **`donut`** — full circle with inner hole (~55% of outer radius by default)\n- **`semi`** — top-half semicircle with inner hole (useful for gauges/progress)\n\n---\n\n## Sparkline Types\n\n### `SparklineConfig`\n\n```ts\ninterface SparklineConfig {\n a11y?: ChartA11y;\n color?: string;\n cornerRadius?: number;\n curve?: 'linear' | 'monotone' | 'step';\n data: MaybeSignal<number[] | StackSegment[]>;\n fillOpacity?: number;\n onClick?: (index: number, value: number) => void;\n onHover?: (index: number | null, value: number | null) => void;\n padPixels?: number;\n strokeWidth?: number;\n transition?: TransitionConfig;\n variant?: SparklineVariant;\n}\n```\n\n| Field | Type | Default | Description |\n| -------------- | ----------------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------- |\n| `data` | `MaybeSignal<number[] \\| StackSegment[]>` | — | Numeric values, or `StackSegment[]` for `'stack'` variant |\n| `variant` | `SparklineVariant` | `'line'` | Chart style |\n| `a11y` | `ChartA11y` | decorative | Accessibility intent — labelled (`{ ariaLabel: '…' }`) or decorative (`{ decorative: true }`). Defaults to decorative when omitted |\n| `color` | `string` | `var(--prism-color-1)` | Stroke/fill color (line/area/bar only) |\n| `curve` | `'linear' \\| 'monotone' \\| 'step'` | `'linear'` | Line interpolation (line/area only) |\n| `strokeWidth` | `number` | `1.5` | Line stroke width (line/area only) |\n| `fillOpacity` | `number` | `0.2` | Fill opacity (area only) |\n| `cornerRadius` | `number` | `4` | Rounded corners for stack segments in pixels. Stack variant only — no effect on line/area/bar |\n| `padPixels` | `number` | `0` | Gap between stack segments in pixels. Stack variant only — no effect on line/area/bar |\n| `transition` | `TransitionConfig` | — | Enter animation (bar/stack only; line/area use RAF interpolation) |\n| `onClick` | `(index, value) => void` | — | Called on click with nearest data index. Not fired for 0- or 1-point data |\n| `onHover` | `(index\\|null, value\\|null) => void` | — | Called on mousemove; `null` on mouseleave. Not fired for 0- or 1-point data |\n\n### `SparklineVariant`\n\n```ts\ntype SparklineVariant = 'area' | 'bar' | 'line' | 'stack';\n```\n\n- **`line`** — polyline path (default)\n- **`area`** — filled area + line overlay\n- **`bar`** — vertical bar per data point\n- **`stack`** — horizontal proportional segments; use `StackSegment[]` for `data` with per-segment colors\n\n### `StackSegment`\n\n```ts\ninterface StackSegment {\n color?: string;\n label?: string;\n value: number;\n}\n```\n\n> **Accessibility:** Without `a11y` the SVG is marked `aria-hidden=\"true\"` (decorative). Set `a11y: { ariaLabel: '…' }` to expose the chart to assistive technology — the SVG will carry `role=\"img\"` and the provided label.\n\n---\n\n## Chart Config Types\n\n### `LineChartConfig`\n\nExtends [`BaseChartConfig`](#basechartconfig).\n\n```ts\ninterface LineChartConfig extends BaseChartConfig {\n series: MaybeSignal<LineSeriesConfig[]>;\n crosshair?: boolean | CrosshairConfig;\n}\n```\n\n### `LineSeriesConfig`\n\n```ts\ninterface LineSeriesConfig extends Series {\n curve?: 'linear' | 'monotone' | 'step'; // default: 'linear'\n strokeWidth?: number; // default: 2\n showPoints?: boolean; // default: false\n pointRadius?: number; // default: 3\n}\n```\n\n---\n\n### `BarChartConfig`\n\nExtends [`BaseChartConfig`](#basechartconfig).\n\n```ts\ntype BarVariant =\n | 'grouped' // vertical grouped (default)\n | 'stacked' // vertical stacked\n | 'grouped-horizontal' // horizontal grouped\n | 'stacked-horizontal'; // horizontal stacked\n\ninterface BarChartConfig extends BaseChartConfig {\n series: MaybeSignal<BarSeriesConfig[]>;\n variant?: BarVariant; // default: 'grouped'\n}\n```\n\n### `BarSeriesConfig`\n\n```ts\ninterface BarSeriesConfig extends Series {\n borderRadius?: number; // default: 0\n}\n```\n\n---\n\n### `AreaChartConfig`\n\nExtends [`BaseChartConfig`](#basechartconfig).\n\n```ts\ninterface AreaChartConfig extends BaseChartConfig {\n series: MaybeSignal<AreaSeriesConfig[]>;\n crosshair?: boolean | CrosshairConfig;\n}\n```\n\n### `AreaSeriesConfig`\n\n```ts\ninterface AreaSeriesConfig extends Series {\n curve?: 'linear' | 'monotone' | 'step'; // default: 'linear'\n fillOpacity?: number; // default: 0.3\n showLine?: boolean; // default: true\n}\n```\n\n---\n\n## Shared Config Types\n\n### `AxisConfig`\n\n```ts\ninterface AxisConfig {\n position?: AxisPosition; // defaults to 'bottom' for xAxis, 'left' for yAxis\n tickCount?: number;\n tickFormat?: (value: Date | number | string) => string;\n label?: string;\n grid?: boolean | GridConfig;\n}\n```\n\n### `GridConfig`\n\n```ts\ninterface GridConfig {\n color?: string;\n dash?: string; // SVG stroke-dasharray value, e.g. '4 2'\n}\n```\n\n### `TooltipConfig`\n\n```ts\ninterface TooltipConfig {\n offset?: number; // default: 8\n render?: (datum: Datum, series: Series) => string; // returns HTML string\n sanitize?: (html: string) => string; // applied before innerHTML injection\n}\n```\n\nThe tooltip is appended inside the chart container (not `document.body`), so it is automatically scoped and cleaned up on `dispose()`.\n\n> ⚠️ **Security:** The string returned by `render` is injected via `innerHTML`. Pass `sanitize` to apply a sanitizer (e.g. DOMPurify) before injection, or ensure all user-supplied values are escaped before interpolation. A `warn` is emitted in development when `render` is set without `sanitize`.\n\n### `CrosshairConfig`\n\n```ts\ninterface CrosshairConfig {\n vertical?: boolean; // default: true\n horizontal?: boolean; // default: false\n snap?: boolean; // default: true\n}\n```\n\n### `LegendConfig`\n\n```ts\ninterface LegendConfig {\n position?: 'top' | 'bottom' | 'left' | 'right'; // default: 'bottom'\n}\n```\n\n### `TransitionConfig`\n\n```ts\ninterface TransitionConfig {\n duration?: number; // ms, default: 300\n easing?: 'linear' | 'ease-in' | 'ease-out' | 'ease-in-out' | ((t: number) => number);\n preference?: 'always' | 'never' | 'system'; // respects `prefers-reduced-motion` when `'system'`\n stagger?: number; // ms delay between bar enter animations, default: 0\n}\n```\n\n> **`stagger`** applies only to bar chart enter animations — new bars grow in sequence with a `stagger`ms delay between each one.\n\n### `ChartMargin`\n\n```ts\ninterface ChartMargin {\n top: number; // default: 20\n right: number; // default: 20\n bottom: number; // default: 40\n left: number; // default: 50\n}\n```\n\n### `ChartDimensions`\n\n```ts\ninterface ChartDimensions {\n height: number;\n margin: ChartMargin;\n width: number;\n}\n```\n\n### `AxisPosition`\n\n```ts\ntype AxisPosition = 'bottom' | 'left' | 'right' | 'top';\n```\n\n### `LegendPosition`\n\n```ts\ntype LegendPosition = 'bottom' | 'left' | 'right' | 'top';\n```\n\n### `PrismTheme`\n\n```ts\ninterface PrismTheme {\n colors?: string[];\n fontFamily?: string;\n gridColor?: string;\n gridOpacity?: number;\n}\n```\n\n### `BarVariant`\n\n```ts\ntype BarVariant = 'grouped' | 'grouped-horizontal' | 'stacked' | 'stacked-horizontal';\n```\n\n---\n\n## Utilities\n\n### `seriesColor`\n\n```ts\nfunction seriesColor(index: number, override?: string): string;\n```\n\nReturns the CSS variable reference for palette color at `index` (wraps at 8). If `override` is provided it is returned as-is. Used internally by all chart factories.\n\n```ts\nimport { seriesColor } from '@vielzeug/prism';\n\nseriesColor(0); // 'var(--prism-color-1)'\nseriesColor(0, '#ff0'); // '#ff0'\n```\n\n### `setTheme`\n\n```ts\ninterface PrismTheme {\n colors?: string[]; // replaces --prism-color-1 … -8\n fontFamily?: string; // sets --prism-font-family\n gridColor?: string; // sets --prism-grid-color\n gridOpacity?: number; // sets --prism-grid-opacity\n}\n\nfunction setTheme(theme: PrismTheme): void;\n```\n\nApplies CSS custom properties to `document.documentElement`. Call once at app startup before mounting charts. Setting `colors` clears any unset color slots left over from a previous `setTheme()` call, so a theme with fewer colors than the last one doesn't leave stale high-index colors behind.\n\n```ts\nimport { setTheme } from '@vielzeug/prism';\n\nsetTheme({ colors: ['#6366f1', '#22d3ee', '#f59e0b', '#10b981'] });\n```\n\n### `resetTheme`\n\n```ts\nfunction resetTheme(): void;\n```\n\nClears every CSS custom property `setTheme()` can set, restoring prism's default theme (from `@vielzeug/prism/theme`). Useful for test teardown or a theme-switcher's \"reset to default\" action.\n\n```ts\nimport { resetTheme, setTheme } from '@vielzeug/prism';\n\nsetTheme({ colors: ['#6366f1'] });\nresetTheme(); // back to the default palette\n```\n\n> `seriesColor`, `setTheme`, and `resetTheme` are all exported from `@vielzeug/prism` (not from the `/theme` CSS subpath).\n\n---\n\n## Interaction Types\n\n> Exported from `@vielzeug/prism` for use in plugins and custom chart extensions. Both types reflect the live state object created internally; `el` is `null` when no legend/tooltip is configured.\n\n### `LegendState`\n\n```ts\ninterface LegendState {\n dispose(): void;\n [Symbol.dispose](): void;\n el: HTMLDivElement | null;\n update(series: { color: string; name: string }[]): void;\n}\n```\n\nThe live legend object available on `ctx.legend` inside `ChartPlugin.install`. Call `update()` to re-render legend items, `dispose()` to remove the element.\n\n### `TooltipState`\n\n```ts\ninterface TooltipState {\n dispose(): void;\n [Symbol.dispose](): void;\n el: HTMLDivElement | null;\n hide(): void;\n show(x: number, y: number, datum: Datum, series: Series): void;\n}\n```\n\nThe live tooltip object available on `ctx.tooltip` inside `ChartPlugin.install`. `x`/`y` are pixel coordinates relative to the chart area; `show()` positions and renders the tooltip.\n\n---\n\n### `ChartPluginContext`\n\n```ts\ninterface ChartPluginContext {\n container: HTMLElement;\n dimensions: Readable<ChartDimensions>;\n disposalSignal: AbortSignal;\n svg: SVGSVGElement;\n}\n```\n\nPassed to `ChartPlugin.install(ctx)`. Gives plugins access to the reactive `dimensions` signal, the host `container`, the root `svg` element, and a `disposalSignal` aborted when the chart is torn down.\n\n```ts\nimport type { ChartPlugin } from '@vielzeug/prism';\nimport { effect } from '@vielzeug/ripple';\n\nconst watermarkPlugin: ChartPlugin = {\n dispose() {},\n install(ctx) {\n // React to size changes\n effect(() => {\n const { width, height } = ctx.dimensions.value;\n /* re-layout watermark */\n });\n },\n};\n```\n\n> **Note:** To observe future resize events use `effect(() => { ctx.dimensions.value; })` from `@vielzeug/ripple` within a reactive scope. To run cleanup when the chart is disposed without relying on your own `dispose()` implementation being called, add a listener to `ctx.disposalSignal` instead: `ctx.disposalSignal.addEventListener('abort', cleanup)`.\n>\n> **Error isolation:** if a plugin's `install()` or `dispose()` throws, the error is logged (dev builds only) and the rest of the chart — and any other installed plugins — continues to work. A throwing plugin never aborts chart creation or teardown.\n\n---\n\n## Animation Utilities\n\n> Exported from `@vielzeug/prism` for use in plugins and custom chart extensions.\n\n### `animate`\n\n```ts\nfunction animate(\n targets: AnimationTarget[],\n config?: TransitionConfig,\n onComplete?: () => void,\n signal?: AbortSignal,\n): () => void;\n```\n\nAnimates SVG element attributes from `from` to `to` values over the given `TransitionConfig` duration. Calls `onComplete` when all animations finish. Returns a cancel function — call it to stop the in-flight animation early (its `requestAnimationFrame` loop is cancelled and `onComplete` is not called).\n\n- **Empty targets or `duration: 0`** — attributes are set immediately and `onComplete` is called synchronously; no RAF is scheduled. The returned cancel function is a no-op in this case.\n- **Negative `stagger`** — clamped to `0`; all elements animate in parallel.\n- **`signal`** — if provided and already aborted (or aborted mid-animation), the RAF loop stops rescheduling itself on its next frame, same effect as calling the returned cancel function.\n\n**Parameters — `AnimationTarget`:**\n\n| Field | Type | Description |\n| ------- | ---------------------------------------------- | --------------------------------- |\n| `el` | `SVGElement` | Target element |\n| `attrs` | `Record<string, { from: number; to: number }>` | Attribute name → start/end values |\n\n```ts\nimport { animate } from '@vielzeug/prism';\n\nconst cancel = animate([{ attrs: { opacity: { from: 0, to: 1 } }, el: rect }], { duration: 300, easing: 'ease-out' });\n\n// Stop early if the element is removed before the animation completes:\ncancel();\n```\n\n### `EasingFn`\n\n```ts\ntype EasingFn = (t: number) => number;\n```\n\nA custom easing function. Receives a normalised time value `t ∈ [0, 1]` and returns a progress value (also typically `[0, 1]`). Pass as `TransitionConfig.easing`. Unknown or invalid easing name strings fall back to `'ease-out'` rather than throwing.\n\n---\n\n## Devtools\n\n> **Import:** `@vielzeug/prism/devtools`\n\nOpt-in debug logging, separate from the internal dev-mode validation warnings in `_dev.ts` (those run automatically and need no import). Tree-shaken from production bundles when this sub-path isn't imported — there is no environment gate to configure.\n\n### `debugChart`\n\n```ts\ninterface DebugChartOptions {\n label?: string; // defaults to 'chart', producing log prefixes like [prism:chart]\n}\n\nfunction debugChart<T extends ChartHandle>(handle: T, options?: DebugChartOptions): T;\n```\n\nWraps an already-created `ChartHandle` with lifecycle logging to `console.debug`. Logs the chart's mount, every resize (via its own `ResizeObserver` on `handle.el`, independent of the chart's internal one), and disposal — each prefixed with `[prism:<label>]`. Returns the same handle unchanged, so it can wrap any `create*Chart()` call in place.\n\n```ts\nimport { createLineChart } from '@vielzeug/prism';\nimport { debugChart } from '@vielzeug/prism/devtools';\n\nconst chart = debugChart(createLineChart(container, config), { label: 'revenue' });\n// [prism:revenue] mounted\n// [prism:revenue] resized 600×300\nchart.dispose();\n// [prism:revenue] disposed\n```\n\n---\n\n## Errors\n\n### `PrismError`\n\nBase class for all prism errors. Use `instanceof PrismError` to catch any prism-originated error.\n\n```ts\nclass PrismError extends Error {}\n```\n\n**Named subclasses**\n\n| Class | Thrown when |\n| -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |\n| `PrismRenderError` | A chart is given a structurally invalid configuration it cannot render at all (e.g. a non-`Element` `container`). Recoverable issues like empty or malformed data emit a dev-mode warning instead — they do not throw. |\n",
|
|
6
|
+
"usage": "---\ntitle: Prism — Usage Guide\ndescription: Concepts, patterns, and best practices for @vielzeug/prism — reactive SVG charts.\n---\n\n[[toc]]\n\n## Basic Usage\n\nEvery chart needs a container element with defined dimensions and the theme CSS:\n\n```ts\nimport { createLineChart } from '@vielzeug/prism';\nimport '@vielzeug/prism/theme';\n\nconst container = document.querySelector<HTMLElement>('#chart')!;\nconst chart = createLineChart(container, {\n series: [\n {\n name: 'Revenue',\n data: [\n { key: 1, value: 10 },\n { key: 2, value: 16 },\n ],\n },\n ],\n});\n\nchart.dispose();\n```\n\n```html\n<div id=\"chart\" style=\"width: 100%; height: 300px;\"></div>\n```\n\nPrism observes the container size via `ResizeObserver` and re-renders automatically on resize. If the container has zero dimensions at mount time, a `warn` is emitted in development — ensure the container has layout before calling the chart factory.\n\n## Reactivity with Signals\n\nPrism accepts both plain values and `@vielzeug/ripple` signals for any data property. When a signal changes, the chart re-renders automatically in the next animation frame.\n\n### Static Data\n\n```ts\nimport { createLineChart } from '@vielzeug/prism';\n\nconst chart = createLineChart(container, {\n series: [\n {\n name: 'Static',\n data: [\n { key: 1, value: 10 },\n { key: 2, value: 20 },\n ],\n },\n ],\n});\n```\n\n### Reactive Data\n\n```ts\nimport { createLineChart } from '@vielzeug/prism';\nimport { signal } from '@vielzeug/ripple';\n\nconst data = signal([\n { key: 1, value: 10 },\n { key: 2, value: 20 },\n]);\n\nconst chart = createLineChart(container, {\n series: [{ name: 'Live', data }],\n});\n\n// Later — chart updates automatically\ndata.value = [...data.value, { key: 3, value: 30 }];\n```\n\n### The `MaybeSignal<T>` Pattern\n\nAll data-bearing config fields use the `MaybeSignal<T>` type:\n\n```ts\ntype MaybeSignal<T> = Readable<T> | T;\n```\n\nPass a plain value when data is fixed, or a `@vielzeug/ripple` signal when it changes dynamically. The chart handles both identically.\n\n## Line Charts\n\n```ts\nimport { createLineChart } from '@vielzeug/prism';\n\nconst chart = createLineChart(container, {\n series: [\n {\n name: 'Revenue',\n data: [\n { key: 1, value: 100 },\n { key: 2, value: 150 },\n { key: 3, value: 130 },\n ],\n color: '#3b82f6',\n curve: 'monotone', // 'linear' | 'monotone' | 'step'\n strokeWidth: 2,\n showPoints: true,\n pointRadius: 4,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n crosshair: true,\n});\n```\n\n### Multiple Series\n\n```ts\nconst chart = createLineChart(container, {\n series: [\n { name: 'Revenue', data: revenueData, color: '#3b82f6' },\n { name: 'Expenses', data: expenseData, color: '#ef4444' },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n});\n```\n\n### Time-based X Axis\n\nWhen data points use `Date` objects for `key`, Prism automatically applies a time scale:\n\n```ts\nconst chart = createLineChart(container, {\n series: [\n {\n name: 'Signups',\n data: [\n { key: new Date('2024-01-01'), value: 50 },\n { key: new Date('2024-02-01'), value: 80 },\n { key: new Date('2024-03-01'), value: 120 },\n ],\n },\n ],\n xAxis: { position: 'bottom', tickFormat: (d) => (d as Date).toLocaleDateString() },\n yAxis: { position: 'left' },\n});\n```\n\n## Bar Charts\n\n```ts\nimport { createBarChart } from '@vielzeug/prism';\n\nconst chart = createBarChart(container, {\n series: [\n {\n name: 'Sales',\n data: [\n { key: 'Q1', value: 200 },\n { key: 'Q2', value: 350 },\n { key: 'Q3', value: 280 },\n { key: 'Q4', value: 400 },\n ],\n borderRadius: 4,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n});\n```\n\n### Variants\n\nSelect the bar layout with `variant`:\n\n| Value | Layout |\n| ---------------------- | -------------------------- |\n| `'grouped'` | Vertical grouped (default) |\n| `'stacked'` | Vertical stacked |\n| `'grouped-horizontal'` | Horizontal grouped |\n| `'stacked-horizontal'` | Horizontal stacked |\n\n> **Note:** `tooltip` and `legend` are always available on the scaffold — omitting them uses a no-op null-object internally, so no conditional checks are needed in plugins or custom render logic.\n\n```ts\nconst chart = createBarChart(container, {\n variant: 'stacked',\n series: [\n { name: 'Mobile', data: mobileData, color: '#3b82f6', borderRadius: 0 },\n { name: 'Desktop', data: desktopData, color: '#10b981', borderRadius: 0 },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n legend: true,\n});\n```\n\nFor horizontal layouts, categories appear on the Y axis and values on the X axis:\n\n```ts\nconst chart = createBarChart(container, {\n variant: 'grouped-horizontal',\n series: [{ name: 'Revenue', data, color: '#3b82f6' }],\n xAxis: { position: 'bottom', grid: true },\n yAxis: { position: 'left' },\n});\n```\n\n### Grouped Bars\n\nMultiple series with `variant: 'grouped'` (default) render side-by-side:\n\n```ts\nconst chart = createBarChart(container, {\n series: [\n { name: '2023', data: lastYearData, color: '#94a3b8' },\n { name: '2024', data: thisYearData, color: '#3b82f6' },\n ],\n});\n```\n\n## Area Charts\n\n```ts\nimport { createAreaChart } from '@vielzeug/prism';\n\nconst chart = createAreaChart(container, {\n series: [\n {\n name: 'Users',\n data: userData,\n curve: 'monotone',\n fillOpacity: 0.2,\n showLine: true,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n crosshair: true,\n});\n```\n\n## Pie, Donut, and Semi-circle Charts\n\nAll three variants use `createPieChart` with the `variant` field:\n\n```ts\nimport { createPieChart } from '@vielzeug/prism';\n\nconst chart = createPieChart(container, {\n data: [\n { label: 'Direct', value: 42, color: '#3b82f6' },\n { label: 'Organic', value: 28, color: '#10b981' },\n { label: 'Referral', value: 18, color: '#f59e0b' },\n { label: 'Social', value: 12, color: '#8b5cf6' },\n ],\n variant: 'donut', // 'pie' | 'donut' | 'semi'\n tooltip: true,\n transition: { duration: 400, easing: 'ease-out' },\n});\n```\n\n### Variants\n\n| Value | Shape |\n| --------- | ------------------------------------------------------- |\n| `'pie'` | Full circle, no hole |\n| `'donut'` | Full circle with inner hole (~55% of outer by default) |\n| `'semi'` | Top-half semicircle with inner hole — useful for gauges |\n\n### Inner Radius\n\n`innerRadius` overrides the automatic calculation:\n\n```ts\ncreatePieChart(container, {\n data,\n variant: 'donut',\n innerRadius: 60, // explicit pixels\n});\n```\n\n### Slice Labels\n\nSet `label` on each `PieSliceConfig` to render text at the arc centroid:\n\n```ts\n{ value: 42, label: '42%' }\n```\n\nStyle labels via CSS:\n\n```css\n:root {\n --prism-pie-label-color: #fff;\n --prism-pie-label-size: 11px;\n}\n```\n\n### Reactive Data\n\n```ts\nimport { signal } from '@vielzeug/ripple';\n\nconst data = signal([\n { label: 'A', value: 40 },\n { label: 'B', value: 60 },\n]);\n\nconst chart = createPieChart(container, { data, variant: 'donut' });\n\ndata.value = [\n { label: 'A', value: 55 },\n { label: 'B', value: 45 },\n];\n```\n\n### Event Hooks\n\n```ts\ncreatePieChart(container, {\n data,\n onHover: (slice, index) => {\n // slice/index are null on mouseleave\n if (slice) console.log(slice.label, slice.value);\n },\n onClick: (slice, index) => {\n console.log('clicked', slice.label);\n },\n});\n```\n\n## Sparklines\n\nSparklines are minimal inline charts with no axes, no legend, and no margin — designed to live inline with text or inside table cells.\n\n```ts\nimport { createSparkline } from '@vielzeug/prism';\n\nconst spark = createSparkline(container, {\n data: [12, 18, 14, 22, 19, 28],\n variant: 'line', // 'line' | 'area' | 'bar' (default: 'line')\n color: '#3b82f6',\n curve: 'monotone',\n strokeWidth: 1.5,\n});\n\nspark.dispose();\n```\n\n### Variants\n\n- **`line`** — simple polyline path (default)\n- **`area`** — filled area + line overlay\n- **`bar`** — vertical bar for each data point\n- **`stack`** — horizontal proportional segments; use `StackSegment[]` for `data` with per-segment colors\n\n### Reactive Data\n\n```ts\nimport { signal } from '@vielzeug/ripple';\n\nconst data = signal([12, 18, 14, 22]);\n\nconst spark = createSparkline(container, { data, variant: 'area' });\n\ndata.value = [...data.value, 30]; // re-renders automatically\n```\n\n### Event Hooks\n\nSparklines use simplified hooks — index-based rather than full `ChartEvent`:\n\n```ts\nconst spark = createSparkline(container, {\n data: [10, 20, 30],\n onHover: (index, value) => {\n // index/value are null on mouseleave\n if (index !== null) console.log(`Hovering point ${index}: ${value}`);\n },\n onClick: (index, value) => {\n console.log(`Clicked point ${index}: ${value}`);\n },\n});\n```\n\n> **Note:** Sparkline SVGs are marked `aria-hidden=\"true\"` since they are decorative. Provide meaningful surrounding text context for accessibility.\n\n## Axes and Grid\n\n```ts\n{\n xAxis: {\n position: 'bottom', // 'top' | 'bottom'\n tickCount: 5,\n tickFormat: (v) => `$${v}`,\n label: 'Month',\n grid: true, // or { color: '#ddd', dash: '4 2' }\n },\n yAxis: {\n position: 'left', // 'left' | 'right'\n grid: { color: '#f0f0f0' },\n label: 'Revenue ($)',\n },\n}\n```\n\n## Tooltips\n\nEnable with `tooltip: true` for default rendering, or provide a custom `render` function returning an HTML string:\n\n```ts\n{\n tooltip: {\n offset: 12,\n render: (datum, series) => `\n <strong>${series.name}</strong><br/>\n Value: ${datum.value.toLocaleString()}\n `,\n },\n}\n```\n\nThe `render` output is injected via `innerHTML`. If you interpolate user-supplied data, pass a `sanitize` function to guard against XSS:\n\n```ts\nimport DOMPurify from 'dompurify';\n\n{\n tooltip: {\n render: (datum, series) => `<b>${series.name}</b>: ${datum.value}`,\n sanitize: (html) => DOMPurify.sanitize(html),\n },\n}\n```\n\nThe tooltip element is scoped inside the chart container (not `document.body`) and is removed automatically on `dispose()`.\n\n## Crosshair\n\nA vertical guide that snaps to the nearest data point:\n\n```ts\n{\n crosshair: true,\n // or configure:\n crosshair: { vertical: true, horizontal: true, snap: true },\n}\n```\n\n## Legend\n\nEnable with `legend: true` (defaults to `bottom`) or configure position:\n\n```ts\n{\n legend: true,\n // or:\n legend: { position: 'top' }, // 'top' | 'bottom' | 'left' | 'right'\n}\n```\n\nThe legend renders as a `div` placed outside the SVG. Each item shows a color swatch and the series `name`. Customize via CSS:\n\n```css\n:root {\n --prism-legend-gap: 1rem;\n --prism-legend-dot-size: 0.5rem;\n --prism-legend-font-size: 0.75rem;\n}\n```\n\n## Event Hooks\n\nAll charts expose `onClick` and `onHover` callbacks on the config:\n\n```ts\nconst chart = createLineChart(container, {\n series: [{ name: 'Revenue', data }],\n onHover: (event) => {\n // event is ChartEvent | null (null on mouseleave)\n if (event) console.log(event.datum, event.series);\n },\n onClick: (event) => {\n console.log('clicked', event.datum);\n },\n});\n```\n\n`ChartEvent` provides:\n\n- `datum` — the nearest `Datum`\n- `series` — the corresponding `Series` config\n- `originalEvent` — the raw `MouseEvent`\n\n> **Pie chart events differ** — `onHover` and `onClick` receive `(slice: PieSliceConfig, index: number)` instead of `ChartEvent`. See [`PieChartConfig`](./api.md#piechartconfig) for details.\n\n## Plugins\n\nExtend any chart with custom behavior using the `ChartPlugin` interface. All chart types — including `createPieChart` — support `plugins`.\n\n```ts\nimport type { ChartPlugin } from '@vielzeug/prism';\n\nfunction createClickLogger(): ChartPlugin {\n const handler = (e: MouseEvent) => console.log('chart clicked', e);\n // `dispose()` receives no arguments, so capture whatever `install()` needs\n // to clean up (here, the svg it attached the listener to) in this closure.\n let svg: SVGSVGElement | undefined;\n\n return {\n install(ctx) {\n svg = ctx.svg;\n svg.addEventListener('click', handler);\n },\n dispose() {\n svg?.removeEventListener('click', handler);\n },\n };\n}\n\nconst chart = createLineChart(container, {\n series: [{ name: 'Revenue', data }],\n plugins: [createClickLogger()],\n});\n\n// Works for pie charts too:\nconst pie = createPieChart(container, {\n data,\n plugins: [createClickLogger()],\n});\n```\n\n> **Alternative to `dispose()`:** `install(ctx)` can instead listen for `ctx.disposalSignal`'s `abort` event to run cleanup, without needing to capture anything for a separate `dispose()` implementation: `ctx.disposalSignal.addEventListener('abort', () => svg.removeEventListener('click', handler))`.\n>\n> **Error isolation:** if a plugin's `install()` or `dispose()` throws, the error is logged in development and the rest of the chart — plus any other installed plugins — keeps working. A throwing plugin never aborts chart creation or teardown.\n\n## Animations\n\nPass a `transition` config to animate enter and update transitions:\n\n```ts\n{\n transition: {\n duration: 400,\n easing: 'ease-out',\n stagger: 30, // bar charts only: ms delay between each bar's enter animation\n },\n}\n```\n\nAll chart types use requestAnimationFrame-based interpolation. Bar charts additionally support `stagger` — a per-bar delay that creates a cascade effect on first render.\n\n## Theming\n\nImport the default theme:\n\n```ts\nimport '@vielzeug/prism/theme';\n```\n\n### Programmatic Theme with `setTheme`\n\nCall `setTheme` once at app startup to apply custom tokens programmatically:\n\n```ts\nimport { setTheme } from '@vielzeug/prism';\n\nsetTheme({\n colors: ['#6366f1', '#22d3ee', '#f59e0b', '#10b981'], // replaces --prism-color-1 through -4\n fontFamily: 'Inter, system-ui, sans-serif', // sets --prism-font-family\n gridColor: '#e2e8f0', // sets --prism-grid-color\n gridOpacity: 0.6, // sets --prism-grid-opacity\n});\n```\n\n`setTheme` writes to `document.documentElement` style, so it takes precedence over CSS file defaults. Call `resetTheme()` to clear every custom property `setTheme` can set and restore the default theme — useful for a theme-switcher's \"reset\" action or test teardown:\n\n```ts\nimport { resetTheme } from '@vielzeug/prism';\n\nresetTheme();\n```\n\n### Custom Theme (CSS)\n\n```css\n:root {\n --prism-color-1: #6366f1;\n --prism-color-2: #22c55e;\n --prism-axis-color: #71717a;\n --prism-grid-color: #f4f4f5;\n --prism-text-color: #18181b;\n --prism-tooltip-bg: #27272a;\n --prism-font-family: 'Inter', system-ui, sans-serif;\n}\n```\n\n### Scoped Themes\n\nApply tokens to a specific container:\n\n```css\n.dark-dashboard {\n --prism-axis-color: #64748b;\n --prism-grid-color: #334155;\n --prism-text-color: #e2e8f0;\n}\n```\n\n### Available Tokens\n\n| Token | Default | Description |\n| ------------------------- | ---------------- | ---------------------- |\n| `--prism-color-{1-8}` | Tailwind palette | Series color palette |\n| `--prism-bg` | `transparent` | Chart background |\n| `--prism-axis-color` | `#94a3b8` | Axis lines and ticks |\n| `--prism-grid-color` | `#e2e8f0` | Grid lines |\n| `--prism-text-color` | `#334155` | Axis labels and text |\n| `--prism-font-family` | `system-ui` | Chart font |\n| `--prism-font-size` | `12px` | Label font size |\n| `--prism-tooltip-bg` | `#1e293b` | Tooltip background |\n| `--prism-tooltip-color` | `#f8fafc` | Tooltip text |\n| `--prism-tooltip-radius` | `6px` | Tooltip border radius |\n| `--prism-crosshair-color` | `#64748b` | Crosshair line |\n| `--prism-crosshair-dash` | `4 2` | Crosshair dash pattern |\n\n## Scales (Standalone)\n\nScales can be used independently for custom visualizations:\n\n```ts\nimport { linearScale, timeScale, bandScale } from '@vielzeug/prism';\n\nconst y = linearScale({ domain: [0, 100], range: [300, 0] });\ny.map(50); // → 150\ny.invert(150); // → 50\ny.ticks(5); // → [0, 20, 40, 60, 80, 100]\n\nconst x = bandScale({ domain: ['A', 'B', 'C'], range: [0, 300] });\nx.map('B'); // → pixel left edge of band B\nx.bandwidth(); // → width of each band\n```\n\n## Lifecycle and Cleanup\n\nEvery chart returns a `ChartHandle`. Always call `dispose()` when removing a chart:\n\n```ts\nconst chart = createLineChart(container, config);\n\n// When done:\nchart.dispose();\n\n// Or with TC39 explicit resource management:\n{\n using chart = createLineChart(container, config);\n // auto-disposed at block end\n}\n```\n\nCalling `dispose()`:\n\n- Cancels all reactive signal effects\n- Disconnects the `ResizeObserver`\n- Removes the SVG element, tooltip, and legend from the DOM\n- Calls `dispose()` on all plugins (a plugin that throws is logged and skipped — it never blocks the rest of teardown)\n- Is idempotent — safe to call multiple times\n\n> **Reactivity is automatic** — charts re-render whenever signal data changes. There is no manual `update()` call needed.\n\n## Responsive Behavior\n\nCharts resize automatically when the container dimensions change. Prism uses `ResizeObserver` internally — no manual `resize()` call is needed.\n\n## Devtools\n\nImport `debugChart()` from the `/devtools` subpath to log a chart's mount, resize, and dispose events to `console.debug`. It's separate from prism's internal validation warnings (those run automatically in development, no import needed) and is tree-shaken from production bundles when this subpath isn't imported.\n\n```ts\nimport { createLineChart } from '@vielzeug/prism';\nimport { debugChart } from '@vielzeug/prism/devtools';\n\nconst chart = debugChart(createLineChart(container, config), { label: 'revenue' });\n// [prism:revenue] mounted\n// [prism:revenue] resized 600×300\nchart.dispose();\n// [prism:revenue] disposed\n```\n\n> `debugChart()` wraps and returns the same `ChartHandle` unchanged, so it drops into any `create*Chart()` call without restructuring your code.\n\n## Framework Integration\n\nPrism renders into a plain DOM element. Attach charts inside mount/unmount lifecycle hooks for any framework.\n\n::: code-group\n\n```tsx [React]\nimport { useEffect, useRef } from 'react';\nimport { createLineChart, type Datum } from '@vielzeug/prism';\n\nfunction LineChart({ data }: { data: Datum[] }) {\n const containerRef = useRef<HTMLDivElement>(null);\n\n useEffect(() => {\n const chart = createLineChart(containerRef.current!, {\n series: [{ data, name: 'Series' }],\n });\n return () => chart.dispose();\n }, [data]);\n\n return <div ref={containerRef} style={{ width: '100%', height: 300 }} />;\n}\n```\n\n```ts [Vue 3]\nimport { onMounted, onUnmounted, ref } from 'vue';\nimport { createLineChart, type ChartHandle, type Datum } from '@vielzeug/prism';\n\nfunction useLineChart(data: Datum[]) {\n const containerRef = ref<HTMLElement | null>(null);\n let chart: ChartHandle | null = null;\n\n onMounted(() => {\n chart = createLineChart(containerRef.value!, { series: [{ data, name: 'Series' }] });\n });\n\n onUnmounted(() => chart?.dispose());\n return { containerRef };\n}\n```\n\n```svelte [Svelte]\n<script lang=\"ts\">\n import { onMount } from 'svelte';\n import { createLineChart, type Datum } from '@vielzeug/prism';\n\n export let data: Datum[] = [];\n let container: HTMLDivElement;\n\n onMount(() => {\n const chart = createLineChart(container, { series: [{ data, name: 'Series' }] });\n return () => chart.dispose();\n });\n</script>\n\n<div bind:this={container} style=\"width:100%;height:300px\"></div>\n```\n\n:::\n\n## Working with Other Vielzeug Libraries\n\n### With Ripple\n\nPass Ripple signals as chart data properties. Prism re-renders automatically when a signal changes.\n\n```ts\nimport { signal } from '@vielzeug/ripple';\nimport { createLineChart } from '@vielzeug/prism';\n\nconst data = signal([\n { key: 1, value: 10 },\n { key: 2, value: 20 },\n]);\n\nconst chart = createLineChart(container, {\n series: [{ data, name: 'Series' }], // signal passed directly\n});\n\n// Updating the signal triggers an automatic re-render:\ndata.value = [\n { key: 1, value: 15 },\n { key: 2, value: 25 },\n];\n```\n\n### With Sourcerer\n\nBind chart data to a Sourcerer remote source so charts update whenever the list refreshes.\n\n```ts\nimport { createPageSource } from '@vielzeug/sourcerer';\nimport { computed, signal } from '@vielzeug/ripple';\nimport { createBarChart } from '@vielzeug/prism';\n\nconst source = createPageSource({ load: ({ query, signal }) => api.stats.list(query, { signal }) });\nconst snapshot = signal(source.snapshot);\nsource.subscribe((next) => (snapshot.value = next));\n\nconst chartData = computed(() => snapshot.value.data.map((item) => ({ key: item.label, value: item.count })));\n\nconst chart = createBarChart(container, {\n series: [{ data: chartData, name: 'Series' }],\n});\n```\n\n## Accessibility\n\nAccessibility is a hard requirement for every chart factory. Each chart's root `<svg>` carries `role=\"img\"` and must have either an `aria-label` or `aria-hidden=\"true\"` — set via the `a11y` config field.\n\nLabel a chart that conveys meaningful data:\n\n```ts\ncreateLineChart(container, {\n a11y: { ariaLabel: 'Revenue by month' },\n series: [...],\n});\n```\n\nMark a decorative chart (e.g. a sparkline next to a text label) to exclude it from the accessibility tree:\n\n```ts\ncreateSparkline(container, {\n a11y: { decorative: true },\n data: [...],\n});\n```\n\nWhen `a11y` is omitted, scaffolded charts (line/bar/area/pie) render with `role=\"img\"` but no `aria-label`; sparklines default to `aria-hidden=\"true\"`. Always set `a11y: { ariaLabel: '…' }` on charts that users need to understand.\n\n## Best Practices\n\n- Ensure the container element has explicit dimensions before calling a chart factory — `ResizeObserver` needs a non-zero layout size to trigger the first render.\n- Call `chart.dispose()` in your framework's unmount/cleanup phase to cancel signal effects and remove DOM nodes.\n- Prefer `signal()` from Ripple for mutable data properties — charts re-render automatically when signals change, with no manual `update()` call.\n- Set `a11y: { ariaLabel: '…' }` on every chart that conveys meaningful data — accessibility is a hard requirement, not an optional add-on.\n- Wrap a chart with `debugChart()` from the `/devtools` subpath only in development code paths; it is tree-shaken in production.\n- For SSR, skip chart creation server-side — Prism depends on DOM APIs and `ResizeObserver`. Render charts only after hydration in a `onMounted`/`useEffect` callback.\n",
|
|
7
|
+
"examples": "---\ntitle: Prism — Examples\ndescription: Interactive code examples for @vielzeug/prism charts.\n---\n\n[[toc]]\n\n## Line Chart\n\nBasic line chart with tooltip and crosshair:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-line\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createLineChart } = Prism;\n createLineChart(document.getElementById('ex-line'), {\n series: [\n {\n name: 'Revenue',\n data: [\n { key: 1, value: 120 },\n { key: 2, value: 180 },\n { key: 3, value: 150 },\n { key: 4, value: 220 },\n { key: 5, value: 195 },\n { key: 6, value: 280 },\n ],\n color: '#3b82f6',\n curve: 'monotone',\n strokeWidth: 2,\n showPoints: true,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n crosshair: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Multi-series Line Chart\n\nMultiple lines with different curves:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-multi-line\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createLineChart } = Prism;\n createLineChart(document.getElementById('ex-multi-line'), {\n series: [\n {\n name: 'Product A',\n data: [\n { key: 1, value: 40 },\n { key: 2, value: 65 },\n { key: 3, value: 55 },\n { key: 4, value: 80 },\n { key: 5, value: 72 },\n ],\n color: '#3b82f6',\n curve: 'monotone',\n },\n {\n name: 'Product B',\n data: [\n { key: 1, value: 20 },\n { key: 2, value: 35 },\n { key: 3, value: 60 },\n { key: 4, value: 45 },\n { key: 5, value: 90 },\n ],\n color: '#10b981',\n curve: 'monotone',\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n crosshair: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Legend — Line Chart\n\nAdd `legend: true` to label each series below the chart:\n\n<ComponentPreview vertical height=\"360px\">\n\n```html\n<div id=\"ex-legend-line\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createLineChart } = Prism;\n createLineChart(document.getElementById('ex-legend-line'), {\n series: [\n {\n name: 'Revenue',\n data: [\n { key: 1, value: 120 },\n { key: 2, value: 180 },\n { key: 3, value: 150 },\n { key: 4, value: 220 },\n { key: 5, value: 195 },\n ],\n color: '#3b82f6',\n curve: 'monotone',\n },\n {\n name: 'Expenses',\n data: [\n { key: 1, value: 80 },\n { key: 2, value: 95 },\n { key: 3, value: 110 },\n { key: 4, value: 130 },\n { key: 5, value: 125 },\n ],\n color: '#ef4444',\n curve: 'monotone',\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n crosshair: true,\n legend: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Bar Chart\n\nGrouped bar chart comparing categories:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-bar\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createBarChart } = Prism;\n createBarChart(document.getElementById('ex-bar'), {\n series: [\n {\n name: '2023',\n data: [\n { key: 'Q1', value: 120 },\n { key: 'Q2', value: 180 },\n { key: 'Q3', value: 150 },\n { key: 'Q4', value: 210 },\n ],\n color: '#94a3b8',\n borderRadius: 4,\n },\n {\n name: '2024',\n data: [\n { key: 'Q1', value: 150 },\n { key: 'Q2', value: 220 },\n { key: 'Q3', value: 190 },\n { key: 'Q4', value: 280 },\n ],\n color: '#3b82f6',\n borderRadius: 4,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Stacked Bar Chart\n\nBar chart with `variant: 'stacked'` — series stack vertically per category:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-bar-stacked\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createBarChart } = Prism;\n createBarChart(document.getElementById('ex-bar-stacked'), {\n series: [\n {\n name: 'Mobile',\n data: [\n { key: 'Q1', value: 80 },\n { key: 'Q2', value: 110 },\n { key: 'Q3', value: 95 },\n { key: 'Q4', value: 130 },\n ],\n color: '#3b82f6',\n borderRadius: 0,\n },\n {\n name: 'Desktop',\n data: [\n { key: 'Q1', value: 60 },\n { key: 'Q2', value: 90 },\n { key: 'Q3', value: 75 },\n { key: 'Q4', value: 100 },\n ],\n color: '#10b981',\n borderRadius: 0,\n },\n {\n name: 'Tablet',\n data: [\n { key: 'Q1', value: 20 },\n { key: 'Q2', value: 30 },\n { key: 'Q3', value: 25 },\n { key: 'Q4', value: 35 },\n ],\n color: '#f59e0b',\n borderRadius: 0,\n },\n ],\n variant: 'stacked',\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n legend: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Horizontal Bar Chart\n\nBar chart with `variant: 'grouped-horizontal'` — categories on the Y axis, values on the X axis:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-bar-horizontal\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createBarChart } = Prism;\n createBarChart(document.getElementById('ex-bar-horizontal'), {\n variant: 'grouped-horizontal',\n series: [\n {\n name: 'Revenue',\n data: [\n { key: 'Q1', value: 80 },\n { key: 'Q2', value: 110 },\n { key: 'Q3', value: 95 },\n { key: 'Q4', value: 130 },\n ],\n color: '#3b82f6',\n },\n ],\n xAxis: { position: 'bottom', grid: true },\n yAxis: { position: 'left' },\n tooltip: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Horizontal Stacked Bar Chart\n\nUse `variant: 'stacked-horizontal'` — horizontal bars stacked per category:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-bar-h-stacked\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createBarChart } = Prism;\n createBarChart(document.getElementById('ex-bar-h-stacked'), {\n variant: 'stacked-horizontal',\n series: [\n {\n name: 'Mobile',\n data: [\n { key: 'Q1', value: 80 },\n { key: 'Q2', value: 110 },\n { key: 'Q3', value: 95 },\n { key: 'Q4', value: 130 },\n ],\n color: '#3b82f6',\n borderRadius: 0,\n },\n {\n name: 'Desktop',\n data: [\n { key: 'Q1', value: 60 },\n { key: 'Q2', value: 90 },\n { key: 'Q3', value: 75 },\n { key: 'Q4', value: 100 },\n ],\n color: '#10b981',\n borderRadius: 0,\n },\n ],\n xAxis: { position: 'bottom', grid: true },\n yAxis: { position: 'left' },\n tooltip: true,\n legend: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Legend — Bar Chart\n\nGrouped bar chart with a legend positioned at the top:\n\n<ComponentPreview vertical height=\"360px\">\n\n```html\n<div id=\"ex-legend-bar\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createBarChart } = Prism;\n createBarChart(document.getElementById('ex-legend-bar'), {\n series: [\n {\n name: '2023',\n data: [\n { key: 'Q1', value: 120 },\n { key: 'Q2', value: 180 },\n { key: 'Q3', value: 150 },\n { key: 'Q4', value: 210 },\n ],\n color: '#94a3b8',\n borderRadius: 4,\n },\n {\n name: '2024',\n data: [\n { key: 'Q1', value: 150 },\n { key: 'Q2', value: 220 },\n { key: 'Q3', value: 190 },\n { key: 'Q4', value: 280 },\n ],\n color: '#3b82f6',\n borderRadius: 4,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n legend: { position: 'top' },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Area Chart\n\nFilled area with monotone curve and low opacity:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-area\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createAreaChart } = Prism;\n createAreaChart(document.getElementById('ex-area'), {\n series: [\n {\n name: 'Signups',\n data: [\n { key: 1, value: 500 },\n { key: 2, value: 650 },\n { key: 3, value: 800 },\n { key: 4, value: 720 },\n { key: 5, value: 900 },\n { key: 6, value: 1100 },\n ],\n color: '#8b5cf6',\n curve: 'monotone',\n fillOpacity: 0.2,\n showLine: true,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: { color: '#f1f5f9' } },\n crosshair: { vertical: true },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Legend — Area Chart\n\nMulti-series area chart with a bottom legend:\n\n<ComponentPreview vertical height=\"360px\">\n\n```html\n<div id=\"ex-legend-area\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createAreaChart } = Prism;\n createAreaChart(document.getElementById('ex-legend-area'), {\n series: [\n {\n name: 'Mobile',\n data: [\n { key: 1, value: 300 },\n { key: 2, value: 420 },\n { key: 3, value: 510 },\n { key: 4, value: 480 },\n { key: 5, value: 620 },\n { key: 6, value: 750 },\n ],\n color: '#8b5cf6',\n curve: 'monotone',\n fillOpacity: 0.25,\n },\n {\n name: 'Desktop',\n data: [\n { key: 1, value: 200 },\n { key: 2, value: 230 },\n { key: 3, value: 290 },\n { key: 4, value: 240 },\n { key: 5, value: 280 },\n { key: 6, value: 350 },\n ],\n color: '#06b6d4',\n curve: 'monotone',\n fillOpacity: 0.25,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n crosshair: true,\n legend: true,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Step Line Chart\n\nLine chart with step interpolation:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-step\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createLineChart } = Prism;\n createLineChart(document.getElementById('ex-step'), {\n series: [\n {\n name: 'Status',\n data: [\n { key: 1, value: 0 },\n { key: 2, value: 1 },\n { key: 3, value: 1 },\n { key: 4, value: 0 },\n { key: 5, value: 1 },\n { key: 6, value: 0 },\n ],\n color: '#f59e0b',\n curve: 'step',\n strokeWidth: 3,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left' },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Reactive Chart\n\nChart that updates when signal data changes:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div style=\"margin-bottom:8px;\">\n <button id=\"ex-reactive-btn\" style=\"padding:4px 12px;border:1px solid #e2e8f0;border-radius:4px;cursor:pointer;\">\n Add Data Point\n </button>\n</div>\n<div id=\"ex-reactive\" style=\"width:100%;height:250px;\"></div>\n<script>\n const { createLineChart } = Prism;\n const { signal } = Ripple;\n\n const data = signal([\n { key: 1, value: 20 },\n { key: 2, value: 35 },\n { key: 3, value: 28 },\n { key: 4, value: 45 },\n ]);\n\n createLineChart(document.getElementById('ex-reactive'), {\n series: [{ name: 'Live', data, color: '#10b981', curve: 'monotone', showPoints: true }],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n crosshair: true,\n transition: { duration: 400, easing: 'ease-out' },\n });\n\n document.getElementById('ex-reactive-btn').addEventListener('click', function () {\n var prev = data.value;\n var nextX = prev.length + 1;\n var nextY = 20 + Math.floor(Math.random() * 40);\n data.value = prev.concat([{ key: nextX, value: nextY }]);\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Reactive Bar Chart\n\nBar chart that updates when signal data changes, with stagger animation on new bars:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div style=\"margin-bottom:8px;\">\n <button id=\"ex-reactive-bar-btn\" style=\"padding:4px 12px;border:1px solid #e2e8f0;border-radius:4px;cursor:pointer;\">\n Add Category\n </button>\n</div>\n<div id=\"ex-reactive-bar\" style=\"width:100%;height:250px;\"></div>\n<script>\n const { createBarChart } = Prism;\n const { signal } = Ripple;\n\n const barData = signal([\n { key: 'Q1', value: 120 },\n { key: 'Q2', value: 180 },\n { key: 'Q3', value: 150 },\n { key: 'Q4', value: 210 },\n ]);\n\n createBarChart(document.getElementById('ex-reactive-bar'), {\n series: [{ name: 'Revenue', data: barData, color: '#6366f1', borderRadius: 4 }],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: true,\n transition: { duration: 400, easing: 'ease-out', stagger: 40 },\n });\n\n var quarters = ['Q5', 'Q6', 'Q7', 'Q8'];\n var qIdx = 0;\n document.getElementById('ex-reactive-bar-btn').addEventListener('click', function () {\n if (qIdx >= quarters.length) return;\n var nextY = 150 + Math.floor(Math.random() * 120);\n barData.value = barData.value.concat([{ key: quarters[qIdx++], value: nextY }]);\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Event Hooks\n\nUsing `onHover` and `onClick` to react to chart interactions:\n\n<ComponentPreview vertical height=\"360px\">\n\n```html\n<div id=\"ex-events-info\" style=\"margin-bottom:8px;font-size:13px;color:#64748b;min-height:20px;\"></div>\n<div id=\"ex-events\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createLineChart } = Prism;\n\n const info = document.getElementById('ex-events-info');\n\n createLineChart(document.getElementById('ex-events'), {\n series: [\n {\n name: 'Revenue',\n data: [\n { key: 1, value: 120 },\n { key: 2, value: 180 },\n { key: 3, value: 150 },\n { key: 4, value: 220 },\n { key: 5, value: 195 },\n { key: 6, value: 280 },\n ],\n color: '#3b82f6',\n curve: 'monotone',\n showPoints: true,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n onHover: function (event) {\n info.textContent = event ? 'Hovering key=' + event.datum.key + ' value=' + event.datum.value : '';\n },\n onClick: function (event) {\n info.textContent = 'Clicked key=' + event.datum.key + ' value=' + event.datum.value;\n },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Pie Chart\n\nBasic pie chart with labeled slices:\n\n<ComponentPreview vertical height=\"340px\">\n\n```html\n<div id=\"ex-pie\" style=\"width:300px;height:300px;\"></div>\n<script>\n const { createPieChart } = Prism;\n createPieChart(document.getElementById('ex-pie'), {\n data: [\n { label: 'Direct', value: 42, color: '#3b82f6' },\n { label: 'Organic', value: 28, color: '#10b981' },\n { label: 'Referral', value: 18, color: '#f59e0b' },\n { label: 'Social', value: 12, color: '#8b5cf6' },\n ],\n variant: 'pie',\n transition: { duration: 600, easing: 'ease-out' },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Donut Chart\n\nDonut chart with tooltip:\n\n<ComponentPreview vertical height=\"340px\">\n\n```html\n<div id=\"ex-donut\" style=\"width:300px;height:300px;\"></div>\n<script>\n const { createPieChart } = Prism;\n createPieChart(document.getElementById('ex-donut'), {\n data: [\n { label: 'Direct', value: 42, color: '#3b82f6' },\n { label: 'Organic', value: 28, color: '#10b981' },\n { label: 'Referral', value: 18, color: '#f59e0b' },\n { label: 'Social', value: 12, color: '#8b5cf6' },\n ],\n variant: 'donut',\n tooltip: true,\n transition: { duration: 600, easing: 'ease-out' },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Semi-circle Donut\n\nSemicircle donut — useful for gauges and progress indicators:\n\n<ComponentPreview vertical height=\"220px\">\n\n```html\n<div id=\"ex-semi\" style=\"width:300px;height:180px;\"></div>\n<script>\n const { createPieChart } = Prism;\n createPieChart(document.getElementById('ex-semi'), {\n data: [\n { label: 'Used', value: 68, color: '#3b82f6' },\n { label: 'Free', value: 32, color: '#e2e8f0' },\n ],\n variant: 'semi',\n transition: { duration: 800, easing: 'ease-out' },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Sparkline — Line\n\nMinimal inline sparkline inside a table cell or card:\n\n<ComponentPreview vertical height=\"80px\">\n\n```html\n<div id=\"ex-spark-line\" style=\"width:200px;height:40px;\"></div>\n<script>\n const { createSparkline } = Prism;\n createSparkline(document.getElementById('ex-spark-line'), {\n data: [12, 18, 14, 22, 19, 28, 24, 32],\n variant: 'line',\n color: '#3b82f6',\n curve: 'monotone',\n strokeWidth: 1.5,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Sparkline — Area\n\nArea variant with fill:\n\n<ComponentPreview vertical height=\"80px\">\n\n```html\n<div id=\"ex-spark-area\" style=\"width:200px;height:40px;\"></div>\n<script>\n const { createSparkline } = Prism;\n createSparkline(document.getElementById('ex-spark-area'), {\n data: [12, 18, 14, 22, 19, 28, 24, 32],\n variant: 'area',\n color: '#8b5cf6',\n curve: 'monotone',\n fillOpacity: 0.25,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Sparkline — Bar\n\nBar variant — one rect per value:\n\n<ComponentPreview vertical height=\"80px\">\n\n```html\n<div id=\"ex-spark-bar\" style=\"width:200px;height:40px;\"></div>\n<script>\n const { createSparkline } = Prism;\n createSparkline(document.getElementById('ex-spark-bar'), {\n data: [12, 18, 14, 22, 19, 28, 24, 32],\n variant: 'bar',\n color: '#10b981',\n transition: { duration: 400, easing: 'ease-out', stagger: 30 },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Sparkline — Reactive\n\nSparkline that updates when signal data changes:\n\n<ComponentPreview vertical height=\"120px\">\n\n```html\n<div style=\"margin-bottom:8px;\">\n <button id=\"ex-spark-btn\" style=\"padding:4px 12px;border:1px solid #e2e8f0;border-radius:4px;cursor:pointer;\">\n Add Point\n </button>\n</div>\n<div id=\"ex-spark-reactive\" style=\"width:200px;height:40px;\"></div>\n<script>\n const { createSparkline } = Prism;\n const { signal } = Ripple;\n\n const sparkData = signal([10, 15, 12, 18, 14]);\n\n createSparkline(document.getElementById('ex-spark-reactive'), {\n data: sparkData,\n variant: 'area',\n color: '#f59e0b',\n curve: 'monotone',\n fillOpacity: 0.2,\n transition: { duration: 300, easing: 'ease-out' },\n });\n\n document.getElementById('ex-spark-btn').addEventListener('click', function () {\n sparkData.value = sparkData.value.concat([10 + Math.floor(Math.random() * 25)]);\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Sparkline — Stack\n\nHorizontal stacked bar — proportional segments with per-segment colors:\n\n<ComponentPreview vertical height=\"80px\">\n\n```html\n<div id=\"ex-spark-stack\" style=\"width:200px;height:40px;\"></div>\n<script>\n const { createSparkline } = Prism;\n createSparkline(document.getElementById('ex-spark-stack'), {\n variant: 'stack',\n data: [\n { label: 'Chrome', value: 341, color: '#3b82f6' },\n { label: 'Safari', value: 217, color: '#06b6d4' },\n { label: 'Firefox', value: 124, color: '#10b981' },\n { label: 'Edge', value: 53, color: '#f59e0b' },\n ],\n cornerRadius: 4,\n padPixels: 4,\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Custom Tooltip\n\nRich HTML tooltip with custom formatting:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-tooltip\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createBarChart } = Prism;\n createBarChart(document.getElementById('ex-tooltip'), {\n series: [\n {\n name: 'Revenue',\n data: [\n { key: 'Jan', value: 4200 },\n { key: 'Feb', value: 5100 },\n { key: 'Mar', value: 4800 },\n { key: 'Apr', value: 6300 },\n { key: 'May', value: 5900 },\n { key: 'Jun', value: 7200 },\n ],\n color: '#6366f1',\n borderRadius: 6,\n },\n ],\n xAxis: { position: 'bottom' },\n yAxis: { position: 'left', grid: true },\n tooltip: {\n render: function (datum, series) {\n return (\n '<div style=\"font-weight:600\">' +\n series.name +\n '</div>' +\n '<div style=\"opacity:0.7;font-size:11px\">' +\n datum.key +\n '</div>' +\n '<div style=\"font-size:14px;margin-top:2px\">$' +\n datum.value.toLocaleString() +\n '</div>'\n );\n },\n },\n });\n</script>\n```\n\n</ComponentPreview>\n\n## Pie Chart with Plugin\n\nA donut chart that installs a custom plugin to draw a total count label in the center hole:\n\n<ComponentPreview vertical height=\"320px\">\n\n```html\n<div id=\"ex-pie-plugin\" style=\"width:100%;height:280px;\"></div>\n<script>\n const { createPieChart } = Prism;\n\n const data = [\n { label: 'Direct', value: 42, color: '#6366f1' },\n { label: 'Organic', value: 28, color: '#10b981' },\n { label: 'Social', value: 18, color: '#f59e0b' },\n { label: 'Referral', value: 12, color: '#8b5cf6' },\n ];\n\n const total = data.reduce((s, d) => s + d.value, 0);\n let centerLabel;\n\n const centerPlugin = {\n install(ctx) {\n const ns = 'http://www.w3.org/2000/svg';\n centerLabel = document.createElementNS(ns, 'text');\n centerLabel.setAttribute('text-anchor', 'middle');\n centerLabel.setAttribute('dominant-baseline', 'middle');\n centerLabel.setAttribute('font-size', '20');\n centerLabel.setAttribute('font-weight', '600');\n centerLabel.setAttribute('fill', 'var(--prism-text-color, #334155)');\n centerLabel.textContent = total;\n ctx.svg.appendChild(centerLabel);\n // Position at SVG center once dimensions are available\n requestAnimationFrame(() => {\n const { width, height } = ctx.dimensions.value;\n if (width && height) {\n centerLabel.setAttribute('x', String(width / 2));\n centerLabel.setAttribute('y', String(height / 2));\n }\n });\n },\n dispose() {\n centerLabel?.remove();\n },\n };\n\n createPieChart(document.getElementById('ex-pie-plugin'), {\n data,\n variant: 'donut',\n tooltip: true,\n transition: { duration: 400, easing: 'ease-out' },\n plugins: [centerPlugin],\n });\n</script>\n```\n\n</ComponentPreview>\n"
|
|
8
|
+
},
|
|
9
|
+
"examples": [],
|
|
10
|
+
"typeSignatures": {
|
|
11
|
+
"EasingFn": "export type { EasingFn } from './animation/easing';",
|
|
12
|
+
"AnimationTarget": "export type { AnimationTarget } from './animation/transition';",
|
|
13
|
+
"animate": "export { animate } from './animation/transition';",
|
|
14
|
+
"createAreaChart": "export { createAreaChart } from './charts/area';",
|
|
15
|
+
"createBarChart": "export { createBarChart } from './charts/bar';",
|
|
16
|
+
"createLineChart": "export { createLineChart } from './charts/line';",
|
|
17
|
+
"createPieChart": "export { createPieChart } from './charts/pie';",
|
|
18
|
+
"createSparkline": "export { createSparkline } from './charts/sparkline';",
|
|
19
|
+
"PrismError": "export { PrismError, PrismRenderError } from './errors';",
|
|
20
|
+
"PrismRenderError": "export { PrismError, PrismRenderError } from './errors';",
|
|
21
|
+
"LegendState": "export type { LegendState } from './interaction/legend';",
|
|
22
|
+
"TooltipState": "export type { TooltipState } from './interaction/tooltip';",
|
|
23
|
+
"bandScale": "export { bandScale } from './scales/band';",
|
|
24
|
+
"linearScale": "export { linearScale } from './scales/linear';",
|
|
25
|
+
"timeScale": "export { timeScale } from './scales/time';",
|
|
26
|
+
"Point": "export type { Point } from './svg/path';",
|
|
27
|
+
"resetTheme": "export { resetTheme, seriesColor, setTheme } from './theme';",
|
|
28
|
+
"seriesColor": "export { resetTheme, seriesColor, setTheme } from './theme';",
|
|
29
|
+
"setTheme": "export { resetTheme, seriesColor, setTheme } from './theme';",
|
|
30
|
+
"AreaChartConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
31
|
+
"AreaSeriesConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
32
|
+
"AxisConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
33
|
+
"AxisPosition": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
34
|
+
"BandScale": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
35
|
+
"BarChartConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
36
|
+
"BarSeriesConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
37
|
+
"BarVariant": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
38
|
+
"BaseChartConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
39
|
+
"ChartA11y": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
40
|
+
"ChartDimensions": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
41
|
+
"ChartEvent": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
42
|
+
"ChartHandle": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
43
|
+
"ChartMargin": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
44
|
+
"ChartPlugin": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
45
|
+
"ChartPluginContext": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
46
|
+
"CrosshairConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
47
|
+
"Datum": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
48
|
+
"GridConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
49
|
+
"LegendConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
50
|
+
"LegendPosition": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
51
|
+
"LineChartConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
52
|
+
"LineSeriesConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
53
|
+
"MaybeSignal": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
54
|
+
"PieChartConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
55
|
+
"PieSliceConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
56
|
+
"PieVariant": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
57
|
+
"PrismTheme": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
58
|
+
"Scale": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
59
|
+
"Series": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
60
|
+
"SparklineConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
61
|
+
"SparklineVariant": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
62
|
+
"StackSegment": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
63
|
+
"TooltipConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';",
|
|
64
|
+
"TransitionConfig": "export type {\n AreaChartConfig,\n AreaSeriesConfig,\n AxisConfig,\n AxisPosition,\n BandScale,\n BarChartConfig,\n BarSeriesConfig,\n BarVariant,\n BaseChartConfig,\n ChartA11y,\n ChartDimensions,\n ChartEvent,\n ChartHandle,\n ChartMargin,\n ChartPlugin,\n ChartPluginContext,\n CrosshairConfig,\n Datum,\n GridConfig,\n LegendConfig,\n LegendPosition,\n LineChartConfig,\n LineSeriesConfig,\n MaybeSignal,\n PieChartConfig,\n PieSliceConfig,\n PieVariant,\n PrismTheme,\n Scale,\n Series,\n SparklineConfig,\n SparklineVariant,\n StackSegment,\n TooltipConfig,\n TransitionConfig,\n} from './types';"
|
|
65
|
+
}
|
|
66
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiSource": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';\nexport { createPulse } from './pulse';\nexport type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';\n",
|
|
3
|
+
"docs": {
|
|
4
|
+
"index": "---\ntitle: Pulse — Typed WebSocket sessions\ndescription: Explicitly connected, typed WebSocket sessions with scoped channels, ref-counted rooms with reactive presence, reconnect restoration, and heartbeat.\npackage: pulse\ncategory: websockets\nkeywords: [websocket, realtime, channels, presence, rooms, reconnect, heartbeat, typed-messaging, ripple]\nrelated: [herald, ripple, courier, clockwork]\nexports:\n [\n createPulse,\n Pulse,\n PulseChannel,\n RoomScope,\n RoomScopeBase,\n PresenceRoomScope,\n PulseOptions,\n PulseSchema,\n ChannelDefinition,\n ChannelDefinitions,\n RoomDefinition,\n RoomDefinitions,\n RoomOptions,\n OutgoingMessage,\n OutgoingTransform,\n PulseError,\n PulseConnectionError,\n PulseTimeoutError,\n PulseRoomTimeoutError,\n PulseAbortError,\n PulseDisposedError,\n PulseProtocolError,\n ]\nenvironments: [browser, node]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"pulse\" />\n\n## Why Pulse?\n\nNative WebSocket leaves connection ownership, event routing, reconnect restoration, and cleanup to each application. Pulse provides those boundaries while making readiness explicit: applications connect before sending, and disconnected messages never disappear silently.\n\n```ts\n// Before\nconst socket = new WebSocket('wss://api.example.com/ws');\nsocket.addEventListener('message', (event) => route(JSON.parse(event.data)));\nsocket.addEventListener('close', () => setTimeout(() => reconnect(), 1_000));\n\n// After\nconst pulse = createPulse<{ server: { 'chat:message': { text: string } }; client: { 'chat:send': { text: string } } }>(\n 'wss://api.example.com/ws',\n { reconnect: true },\n);\ntry {\n await pulse.connect();\n pulse.on('chat:message', (message) => console.log(message.text));\n pulse.send('chat:send', { text: 'Hello!' });\n} catch (error) {\n console.error('Pulse connection failed:', error);\n}\n```\n\n| Feature | Pulse | Native WebSocket | socket.io-client |\n| --- | --- | --- | --- |\n| Bundle size | <PackageInfo package=\"pulse\" type=\"size\" /> | 0 B | ~44 kB gzip |\n| Explicit readiness | <ore-icon name=\"check\" size=\"16\"></ore-icon> | Manual | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n| Session restoration | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | Protocol-specific |\n| Typed scoped channels | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | Basic |\n| Typed rooms with presence | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n| Zero runtime dependencies | <ore-icon name=\"triangle-alert\" size=\"16\"></ore-icon> ripple | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"x\" size=\"16\"></ore-icon> |\n\n<div class=\"decision-callout\">\n\n**Use Pulse when** you need a typed WebSocket session whose reconnect and cleanup behavior must be deterministic.\n\n**Consider native WebSocket when** a single untyped connection does not need retry, routing, or session restoration.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/pulse @vielzeug/ripple\n```\n\n```sh [npm]\nnpm install @vielzeug/pulse @vielzeug/ripple\n```\n\n```sh [yarn]\nyarn add @vielzeug/pulse @vielzeug/ripple\n```\n\n:::\n\n## Quick Start\n\nDefine the protocol schema at construction time, create scopes, then connect before sending.\n\n```ts\nimport { createPulse } from '@vielzeug/pulse';\n\ntype Schema = {\n server: { 'chat:message': { text: string } };\n client: { 'chat:send': { text: string } };\n channels: {\n chat: {\n client: { send: { text: string } };\n server: { message: { text: string } };\n };\n };\n rooms: {\n lobby: { presence: { name: string } };\n };\n};\n\nconst pulse = createPulse<Schema>('wss://api.example.com/ws', {\n reconnect: true,\n onError: (error) => console.error(error),\n});\nconst chat = pulse.channel('chat');\nconst lobby = pulse.room('lobby');\n\ntry {\n await pulse.connect();\n chat.send('send', { text: 'Hello!' });\n await lobby.joined;\n lobby.updatePresence({ name: 'Ada' });\n} catch (error) {\n console.error('Pulse connection failed:', error);\n}\n\npulse.dispose();\n```\n\n## Features\n\n<div class=\"features-grid\">\n\n- **`connect()`** — explicit readiness; application messages throw while disconnected.\n- **`channel()`** — named, schema-bound scopes with independent disposal and reference-counted server subscriptions.\n- **`room()`** — named, schema-bound ref-counted room scopes with optional reactive presence. The first scope sends `join`; the last disposal sends `leave`.\n- **`reconnect`** — ordered restoration of channel subscriptions, room memberships, and local presence state.\n- **`transform`** — one synchronous transform or filter for application messages.\n- **`onError`** — typed connection and protocol errors.\n- **`heartbeat`** — ping/pong liveness detection that uses the same reconnect controller.\n- **`status` and `rooms`** — ripple readables for transport and confirmed membership state.\n\n</div>\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Examples](./examples.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Ripple](/ripple/) — provides the reactive values exposed by Pulse.\n- [Herald](/herald/) — receives routed Pulse events in an in-process application bus.\n- [Courier](/courier/) — handles request/response traffic alongside a Pulse session.\n- [Clockwork](/clockwork/) — models application-level authentication or session workflows.\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
|
|
5
|
+
"api": "---\ntitle: API — Pulse\ndescription: Complete API reference for Pulse, including schema types, options, scopes, and error classes.\npackage: pulse\ncategory: websockets\n---\n\n<!-- markdownlint-disable MD025 -->\n\n[[toc]]\n\n## API Overview\n\n| Symbol | Purpose | Execution mode | Common gotcha |\n| --- | --- | --- | --- |\n| `createPulse()` | Create a typed WebSocket session instance. | Sync (returns `Pulse`) | Does not open the connection — call `connect()`. |\n| `Pulse` | Main instance: channels, rooms, messaging, lifecycle. | Sync methods, async `connect()`/`wait()` | `send()` throws while disconnected. |\n| `PulseChannel` | Scoped channel namespace with independent disposal. | Sync methods, async `wait()` | Each call returns a new scope; ref-counted subscription. |\n| `RoomScope` | Ref-counted room membership with optional presence. | Sync methods, async `joined` | `joined` rejects on transport close or timeout. |\n| `PulseSchema` | Declares server/client events, channels, and rooms. | Type-only | Infer all named scope types from this schema. |\n| `PulseOptions` | Configuration: heartbeat, reconnect, transform, onError. | Type-only | `reconnect` and `heartbeat` default to `false`. |\n| `PulseError` | Base class for all Pulse errors. | Runtime | Check `instanceof` against subclasses. |\n\n## Package Entry Point\n\n| Import | Purpose |\n| --- | --- |\n| `@vielzeug/pulse` | All public exports: `createPulse`, types, and error classes. |\n\n## `createPulse()`\n\n```ts\nfunction createPulse<S extends PulseSchema = PulseSchema>(url: string, options?: PulseOptions): Pulse<S>\n```\n\nCreates a Pulse instance. The WebSocket is not opened until `connect()` is called.\n\n### Type parameters\n\n| Parameter | Constraint | Description |\n| --- | --- | --- |\n| `S` | `PulseSchema` | Schema declaring server events, client events, channels, and rooms. |\n\n### Parameters\n\n| Parameter | Type | Description |\n| --- | --- | --- |\n| `url` | `string` | WebSocket URL. |\n| `options` | `PulseOptions` | Optional configuration. |\n\n### Returns\n\n`Pulse<S>` — the Pulse instance.\n\n---\n\n## `PulseSchema`\n\n```ts\ntype PulseSchema = {\n server?: MessageMap;\n client?: MessageMap;\n channels?: ChannelDefinitions;\n rooms?: RoomDefinitions;\n};\n```\n\nDeclare all protocol surfaces once at construction. Named scopes infer their types from this schema.\n\n| Field | Type | Description |\n| --- | --- | --- |\n| `server` | `MessageMap` | Root events the server sends. |\n| `client` | `MessageMap` | Root events the client sends. |\n| `channels` | `ChannelDefinitions` | Named channel schemas. |\n| `rooms` | `RoomDefinitions` | Named room schemas with optional presence. |\n\n---\n\n## `PulseOptions`\n\n```ts\ntype PulseOptions = {\n heartbeat?: boolean | HeartbeatOptions;\n onError?: (error: PulseError) => void;\n protocols?: string | string[];\n reconnect?: boolean | ReconnectOptions;\n transform?: OutgoingTransform;\n};\n```\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `heartbeat` | `boolean \\| HeartbeatOptions` | `false` | Ping/pong keep-alive. |\n| `onError` | `(error: PulseError) => void` | — | Receives typed transport and protocol errors. |\n| `protocols` | `string \\| string[]` | — | Sub-protocols passed to the WebSocket constructor. |\n| `reconnect` | `boolean \\| ReconnectOptions` | `false` | Auto-reconnect on unexpected close. |\n| `transform` | `OutgoingTransform` | — | Transform or filter outgoing application messages. |\n\n---\n\n## `HeartbeatOptions`\n\n```ts\ntype HeartbeatOptions = {\n interval?: number;\n timeout?: number;\n};\n```\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `interval` | `number` | `30_000` | Interval between pings in ms. |\n| `timeout` | `number` | `5_000` | How long to wait for a pong before treating the connection as dead. |\n\n---\n\n## `ReconnectOptions`\n\n```ts\ntype ReconnectOptions = {\n delay?: number | ((attempt: number) => number);\n maxAttempts?: number;\n};\n```\n\n| Option | Type | Default | Description |\n| --- | --- | --- | --- |\n| `delay` | `number \\| ((attempt: number) => number)` | Full-jitter exponential backoff capped at 30 s | Delay between reconnect attempts in ms. `attempt` is zero-based. |\n| `maxAttempts` | `number` | `5` | Maximum number of reconnect attempts after initial failure. |\n\n---\n\n## `OutgoingMessage`\n\n```ts\ntype OutgoingMessage = { channel?: string; event: string; payload: unknown };\n```\n\nAn outgoing application message before it is serialized.\n\n---\n\n## `OutgoingTransform`\n\n```ts\ntype OutgoingTransform = (message: Readonly<OutgoingMessage>) => OutgoingMessage | null;\n```\n\nTransform or filter outgoing application messages. Internal protocol frames (subscribe, join, leave, presence, ping) bypass this hook. Return `null` to drop the message.\n\n---\n\n## `Pulse`\n\n```ts\ntype Pulse<S extends PulseSchema = PulseSchema> = {\n // Channels\n channel<K extends keyof ChannelMap<S> & string>(\n name: K,\n ): PulseChannel<ChannelMap<S>[K]['server'], ChannelMap<S>[K]['client']>;\n\n // Connection\n connect(): Promise<void>;\n disconnect(code?: number, reason?: string): void;\n\n // Lifecycle\n readonly disposalSignal: AbortSignal;\n dispose(): void;\n readonly disposed: boolean;\n\n // Messaging\n on<K extends EventKey<ServerEvents<S>>>(event: K, handler: (payload: ServerEvents<S>[K]) => void): Unsubscribe;\n once<K extends EventKey<ServerEvents<S>>>(event: K, handler: (payload: ServerEvents<S>[K]) => void): Unsubscribe;\n send<K extends EventKey<ClientEvents<S>>>(event: K, payload: ClientEvents<S>[K]): void;\n wait<K extends EventKey<ServerEvents<S>>>(event: K, opts?: { signal?: AbortSignal; timeout?: number }): Promise<ServerEvents<S>[K]>;\n\n // Rooms\n room<K extends keyof RoomMap<S> & string>(name: K, opts?: RoomOptions): RoomScope<RoomMap<S>[K]>;\n readonly rooms: Readable<ReadonlySet<string>>;\n\n // Status\n readonly status: Readable<PulseStatus>;\n\n [Symbol.dispose](): void;\n};\n```\n\n### `channel(name)`\n\nCreates an isolated message namespace over the shared connection. Each call returns an independently disposable scope. The server subscription is reference-counted.\n\n### `connect()`\n\nExplicitly opens the connection. Resolves after session restoration completes. Rejects if the connection closes before opening.\n\n### `disconnect(code?, reason?)`\n\nCloses the connection without triggering reconnection. Default code is `1000`.\n\n### `dispose()`\n\nPermanently closes the connection and releases all resources. Idempotent.\n\n### `on(event, handler)`\n\nSubscribes to a typed server event. Returns an unsubscribe function.\n\n### `once(event, handler)`\n\nSubscribes once — auto-removes after first invocation.\n\n### `send(event, payload)`\n\nSends a typed event to the server. Throws `PulseConnectionError` unless the connection is open.\n\n### `wait(event, opts?)`\n\nResolves on the next emission of the given server event. Rejects when `opts.signal` aborts, the timeout elapses, or the instance is disposed.\n\n### `room(name, opts?)`\n\nCreates a ref-counted room scope. The first scope sends `join`; the last disposal sends `leave`. When the room definition includes `presence`, the scope exposes reactive presence state.\n\n### `rooms`\n\nReactive set of rooms the client is currently a confirmed member of.\n\n### `status`\n\nReactive connection status: `'connecting' | 'open' | 'reconnecting' | 'closed'`.\n\n---\n\n## `PulseChannel`\n\n```ts\ntype PulseChannel<TServer extends MessageMap = MessageMap, TClient extends MessageMap = MessageMap> = {\n readonly disposalSignal: AbortSignal;\n readonly disposed: boolean;\n readonly name: string;\n dispose(): void;\n on<K extends EventKey<TServer>>(event: K, handler: (payload: TServer[K]) => void): Unsubscribe;\n once<K extends EventKey<TServer>>(event: K, handler: (payload: TServer[K]) => void): Unsubscribe;\n send<K extends EventKey<TClient>>(event: K, payload: TClient[K]): void;\n wait<K extends EventKey<TServer>>(event: K, opts?: { signal?: AbortSignal; timeout?: number }): Promise<TServer[K]>;\n [Symbol.dispose](): void;\n};\n```\n\n---\n\n## `RoomScope`\n\n```ts\ntype RoomScope<R extends RoomDefinition = RoomDefinition> = R extends { presence: infer P }\n ? P extends undefined\n ? RoomScopeBase\n : PresenceRoomScope<P>\n : RoomScopeBase;\n```\n\nA room scope. When the room definition includes `presence`, the scope is a `PresenceRoomScope`; otherwise it is a `RoomScopeBase`.\n\n### `RoomScopeBase`\n\n```ts\ntype RoomScopeBase = {\n readonly disposalSignal: AbortSignal;\n readonly disposed: boolean;\n readonly name: string;\n readonly joined: Promise<void>;\n dispose(): void;\n [Symbol.dispose](): void;\n};\n```\n\n### `PresenceRoomScope`\n\n```ts\ntype PresenceRoomScope<T = unknown> = RoomScopeBase & {\n readonly presence: Readable<ReadonlyMap<string, T>>;\n updatePresence(state: T): void;\n onJoin(handler: (memberId: string, state: T) => void): Unsubscribe;\n onLeave(handler: (memberId: string) => void): Unsubscribe;\n};\n```\n\n| Member | Type | Description |\n| --- | --- | --- |\n| `presence` | `Readable<ReadonlyMap<string, T>>` | Reactive map of `memberId → state`. |\n| `updatePresence(state)` | `(state: T) => void` | Broadcast this client's presence state. Throws `PulseConnectionError` unless open. |\n| `onJoin(handler)` | `(handler) => Unsubscribe` | Called whenever a new member joins with their initial state. |\n| `onLeave(handler)` | `(handler) => Unsubscribe` | Called whenever a member leaves. |\n\n### `RoomOptions`\n\n```ts\ntype RoomOptions = {\n signal?: AbortSignal;\n timeout?: number;\n};\n```\n\n| Option | Type | Description |\n| --- | --- | --- |\n| `signal` | `AbortSignal` | Aborts the join, rejecting `joined` with `PulseAbortError`. |\n| `timeout` | `number` | Join timeout in ms. Rejects `joined` with `PulseRoomTimeoutError`. |\n\n---\n\n## Errors\n\nAll errors extend `PulseError`.\n\n### `PulseError`\n\nBase class for all Pulse errors.\n\n### `PulseConnectionError`\n\nTransport failure, send while disconnected, or room join rejected on close.\n\n### `PulseProtocolError`\n\nMalformed frame or server error frame.\n\n### `PulseTimeoutError`\n\n`wait()` timed out before the server event arrived.\n\n### `PulseRoomTimeoutError`\n\nRoom scope `joined` timed out before the server confirmed membership.\n\n### `PulseAbortError`\n\n`wait()` or room `joined` aborted via AbortSignal.\n\n### `PulseDisposedError`\n\nOperation attempted after disposal.\n\n---\n\n## Channel and room definitions\n\n### `ChannelDefinition`\n\n```ts\ntype ChannelDefinition = { client: MessageMap; server: MessageMap };\n```\n\n### `ChannelDefinitions`\n\n```ts\ntype ChannelDefinitions = Record<string, ChannelDefinition>;\n```\n\n### `RoomDefinition`\n\n```ts\ntype RoomDefinition = { presence?: unknown };\n```\n\n### `RoomDefinitions`\n\n```ts\ntype RoomDefinitions = Record<string, RoomDefinition>;\n```\n\n---\n\n## Utility types\n\n### `MessageMap`\n\n```ts\ntype MessageMap = Record<string, unknown>;\n```\n\n### `EventKey`\n\n```ts\ntype EventKey<T extends MessageMap> = keyof T & string;\n```\n\n### `ServerEvents`\n\n```ts\ntype ServerEvents<S extends PulseSchema> = S extends { server: infer M extends MessageMap } ? M : MessageMap;\n```\n\nExtract server events from a schema, defaulting to an empty map.\n\n### `ClientEvents`\n\n```ts\ntype ClientEvents<S extends PulseSchema> = S extends { client: infer M extends MessageMap } ? M : MessageMap;\n```\n\nExtract client events from a schema, defaulting to an empty map.\n\n### `RoomMap`\n\n```ts\ntype RoomMap<S extends PulseSchema> = S extends { rooms: infer R extends RoomDefinitions } ? R : RoomDefinitions;\n```\n\nExtract room definitions from a schema, defaulting to an empty map.\n\n### `Unsubscribe`\n\n```ts\ntype Unsubscribe = () => void;\n```\n\n### `PulseStatus`\n\n```ts\ntype PulseStatus = 'connecting' | 'open' | 'reconnecting' | 'closed';\n```\n",
|
|
6
|
+
"usage": "---\ntitle: Usage — Pulse\ndescription: Practical guide for connecting, sending, subscribing, joining rooms, and managing lifecycle with Pulse.\npackage: pulse\ncategory: websockets\n---\n\n<!-- markdownlint-disable MD025 -->\n\n[[toc]]\n\n## Basic Usage\n\nDeclare server events, client events, channel schemas, and room schemas once at construction. Named scopes infer their types from this schema.\n\n```ts\nimport { createPulse } from '@vielzeug/pulse';\n\ntype Schema = {\n // Root events the server sends\n server: { 'chat:message': { text: string }; notice: string };\n // Root events the client sends\n client: { 'chat:send': { text: string } };\n // Named channel scopes\n channels: {\n chat: {\n client: { send: { text: string } };\n server: { message: { text: string } };\n };\n alerts: {\n client: { subscribe: { topic: string } };\n server: { alert: { topic: string; severity: 'info' | 'warn' | 'error' } };\n };\n };\n // Named room scopes with optional presence state\n rooms: {\n lobby: { presence: { name: string; color: string } };\n announcements: {};\n };\n};\n```\n\n## Create and connect\n\n```ts\nconst pulse = createPulse<Schema>('wss://api.example.com/ws', {\n reconnect: { delay: 1_000, maxAttempts: 5 },\n heartbeat: { interval: 30_000, timeout: 5_000 },\n onError: (error) => console.error(error),\n});\n\ntry {\n await pulse.connect();\n} catch (error) {\n console.error('Connection failed:', error);\n}\n```\n\n`connect()` opens the WebSocket and resolves after session restoration completes. `send()` throws `PulseConnectionError` while disconnected — Pulse never silently drops or buffers application messages.\n\n## Send and receive root events\n\n```ts\npulse.on('chat:message', (message) => console.log(message.text));\npulse.send('chat:send', { text: 'Hello!' });\n```\n\n## Channels\n\nEach `channel()` call returns an independently disposable scope. The server subscription is reference-counted: the first scope sends `subscribe`, the last disposal sends `unsubscribe`.\n\n```ts\nconst chat = pulse.channel('chat');\n\nchat.on('message', (message) => console.log(message.text));\nchat.send('send', { text: 'Hello!' });\n\n// Later\nchat.dispose();\n```\n\nUse `using` for automatic cleanup:\n\n```ts\n{\n using chat = pulse.channel('chat');\n chat.on('message', (message) => console.log(message.text));\n} // chat.dispose() called automatically\n```\n\n## Rooms and presence\n\nEach `room()` call returns a ref-counted room scope. The first scope sends `join`; the last disposal sends `leave`. When the room definition includes `presence`, the scope exposes reactive presence state.\n\n```ts\nconst lobby = pulse.room('lobby');\n\n// joined resolves when the server confirms membership\nawait lobby.joined;\n\n// Reactive presence map: memberId → state\nlobby.onJoin((memberId, state) => console.log(`${memberId} joined: ${state.name}`));\nlobby.onLeave((memberId) => console.log(`${memberId} left`));\n\n// Broadcast your presence\nlobby.updatePresence({ name: 'Ada', color: 'blue' });\n\n// Read current presence\nfor (const [memberId, state] of lobby.presence.value) {\n console.log(`${memberId}: ${state.name}`);\n}\n\n// Leave\nlobby.dispose();\n```\n\nPlain rooms (without presence) work the same way but don't expose presence members:\n\n```ts\nconst announcements = pulse.room('announcements');\nawait announcements.joined;\nannouncements.dispose();\n```\n\n### Room scope options\n\n```ts\n// Timeout if the server doesn't confirm in time\nconst lobby = pulse.room('lobby', { timeout: 5_000 });\ntry {\n await lobby.joined;\n} catch (error) {\n console.error('Join failed:', error);\n}\n\n// Abort via AbortSignal\nconst ctrl = new AbortController();\nconst lobby = pulse.room('lobby', { signal: ctrl.signal });\nctrl.abort(); // joined rejects with PulseAbortError, scope auto-disposes\n```\n\n### Reactive rooms set\n\n`pulse.rooms` is a ripple readable that tracks confirmed room memberships:\n\n```ts\nimport { effect } from '@vielzeug/ripple';\n\neffect(() => {\n console.log('Joined rooms:', [...pulse.rooms.value]);\n});\n```\n\n## Reconnect\n\nWhen the connection drops unexpectedly, Pulse reconnects using the configured strategy. On reconnect, it restores:\n\n1. Channel subscriptions (sends `subscribe` for each active channel).\n2. Room memberships (sends `join` for each active room scope).\n3. Local presence state (sends `presence` with the last successfully published state).\n\n```ts\nconst pulse = createPulse<Schema>('wss://api.example.com/ws', {\n reconnect: {\n delay: (attempt) => Math.min(1_000 * 2 ** attempt, 30_000),\n maxAttempts: 5,\n },\n});\n```\n\n`joined` rejects on transport close. For post-reconnect membership, read `pulse.rooms` instead.\n\n## Heartbeat\n\n```ts\nconst pulse = createPulse<Schema>('wss://api.example.com/ws', {\n heartbeat: { interval: 30_000, timeout: 5_000 },\n});\n```\n\nPulse sends periodic pings. If a pong doesn't arrive before the timeout, it forces a reconnect using the same reconnect controller.\n\n## Transform outgoing messages\n\n```ts\nconst pulse = createPulse<Schema>('wss://api.example.com/ws', {\n transform: (message) => {\n // Add a timestamp to all messages\n return { ...message, payload: { ...message.payload, ts: Date.now() } };\n },\n});\n```\n\nReturn `null` to drop a message:\n\n```ts\nconst pulse = createPulse<Schema>('wss://api.example.com/ws', {\n transform: (message) => (message.event === 'debug' ? null : message),\n});\n```\n\n## Wait for a specific event\n\n```ts\nconst notice = await pulse.wait('notice', { timeout: 10_000 });\nconsole.log(notice);\n```\n\n## Dispose\n\n```ts\npulse.dispose();\n```\n\nDisposal is idempotent. It closes the connection, rejects pending room joins, clears all listeners, and aborts all scope disposal signals.\n\n## Error handling\n\n```ts\nconst pulse = createPulse<Schema>('wss://api.example.com/ws', {\n onError: (error) => {\n if (error instanceof PulseConnectionError) {\n console.error('Connection error:', error);\n } else if (error instanceof PulseProtocolError) {\n console.error('Protocol error:', error);\n }\n },\n});\n```\n\n| Error | When |\n| --- | --- |\n| `PulseConnectionError` | Transport failure, send while disconnected, room join rejected on close. |\n| `PulseProtocolError` | Malformed frame or server error frame. |\n| `PulseTimeoutError` | `wait()` times out. |\n| `PulseRoomTimeoutError` | Room scope `joined` times out. |\n| `PulseAbortError` | `wait()` or room `joined` aborted via AbortSignal. |\n| `PulseDisposedError` | Operation attempted after disposal. |\n\n## Best Practices\n\n- Await `connect()` before sending; never assume construction opens the transport.\n- Define the full schema at `createPulse()` so named scopes are type-safe without per-call generics.\n- Use `using` declarations for channel and room scopes so disposal is automatic at block exit.\n- Always call `dispose()` when done — it closes the connection, rejects pending joins, and clears listeners.\n- Provide an `onError` handler; Pulse reports transport and protocol errors there rather than throwing asynchronously.\n- Read `pulse.rooms` for post-reconnect membership; `joined` rejects on transport close.\n- Set a `timeout` on room scopes when the server may never confirm membership.\n- Keep `transform` synchronous; resolve async policy decisions before calling `send()`.\n",
|
|
7
|
+
"examples": "---\ntitle: Examples — Pulse\ndescription: Practical examples for common Pulse usage patterns.\npackage: pulse\ncategory: websockets\n---\n\n<!-- markdownlint-disable MD025 -->\n\n- [Basic Connection](./examples/basic-connection.md)\n- [Channel Multiplexing](./examples/channels.md)\n- [Outgoing Transform](./examples/middleware.md)\n- [Reconnect and Heartbeat](./examples/reconnect-and-heartbeat.md)\n- [Rooms and Presence](./examples/rooms-and-presence.md)\n"
|
|
8
|
+
},
|
|
9
|
+
"examples": [
|
|
10
|
+
{
|
|
11
|
+
"id": "channels",
|
|
12
|
+
"code": "import { createPulse } from '@vielzeug/pulse'\n\n// Isolated channel namespace — listeners and sends are scoped to 'chat'\nconst pulse = createPulse('wss://api.example.com/ws')\nconst chat = pulse.channel('chat')\n\n// Listeners scoped to the channel\nchat.on('message', ({ from, text }) => {\n console.log('[chat] ' + from + ': ' + text)\n})\n\ntry {\n await pulse.connect()\n // Send scoped to the channel\n chat.send('send', { text: 'hey!' })\n} catch (err) {\n console.log('connect failed:', err.message)\n}\n\n// Wait with a per-event timeout\ntry {\n const msg = await chat.wait('message', { timeout: 3_000 })\n console.log('got:', msg.text)\n} catch (err) {\n console.log('channel wait timed out:', err.message)\n}\n\n// Disposing the channel removes all its listeners\n// but the underlying pulse connection stays open\nchat.dispose()\nconsole.log('channel disposed, pulse still open:', pulse.status.value)\n\npulse.dispose()",
|
|
13
|
+
"name": "Typed Channels"
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
"id": "connect-and-send",
|
|
17
|
+
"code": "import { createPulse } from '@vielzeug/pulse'\n\n// Typed WebSocket client: on(), once(), send(), wait()\nconst pulse = createPulse('wss://api.example.com/ws', {\n reconnect: { maxAttempts: 5 },\n onError: (error) => console.log('transport error:', error.message),\n})\n\n// Subscribe before connecting — listeners are synchronous\nconst unsub = pulse.on('chat:message', ({ from, text }) => {\n console.log('[' + from + '] ' + text)\n})\n\n// One-shot listener: fires once and auto-removes\npulse.once('chat:message', (msg) => {\n console.log('first message:', msg.text)\n})\n\n// Connect; send when open\ntry {\n await pulse.connect()\n pulse.send('chat:send', { text: 'Hello, world!' })\n} catch (err) {\n console.log('connect failed:', err.message)\n}\n\n// Await next server event with a 5 s deadline\ntry {\n const msg = await pulse.wait('chat:message', { timeout: 500 })\n console.log('received:', msg.text)\n} catch (err) {\n console.log('wait ended:', err.message)\n}\n\nunsub()\npulse.dispose()",
|
|
18
|
+
"name": "Connect & Send"
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
"id": "lifecycle",
|
|
22
|
+
"code": "import { createPulse, PulseDisposedError } from '@vielzeug/pulse'\n\n// Status signal, disposalSignal, and error handling on dispose\nconst pulse = createPulse('wss://api.example.com/ws', {\n reconnect: { delay: 1_000, maxAttempts: 3 },\n heartbeat: { interval: 30_000, timeout: 5_000 },\n onError: (error) => console.log('Pulse error:', error.message),\n})\n\n// Construction is closed. connect() makes the transport available.\nconsole.log('initial status:', pulse.status.value)\n\n// disposalSignal aborts when dispose() is called\npulse.disposalSignal.addEventListener('abort', () => {\n console.log('disposal signal fired')\n})\n\ntry {\n await pulse.connect()\n console.log('connected:', pulse.status.value)\n} catch (err) {\n console.log('connect failed:', err.message)\n}\n\n// dispose() is idempotent — safe to call multiple times\npulse.dispose()\npulse.dispose()\nconsole.log('disposed:', pulse.disposed)\n\n// Methods reject with PulseDisposedError after dispose\ntry {\n await pulse.connect()\n} catch (err) {\n if (err instanceof PulseDisposedError) {\n console.log('connect() rejected with PulseDisposedError — correct')\n }\n}",
|
|
23
|
+
"name": "Lifecycle & Disposal"
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "reconnect",
|
|
27
|
+
"code": "import { createPulse, PulseConnectionError } from '@vielzeug/pulse'\n\n// Channels, rooms, and local presence state are restored on reconnect.\nconst pulse = createPulse('wss://api.example.com/ws', {\n reconnect: { delay: 500, maxAttempts: 3 },\n onError: (error) => console.log('transport error:', error.message),\n})\n\n// Channel is tracked: re-subscribed automatically after every reconnect\nconst chat = pulse.channel('chat')\nchat.on('message', ({ from, text }) => console.log(from + ': ' + text))\n\n// Connect explicitly to observe the status\ntry {\n await pulse.connect()\n console.log('connected, status:', pulse.status.value)\n} catch (err) {\n if (err instanceof PulseConnectionError) {\n console.log('connection failed:', err.message)\n }\n}\n\nconsole.log('channel name:', chat.name)\nconsole.log('channel disposed?', chat.disposed)\n\n// Disposing a channel removes it from re-subscription tracking\nchat.dispose()\nconsole.log('channel disposed, pulse still running:', !pulse.disposed)\n\npulse.dispose()",
|
|
28
|
+
"name": "Reconnect & Restoration"
|
|
29
|
+
},
|
|
30
|
+
{
|
|
31
|
+
"id": "rooms-presence",
|
|
32
|
+
"code": "import { createPulse } from '@vielzeug/pulse'\n\n// Room scopes: ref-counted membership with reactive presence\nconst pulse = createPulse('wss://api.example.com/ws')\nconst lobby = pulse.room('lobby')\n\ntry {\n await pulse.connect()\n\n // Wait for server confirmation\n await lobby.joined\n console.log('joined lobby, rooms:', [...pulse.rooms.value])\n\n // Broadcast our own presence\n lobby.updatePresence({ avatar: '/me.png', name: 'Alice', status: 'online' })\n\n // Reactive presence map: memberId → state\n const printMembers = () => {\n for (const [id, state] of lobby.presence.value) {\n console.log(' ' + id + ': ' + state.name + ' (' + state.status + ')')\n }\n }\n\n // React to individual joins and leaves\n lobby.onJoin((id, state) => console.log(state.name + ' joined'))\n lobby.onLeave((id) => console.log(id + ' left'))\n} catch (err) {\n console.log('connection or room operation failed:', err.message)\n}\n\n// Dispose the room scope — sends leave when last scope is released\nlobby.dispose()\nconsole.log('rooms after leave:', [...pulse.rooms.value])\n\npulse.dispose()",
|
|
33
|
+
"name": "Rooms & Presence"
|
|
34
|
+
}
|
|
35
|
+
],
|
|
36
|
+
"typeSignatures": {
|
|
37
|
+
"PulseAbortError": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';",
|
|
38
|
+
"PulseConnectionError": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';",
|
|
39
|
+
"PulseDisposedError": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';",
|
|
40
|
+
"PulseError": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';",
|
|
41
|
+
"PulseProtocolError": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';",
|
|
42
|
+
"PulseRoomTimeoutError": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';",
|
|
43
|
+
"PulseTimeoutError": "export {\n PulseAbortError,\n PulseConnectionError,\n PulseDisposedError,\n PulseError,\n PulseProtocolError,\n PulseRoomTimeoutError,\n PulseTimeoutError,\n} from './errors';",
|
|
44
|
+
"createPulse": "export { createPulse } from './pulse';",
|
|
45
|
+
"ChannelDefinition": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
46
|
+
"ChannelDefinitions": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
47
|
+
"ClientEvents": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
48
|
+
"EventKey": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
49
|
+
"HeartbeatOptions": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
50
|
+
"MessageMap": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
51
|
+
"OutgoingMessage": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
52
|
+
"OutgoingTransform": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
53
|
+
"PresenceRoomScope": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
54
|
+
"Pulse": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
55
|
+
"PulseChannel": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
56
|
+
"PulseOptions": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
57
|
+
"PulseSchema": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
58
|
+
"PulseStatus": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
59
|
+
"ReconnectOptions": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
60
|
+
"RoomDefinition": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
61
|
+
"RoomDefinitions": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
62
|
+
"RoomMap": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
63
|
+
"RoomOptions": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
64
|
+
"RoomScope": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
65
|
+
"RoomScopeBase": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
66
|
+
"ServerEvents": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';",
|
|
67
|
+
"Unsubscribe": "export type {\n ChannelDefinition,\n ChannelDefinitions,\n ClientEvents,\n EventKey,\n HeartbeatOptions,\n MessageMap,\n OutgoingMessage,\n OutgoingTransform,\n PresenceRoomScope,\n Pulse,\n PulseChannel,\n PulseOptions,\n PulseSchema,\n PulseStatus,\n ReconnectOptions,\n RoomDefinition,\n RoomDefinitions,\n RoomMap,\n RoomOptions,\n RoomScope,\n RoomScopeBase,\n ServerEvents,\n Unsubscribe,\n} from './types';"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"apiSource": "/**\n * Refine components register through their explicit component entry points.\n *\n * Keeping the package root free of registration side effects makes dependency\n * ownership and bundle contents obvious to application code.\n */\nexport { RefineError } from './errors';\n",
|
|
3
|
+
"docs": {
|
|
4
|
+
"index": "---\ntitle: Refine — Web component library\ndescription: Accessible, themeable web components built with Ore for framework and vanilla DOM apps.\npackage: refine\ncategory: ui-components\nkeywords: [web-components, accessible, themeable, ui, components, design-system]\nrelated: [ore, orbit, forge, keymap]\nexports:\n [\n ore-accordion,\n ore-accordion-item,\n ore-alert,\n ore-async,\n ore-avatar,\n ore-avatar-group,\n ore-badge,\n ore-box,\n ore-breadcrumb,\n ore-breadcrumb-item,\n ore-button,\n ore-button-group,\n ore-calendar,\n ore-card,\n ore-carousel,\n ore-chat-message,\n ore-checkbox,\n ore-checkbox-group,\n ore-chip,\n ore-combobox,\n ore-command-palette,\n ore-command-palette-item,\n ore-datagrid,\n ore-date-picker,\n ore-dialog,\n ore-drawer,\n ore-file-input,\n ore-grid,\n ore-grid-item,\n ore-icon,\n ore-input,\n ore-list,\n ore-list-item,\n ore-menu,\n ore-menu-item,\n ore-menu-separator,\n ore-message-composer,\n ore-navbar,\n ore-navbar-item,\n ore-number-input,\n ore-otp-input,\n ore-pagination,\n ore-password-strength,\n ore-popover,\n ore-progress,\n ore-radio,\n ore-radio-group,\n ore-rating,\n ore-select,\n ore-separator,\n ore-sidebar,\n ore-sidebar-group,\n ore-sidebar-item,\n ore-skeleton,\n ore-slider,\n ore-step,\n ore-stepper,\n ore-switch,\n ore-tab-item,\n ore-tab-panel,\n ore-table,\n ore-tabs,\n ore-text,\n ore-textarea,\n ore-time-picker,\n ore-toast,\n ore-tooltip,\n ore-typing-indicator,\n ]\nenvironments: [browser]\n---\n\n<!-- markdownlint-disable MD025 MD033 MD060 -->\n\n<PackageHero package=\"refine\" />\n\n## Why Refine?\n\nEvery project needs UI primitives. Refine provides accessible web components that work natively anywhere HTML is rendered—no framework required.\n\n```html\n<!-- Before — roll your own button with ARIA -->\n<button class=\"btn btn-primary\" role=\"button\" aria-pressed=\"false\" tabindex=\"0\">\n <span class=\"btn-spinner\" aria-hidden=\"true\"></span>\n Save\n</button>\n\n<!-- After — Refine -->\n<ore-button variant=\"primary\" loading>Save</ore-button>\n```\n\n| Feature | Refine | Shoelace | Material Web |\n| ------------------ | ------------------------------------------- | ------------------------------------------ | ------------------------------------------ |\n| Bundle size | <PackageInfo package=\"refine\" type=\"size\" /> | ~145 kB | ~200 kB |\n| Built with | Ore | Lit | Lit |\n| Accessible | WCAG AA | WCAG AA | WCAG AA |\n| Framework agnostic | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> | <ore-icon name=\"check\" size=\"16\"></ore-icon> |\n\n<div class=\"decision-callout\">\n\n**Use Refine when** you want accessible web components that match the Vielzeug design system without a heavy framework dependency.\n\n**Consider Shoelace or Material Web** if your team is already standardized on those ecosystems and you need their established component catalogs.\n\n</div>\n\n## Installation\n\n::: code-group\n\n```sh [pnpm]\npnpm add @vielzeug/refine\n```\n\n```sh [npm]\nnpm install @vielzeug/refine\n```\n\n```sh [yarn]\nyarn add @vielzeug/refine\n```\n\n:::\n\n## Quick Start\n\n```ts\n// 1. Import global styles once\nimport '@vielzeug/refine/fouc.css'; // Hide unupgraded custom elements until first paint\nimport '@vielzeug/refine/tokens.css'; // Tokens, animations, cascade layers\n\n// 2. Register only the elements you need\nimport '@vielzeug/refine/button';\nimport '@vielzeug/refine/input';\nimport '@vielzeug/refine/card';\n```\n\n```html\n<ore-button variant=\"solid\" color=\"primary\">Save</ore-button>\n<ore-input label=\"Email\" type=\"email\" required></ore-input>\n<ore-card padding=\"lg\">\n <span slot=\"header\">Account</span>\n <p>Card content goes here.</p>\n</ore-card>\n```\n\n```ts\n```\n\n### CDN / Vanilla HTML\n\nUse the self-contained IIFE bundle to load Refine directly from a CDN in any HTML page — no build step required:\n\n```html\n<!-- 1. Styles -->\n<link rel=\"stylesheet\" href=\"https://unpkg.com/@vielzeug/refine/dist/styles/fouc.css\" />\n<link rel=\"stylesheet\" href=\"https://unpkg.com/@vielzeug/refine/dist/styles/tokens.css\" />\n\n<!-- 2. All components (IIFE — registers global Refine namespace) -->\n<script src=\"https://unpkg.com/@vielzeug/refine/dist/refine.iife.js\"></script>\n```\n\nFor bundler-based projects that still want a CDN URL, use the ESM bundle via an import map:\n\n```html\n<script type=\"importmap\">\n {\n \"imports\": {\n \"@vielzeug/refine\": \"https://esm.sh/@vielzeug/refine\",\n \"@vielzeug/refine/button\": \"https://esm.sh/@vielzeug/refine/button\",\n \"@vielzeug/refine/input\": \"https://esm.sh/@vielzeug/refine/input\"\n }\n }\n</script>\n\n<script type=\"module\">\n import '@vielzeug/refine/button';\n import '@vielzeug/refine/input';\n</script>\n```\n\n### Package Entry Points\n\n| Import | Purpose |\n| ------------------------ | ----------------------------------------- |\n| `@vielzeug/refine/fouc.css` | FOUC suppression for unupgraded custom elements |\n| `@vielzeug/refine/tokens.css` | Global design tokens and cascade layers |\n| `@vielzeug/refine/styles/preflight.css` | Optional browser-default reset (includes FOUC suppression) |\n\nComponent registration happens through side-effect imports such as `@vielzeug/refine/button` and `@vielzeug/refine/dialog`.\n\n### Components\n\n**Content:** `ore-avatar`, `ore-avatar-group`, `ore-breadcrumb`, `ore-card`, `ore-carousel`, `ore-carousel-slide`, `ore-chat-message`, `ore-icon`, `ore-list`, `ore-list-item`, `ore-marquee`, `ore-pagination`, `ore-separator`, `ore-step`, `ore-stepper`, `ore-table`, `ore-text`\n\n**Disclosure:** `ore-accordion`, `ore-accordion-item`, `ore-tabs`, `ore-tab-item`, `ore-tab-panel`\n\n**Feedback:** `ore-alert`, `ore-async`, `ore-badge`, `ore-chip`, `ore-password-strength`, `ore-progress`, `ore-skeleton`, `ore-toast`, `ore-typing-indicator`\n\n**Inputs:** `ore-button`, `ore-button-group`, `ore-calendar`, `ore-checkbox`, `ore-checkbox-group`, `ore-column`, `ore-combobox`, `ore-datagrid`, `ore-date-picker`, `ore-file-input`, `ore-input`, `ore-message-composer`, `ore-number-input`, `ore-otp-input`, `ore-radio`, `ore-radio-group`, `ore-rating`, `ore-select`, `ore-slider`, `ore-switch`, `ore-textarea`, `ore-time-picker`\n\n**Layout:** `ore-box`, `ore-grid`, `ore-grid-item`, `ore-navbar`, `ore-sidebar`\n\n**Overlay:** `ore-command-palette`, `ore-command-palette-item`, `ore-dialog`, `ore-drawer`, `ore-menu`, `ore-popover`, `ore-tooltip`\n\n## Features\n\n<div class=\"features-grid\">\n\n- **Accessible** — keyboard navigation, ARIA wiring, and focus management across interactive components\n- **Themeable** — global tokens plus component-level CSS custom properties\n- **Framework agnostic** — works anywhere HTML can be rendered\n- **Tree-shakeable** — import only the component entry points you register\n- **Comprehensive surface** — inputs, content, disclosure, feedback, layout, and overlay primitives\n- **Zero runtime deps** — <PackageInfo package=\"refine\" type=\"size\" /> gzipped\n\n</div>\n\n### Prerequisites\n\n- Browser runtime with Custom Elements support.\n- Import `@vielzeug/refine/fouc.css` and `@vielzeug/refine/tokens.css` before rendering components.\n- For SSR, render placeholders server-side and hydrate components only on the client.\n\n## Documentation\n\n<div class=\"doc-links\">\n\n- [Usage Guide](./usage.md)\n- [API Reference](./api.md)\n- [Migration Guide](./migration.md)\n\n</div>\n\n## See Also\n\n<div class=\"see-also\">\n\n- [Ore](/ore/) — Web component runtime that powers Refine\n- [Orbit](/orbit/) — Floating UI positioning used in Refine's overlays\n- [Forge](/forge/) — Form state management for use with Refine inputs\n- [Keymap](/keymap/) — Keyboard shortcut manager that powers the command palette's global trigger\n\n</div>\n\n<!-- markdownlint-enable MD025 MD033 MD060 -->\n",
|
|
5
|
+
"api": "---\ntitle: Refine — API Reference\ndescription: Published component registration and stylesheet entry points for @vielzeug/refine.\n---\n\n# API Reference\n\n[[toc]]\n\nRefine deliberately publishes components, not a second headless framework. Register each element through its component\nsubpath and import its types from the same path.\n\n## Styles\n\n```ts\nimport '@vielzeug/refine/fouc.css'; // Hide unupgraded custom elements until first paint\nimport '@vielzeug/refine/tokens.css'; // Required: tokens, animations, cascade layers\nimport '@vielzeug/refine/styles/preflight.css'; // Optional: normalizes browser defaults.\n```\n\n`fouc.css` suppresses flash-of-unstyled-content by hiding custom elements (`:not(:defined)`)\nuntil their shadow DOM attaches. Import it in your CSS bundle — not via JS injection — so the\nrule is available at first paint. `tokens.css` defines Refine's design tokens, animations, and\ncascade-layer order without modifying global element defaults. `preflight.css` is a separate\nopt-in reset that also imports `fouc.css`.\n\nDirect CSS entry points are also available when needed:\n\n| Import path | Purpose |\n| --- | --- |\n| `@vielzeug/refine/fouc.css` | FOUC suppression for unupgraded custom elements |\n| `@vielzeug/refine/tokens.css` | Tokens, animation helpers, and cascade layers |\n| `@vielzeug/refine/styles/theme.css` | Theme token declarations |\n| `@vielzeug/refine/styles/animation.css` | Animation helpers |\n| `@vielzeug/refine/styles/layers.css` | Cascade layer declarations |\n| `@vielzeug/refine/styles/preflight.css` | Optional browser-default reset (includes FOUC suppression) |\n\n## Components\n\nEach component has a single registration and type entry point:\n\n```ts\nimport '@vielzeug/refine/button';\nimport type { OreButtonEvents, OreButtonProps } from '@vielzeug/refine/button';\n```\n\nThe package root only exports `RefineError`; it does not register elements. This keeps component ownership and bundle\ncontents explicit.\n\n| Area | Components |\n| --- | --- |\n| Content | `accordion`, `accordion-item`, `avatar`, `avatar-group`, `badge`, `breadcrumb`, `card`, `carousel`, `chat-message`, `code-window`, `copy-command`, `icon`, `list`, `list-item`, `marquee`, `pagination`, `separator`, `step`, `stepper`, `table`, `text` |\n| Feedback | `alert`, `async`, `chip`, `password-strength`, `progress`, `skeleton`, `toast`, `typing-indicator` |\n| Inputs | `button`, `button-group`, `calendar`, `checkbox`, `checkbox-group`, `combobox`, `datagrid`, `date-picker`, `file-input`, `input`, `message-composer`, `number-input`, `otp-input`, `radio`, `radio-group`, `rating`, `select`, `slider`, `switch`, `textarea`, `time-picker` |\n| Layout | `box`, `grid`, `grid-item`, `navbar`, `sidebar` |\n| Overlays | `command-palette`, `dialog`, `drawer`, `menu`, `popover`, `tooltip` |\n\nEach component's documentation page describes its attributes, properties, events, slots, parts, and custom properties.\n\n## Events and Form Controls\n\nForm controls expose their current `.value` or `.checked` property and dispatch standard `input` and `change` events.\nRead the property from `event.currentTarget`; do not rely on framework-specific custom-event casts.\n\nStateful overlays expose `open` and `default-open` properties/attributes and dispatch `open-change` with\n`{ open, reason }` detail. The per-component pages describe valid reasons and focus behavior.\n",
|
|
6
|
+
"usage": "---\ntitle: Refine — Usage Guide\ndescription: Installation, attributes, events, slots, and ecosystem integration for Refine components.\n---\n\n# Usage Guide\n\n[[toc]]\n\nRefine components are native Web Components. Once imported, they behave like regular HTML elements — set attributes, listen to DOM events, use slots for content projection.\n\n## Installation\n\nImport the global styles first, then register only the components you need:\n\n```ts\nimport '@vielzeug/refine/tokens.css';\nimport '@vielzeug/refine/button';\nimport '@vielzeug/refine/input';\nimport '@vielzeug/refine/dialog';\n```\n\nThe token stylesheet supplies Refine's design tokens and cascade layers without changing browser defaults. Add the reset only when your application explicitly wants it:\n\n```ts\nimport '@vielzeug/refine/styles/preflight.css';\n```\n\n## Attributes and Events\n\nSet attributes directly on the element. Attributes map to component props:\n\n```html\n<ore-button variant=\"outline\" color=\"secondary\" size=\"lg\" disabled>\n Large Outline Button\n</ore-button>\n```\n\nComponents emit standard DOM events. Common event names: `click`, `input`, `change`, and `open-change`. Custom events carry a `detail` object:\n\n```javascript\nconst input = document.querySelector('ore-input');\n\ninput.addEventListener('input', () => {\n console.log(input.value);\n});\n```\n\nNative browser events (`click`, `focus`, `blur`) work as normal. Custom events with `event.detail` require `addEventListener` in React 18 and earlier — see the [Framework Integration](./frameworks.md) guide.\n\n## Slots\n\nSlots let you pass HTML into named regions of a component without JavaScript.\n\nContent placed directly inside the element fills the default slot:\n\n```html\n<ore-button>Save Changes</ore-button>\n<ore-card>Any HTML content here</ore-card>\n```\n\nComponents with distinct regions expose named slots:\n\n```html\n<ore-card>\n <span slot=\"header\">Card Heading</span>\n <p>Main body content fills the default slot.</p>\n <div slot=\"footer\">\n <ore-button size=\"sm\" variant=\"outline\">Cancel</ore-button>\n <ore-button size=\"sm\">Confirm</ore-button>\n </div>\n</ore-card>\n```\n\nMany input components expose `prefix` and `suffix` slots for icons or actions:\n\n```html\n<ore-button>\n <ore-icon slot=\"prefix\" name=\"arrow-left\" size=\"18\"></ore-icon>\n Back\n</ore-button>\n\n<ore-input label=\"Search\">\n <ore-icon slot=\"suffix\" name=\"search\" size=\"18\" aria-hidden=\"true\"></ore-icon>\n</ore-input>\n```\n\nEach component's available slots are listed in its API Reference table.\n\n## Composing with Ore and Ripple\n\nRefine components are plain HTML elements — they compose naturally with [Ore](/ore/) custom elements and [Ripple](/ripple/) signals.\n\n**Build a custom component that wraps Refine elements:**\n\n```ts\nimport '@vielzeug/refine/button';\nimport '@vielzeug/refine/input';\nimport { define, html } from '@vielzeug/ore';\nimport { signal } from '@vielzeug/ripple';\n\ndefine('my-search-bar', () => {\n const query = signal('');\n return html`\n <ore-input\n .value=${query}\n @input=${(e) => (query.value = e.currentTarget.value)}\n label=\"Search\"\n />\n <ore-button @click=${() => search(query.value)} variant=\"solid\" color=\"primary\">\n Search\n </ore-button>\n `;\n});\n```\n\n**Drive component state from reactive signals:**\n\n```ts\nimport { signal, effect } from '@vielzeug/ripple';\n\nconst isLoading = signal(false);\nconst btn = document.querySelector('ore-button');\n\neffect(() => {\n btn.loading = isLoading.value;\n});\n```\n\n## Framework Integration\n\nFor React, Vue, Svelte, and Angular wiring — including event handling, TypeScript declarations, Vite setup, and SSR guards — see the [Framework Integration](./frameworks.md) guide.\n\n## Accessibility\n\nAll Refine components target WCAG 2.1 AA. ARIA roles and states are managed automatically. For the full compliance contract, per-component coverage, and testing strategy, see the [Accessibility](./accessibility.md) page.\n\nThe two things you always control:\n\n- **Icon-only buttons** require a `label` attribute — it becomes `aria-label`.\n- **Decorative icons** should have `aria-hidden=\"true\"` so screen readers skip them.\n"
|
|
7
|
+
},
|
|
8
|
+
"examples": [],
|
|
9
|
+
"typeSignatures": {
|
|
10
|
+
"RefineError": "export { RefineError } from './errors';"
|
|
11
|
+
}
|
|
12
|
+
}
|