uplot-plus 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (58) hide show
  1. package/README.md +107 -225
  2. package/dist/index.cjs +1 -1
  3. package/dist/index.js +2427 -2098
  4. package/dist/src/annotations.d.ts.map +1 -1
  5. package/dist/src/axes/layout.d.ts.map +1 -1
  6. package/dist/src/components/Axis.d.ts +0 -3
  7. package/dist/src/components/Axis.d.ts.map +1 -1
  8. package/dist/src/components/BoxWhisker.d.ts +24 -0
  9. package/dist/src/components/BoxWhisker.d.ts.map +1 -0
  10. package/dist/src/components/Candlestick.d.ts +18 -0
  11. package/dist/src/components/Candlestick.d.ts.map +1 -0
  12. package/dist/src/components/Chart.d.ts +1 -1
  13. package/dist/src/components/Chart.d.ts.map +1 -1
  14. package/dist/src/components/Heatmap.d.ts +14 -0
  15. package/dist/src/components/Heatmap.d.ts.map +1 -0
  16. package/dist/src/components/Scale.d.ts +0 -3
  17. package/dist/src/components/Scale.d.ts.map +1 -1
  18. package/dist/src/components/Series.d.ts +0 -3
  19. package/dist/src/components/Series.d.ts.map +1 -1
  20. package/dist/src/components/Sparkline.d.ts.map +1 -1
  21. package/dist/src/components/Vector.d.ts +16 -0
  22. package/dist/src/components/Vector.d.ts.map +1 -0
  23. package/dist/src/components/ZoomRanger.d.ts.map +1 -1
  24. package/dist/src/components/annotations/HLine.d.ts.map +1 -1
  25. package/dist/src/components/annotations/Region.d.ts.map +1 -1
  26. package/dist/src/components/annotations/VLine.d.ts.map +1 -1
  27. package/dist/src/components/annotations/useAnnotationDraw.d.ts +8 -0
  28. package/dist/src/components/annotations/useAnnotationDraw.d.ts.map +1 -0
  29. package/dist/src/core/DataStore.d.ts.map +1 -1
  30. package/dist/src/core/Scale.d.ts +5 -0
  31. package/dist/src/core/Scale.d.ts.map +1 -1
  32. package/dist/src/core/ScaleManager.d.ts.map +1 -1
  33. package/dist/src/hooks/useChartStore.d.ts +6 -4
  34. package/dist/src/hooks/useChartStore.d.ts.map +1 -1
  35. package/dist/src/hooks/useInteraction.d.ts +1 -2
  36. package/dist/src/hooks/useInteraction.d.ts.map +1 -1
  37. package/dist/src/hooks/useRegisterConfig.d.ts +16 -0
  38. package/dist/src/hooks/useRegisterConfig.d.ts.map +1 -0
  39. package/dist/src/index.d.ts +10 -3
  40. package/dist/src/index.d.ts.map +1 -1
  41. package/dist/src/paths/bars.d.ts +2 -0
  42. package/dist/src/paths/bars.d.ts.map +1 -1
  43. package/dist/src/paths/utils.d.ts +0 -5
  44. package/dist/src/paths/utils.d.ts.map +1 -1
  45. package/dist/src/rendering/drawRangeBox.d.ts +29 -0
  46. package/dist/src/rendering/drawRangeBox.d.ts.map +1 -0
  47. package/dist/src/time/timeIncrs.d.ts.map +1 -1
  48. package/dist/src/time/timeSplits.d.ts +1 -1
  49. package/dist/src/time/timeSplits.d.ts.map +1 -1
  50. package/dist/src/types/chart.d.ts +6 -31
  51. package/dist/src/types/chart.d.ts.map +1 -1
  52. package/dist/src/types/index.d.ts +3 -1
  53. package/dist/src/types/index.d.ts.map +1 -1
  54. package/dist/src/types/interaction.d.ts +62 -0
  55. package/dist/src/types/interaction.d.ts.map +1 -0
  56. package/package.json +2 -3
  57. package/dist/src/paths/candlestick.d.ts +0 -35
  58. package/dist/src/paths/candlestick.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,35 +1,15 @@
1
1
  # uPlot+
2
2
 
3
- High-performance React charting library ripped off from uPlot. Might perform occasionally better than original uPlot in React context (or worse). Definitely easier to use in React context.
3
+ High-performance React charting library ripped off from [uPlot](https://github.com/leeoniya/uplot). Might perform occasionally better than original uPlot in React context (or worse). Definitely easier to use in React context.
4
4
 
5
- **[Live Demo (99 examples)](https://yeonsoo-p.github.io/uPlot-Plus/)**
5
+ **[Live Demo (101 examples)](https://yeonsoo-p.github.io/uPlot-Plus/)**
6
6
 
7
- ## Features
8
-
9
- - **Canvas 2D rendering** — no SVG or DOM elements for data visualization
10
- - **Native React components** — declarative `<Chart>`, `<Series>`, `<Scale>`, `<Axis>` API
11
- - **Multi-x-axis support** — multiple data groups with independent x-ranges on one chart
12
- - **TypeScript-first** — strict types, full type exports, no `any`
13
- - **7 path builders** — linear, stepped, bars, monotone cubic, Catmull-Rom, points, candlestick
14
- - **Interactive** — wheel/touch zoom, drag-to-zoom, cursor snapping, series focus
15
- - **Cursor sync** — linked crosshairs and tooltips across multiple charts
16
- - **Compact bundle** — ~128KB (~36KB gzip), React 18+ peer dependency
17
- - **Dual output** — ES module + CommonJS
18
-
19
- ## Installation
20
-
21
- ```sh
22
- npm install uplot-plus
23
- ```
24
-
25
- Peer dependencies:
7
+ ## Quick Start
26
8
 
27
9
  ```sh
28
- npm install react react-dom
10
+ npm install uplot-plus react react-dom
29
11
  ```
30
12
 
31
- ## Quick Start
32
-
33
13
  Scales, axes, and colors are auto-injected when omitted — the simplest chart is just data + series:
34
14
 
35
15
  ```tsx
@@ -37,13 +17,9 @@ import { Chart, Series } from 'uplot-plus';
37
17
 
38
18
  const data = { x: [1, 2, 3, 4, 5], y: [10, 25, 13, 30, 18] };
39
19
 
40
- function App() {
41
- return (
42
- <Chart width={800} height={400} data={data}>
43
- <Series group={0} index={0} label="Revenue" />
44
- </Chart>
45
- );
46
- }
20
+ <Chart width={800} height={400} data={data}>
21
+ <Series group={0} index={0} label="Revenue" />
22
+ </Chart>
47
23
  ```
48
24
 
49
25
  For full control, declare scales, axes, and series explicitly:
@@ -51,231 +27,142 @@ For full control, declare scales, axes, and series explicitly:
51
27
  ```tsx
52
28
  import { Chart, Scale, Series, Axis } from 'uplot-plus';
53
29
 
54
- const data = [
55
- {
56
- x: [1, 2, 3, 4, 5],
57
- series: [
58
- [10, 25, 13, 30, 18],
59
- [5, 15, 20, 12, 28],
60
- ],
61
- },
62
- ];
30
+ const data = [{ x: [1, 2, 3, 4, 5], series: [[10, 25, 13, 30, 18], [5, 15, 20, 12, 28]] }];
63
31
 
64
- function App() {
65
- return (
66
- <Chart width={800} height={400} data={data}>
67
- <Scale id="x" />
68
- <Scale id="y" />
69
- <Axis scale="x" label="X-Axis" />
70
- <Axis scale="y" label="Y-Axis" />
71
- <Series group={0} index={0} yScale="y" stroke="#e74c3c" width={2} label="Series A" />
72
- <Series group={0} index={1} yScale="y" stroke="#3498db" width={2} label="Series B" />
73
- </Chart>
74
- );
75
- }
76
- ```
77
-
78
- ## Components
79
-
80
- | Component | Description |
81
- |-----------|-------------|
82
- | `<Chart>` | Root container — creates the canvas, manages the chart store |
83
- | `<Scale>` | Registers a scale (linear, log, asinh, ordinal) |
84
- | `<Series>` | Registers a data series with stroke, fill, path builder |
85
- | `<Axis>` | Renders an axis with ticks, labels, grid lines |
86
- | `<Band>` | Fills a region between two series |
87
- | `<Legend>` | Interactive legend with live cursor values, click-to-toggle |
88
- | `<Tooltip>` | Floating tooltip at cursor position, auto-flips at edges |
89
- | `<FloatingLegend>` | Draggable or cursor-following legend panel with idle opacity fade |
90
- | `<HoverLabel>` | Shows nearest series info after a hover delay |
91
- | `<ZoomRanger>` | Overview mini-chart with draggable selection for zoom control |
92
- | `<Timeline>` | Horizontal lanes of colored event spans |
93
- | `<Sparkline>` | Compact inline chart for tables and dashboards (no axes, no interaction) |
94
- | `<ResponsiveChart>` | Auto-sizes to container via ResizeObserver |
95
- | `<HLine>` | Declarative horizontal line annotation |
96
- | `<VLine>` | Declarative vertical line annotation |
97
- | `<Region>` | Declarative shaded region annotation |
98
- | `<AnnotationLabel>` | Declarative text label at data coordinates |
99
-
100
- > Full props reference, usage examples, and demo links: [docs/COMPONENTS.md](docs/COMPONENTS.md)
101
-
102
- ## Data Model
103
-
104
- Three input forms — use whichever fits your data:
105
-
106
- ```ts
107
- // Simplest: single series
108
- const data = { x: [1, 2, 3, 4, 5], y: [10, 20, 30, 40, 50] };
109
-
110
- // Multiple series sharing one x-axis
111
- const data = [
112
- {
113
- x: [1, 2, 3, 4, 5],
114
- series: [
115
- [10, 20, 30, 40, 50], // series 0
116
- [5, 15, 25, 35, 45], // series 1
117
- ],
118
- },
119
- ];
120
-
121
- // Multi x-axis — two groups with independent x-ranges
122
- const multiData = [
123
- { x: [0, 1, 2, 3], series: [[10, 20, 15, 25]] },
124
- { x: [0, 0.5, 1.5, 2.5, 3], series: [[8, 18, 22, 12, 30]] },
125
- ];
32
+ <Chart width={800} height={400} data={data}>
33
+ <Scale id="x" />
34
+ <Scale id="y" />
35
+ <Axis scale="x" label="X-Axis" />
36
+ <Axis scale="y" label="Y-Axis" />
37
+ <Series group={0} index={0} yScale="y" stroke="#e74c3c" label="Series A" />
38
+ <Series group={0} index={1} yScale="y" stroke="#3498db" label="Series B" />
39
+ </Chart>
126
40
  ```
127
41
 
128
- Each series is referenced by a `(group, index)` tuple — `group` is the index into the `ChartData` array, `index` is the index into that group's `series` array.
42
+ ## Chart Types
129
43
 
130
- Null values in series arrays create gaps in the chart. Use `spanGaps` on `<Series>` to bridge them.
131
-
132
- ## Path Builders
133
-
134
- | Builder | Import | Use case |
135
- |---------|--------|----------|
136
- | `linear()` | `linear` | Line/area charts (default). Pixel-level decimation for large datasets |
137
- | `stepped()` | `stepped` | Step charts — step-after, step-before, or mid-step |
138
- | `bars()` | `bars` | Bar/column charts with configurable width and gaps |
139
- | `groupedBars()` | `groupedBars` | Side-by-side grouped bar charts |
140
- | `stackedBars()` | `stackedBars` | Stacked bar charts |
141
- | `monotoneCubic()` | `monotoneCubic` | Smooth curves that preserve monotonicity (no overshoot) |
142
- | `catmullRom()` | `catmullRom` | Centripetal Catmull-Rom splines |
143
- | `points()` | `points` | Scatter plots — points only, no connecting lines |
144
- | `drawCandlesticks()` | `drawCandlesticks` | OHLC financial candlestick charts |
44
+ All chart types are configured via the `paths` prop on `<Series>`, or via specialized components:
145
45
 
146
46
  ```tsx
147
- import { Series, bars } from 'uplot-plus';
47
+ import { Series, bars, stepped, monotoneCubic, points } from 'uplot-plus';
148
48
 
149
- <Series group={0} index={0} yScale="y" paths={bars()} stroke="#3498db" fill="#3498db80" />
49
+ <Series paths={bars()} /> // Bar / column charts
50
+ <Series paths={stepped()} /> // Step charts
51
+ <Series paths={monotoneCubic()} /> // Smooth curves
52
+ <Series paths={points()} /> // Scatter plots
150
53
  ```
151
54
 
152
- ## Event Callbacks
55
+ | Type | How to use |
56
+ | ---- | ---------- |
57
+ | Line / area | Default — just `<Series />` with optional `fill` |
58
+ | Bar / column | `<Series paths={bars()} />` — also `groupedBars()`, `stackedBars()` |
59
+ | Step | `<Series paths={stepped()} />` — step-after, step-before, mid-step |
60
+ | Smooth curve | `<Series paths={monotoneCubic()} />` or `catmullRom()` |
61
+ | Scatter | `<Series paths={points()} />` |
62
+ | Candlestick | `<Candlestick />` — OHLC financial charts |
63
+ | Box & whisker | `<BoxWhisker boxes={[...]} />` — quartile distributions |
64
+ | Heatmap | `<Heatmap grid={[...]} />` — 2D colored grid |
65
+ | Vector field | `<Vector directions={[...]} />` — directional arrows on data |
66
+ | Timeline | `<Timeline lanes={[...]} />` — horizontal event lanes |
67
+ | Sparkline | `<Sparkline data={data} />` — compact inline chart |
153
68
 
154
- React-idiomatic event handling — all callbacks receive resolved chart data (nearest point, data values, coordinates).
69
+ ## Interactions
155
70
 
156
- ```tsx
157
- import { Chart, Scale, Series, Axis } from 'uplot-plus';
71
+ Every user gesture maps to a chart reaction via the **action map**. Default behavior works out of the box — drag to zoom, double-click to reset, y-axis gutter drag to pan:
158
72
 
159
- <Chart
160
- data={data} width={800} height={400}
161
- onClick={(info) => {
162
- if (info.point) {
163
- console.log(`Clicked series ${info.point.seriesIdx} at y=${info.point.yVal}`);
164
- }
165
- }}
166
- onContextMenu={(info) => {
167
- // Right-click with resolved nearest point
168
- showContextMenu(info.srcEvent, info.point);
169
- }}
170
- onDblClick={(info) => {
171
- // Return false to prevent default zoom reset
172
- return false;
173
- }}
174
- onSelect={(sel) => {
175
- // Intercept drag selection — fetch detail data instead of zooming
176
- fetchData(sel.ranges['x'].min, sel.ranges['x'].max);
177
- return false; // prevent zoom
178
- }}
179
- onScaleChange={(scaleId, min, max) => {
180
- console.log(`Scale ${scaleId} changed: [${min}, ${max}]`);
181
- }}
182
- onCursorMove={(info) => { /* fires on every mouse move */ }}
183
- onCursorLeave={() => { /* cursor left the plot */ }}
184
- >
185
- <Scale id="x" />
186
- <Scale id="y" />
187
- <Axis scale="x" />
188
- <Axis scale="y" />
189
- <Series group={0} index={0} yScale="y" stroke="#e74c3c" width={2} label="Series A" />
73
+ ```tsx
74
+ // Defaults: leftDrag→zoomX, leftDblclick→reset, wheel→zoomX, yGutterDrag→panY, xGutterDrag→panX
75
+ <Chart data={data} width={800} height={400}>
76
+ <Series group={0} index={0} />
190
77
  </Chart>
191
78
  ```
192
79
 
193
- ### Controlled Scales
194
-
195
- Control zoom and pan declaratively through React state — no imperative refs needed:
80
+ Override any gesture by passing `[action, reaction]` tuples — merged with defaults internally:
196
81
 
197
82
  ```tsx
198
- import { useState, useCallback } from 'react';
199
- import { Chart, Scale, Series, Axis } from 'uplot-plus';
83
+ // Wheel zooms both axes, shift+wheel zooms Y only
84
+ <Chart actions={[['wheel', 'zoomXY'], ['shiftWheel', 'zoomY']]} />
200
85
 
201
- function ZoomableChart({ data }) {
202
- const [xRange, setXRange] = useState<[number, number] | null>(null);
203
-
204
- const onScaleChange = useCallback((id: string, min: number, max: number) => {
205
- if (id === 'x') setXRange([min, max]);
206
- }, []);
207
-
208
- return (
209
- <>
210
- <button onClick={() => setXRange(null)}>Reset Zoom</button>
211
- <Chart data={data} width={800} height={400} onScaleChange={onScaleChange}>
212
- <Scale id="x"
213
- auto={xRange == null} min={xRange?.[0]} max={xRange?.[1]} />
214
- <Scale id="y" />
215
- {/* ... axes, series */}
216
- </Chart>
217
- </>
218
- );
219
- }
220
- ```
221
-
222
- ## Hooks
86
+ // Middle-drag pans, disable double-click reset
87
+ <Chart actions={[['middleDrag', 'panXY'], ['leftDblclick', 'none']]} />
223
88
 
224
- ### `useChart()`
89
+ // Focus mode: hover dims non-nearest series
90
+ import { focus } from 'uplot-plus';
91
+ <Chart actions={[['hover', focus(0.15)]]} />
92
+ ```
225
93
 
226
- Access the chart store from a child component of `<Chart>`. This is an advanced API for building custom chart sub-components that need direct store access — for most use cases, prefer event callbacks and controlled Scale props.
94
+ Custom function matchers for actions the built-in classifiers don't cover:
227
95
 
228
96
  ```tsx
229
- import { useChart } from 'uplot-plus';
97
+ <Chart actions={[
98
+ // String → function: built-in classifier handles shift+click
99
+ ['shiftLeftClick', (store) => { /* toggle series */ }],
230
100
 
231
- function CustomControl() {
232
- const store = useChart();
233
- return <button onClick={() => store.toggleSeries(0, 0)}>Toggle</button>;
234
- }
235
- ```
101
+ // String → function: keyboard shortcut
102
+ ['shiftKeyX', (store) => { /* reset widths */ }],
236
103
 
237
- ### `useDrawHook()` / `useCursorDrawHook()`
104
+ // Function → function: truly custom (e.g. Q key held + click)
105
+ [(e, ctx) => isQHeld && ctx.action === 'leftClick', (store) => { /* custom */ }],
106
+ ]} />
107
+ ```
238
108
 
239
- Register custom Canvas 2D draw callbacks from child components. For most cases, prefer the `onDraw` / `onCursorDraw` props on `<Chart>` — these hooks are useful when building reusable chart sub-components.
109
+ **Built-in actions:** `{mod?}{Button}{Type}` `leftDrag`, `shiftMiddleClick`, `ctrlRightDrag`, `wheel`, `shiftWheel`, `xGutterDrag`, `yGutterDrag`, `hover`, `touchDrag`, `pinch`, `key{Key}`, `shiftKey{Key}`
240
110
 
241
- ```tsx
242
- import { useDrawHook } from 'uplot-plus';
243
- import type { DrawCallback } from 'uplot-plus';
111
+ **Built-in reactions:** `zoomX`, `zoomY`, `zoomXY`, `panX`, `panY`, `panXY`, `reset`, `none`
244
112
 
245
- const onDraw: DrawCallback = (dc) => {
246
- dc.ctx.fillStyle = 'rgba(255,0,0,0.2)';
247
- dc.ctx.fillRect(dc.plotBox.left, dc.plotBox.top, dc.plotBox.width, dc.plotBox.height);
248
- };
249
- ```
113
+ ## Components
250
114
 
251
- ### `useStreamingData()`
115
+ | Component | Description |
116
+ |-----------|-------------|
117
+ | `<Chart>` | Root container — creates the canvas, manages the chart store |
118
+ | `<Scale>` | Registers a scale (linear, log, asinh, ordinal) |
119
+ | `<Series>` | Registers a data series with stroke, fill, path builder |
120
+ | `<Axis>` | Renders an axis with ticks, labels, grid lines |
121
+ | `<Band>` | Fills a region between two series |
122
+ | `<Legend>` | Interactive legend with live cursor values, click-to-toggle |
123
+ | `<Tooltip>` | Floating tooltip at cursor position, auto-flips at edges |
124
+ | `<FloatingLegend>` | Draggable or cursor-following legend panel |
125
+ | `<HoverLabel>` | Shows nearest series info after a hover delay |
126
+ | `<ZoomRanger>` | Overview mini-chart with draggable selection for zoom control |
127
+ | `<Timeline>` | Horizontal lanes of colored event spans |
128
+ | `<Sparkline>` | Compact inline chart for tables and dashboards |
129
+ | `<BoxWhisker>` | Box-and-whisker plot with quartiles, whiskers, and median |
130
+ | `<Candlestick>` | OHLC financial candlestick chart |
131
+ | `<Heatmap>` | 2D grid of colored cells with configurable color map |
132
+ | `<Vector>` | Directional arrows overlaid on data points |
133
+ | `<HLine>` | Horizontal line annotation |
134
+ | `<VLine>` | Vertical line annotation |
135
+ | `<Region>` | Shaded region annotation |
136
+ | `<AnnotationLabel>` | Text label at data coordinates |
137
+
138
+ > Full props reference: [docs/COMPONENTS.md](docs/COMPONENTS.md)
252
139
 
253
- Sliding-window data management for real-time charts:
140
+ ## Data Model
254
141
 
255
- ```tsx
256
- import { useStreamingData } from 'uplot-plus';
142
+ Three input forms — use whichever fits your data:
257
143
 
258
- const { data, push, pushGroup, start, stop, fps } = useStreamingData(initialData, {
259
- window: 1000, // keep last 1000 points
260
- batchSize: 10, // push 10 points per tick
261
- });
144
+ ```ts
145
+ // Simplest: single series
146
+ const data = { x: [1, 2, 3, 4, 5], y: [10, 20, 30, 40, 50] };
262
147
 
263
- // Push into group 0 (default):
264
- push([newX], [newY1], [newY2]);
148
+ // Multiple series sharing one x-axis
149
+ const data = [{ x: [1, 2, 3, 4, 5], series: [[10, 20, 30], [5, 15, 25]] }];
265
150
 
266
- // Push into a specific group (for multi-x-axis charts):
267
- pushGroup(1, [newX], [newY1]);
151
+ // Multi x-axis two groups with independent x-ranges
152
+ const data = [
153
+ { x: [0, 1, 2, 3], series: [[10, 20, 15, 25]] },
154
+ { x: [0, 0.5, 1.5, 2.5, 3], series: [[8, 18, 22, 12, 30]] },
155
+ ];
268
156
  ```
269
157
 
270
- ## Annotations
158
+ Null values in series arrays create gaps. Use `spanGaps` on `<Series>` to bridge them.
271
159
 
272
- Declarative annotation components — place inside `<Chart>`:
160
+ ## Annotations
273
161
 
274
162
  ```tsx
275
163
  import { HLine, VLine, Region, AnnotationLabel } from 'uplot-plus';
276
164
 
277
165
  <Chart data={data}>
278
- {/* ... scales, axes, series */}
279
166
  <HLine value={65} yScale="y" stroke="#e74c3c" dash={[6, 4]} label="Threshold" />
280
167
  <VLine value={100} xScale="x" stroke="#8e44ad" dash={[4, 4]} />
281
168
  <Region yMin={40} yMax={60} yScale="y" fill="rgba(46,204,113,0.12)" />
@@ -283,27 +170,22 @@ import { HLine, VLine, Region, AnnotationLabel } from 'uplot-plus';
283
170
  </Chart>
284
171
  ```
285
172
 
286
- Imperative helpers are available for advanced draw hooks that need programmatic control:
287
-
288
- ```tsx
289
- import { drawHLine, drawVLine, drawLabel, drawRegion } from 'uplot-plus';
290
- ```
291
-
292
173
  ## Utilities
293
174
 
294
175
  | Category | Functions |
295
- | ---------- | ----------- |
176
+ | -------- | --------- |
296
177
  | Axis formatters | `fmtCompact`, `fmtSuffix`, `fmtPrefix`, `fmtWrap`, `fmtHourMin`, `fmtMonthName`, `fmtDateStr`, `fmtLabels` |
297
178
  | Color helpers | `fadeGradient`, `withAlpha`, `palette` |
298
179
  | Data transforms | `stackGroup`, `alignData` |
299
- | Scale math | `valToPos`, `posToVal` |
300
180
 
301
- > Full API, signatures, and examples: [docs/UTILITIES.md](docs/UTILITIES.md)
181
+ > Full API and examples: [docs/UTILITIES.md](docs/UTILITIES.md)
182
+
183
+ > Advanced: [Event callbacks, hooks, controlled scales](docs/ADVANCED.md)
302
184
 
303
185
  ## Development
304
186
 
305
187
  ```sh
306
- npm run dev # Start demo dev server (99 examples)
188
+ npm run dev # Start demo dev server (101 examples)
307
189
  npm run build # Build library (ES + CJS to dist/)
308
190
  npm run typecheck # TypeScript strict check
309
191
  npm run lint # ESLint