wickchart 0.4.0 → 1.2.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # HabView
1
+ # WickChart
2
2
 
3
- **`<hab-chart>` — a modern, simpler, more useful charting web component.**
3
+ **`<wick-chart>` — a modern, simpler, more useful charting web component.**
4
4
 
5
5
  A TradingView-style financial chart as a single framework-agnostic Web Component.
6
6
  One file, zero dependencies, one HTML tag. Canvas-rendered, fast, themeable, and
@@ -14,9 +14,10 @@ npm install wickchart
14
14
 
15
15
  ```js
16
16
  // any bundler / framework — TypeScript types included
17
- import 'wickchart'; // registers <hab-chart>
18
- import HabChart from 'wickchart'; // for HabChart.registerIndicator(...)
17
+ import 'wickchart'; // registers <wick-chart>
18
+ import WickChart from 'wickchart'; // for WickChart.registerIndicator(...)
19
19
  import { encodeStateQuery } from 'wickchart/core'; // pure helpers
20
+ import { WickChart } from 'wickchart/react'; // React bindings (optional)
20
21
  ```
21
22
 
22
23
  Or straight from a CDN — no install, no build:
@@ -24,10 +25,10 @@ Or straight from a CDN — no install, no build:
24
25
  ```html
25
26
  <script type="module" src="https://unpkg.com/wickchart"></script>
26
27
 
27
- <hab-chart label="BTC · 1h" type="candles" indicators="sma:20 volume"></hab-chart>
28
+ <wick-chart label="BTC · 1h" type="candles" indicators="sma:20 volume"></wick-chart>
28
29
 
29
30
  <script type="module">
30
- const chart = document.querySelector('hab-chart');
31
+ const chart = document.querySelector('wick-chart');
31
32
  chart.setData(bars); // [{ time, open, high, low, close, volume }]
32
33
  chart.update(bar); // stream live updates
33
34
  </script>
@@ -37,7 +38,7 @@ Works in plain HTML, React, Vue, Svelte, Angular — anywhere a `<div>` works.
37
38
  TypeScript declarations ship inside the package (generated at pack time from
38
39
  the JSDoc-annotated source — the repo itself stays 100% dependency-free JS).
39
40
 
40
- ## Declarative live charts with `<hab-feed>`
41
+ ## Declarative live charts with `<wick-feed>`
41
42
 
42
43
  One more script tag and your chart is fully live — data, backfill, streaming —
43
44
  with **zero JavaScript written**:
@@ -45,13 +46,13 @@ with **zero JavaScript written**:
45
46
  ```html
46
47
  <script type="module" src="https://unpkg.com/wickchart/feed"></script>
47
48
 
48
- <hab-feed for="chart" binance="BTCUSDT" tf="1h"></hab-feed>
49
- <hab-chart id="chart" indicators="sma:20 volume" profile></hab-chart>
49
+ <wick-feed for="chart" binance="BTCUSDT" tf="1h"></wick-feed>
50
+ <wick-chart id="chart" indicators="sma:20 volume" profile></wick-chart>
50
51
  ```
51
52
 
52
53
  | Attribute | Meaning |
53
54
  | ----------- | ----------------------------------------------------------------------- |
54
- | `for` | target `<hab-chart>` id (auto-pairs with the first chart when omitted) |
55
+ | `for` | target `<wick-chart>` id (auto-pairs with the first chart when omitted) |
55
56
  | `binance` | Binance symbol (`BTCUSDT`) — REST load + WebSocket live + backfill |
56
57
  | `demo` | deterministic offline synthetic feed (`demo="ETH"` picks a base price) |
57
58
  | `url` | generic REST endpoint returning a JSON array of bars (+ `poll="10"` sec) |
@@ -61,7 +62,7 @@ with **zero JavaScript written**:
61
62
 
62
63
  The element reflects its state in the `status` attribute (`loading`, `live`,
63
64
  `polling`, `fallback`, `loaded`, `waiting`, `idle`) and emits
64
- `hab-feed:status` / `hab-feed:fallback` events. When Binance is unreachable
65
+ `wick-feed:status` / `wick-feed:fallback` events. When Binance is unreachable
65
66
  (geo-blocked, offline), it degrades gracefully: WebSocket → REST polling → a
66
67
  synthetic stream bridged from the last real price, so the chart never goes
67
68
  blank. It also wires `chart.onloadmore` for infinite backfill automatically.
@@ -71,7 +72,7 @@ blank. It also wires `chart.onloadmore` for infinite backfill automatically.
71
72
  ## Why another chart library?
72
73
 
73
74
  TradingView's charting library is powerful but heavy and enterprise-licensed;
74
- most wrappers add build steps and framework lock-in. HabView takes the opposite
75
+ most wrappers add build steps and framework lock-in. WickChart takes the opposite
75
76
  bet:
76
77
 
77
78
  - **Zero dependencies, single file** (~40 KB unminified, no build step required)
@@ -82,7 +83,20 @@ bet:
82
83
  outside the component (Shadow DOM friendly)
83
84
  - **Accessible** — focusable, arrow-key crosshair, ARIA summary of the data
84
85
 
85
- ## Run the demo
86
+ ## Try it online
87
+
88
+ The demo site is deployed to GitHub Pages:
89
+ **https://benyblack.github.io/wickchart/** — a landing page with a live hero
90
+ chart, the full interactive demo, the zero-JavaScript declarative page, and a
91
+ [React demo](./demo/react.html) driven entirely by React state.
92
+
93
+ **Full documentation lives at
94
+ [benyblack.github.io/wickchart/docs.html](./docs.html)** — every attribute,
95
+ method, event, the WickScript reference, overlays (with a live JSON
96
+ playground), feeds, theming and framework bindings, each with runnable
97
+ examples. This README covers the same ground in plain markdown.
98
+
99
+ ## Run the demo locally
86
100
 
87
101
  ```bash
88
102
  npm run dev # serves on http://localhost:5173
@@ -99,6 +113,101 @@ with graceful fallback to synthetic data if it isn't.
99
113
 
100
114
  ---
101
115
 
116
+ ## Frameworks
117
+
118
+ `<wick-chart>` is framework-agnostic — attributes, one `data` property,
119
+ standard DOM events. The one opinionated wrapper ships as `wickchart/react`,
120
+ which turns that contract into idiomatic React with proper event
121
+ subscription/cleanup. `react` is an **optional** peer dependency: nothing
122
+ changes if you never import `wickchart/react`.
123
+
124
+ ### React
125
+
126
+ ```bash
127
+ npm install wickchart react
128
+ ```
129
+
130
+ ```jsx
131
+ import { WickChart, useWickChart } from 'wickchart/react';
132
+
133
+ // drop-in component — props map 1:1 onto the element
134
+ export function PriceChart({ bars, onRange }) {
135
+ return (
136
+ <WickChart
137
+ type="candles"
138
+ indicators="sma:20 ema:50 volume"
139
+ volshading
140
+ label="BTC · 1h"
141
+ data={bars} // bars are assigned as a property
142
+ onRange={onRange} // subscribes to wick:range
143
+ onAlert={(e) => toast(`crossed ${e.detail.price}`)}
144
+ style={{ height: 420 }}
145
+ />
146
+ );
147
+ }
148
+
149
+ // or the hook, when you need the imperative API
150
+ function PracticeChart({ bars }) {
151
+ const { ref, chart } = useWickChart({ data: bars, indicators: 'sma:20' });
152
+ // chart.getDataWindow(), chart.addAlert(...), chart.getState() … after mount
153
+ return <wick-chart ref={ref} style={{ height: 420 }} />;
154
+ }
155
+ ```
156
+
157
+ Rules of thumb:
158
+
159
+ - **Pass a fresh array** to `data` when the bars change — the binding compares
160
+ by reference, and reassignment is what triggers a redraw (don't mutate).
161
+ The same rule applies to `overlays` (see
162
+ [Server-side overlays](#server-side-overlays-zones--levels)).
163
+ - **String/number/boolean props become attributes** (`type`, `indicators`,
164
+ `volshading`, …); `className`/`style`/`id` reach React as usual.
165
+ - **`onXxx` subscribes to `wick:xxx`** with cleanup on unmount; an
166
+ `events={{ range: fn }}` object works too.
167
+ - Works the same on React 16.8 → 19 — no custom-element event caveats.
168
+
169
+ No build step? The [React demo](./demo/react.html) runs straight off a CDN
170
+ import map — `react` and `react-dom` from esm.sh, the bindings from the
171
+ package source.
172
+
173
+ ### Vue 3
174
+
175
+ ```vue
176
+ <script setup>
177
+ import { ref, onMounted } from 'vue';
178
+ import 'wickchart';
179
+ const chart = ref(null);
180
+ const bars = ref([]);
181
+ onMounted(async () => {
182
+ bars.value = await loadBars();
183
+ chart.value.data = bars.value;
184
+ chart.value.addEventListener('wick:range', (e) => console.log(e.detail));
185
+ });
186
+ </script>
187
+
188
+ <template>
189
+ <wick-chart ref="chart" type="candles" indicators="sma:20"
190
+ style="height: 420px"></wick-chart>
191
+ </template>
192
+ ```
193
+
194
+ ### Svelte
195
+
196
+ ```svelte
197
+ <script>
198
+ import 'wickchart';
199
+ let el;
200
+ let bars = [];
201
+ $: if (el && bars.length) el.data = bars;
202
+ </script>
203
+
204
+ <wick-chart bind:this={el} type="candles" indicators="sma:20"
205
+ on:wick:alert={(e) => console.log(e.detail)}
206
+ style="height: 420px"></wick-chart>
207
+ ```
208
+
209
+ ---
210
+
102
211
  ## Data format
103
212
 
104
213
  Bars are plain objects; `time` accepts **milliseconds or seconds** (auto-detected).
@@ -126,6 +235,7 @@ chart.setData([
126
235
  | `profile` | off | Volume profile overlay (POC + 70% value area) |
127
236
  | `annotations` | off | Smart annotations (volume spikes, gaps, pivots, RSI divergences) |
128
237
  | `volshading` | off | Volatility-regime background shading (see below) |
238
+ | `overlays` | – | JSON array of server-side zones & levels (see below) |
129
239
 
130
240
  \* `indicators=""` disables everything, including volume. Token syntax:
131
241
  `name[:param[/param…]][@color]` — e.g. `sma:20@#ff0000`, `macd:12/26/9`.
@@ -147,7 +257,7 @@ Register your own — anything from a one-liner moving average to a multi-line
147
257
  pane:
148
258
 
149
259
  ```js
150
- HabChart.registerIndicator('vwap', {
260
+ WickChart.registerIndicator('vwap', {
151
261
  kind: 'overlay', // or 'pane'
152
262
  params: { period: 20 }, // defaults; set via indicators="vwap:30"
153
263
  compute(bars, params) { // bars: normalized {time,open,high,low,close,volume}
@@ -165,11 +275,11 @@ HabChart.registerIndicator('vwap', {
165
275
  chart.indicators = 'vwap:20';
166
276
  ```
167
277
 
168
- `import HabChart from 'wickchart'` gives you the class for
169
- `HabChart.registerIndicator(...)` (the element is registered as a side effect
278
+ `import WickChart from 'wickchart'` gives you the class for
279
+ `WickChart.registerIndicator(...)` (the element is registered as a side effect
170
280
  of importing the package).
171
281
 
172
- ### HabScript — custom indicators as expressions
282
+ ### WickScript — custom indicators as expressions
173
283
 
174
284
  No build step, no JS: write an indicator inline in the attribute. `expr:{…}`
175
285
  draws on the price chart; `pexpr:{…}` gets its own pane. Add an optional
@@ -177,10 +287,10 @@ draws on the price chart; `pexpr:{…}` gets its own pane. Add an optional
177
287
  shareable URLs.
178
288
 
179
289
  ```html
180
- <hab-chart indicators="sma:20 expr:{(close - sma(close,20)) / sma(close,20) * 100}@ff6a00"></hab-chart>
290
+ <wick-chart indicators="sma:20 expr:{(close - sma(close,20)) / sma(close,20) * 100}@ff6a00"></wick-chart>
181
291
 
182
292
  <!-- oscillator in its own pane -->
183
- <hab-chart indicators="pexpr:{rsi(close,14)} pexpr:{change(close) / close * 100}"></hab-chart>
293
+ <wick-chart indicators="pexpr:{rsi(close,14)} pexpr:{change(close) / close * 100}"></wick-chart>
184
294
  ```
185
295
 
186
296
  | Series variables | |
@@ -213,7 +323,7 @@ attribute syntax:
213
323
  ```js
214
324
  import { scriptIndicator } from 'wickchart/core';
215
325
 
216
- HabChart.registerIndicator('spread', scriptIndicator('close - ema(close,21)'));
326
+ WickChart.registerIndicator('spread', scriptIndicator('close - ema(close,21)'));
217
327
  chart.indicators = 'spread'; // now usable like any built-in
218
328
  ```
219
329
 
@@ -222,7 +332,7 @@ press **+ Expr** — invalid expressions show the compiler's error inline).
222
332
 
223
333
  ### Volatility-regime shading
224
334
 
225
- `<hab-chart volshading>` tints the price pane background by realized
335
+ `<wick-chart volshading>` tints the price pane background by realized
226
336
  volatility — the rolling stddev of log returns (20 bars by default),
227
337
  classified against its own full-history percentiles: **calm** (≤ 30th
228
338
  percentile, subtle blue), **normal** (untinted), **hot** (≥ 70th percentile,
@@ -231,9 +341,9 @@ read instantly, and the legend shows the hovered bar's regime and
231
341
  percentile (`VOL 30/70 · hot · 94%ile`).
232
342
 
233
343
  ```html
234
- <hab-chart volshading></hab-chart> <!-- defaults 30/70, 20 bars -->
235
- <hab-chart volshading="20/85"></hab-chart> <!-- custom cutoffs -->
236
- <hab-chart volshading="20/85/50"></hab-chart> <!-- + 50-bar vol window -->
344
+ <wick-chart volshading></wick-chart> <!-- defaults 30/70, 20 bars -->
345
+ <wick-chart volshading="20/85"></wick-chart> <!-- custom cutoffs -->
346
+ <wick-chart volshading="20/85/50"></wick-chart> <!-- + 50-bar vol window -->
237
347
  ```
238
348
 
239
349
  Cutoffs are clamped so the low percentile always stays at least 2 points
@@ -243,6 +353,69 @@ classifies everything as normal. The pieces are exported from
243
353
  `wickchart/core` (`calcRealizedVol`, `volRegimeBands`, `percentileOfSorted`)
244
354
  if you want to build on them.
245
355
 
356
+ ### Server-side overlays (zones & levels)
357
+
358
+ Draw analysis from your own API straight onto the chart: supply/demand
359
+ **zones** (time × price rectangles) and horizontal **levels**, rendered
360
+ behind the candles. Zones without a `to` extend into future space past the
361
+ last bar, like TradingView drawings.
362
+
363
+ ```js
364
+ const res = await fetch('https://api.example.com/analysis?symbol=BTC');
365
+ chart.setOverlays(await res.json());
366
+ ```
367
+
368
+ ```js
369
+ [
370
+ // zone: from/to are timestamps (ms or s); null → chart edge
371
+ { type: 'zone', from: 1753920000000, priceFrom: 33000, priceTo: 35600,
372
+ color: '#ef5350', alpha: 0.25, label: 'demand' },
373
+ { type: 'zone', from: 1753920000000, // no `to` → extends
374
+ priceFrom: 37700, priceTo: 40900, color: '#26a69a' }, // to the right edge
375
+ // level: horizontal price line, full width by default
376
+ { type: 'level', price: 28700, color: '#3f51b5', label: 'S1' },
377
+ { type: 'level', price: 22800, color: '#3f51b5', dash: true },
378
+ ]
379
+ ```
380
+
381
+ - `addOverlay(o)` upserts one (by `id`), `removeOverlay(id)`,
382
+ `clearOverlays()`, and `chart.overlays` reads them back.
383
+ - Colors accept hex / `rgb()` / CSS names plus the palette keys
384
+ `up` | `down` | `accent`; `alpha` clamps to 0.02–0.8 (default 0.22).
385
+ - Timestamps snap to bars (before the first bar clamps left, after the last
386
+ clamps right); invalid entries are dropped, never thrown — it's API data.
387
+ - Fully declarative, too — the same JSON as an attribute:
388
+
389
+ ```html
390
+ <wick-chart overlays='[{"type":"level","price":28700,"color":"#3f51b5","label":"S1"}]'></wick-chart>
391
+ ```
392
+
393
+ The React binding takes `overlays` as a prop (fresh array → re-apply), and
394
+ `normalizeOverlays` / `barIndexForTime` / `resolveOverlayColor` are exported
395
+ from `wickchart/core`.
396
+
397
+ ### Scenario mode — ghost paths & volatility cones
398
+
399
+ Project what-if into future space: a ghost path of hypothetical prices plus
400
+ a volatility cone (±1σ/±2σ bands widening with √h from realized vol).
401
+
402
+ ```js
403
+ chart.setScenario({
404
+ path: [64000, 65500, 66800, 68000], // prices for future bars 1..N
405
+ cone: true, // σ-bands from realized vol (default)
406
+ label: 'bull case',
407
+ color: 'up', // up | down | accent or safe colors
408
+ });
409
+ chart.setScenario({ horizon: 48 }); // cone-only projection
410
+ chart.clearScenario();
411
+ ```
412
+
413
+ Setting a scenario reserves future space on the right so the cone stays
414
+ visible; the horizon defaults to the path length (1–500) and `levels` are σ
415
+ multipliers (default `[1, 2]`). Like overlays, scenarios are analysis data —
416
+ excluded from shareable state, and the same shape a server-side model could
417
+ push. `calcVolCone` / `normalizeScenario` are exported from `wickchart/core`.
418
+
246
419
  ### AI-ready data window — `getDataWindow()`
247
420
 
248
421
  One call turns whatever is on screen into a compact, LLM-pasteable summary.
@@ -260,6 +433,31 @@ s.volPctile; // 84 → hot regime relative to the window itself
260
433
  s.patterns; // [{ time, note }] — most recent first
261
434
  ```
262
435
 
436
+ ### AI agent interface — the chart as a tool surface
437
+
438
+ The chart can publish its own **tool manifest** and accept validated
439
+ tool-calls, so any LLM can operate it with zero glue code — the chart never
440
+ touches the network; you supply the model call.
441
+
442
+ ```js
443
+ chart.aiTools(); // manifest: get_data_window, set_indicators, set_overlays, add_alert, …
444
+ chart.aiPrompt(); // system prompt demanding JSON [{tool, args}] ops
445
+ chart.aiContext(); // grounding: current state + visible-window summary
446
+ chart.applyAI(ops); // validated dispatcher — per-op {ok, result} / {ok:false, error}
447
+
448
+ const { results } = await chart.ask(
449
+ 'add RSI, mark the demand zone, and alert me on volume spikes',
450
+ { run: async (payload) => (await callMyLLM(payload)).ops }
451
+ );
452
+ ```
453
+
454
+ Every op is whitelisted and its args validated (indicator names checked
455
+ against the registry, overlays through the sanitizer, enums enforced) — LLM
456
+ output is treated as untrusted input, and a bad op returns an error the
457
+ model can self-correct from instead of throwing. The
458
+ [docs page](./docs.html) has a live playground driving `applyAI()` with an
459
+ offline demo agent (no network, no keys).
460
+
263
461
  `text` renders like:
264
462
 
265
463
  ```
@@ -277,7 +475,7 @@ from `wickchart/core` for server-side use.
277
475
 
278
476
  ### Sonification — the chart by ear
279
477
 
280
- `<hab-chart sonify>` maps price to pitch (180–880 Hz across the visible
478
+ `<wick-chart sonify>` maps price to pitch (180–880 Hz across the visible
281
479
  scale, log-aware): moving the crosshair with the mouse or **arrow keys** plays
282
480
  a short tone per bar, so trend and shape are audible — a rare accessibility
283
481
  win for screen-reader users. `chart.playRange()` sweeps the whole visible
@@ -291,7 +489,7 @@ Tag charts with the same channel and they share pointers — across browser
291
489
  tabs, or between multiple charts on one page:
292
490
 
293
491
  ```html
294
- <hab-chart co-view="btc-room"></hab-chart>
492
+ <wick-chart co-view="btc-room"></wick-chart>
295
493
  ```
296
494
 
297
495
  Hovering in one tab draws a ghost crosshair (accent, dotted, with the time
@@ -302,12 +500,12 @@ stops moving. Same-origin only (BroadcastChannel); the connection follows the
302
500
 
303
501
  ### Smart annotations
304
502
 
305
- `<hab-chart annotations>` marks notable events on the visible range — volume
503
+ `<wick-chart annotations>` marks notable events on the visible range — volume
306
504
  spikes (>3× average), price gaps, 41-bar pivot highs/lows, and RSI
307
505
  divergences — with lettered badges (V/G/H/L/D). Hover a badged bar and the
308
506
  legend shows a one-line insight ("Volume 4.2× average", "Bearish RSI
309
507
  divergence"). The current set is emitted on every recompute via the
310
- `hab:annotations` event, so hosts can build their own UI from it. Badges are
508
+ `wick:annotations` event, so hosts can build their own UI from it. Badges are
311
509
  hidden at extreme zoom-out, where bars collapse into columns.
312
510
 
313
511
  ### Example: VWAP via the registry
@@ -316,9 +514,9 @@ VWAP ships in the demo but *not* as a builtin — it's the reference for writing
316
514
  your own (session-anchored, resets each trading day):
317
515
 
318
516
  ```js
319
- import HabChart from 'wickchart';
517
+ import WickChart from 'wickchart';
320
518
 
321
- HabChart.registerIndicator('vwap', {
519
+ WickChart.registerIndicator('vwap', {
322
520
  kind: 'overlay',
323
521
  params: {},
324
522
  compute(bars) {
@@ -381,22 +579,29 @@ chart.addPosition({ id: 'x1', side: 'short', entry: 66000, qty: 1 });
381
579
  chart.removePosition('x1');
382
580
 
383
581
  chart.addAlert({ price: 65000, direction: 'above' }); // 'above' | 'below' | 'cross'
384
- chart.addEventListener('hab:alert', (e) => {
582
+ chart.addEventListener('wick:alert', (e) => {
385
583
  console.log('crossed!', e.detail.id, e.detail.price);
386
584
  });
585
+
586
+ // scripted alerts — any WickScript predicate, fired on its false→true edge
587
+ chart.addAlert({ when: 'crossup(rsi(close,14), 30)' });
588
+ chart.addAlert({ when: 'volume > sma(volume,20) * 3', once: false }); // re-arms
387
589
  ```
388
590
 
389
591
  The P&L chip recalculates on every streamed bar. Alerts are edge-triggered
390
592
  (fire once per crossing) and one-shot by default (`once: false` to re-arm).
593
+ Scripted alerts are evaluated locally on every streamed bar — the event
594
+ carries the triggering close as `price` plus the `when` source; an invalid
595
+ predicate is rejected (`addAlert` returns `null`), never thrown.
391
596
 
392
597
  ### Stats & measure
393
598
 
394
- `<hab-chart stats>` shows live statistics of the visible range — return %,
599
+ `<wick-chart stats>` shows live statistics of the visible range — return %,
395
600
  max drawdown, annualized volatility, up/down bar counts, average volume —
396
601
  recalculated as you pan and zoom.
397
602
 
398
603
  Hold **Shift and drag** across the chart to measure a move: an overlay shows
399
- Δprice, Δ%, bar count and elapsed time, and a `hab:measure` event fires on
604
+ Δprice, Δ%, bar count and elapsed time, and a `wick:measure` event fires on
400
605
  release (`detail.from` / `detail.to` carry index, time and price). Click or
401
606
  press `Esc` to clear.
402
607
 
@@ -423,9 +628,9 @@ Reflected properties (`chart.type = 'line'`) work for `theme`, `type`, `label`,
423
628
 
424
629
  | Event | Detail |
425
630
  | --------------- | ---------------------------------------------------------- |
426
- | `hab:crosshair` | `{ index, bar, x, y, price }` on hover / arrows, `null` on leave |
427
- | `hab:range` | `{ from, to }` after zoom / pan / jump |
428
- | `hab:select` | `{ index, bar, price }` on click/tap (e.g. open an order form at that price) |
631
+ | `wick:crosshair` | `{ index, bar, x, y, price }` on hover / arrows, `null` on leave |
632
+ | `wick:range` | `{ from, to }` after zoom / pan / jump |
633
+ | `wick:select` | `{ index, bar, price }` on click/tap (e.g. open an order form at that price) |
429
634
 
430
635
  ## Theming
431
636
 
@@ -433,18 +638,18 @@ All colors are CSS custom properties settable on the element (they pierce the
433
638
  Shadow DOM):
434
639
 
435
640
  ```css
436
- hab-chart {
437
- --hab-bg: #0d1117; /* transparent works too */
438
- --hab-up: #16c784;
439
- --hab-down: #ea3943;
440
- --hab-accent: #4c8dff; /* line & area color */
441
- --hab-text: #8b949e; /* axis text */
442
- --hab-text-strong: #e6edf3; /* legend values */
443
- --hab-grid: rgba(230,237,243,.05);
444
- --hab-border: rgba(230,237,243,.09);
445
- --hab-crosshair: rgba(230,237,243,.42);
446
- --hab-rsi: #a78bfa;
447
- --hab-overlay-0: #f0b429; /* SMA color, …-1, -2, … for more overlays */
641
+ wick-chart {
642
+ --wick-bg: #0d1117; /* transparent works too */
643
+ --wick-up: #16c784;
644
+ --wick-down: #ea3943;
645
+ --wick-accent: #4c8dff; /* line & area color */
646
+ --wick-text: #8b949e; /* axis text */
647
+ --wick-text-strong: #e6edf3; /* legend values */
648
+ --wick-grid: rgba(230,237,243,.05);
649
+ --wick-border: rgba(230,237,243,.09);
650
+ --wick-crosshair: rgba(230,237,243,.42);
651
+ --wick-rsi: #a78bfa;
652
+ --wick-overlay-0: #f0b429; /* SMA color, …-1, -2, … for more overlays */
448
653
  }
449
654
  ```
450
655
 
@@ -507,6 +712,27 @@ column, and an offscreen layer so hover only repaints the crosshair.
507
712
  - Incremental (O(1)) indicator updates for high-frequency streaming
508
713
  - Min/max downsampling and/or an offscreen hover layer if profiling ever demands
509
714
 
715
+ ## Migrating from 0.x (HabView)
716
+
717
+ 1.0 renames the public surface to the WickChart brand. The 0.x names keep
718
+ working as **deprecated aliases** (removed in 2.0), so upgrading is safe to
719
+ do lazily:
720
+
721
+ | 0.x (deprecated alias) | 1.0 canonical |
722
+ |---|---|
723
+ | `<hab-chart>` / `<hab-feed>` | `<wick-chart>` / `<wick-feed>` |
724
+ | `hab:range`, `hab:select`, `hab:alert`, `hab:crosshair`, `hab:measure`, `hab:annotations` | `wick:*` of the same name (both fire during 1.x) |
725
+ | `hab-feed:status` / `hab-feed:fallback` | `wick-feed:status` / `wick-feed:fallback` (both fire during 1.x) |
726
+ | `--hab-bg`, `--hab-up`, … | `--wick-*` of the same name (`--wick-*` wins; `--hab-*` is the fallback) |
727
+ | `HabChart` / `HabFeed` classes | `WickChart` / `WickFeed` (also as named exports) |
728
+ | HabScript (the `expr:{…}` language) | WickScript — syntax unchanged |
729
+ | `import … from 'wickchart/src/hab-chart.js'` | use the package entry points (`wickchart`, `wickchart/core`, `wickchart/feed`) — module files are renamed |
730
+
731
+ Two behavioral notes: custom indicators registered via
732
+ `WickChart.registerIndicator()` are shared with the legacy `<hab-chart>`
733
+ alias (one registry), and cross-tab co-view channels are now prefixed
734
+ `wick-co-view:` (a 0.x tab and a 1.x tab won't pair — refresh both).
735
+
510
736
  ## License
511
737
 
512
738
  MIT
package/package.json CHANGED
@@ -1,23 +1,27 @@
1
1
  {
2
2
  "name": "wickchart",
3
- "version": "0.4.0",
4
- "description": "<hab-chart> — a modern, dependency-free financial charting web component. Candles, line & area charts, crosshair, zoom/pan, indicators, live streaming, theming.",
3
+ "version": "1.2.0",
4
+ "description": "<wick-chart> — a modern, dependency-free financial charting web component. Candles, line & area charts, crosshair, zoom/pan, indicators (incl. a safe expression mini-language), live streaming via <wick-feed>, theming.",
5
5
  "type": "module",
6
- "main": "src/hab-chart.js",
7
- "module": "src/hab-chart.js",
8
- "types": "types/hab-chart.d.ts",
6
+ "main": "src/wick-chart.js",
7
+ "module": "src/wick-chart.js",
8
+ "types": "types/wick-chart.d.ts",
9
9
  "exports": {
10
10
  ".": {
11
- "types": "./types/hab-chart.d.ts",
12
- "default": "./src/hab-chart.js"
11
+ "types": "./types/wick-chart.d.ts",
12
+ "default": "./src/wick-chart.js"
13
13
  },
14
14
  "./core": {
15
15
  "types": "./types/core.d.ts",
16
16
  "default": "./src/core.js"
17
17
  },
18
18
  "./feed": {
19
- "types": "./types/hab-feed.d.ts",
20
- "default": "./src/hab-feed.js"
19
+ "types": "./types/wick-feed.d.ts",
20
+ "default": "./src/wick-feed.js"
21
+ },
22
+ "./react": {
23
+ "types": "./types/react.d.ts",
24
+ "default": "./src/react.js"
21
25
  }
22
26
  },
23
27
  "files": [
@@ -25,14 +29,23 @@
25
29
  "types"
26
30
  ],
27
31
  "sideEffects": [
28
- "src/hab-chart.js"
32
+ "src/wick-chart.js",
33
+ "src/react.js"
29
34
  ],
35
+ "peerDependencies": {
36
+ "react": ">=16.8"
37
+ },
38
+ "peerDependenciesMeta": {
39
+ "react": {
40
+ "optional": true
41
+ }
42
+ },
30
43
  "scripts": {
31
44
  "dev": "npx --yes serve . -l 5173",
32
45
  "test": "node --test \"tests/*.test.mjs\"",
33
- "build:types": "tsc -p tsconfig.json",
46
+ "build:types": "node -e \"require('fs').rmSync('types', { recursive: true, force: true });\" && tsc -p tsconfig.json",
34
47
  "prepack": "npm run build:types",
35
- "ci": "npm run build:types && npm test && node --check src/hab-chart.js && node --check src/core.js && node --check demo/app.js"
48
+ "ci": "npm run build:types && npm test && node --check src/wick-chart.js && node --check src/wick-feed.js && node --check src/core.js && node --check src/react.js && node --check src/react-core.js && node --check demo/app.js"
36
49
  },
37
50
  "keywords": [
38
51
  "chart",
@@ -52,6 +65,10 @@
52
65
  "url": "git+https://github.com/benyblack/wickchart.git"
53
66
  },
54
67
  "devDependencies": {
68
+ "@types/react": "^19.1.0",
69
+ "jsdom": "^26.1.0",
70
+ "react": "^19.1.0",
71
+ "react-dom": "^19.1.0",
55
72
  "typescript": "^7.0.2"
56
73
  }
57
74
  }