wickchart 0.4.0 → 1.0.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,8 +14,8 @@ 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
20
  ```
21
21
 
@@ -24,10 +24,10 @@ Or straight from a CDN — no install, no build:
24
24
  ```html
25
25
  <script type="module" src="https://unpkg.com/wickchart"></script>
26
26
 
27
- <hab-chart label="BTC · 1h" type="candles" indicators="sma:20 volume"></hab-chart>
27
+ <wick-chart label="BTC · 1h" type="candles" indicators="sma:20 volume"></wick-chart>
28
28
 
29
29
  <script type="module">
30
- const chart = document.querySelector('hab-chart');
30
+ const chart = document.querySelector('wick-chart');
31
31
  chart.setData(bars); // [{ time, open, high, low, close, volume }]
32
32
  chart.update(bar); // stream live updates
33
33
  </script>
@@ -37,7 +37,7 @@ Works in plain HTML, React, Vue, Svelte, Angular — anywhere a `<div>` works.
37
37
  TypeScript declarations ship inside the package (generated at pack time from
38
38
  the JSDoc-annotated source — the repo itself stays 100% dependency-free JS).
39
39
 
40
- ## Declarative live charts with `<hab-feed>`
40
+ ## Declarative live charts with `<wick-feed>`
41
41
 
42
42
  One more script tag and your chart is fully live — data, backfill, streaming —
43
43
  with **zero JavaScript written**:
@@ -45,13 +45,13 @@ with **zero JavaScript written**:
45
45
  ```html
46
46
  <script type="module" src="https://unpkg.com/wickchart/feed"></script>
47
47
 
48
- <hab-feed for="chart" binance="BTCUSDT" tf="1h"></hab-feed>
49
- <hab-chart id="chart" indicators="sma:20 volume" profile></hab-chart>
48
+ <wick-feed for="chart" binance="BTCUSDT" tf="1h"></wick-feed>
49
+ <wick-chart id="chart" indicators="sma:20 volume" profile></wick-chart>
50
50
  ```
51
51
 
52
52
  | Attribute | Meaning |
53
53
  | ----------- | ----------------------------------------------------------------------- |
54
- | `for` | target `<hab-chart>` id (auto-pairs with the first chart when omitted) |
54
+ | `for` | target `<wick-chart>` id (auto-pairs with the first chart when omitted) |
55
55
  | `binance` | Binance symbol (`BTCUSDT`) — REST load + WebSocket live + backfill |
56
56
  | `demo` | deterministic offline synthetic feed (`demo="ETH"` picks a base price) |
57
57
  | `url` | generic REST endpoint returning a JSON array of bars (+ `poll="10"` sec) |
@@ -61,7 +61,7 @@ with **zero JavaScript written**:
61
61
 
62
62
  The element reflects its state in the `status` attribute (`loading`, `live`,
63
63
  `polling`, `fallback`, `loaded`, `waiting`, `idle`) and emits
64
- `hab-feed:status` / `hab-feed:fallback` events. When Binance is unreachable
64
+ `wick-feed:status` / `wick-feed:fallback` events. When Binance is unreachable
65
65
  (geo-blocked, offline), it degrades gracefully: WebSocket → REST polling → a
66
66
  synthetic stream bridged from the last real price, so the chart never goes
67
67
  blank. It also wires `chart.onloadmore` for infinite backfill automatically.
@@ -71,7 +71,7 @@ blank. It also wires `chart.onloadmore` for infinite backfill automatically.
71
71
  ## Why another chart library?
72
72
 
73
73
  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
74
+ most wrappers add build steps and framework lock-in. WickChart takes the opposite
75
75
  bet:
76
76
 
77
77
  - **Zero dependencies, single file** (~40 KB unminified, no build step required)
@@ -82,7 +82,13 @@ bet:
82
82
  outside the component (Shadow DOM friendly)
83
83
  - **Accessible** — focusable, arrow-key crosshair, ARIA summary of the data
84
84
 
85
- ## Run the demo
85
+ ## Try it online
86
+
87
+ The demo site is deployed to GitHub Pages:
88
+ **https://benyblack.github.io/wickchart/** — a landing page with a live hero
89
+ chart, the full interactive demo, and the zero-JavaScript declarative page.
90
+
91
+ ## Run the demo locally
86
92
 
87
93
  ```bash
88
94
  npm run dev # serves on http://localhost:5173
@@ -147,7 +153,7 @@ Register your own — anything from a one-liner moving average to a multi-line
147
153
  pane:
148
154
 
149
155
  ```js
150
- HabChart.registerIndicator('vwap', {
156
+ WickChart.registerIndicator('vwap', {
151
157
  kind: 'overlay', // or 'pane'
152
158
  params: { period: 20 }, // defaults; set via indicators="vwap:30"
153
159
  compute(bars, params) { // bars: normalized {time,open,high,low,close,volume}
@@ -165,11 +171,11 @@ HabChart.registerIndicator('vwap', {
165
171
  chart.indicators = 'vwap:20';
166
172
  ```
167
173
 
168
- `import HabChart from 'wickchart'` gives you the class for
169
- `HabChart.registerIndicator(...)` (the element is registered as a side effect
174
+ `import WickChart from 'wickchart'` gives you the class for
175
+ `WickChart.registerIndicator(...)` (the element is registered as a side effect
170
176
  of importing the package).
171
177
 
172
- ### HabScript — custom indicators as expressions
178
+ ### WickScript — custom indicators as expressions
173
179
 
174
180
  No build step, no JS: write an indicator inline in the attribute. `expr:{…}`
175
181
  draws on the price chart; `pexpr:{…}` gets its own pane. Add an optional
@@ -177,10 +183,10 @@ draws on the price chart; `pexpr:{…}` gets its own pane. Add an optional
177
183
  shareable URLs.
178
184
 
179
185
  ```html
180
- <hab-chart indicators="sma:20 expr:{(close - sma(close,20)) / sma(close,20) * 100}@ff6a00"></hab-chart>
186
+ <wick-chart indicators="sma:20 expr:{(close - sma(close,20)) / sma(close,20) * 100}@ff6a00"></wick-chart>
181
187
 
182
188
  <!-- oscillator in its own pane -->
183
- <hab-chart indicators="pexpr:{rsi(close,14)} pexpr:{change(close) / close * 100}"></hab-chart>
189
+ <wick-chart indicators="pexpr:{rsi(close,14)} pexpr:{change(close) / close * 100}"></wick-chart>
184
190
  ```
185
191
 
186
192
  | Series variables | |
@@ -213,7 +219,7 @@ attribute syntax:
213
219
  ```js
214
220
  import { scriptIndicator } from 'wickchart/core';
215
221
 
216
- HabChart.registerIndicator('spread', scriptIndicator('close - ema(close,21)'));
222
+ WickChart.registerIndicator('spread', scriptIndicator('close - ema(close,21)'));
217
223
  chart.indicators = 'spread'; // now usable like any built-in
218
224
  ```
219
225
 
@@ -222,7 +228,7 @@ press **+ Expr** — invalid expressions show the compiler's error inline).
222
228
 
223
229
  ### Volatility-regime shading
224
230
 
225
- `<hab-chart volshading>` tints the price pane background by realized
231
+ `<wick-chart volshading>` tints the price pane background by realized
226
232
  volatility — the rolling stddev of log returns (20 bars by default),
227
233
  classified against its own full-history percentiles: **calm** (≤ 30th
228
234
  percentile, subtle blue), **normal** (untinted), **hot** (≥ 70th percentile,
@@ -231,9 +237,9 @@ read instantly, and the legend shows the hovered bar's regime and
231
237
  percentile (`VOL 30/70 · hot · 94%ile`).
232
238
 
233
239
  ```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 -->
240
+ <wick-chart volshading></wick-chart> <!-- defaults 30/70, 20 bars -->
241
+ <wick-chart volshading="20/85"></wick-chart> <!-- custom cutoffs -->
242
+ <wick-chart volshading="20/85/50"></wick-chart> <!-- + 50-bar vol window -->
237
243
  ```
238
244
 
239
245
  Cutoffs are clamped so the low percentile always stays at least 2 points
@@ -277,7 +283,7 @@ from `wickchart/core` for server-side use.
277
283
 
278
284
  ### Sonification — the chart by ear
279
285
 
280
- `<hab-chart sonify>` maps price to pitch (180–880 Hz across the visible
286
+ `<wick-chart sonify>` maps price to pitch (180–880 Hz across the visible
281
287
  scale, log-aware): moving the crosshair with the mouse or **arrow keys** plays
282
288
  a short tone per bar, so trend and shape are audible — a rare accessibility
283
289
  win for screen-reader users. `chart.playRange()` sweeps the whole visible
@@ -291,7 +297,7 @@ Tag charts with the same channel and they share pointers — across browser
291
297
  tabs, or between multiple charts on one page:
292
298
 
293
299
  ```html
294
- <hab-chart co-view="btc-room"></hab-chart>
300
+ <wick-chart co-view="btc-room"></wick-chart>
295
301
  ```
296
302
 
297
303
  Hovering in one tab draws a ghost crosshair (accent, dotted, with the time
@@ -302,12 +308,12 @@ stops moving. Same-origin only (BroadcastChannel); the connection follows the
302
308
 
303
309
  ### Smart annotations
304
310
 
305
- `<hab-chart annotations>` marks notable events on the visible range — volume
311
+ `<wick-chart annotations>` marks notable events on the visible range — volume
306
312
  spikes (>3× average), price gaps, 41-bar pivot highs/lows, and RSI
307
313
  divergences — with lettered badges (V/G/H/L/D). Hover a badged bar and the
308
314
  legend shows a one-line insight ("Volume 4.2× average", "Bearish RSI
309
315
  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
316
+ `wick:annotations` event, so hosts can build their own UI from it. Badges are
311
317
  hidden at extreme zoom-out, where bars collapse into columns.
312
318
 
313
319
  ### Example: VWAP via the registry
@@ -316,9 +322,9 @@ VWAP ships in the demo but *not* as a builtin — it's the reference for writing
316
322
  your own (session-anchored, resets each trading day):
317
323
 
318
324
  ```js
319
- import HabChart from 'wickchart';
325
+ import WickChart from 'wickchart';
320
326
 
321
- HabChart.registerIndicator('vwap', {
327
+ WickChart.registerIndicator('vwap', {
322
328
  kind: 'overlay',
323
329
  params: {},
324
330
  compute(bars) {
@@ -381,7 +387,7 @@ chart.addPosition({ id: 'x1', side: 'short', entry: 66000, qty: 1 });
381
387
  chart.removePosition('x1');
382
388
 
383
389
  chart.addAlert({ price: 65000, direction: 'above' }); // 'above' | 'below' | 'cross'
384
- chart.addEventListener('hab:alert', (e) => {
390
+ chart.addEventListener('wick:alert', (e) => {
385
391
  console.log('crossed!', e.detail.id, e.detail.price);
386
392
  });
387
393
  ```
@@ -391,12 +397,12 @@ The P&L chip recalculates on every streamed bar. Alerts are edge-triggered
391
397
 
392
398
  ### Stats & measure
393
399
 
394
- `<hab-chart stats>` shows live statistics of the visible range — return %,
400
+ `<wick-chart stats>` shows live statistics of the visible range — return %,
395
401
  max drawdown, annualized volatility, up/down bar counts, average volume —
396
402
  recalculated as you pan and zoom.
397
403
 
398
404
  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
405
+ Δprice, Δ%, bar count and elapsed time, and a `wick:measure` event fires on
400
406
  release (`detail.from` / `detail.to` carry index, time and price). Click or
401
407
  press `Esc` to clear.
402
408
 
@@ -423,9 +429,9 @@ Reflected properties (`chart.type = 'line'`) work for `theme`, `type`, `label`,
423
429
 
424
430
  | Event | Detail |
425
431
  | --------------- | ---------------------------------------------------------- |
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) |
432
+ | `wick:crosshair` | `{ index, bar, x, y, price }` on hover / arrows, `null` on leave |
433
+ | `wick:range` | `{ from, to }` after zoom / pan / jump |
434
+ | `wick:select` | `{ index, bar, price }` on click/tap (e.g. open an order form at that price) |
429
435
 
430
436
  ## Theming
431
437
 
@@ -433,18 +439,18 @@ All colors are CSS custom properties settable on the element (they pierce the
433
439
  Shadow DOM):
434
440
 
435
441
  ```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 */
442
+ wick-chart {
443
+ --wick-bg: #0d1117; /* transparent works too */
444
+ --wick-up: #16c784;
445
+ --wick-down: #ea3943;
446
+ --wick-accent: #4c8dff; /* line & area color */
447
+ --wick-text: #8b949e; /* axis text */
448
+ --wick-text-strong: #e6edf3; /* legend values */
449
+ --wick-grid: rgba(230,237,243,.05);
450
+ --wick-border: rgba(230,237,243,.09);
451
+ --wick-crosshair: rgba(230,237,243,.42);
452
+ --wick-rsi: #a78bfa;
453
+ --wick-overlay-0: #f0b429; /* SMA color, …-1, -2, … for more overlays */
448
454
  }
449
455
  ```
450
456
 
@@ -507,6 +513,27 @@ column, and an offscreen layer so hover only repaints the crosshair.
507
513
  - Incremental (O(1)) indicator updates for high-frequency streaming
508
514
  - Min/max downsampling and/or an offscreen hover layer if profiling ever demands
509
515
 
516
+ ## Migrating from 0.x (HabView)
517
+
518
+ 1.0 renames the public surface to the WickChart brand. The 0.x names keep
519
+ working as **deprecated aliases** (removed in 2.0), so upgrading is safe to
520
+ do lazily:
521
+
522
+ | 0.x (deprecated alias) | 1.0 canonical |
523
+ |---|---|
524
+ | `<hab-chart>` / `<hab-feed>` | `<wick-chart>` / `<wick-feed>` |
525
+ | `hab:range`, `hab:select`, `hab:alert`, `hab:crosshair`, `hab:measure`, `hab:annotations` | `wick:*` of the same name (both fire during 1.x) |
526
+ | `hab-feed:status` / `hab-feed:fallback` | `wick-feed:status` / `wick-feed:fallback` (both fire during 1.x) |
527
+ | `--hab-bg`, `--hab-up`, … | `--wick-*` of the same name (`--wick-*` wins; `--hab-*` is the fallback) |
528
+ | `HabChart` / `HabFeed` classes | `WickChart` / `WickFeed` (also as named exports) |
529
+ | HabScript (the `expr:{…}` language) | WickScript — syntax unchanged |
530
+ | `import … from 'wickchart/src/hab-chart.js'` | use the package entry points (`wickchart`, `wickchart/core`, `wickchart/feed`) — module files are renamed |
531
+
532
+ Two behavioral notes: custom indicators registered via
533
+ `WickChart.registerIndicator()` are shared with the legacy `<hab-chart>`
534
+ alias (one registry), and cross-tab co-view channels are now prefixed
535
+ `wick-co-view:` (a 0.x tab and a 1.x tab won't pair — refresh both).
536
+
510
537
  ## License
511
538
 
512
539
  MIT
package/package.json CHANGED
@@ -1,23 +1,23 @@
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.0.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
21
  }
22
22
  },
23
23
  "files": [
@@ -25,14 +25,14 @@
25
25
  "types"
26
26
  ],
27
27
  "sideEffects": [
28
- "src/hab-chart.js"
28
+ "src/wick-chart.js"
29
29
  ],
30
30
  "scripts": {
31
31
  "dev": "npx --yes serve . -l 5173",
32
32
  "test": "node --test \"tests/*.test.mjs\"",
33
- "build:types": "tsc -p tsconfig.json",
33
+ "build:types": "node -e \"require('fs').rmSync('types', { recursive: true, force: true });\" && tsc -p tsconfig.json",
34
34
  "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"
35
+ "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 demo/app.js"
36
36
  },
37
37
  "keywords": [
38
38
  "chart",
package/src/core.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* ==========================================================================
2
- * HabView core — pure, DOM-free functions shared by <hab-chart> and tests.
2
+ * WickChart core — pure, DOM-free functions shared by <wick-chart> and tests.
3
3
  * Importable in the browser (ESM) and in Node (`node --test`).
4
4
  * MIT License.
5
5
  * ========================================================================== */
@@ -252,7 +252,8 @@ export const fmtFull = (t) => {
252
252
  };
253
253
 
254
254
  /* ------------------------------------------------------------------ *
255
- * Themes (every key overridable via --hab-* CSS custom properties)
255
+ * Themes (every key overridable via --wick-* CSS custom properties;
256
+ * the 0.x --hab-* names still work as fallbacks)
256
257
  * ------------------------------------------------------------------ */
257
258
 
258
259
  export const THEMES = {
@@ -867,7 +868,7 @@ export const BUILTIN_INDICATORS = new Map(
867
868
  /**
868
869
  * Parse an `indicators` attribute string against a registry.
869
870
  * Token: `name[:param[/param…]][@color]`, the `volume` keyword, and
870
- * HabScript blobs `expr:{…}` (overlay) / `pexpr:{…}` (separate pane).
871
+ * WickScript blobs `expr:{…}` (overlay) / `pexpr:{…}` (separate pane).
871
872
  * @param {string|null|undefined} str
872
873
  * @param {Map<string, IndicatorDef>} registry
873
874
  * @returns {{overlays: IndicatorEntry[], panes: IndicatorEntry[], volume: boolean, unknown: string[]}}
@@ -940,11 +941,12 @@ export function parseIndicators(str, registry) {
940
941
  }
941
942
 
942
943
  /* ------------------------------------------------------------------ *
943
- * HabScript — safe expression mini-language for custom indicators
944
+ * WickScript — safe expression mini-language for custom indicators
944
945
  *
945
946
  * `expr:{(close - sma(close,20)) / sma(close,20)}` compiles through a
946
947
  * hand-written tokenizer + recursive-descent parser (no eval / Function)
947
- * and evaluates element-wise over the bar series.
948
+ * and evaluates element-wise over the bar series. (Called "HabScript" in
949
+ * 0.x releases.)
948
950
  * ------------------------------------------------------------------ */
949
951
 
950
952
  const SCRIPT_MAX_LEN = 512;
@@ -1156,7 +1158,7 @@ function validateScriptNode(n) {
1156
1158
  }
1157
1159
 
1158
1160
  /**
1159
- * Compile a HabScript expression. Throws a descriptive error on any syntax
1161
+ * Compile a WickScript expression. Throws a descriptive error on any syntax
1160
1162
  * or semantic problem — never evaluates strings at runtime.
1161
1163
  * @param {string} src
1162
1164
  * @returns {{src: string, ast: object}}
@@ -1303,7 +1305,7 @@ export function evalScript(compiled, bars) {
1303
1305
  }
1304
1306
 
1305
1307
  /**
1306
- * Build an indicator definition from a HabScript expression — used inline by
1308
+ * Build an indicator definition from a WickScript expression — used inline by
1307
1309
  * `indicators="expr:{…}"` / `pexpr:{…}"`, or register it under a name:
1308
1310
  * `HabChart.registerIndicator('myspread', scriptIndicator('close - ema(close,21)'))`.
1309
1311
  * @param {string} src
package/src/feeds.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /* ==========================================================================
2
- * HabView feeds — data-source helpers shared by <hab-feed> and the demo app.
2
+ * WickChart feeds — data-source helpers shared by <wick-feed> and the demo app.
3
3
  * Browser module (uses fetch/WebSocket inside functions); importable in Node
4
4
  * for unit-testing the pure generators.
5
5
  * MIT License.
@@ -1,16 +1,19 @@
1
1
  /* ==========================================================================
2
- * <hab-chart> — a modern, dependency-free financial charting web component.
2
+ * <wick-chart> — a modern, dependency-free financial charting web component.
3
3
  *
4
- * <hab-chart label="BTC · 1h" type="candles" indicators="sma:20 volume">
5
- * </hab-chart>
4
+ * <wick-chart label="BTC · 1h" type="candles" indicators="sma:20 volume">
5
+ * </wick-chart>
6
6
  * <script type="module">
7
- * const chart = document.querySelector('hab-chart');
7
+ * const chart = document.querySelector('wick-chart');
8
8
  * chart.setData(bars); // [{ time, open, high, low, close, volume }]
9
9
  * chart.update(bar); // streaming update / append
10
10
  * </script>
11
11
  *
12
12
  * Zero dependencies. Canvas-rendered. Framework-agnostic (works in React,
13
- * Vue, Svelte, plain HTML). Themeable with --hab-* CSS custom properties.
13
+ * Vue, plain HTML). Themeable with --wick-* CSS custom properties.
14
+ *
15
+ * The 0.x names (<hab-chart>, --hab-*, hab:* events) still work as
16
+ * deprecated aliases — see the README migration notes.
14
17
  *
15
18
  * MIT License.
16
19
  * ========================================================================== */
@@ -29,14 +32,18 @@ import {
29
32
  } from './core.js';
30
33
 
31
34
  /* ------------------------------------------------------------------ *
32
- * <hab-chart>
35
+ * <wick-chart>
33
36
  * ------------------------------------------------------------------ */
34
37
 
38
+ /** Indicator registry — module scope so registrations are shared by
39
+ * <wick-chart> and the deprecated <hab-chart> alias element. */
40
+ const REGISTRY = new Map(BUILTIN_INDICATORS);
41
+
35
42
  /* SSR safety: importing this module under Node (Next.js/Nuxt server render)
36
43
  * must not throw — the element simply registers only in browsers. */
37
44
  const HTMLElementBase = typeof HTMLElement !== 'undefined' ? HTMLElement : class {};
38
45
 
39
- class HabChart extends HTMLElementBase {
46
+ class WickChart extends HTMLElementBase {
40
47
  static get observedAttributes() {
41
48
  return ['theme', 'type', 'log', 'auto', 'indicators', 'precision', 'label', 'stats', 'profile', 'annotations', 'volshading', 'co-view', 'sonify'];
42
49
  }
@@ -55,7 +62,7 @@ class HabChart extends HTMLElementBase {
55
62
  contain: content;
56
63
  }
57
64
  :host(:focus-visible) {
58
- outline: 2px solid var(--hab-accent, #4c8dff);
65
+ outline: 2px solid var(--wick-accent, var(--hab-accent, #4c8dff));
59
66
  outline-offset: -2px;
60
67
  }
61
68
  .wrap { position: absolute; inset: 0; overflow: hidden; }
@@ -78,26 +85,26 @@ class HabChart extends HTMLElementBase {
78
85
  }
79
86
  .legend .row { display: flex; align-items: baseline; gap: 12px; flex-wrap: wrap; }
80
87
  .legend .sym {
81
- color: var(--hab-text-strong, #e6edf3);
88
+ color: var(--wick-text-strong, var(--hab-text-strong, #e6edf3));
82
89
  font-weight: 700;
83
90
  font-size: 13px;
84
91
  letter-spacing: 0.02em;
85
92
  }
86
93
  .legend .kv { display: inline-flex; gap: 5px; align-items: baseline; white-space: nowrap; }
87
- .legend .k { color: var(--hab-text, #8b949e); font-size: 11px; }
88
- .legend .v { color: var(--hab-text-strong, #e6edf3); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
94
+ .legend .k { color: var(--wick-text, var(--hab-text, #8b949e)); font-size: 11px; }
95
+ .legend .v { color: var(--wick-text-strong, var(--hab-text-strong, #e6edf3)); font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
89
96
  .legend .pct { font-weight: 600; font-variant-numeric: tabular-nums; white-space: nowrap; }
90
- .legend .up { color: var(--hab-up, #16c784); }
91
- .legend .dn { color: var(--hab-down, #ea3943); }
97
+ .legend .up { color: var(--wick-up, var(--hab-up, #16c784)); }
98
+ .legend .dn { color: var(--wick-down, var(--hab-down, #ea3943)); }
92
99
  .legend .ind {
93
100
  display: inline-flex; align-items: center; gap: 6px;
94
- color: var(--hab-text, #8b949e); font-size: 11.5px; white-space: nowrap;
101
+ color: var(--wick-text, var(--hab-text, #8b949e)); font-size: 11.5px; white-space: nowrap;
95
102
  }
96
103
  .legend .ind i { width: 8px; height: 2.5px; border-radius: 2px; display: inline-block; }
97
104
  .legend .ind .v { font-size: 12px; }
98
105
  .legend .insight {
99
- color: var(--hab-accent, #4c8dff);
100
- background: var(--hab-chip, rgba(127, 137, 153, 0.12));
106
+ color: var(--wick-accent, var(--hab-accent, #4c8dff));
107
+ background: var(--wick-chip, var(--hab-chip, rgba(127, 137, 153, 0.12)));
101
108
  border-radius: 6px;
102
109
  padding: 1px 8px;
103
110
  font-size: 11.5px;
@@ -106,7 +113,7 @@ class HabChart extends HTMLElementBase {
106
113
  .nodata {
107
114
  position: absolute; inset: 0;
108
115
  display: flex; align-items: center; justify-content: center;
109
- color: var(--hab-text, #8b949e);
116
+ color: var(--wick-text, var(--hab-text, #8b949e));
110
117
  font: 500 13px ${FONT_STACK};
111
118
  pointer-events: none;
112
119
  }
@@ -119,25 +126,25 @@ class HabChart extends HTMLElementBase {
119
126
  }
120
127
  .hud .pos {
121
128
  display: inline-flex; gap: 9px; align-items: baseline; white-space: nowrap;
122
- background: var(--hab-chip, rgba(127, 137, 153, 0.12));
123
- border: 1px solid var(--hab-border, rgba(148, 163, 184, 0.2));
129
+ background: var(--wick-chip, var(--hab-chip, rgba(127, 137, 153, 0.12)));
130
+ border: 1px solid var(--wick-border, var(--hab-border, rgba(148, 163, 184, 0.2)));
124
131
  border-radius: 7px;
125
132
  padding: 3px 9px;
126
133
  }
127
134
  .hud .statsrow {
128
135
  display: inline-flex; gap: 12px; white-space: nowrap;
129
- background: var(--hab-chip, rgba(127, 137, 153, 0.12));
130
- border: 1px solid var(--hab-border, rgba(148, 163, 184, 0.2));
136
+ background: var(--wick-chip, var(--hab-chip, rgba(127, 137, 153, 0.12)));
137
+ border: 1px solid var(--wick-border, var(--hab-border, rgba(148, 163, 184, 0.2)));
131
138
  border-radius: 7px;
132
139
  padding: 3px 10px;
133
- color: var(--hab-text, #8b949e);
140
+ color: var(--wick-text, var(--hab-text, #8b949e));
134
141
  font-variant-numeric: tabular-nums;
135
142
  }
136
- .hud .statsrow b { color: var(--hab-text-strong, #e6edf3); font-weight: 600; }
137
- .hud .k { color: var(--hab-text, #8b949e); font-weight: 500; }
138
- .hud .v { color: var(--hab-text-strong, #e6edf3); font-variant-numeric: tabular-nums; }
139
- .hud .up { color: var(--hab-up, #16c784); }
140
- .hud .dn { color: var(--hab-down, #ea3943); }
143
+ .hud .statsrow b { color: var(--wick-text-strong, var(--hab-text-strong, #e6edf3)); font-weight: 600; }
144
+ .hud .k { color: var(--wick-text, var(--hab-text, #8b949e)); font-weight: 500; }
145
+ .hud .v { color: var(--wick-text-strong, var(--hab-text-strong, #e6edf3)); font-variant-numeric: tabular-nums; }
146
+ .hud .up { color: var(--wick-up, var(--hab-up, #16c784)); }
147
+ .hud .dn { color: var(--wick-down, var(--hab-down, #ea3943)); }
141
148
  </style>
142
149
  <div class="wrap" part="wrap">
143
150
  <canvas part="canvas" role="img"></canvas>
@@ -305,7 +312,7 @@ class HabChart extends HTMLElementBase {
305
312
  this._label = val || '';
306
313
  break;
307
314
  case 'indicators':
308
- this._ind = parseIndicators(val, HabChart._registry());
315
+ this._ind = parseIndicators(val, WickChart._registry());
309
316
  break;
310
317
  case 'stats':
311
318
  this._stats = val != null && val !== 'false';
@@ -339,20 +346,15 @@ class HabChart extends HTMLElementBase {
339
346
  * Indicator registry
340
347
  * ------------------------------------------------------------ */
341
348
 
342
- static _registryMap = null;
343
-
344
- /** Lazily-built registry, seeded with the built-in indicators. */
349
+ /** Indicator registry (module scope — shared with the legacy alias tag). */
345
350
  static _registry() {
346
- if (!HabChart._registryMap) {
347
- HabChart._registryMap = new Map(BUILTIN_INDICATORS);
348
- }
349
- return HabChart._registryMap;
351
+ return REGISTRY;
350
352
  }
351
353
 
352
354
  /**
353
355
  * Register a custom indicator.
354
356
  *
355
- * HabChart.registerIndicator('vwap', {
357
+ * WickChart.registerIndicator('vwap', {
356
358
  * kind: 'overlay', // or 'pane'
357
359
  * params: { period: 20 }, // defaults; settable via name:period
358
360
  * compute(bars, params) { // bars: normalized {time,o,h,l,c,v}
@@ -373,7 +375,7 @@ class HabChart extends HTMLElementBase {
373
375
  if (!def || typeof def.compute !== 'function') {
374
376
  throw new Error('registerIndicator: def.compute must be a function');
375
377
  }
376
- HabChart._registry().set(name.toLowerCase(), {
378
+ REGISTRY.set(name.toLowerCase(), {
377
379
  kind: def.kind === 'pane' ? 'pane' : 'overlay',
378
380
  ...def,
379
381
  });
@@ -403,7 +405,7 @@ class HabChart extends HTMLElementBase {
403
405
  }
404
406
  const norm = [];
405
407
  for (const b of bars) {
406
- const nb = HabChart._normBar(b);
408
+ const nb = WickChart._normBar(b);
407
409
  if (nb) norm.push(nb);
408
410
  }
409
411
  // skip the O(n log n) sort when already ascending (typical for feeds)
@@ -432,7 +434,7 @@ class HabChart extends HTMLElementBase {
432
434
  * @param {import('./core.js').Bar} bar
433
435
  */
434
436
  update(bar) {
435
- const b = HabChart._normBar(bar);
437
+ const b = WickChart._normBar(bar);
436
438
  if (!b) return;
437
439
  const d = this._data;
438
440
  const last = d[d.length - 1];
@@ -492,7 +494,7 @@ class HabChart extends HTMLElementBase {
492
494
  }
493
495
  const older = [];
494
496
  for (const b of bars) {
495
- const nb = HabChart._normBar(b);
497
+ const nb = WickChart._normBar(b);
496
498
  if (nb) older.push(nb);
497
499
  }
498
500
  const { bars: merged, added } = mergeOlderData(this._data, older);
@@ -540,14 +542,14 @@ class HabChart extends HTMLElementBase {
540
542
  setVisibleRange(range) {
541
543
  const d = this._data;
542
544
  if (!d.length || !range || !this._ly) return;
543
- const from = HabChart._timeToMs(range.from);
544
- const to = HabChart._timeToMs(range.to);
545
- let i0 = HabChart._indexForTime(d, from);
546
- let i1 = HabChart._indexForTime(d, to);
545
+ const from = WickChart._timeToMs(range.from);
546
+ const to = WickChart._timeToMs(range.to);
547
+ let i0 = WickChart._indexForTime(d, from);
548
+ let i1 = WickChart._indexForTime(d, to);
547
549
  if (i0 > i1) [i0, i1] = [i1, i0];
548
550
  if (i1 - i0 < 2) return;
549
551
  const { plotRight } = this._ly;
550
- this._view.spacing = clamp(plotRight / (i1 - i0), this._minSpacing(), HabChart._MAX_SP);
552
+ this._view.spacing = clamp(plotRight / (i1 - i0), this._minSpacing(), WickChart._MAX_SP);
551
553
  this._view.rightIndex = i1;
552
554
  this._auto = false;
553
555
  this._clampView();
@@ -725,7 +727,8 @@ class HabChart extends HTMLElementBase {
725
727
  }
726
728
 
727
729
  /**
728
- * Price alert. Fires `hab:alert` ({id, price, bar}) on an edge crossing
730
+ * Price alert. Fires `wick:alert` ({id, price, bar}) on an edge crossing
731
+ * (plus the deprecated `hab:alert` alias)
729
732
  * during streaming updates.
730
733
  * @param {{id?: string, price: number, direction?: 'above'|'below'|'cross',
731
734
  * once?: boolean}} alert
@@ -764,9 +767,7 @@ class HabChart extends HTMLElementBase {
764
767
  if (a.fired) continue;
765
768
  if (checkAlertCross(a, prevClose, bar.close)) {
766
769
  a.fired = true;
767
- this.dispatchEvent(
768
- new CustomEvent('hab:alert', { detail: { id: a.id, price: a.price, bar } })
769
- );
770
+ this._fire('alert', { id: a.id, price: a.price, bar });
770
771
  if (a.once) this._alerts = this._alerts.filter((x) => x !== a);
771
772
  }
772
773
  }
@@ -808,7 +809,7 @@ class HabChart extends HTMLElementBase {
808
809
  if (!b) return null;
809
810
  const t = b.time != null ? b.time : b.t;
810
811
  if (!isNum(t)) return null;
811
- const time = HabChart._timeToMs(t);
812
+ const time = WickChart._timeToMs(t);
812
813
  const close = isNum(b.close) ? b.close : isNum(b.value) ? b.value : NaN;
813
814
  if (!isNum(close)) return null;
814
815
  const open = isNum(b.open) ? b.open : close;
@@ -887,8 +888,9 @@ class HabChart extends HTMLElementBase {
887
888
  if (this._pal && this._palKey === this._theme) return this._pal;
888
889
  const base = THEMES[this._theme] || THEMES.dark;
889
890
  const cs = getComputedStyle(this);
891
+ // --wick-* is canonical; --hab-* still honored as the 0.x fallback
890
892
  const get = (name, fallback) => {
891
- const v = cs.getPropertyValue('--hab-' + name).trim();
893
+ const v = cs.getPropertyValue('--wick-' + name).trim() || cs.getPropertyValue('--hab-' + name).trim();
892
894
  return v || fallback;
893
895
  };
894
896
  const pal = {};
@@ -899,7 +901,8 @@ class HabChart extends HTMLElementBase {
899
901
  o.push(get('overlay-' + i, base.overlay[i]));
900
902
  }
901
903
  // allow single overlay color
902
- const single = cs.getPropertyValue('--hab-overlay').trim();
904
+ const single =
905
+ cs.getPropertyValue('--wick-overlay').trim() || cs.getPropertyValue('--hab-overlay').trim();
903
906
  pal.overlay = single ? base.overlay.map(() => single) : o;
904
907
  } else {
905
908
  pal[k] = get(k.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase()), base[k]);
@@ -1018,7 +1021,7 @@ class HabChart extends HTMLElementBase {
1018
1021
  if (!d.length || !this._ly) return;
1019
1022
  const { plotRight } = this._ly;
1020
1023
  const target = Math.min(d.length, 150);
1021
- this._view.spacing = clamp(plotRight / target, this._minSpacing(), HabChart._MAX_SP);
1024
+ this._view.spacing = clamp(plotRight / target, this._minSpacing(), WickChart._MAX_SP);
1022
1025
  this._view.rightIndex = d.length - 1 + this._rightMargin();
1023
1026
  }
1024
1027
 
@@ -1027,7 +1030,7 @@ class HabChart extends HTMLElementBase {
1027
1030
  const ly = this._ly;
1028
1031
  if (!d.length || !ly) return;
1029
1032
  const v = this._view;
1030
- v.spacing = clamp(v.spacing, this._minSpacing(), HabChart._MAX_SP);
1033
+ v.spacing = clamp(v.spacing, this._minSpacing(), WickChart._MAX_SP);
1031
1034
  const visible = ly.plotRight / v.spacing;
1032
1035
  const maxRight = d.length - 1 + Math.max(6, visible * 0.5);
1033
1036
  const minRight = Math.min(2, d.length - 1);
@@ -1457,9 +1460,7 @@ class HabChart extends HTMLElementBase {
1457
1460
  this._annoList = detectAnnotations(this._data, i0, i1, this._cachedRSI14());
1458
1461
  this._annoKey = akey;
1459
1462
  this._legendKey = ''; // legend may now show insights at the hovered bar
1460
- this.dispatchEvent(
1461
- new CustomEvent('hab:annotations', { detail: { annotations: this._annoList } })
1462
- );
1463
+ this._fire('annotations', { annotations: this._annoList });
1463
1464
  }
1464
1465
  const A = this._annoList;
1465
1466
  if (A.length) {
@@ -2353,7 +2354,7 @@ class HabChart extends HTMLElementBase {
2353
2354
  const s = clamp(
2354
2355
  (this._pinch.spacing * dist) / this._pinch.dist,
2355
2356
  this._minSpacing(),
2356
- HabChart._MAX_SP
2357
+ WickChart._MAX_SP
2357
2358
  );
2358
2359
  this._view.spacing = s;
2359
2360
  this._view.rightIndex = this._pinch.idxAtMid + (ly.plotRight - mid.x) / s;
@@ -2406,15 +2407,11 @@ class HabChart extends HTMLElementBase {
2406
2407
  const d = this._data;
2407
2408
  const barA = d[clamp(m.iA, 0, d.length - 1)];
2408
2409
  const barB = d[clamp(m.iB, 0, d.length - 1)];
2409
- this.dispatchEvent(
2410
- new CustomEvent('hab:measure', {
2411
- detail: {
2412
- from: { index: m.iA, time: barA.time, price: m.pA },
2413
- to: { index: m.iB, time: barB.time, price: m.pB },
2414
- bars: Math.abs(m.iB - m.iA),
2415
- },
2416
- })
2417
- );
2410
+ this._fire('measure', {
2411
+ from: { index: m.iA, time: barA.time, price: m.pA },
2412
+ to: { index: m.iB, time: barB.time, price: m.pB },
2413
+ bars: Math.abs(m.iB - m.iA),
2414
+ });
2418
2415
  }
2419
2416
  } else if (this._pan && had && !this._pan.moved && this._data.length) {
2420
2417
  if (this._measure) {
@@ -2426,11 +2423,7 @@ class HabChart extends HTMLElementBase {
2426
2423
  const pt = this._localPoint(e);
2427
2424
  const idx = clamp(Math.round(this._indexForX(pt.x)), 0, this._data.length - 1);
2428
2425
  const price = this._yToPrice(pt.y);
2429
- this.dispatchEvent(
2430
- new CustomEvent('hab:select', {
2431
- detail: { index: idx, bar: this._data[idx], price },
2432
- })
2433
- );
2426
+ this._fire('select', { index: idx, bar: this._data[idx], price });
2434
2427
  }
2435
2428
  }
2436
2429
  this._pan = null;
@@ -2467,7 +2460,7 @@ class HabChart extends HTMLElementBase {
2467
2460
 
2468
2461
  const factor = Math.exp(-dy * (e.ctrlKey ? 0.008 : 0.0016));
2469
2462
  const oldSp = this._view.spacing;
2470
- const newSp = clamp(oldSp * factor, this._minSpacing(), HabChart._MAX_SP);
2463
+ const newSp = clamp(oldSp * factor, this._minSpacing(), WickChart._MAX_SP);
2471
2464
  if (newSp === oldSp) return;
2472
2465
  const idxAtCursor = this._indexForX(pt.x);
2473
2466
  this._view.spacing = newSp;
@@ -2504,12 +2497,12 @@ class HabChart extends HTMLElementBase {
2504
2497
  this._invalidate();
2505
2498
  this._emitRange();
2506
2499
  } else if (key === '+' || key === '=') {
2507
- this._view.spacing = clamp(this._view.spacing * 1.25, this._minSpacing(), HabChart._MAX_SP);
2500
+ this._view.spacing = clamp(this._view.spacing * 1.25, this._minSpacing(), WickChart._MAX_SP);
2508
2501
  this._clampView();
2509
2502
  this._invalidate();
2510
2503
  this._emitRange();
2511
2504
  } else if (key === '-' || key === '_') {
2512
- this._view.spacing = clamp(this._view.spacing / 1.25, this._minSpacing(), HabChart._MAX_SP);
2505
+ this._view.spacing = clamp(this._view.spacing / 1.25, this._minSpacing(), WickChart._MAX_SP);
2513
2506
  this._clampView();
2514
2507
  this._invalidate();
2515
2508
  this._emitRange();
@@ -2636,7 +2629,7 @@ class HabChart extends HTMLElementBase {
2636
2629
  price: this._yToPrice(hover.y),
2637
2630
  };
2638
2631
  }
2639
- this.dispatchEvent(new CustomEvent('hab:crosshair', { detail }));
2632
+ this._fire('crosshair', detail);
2640
2633
 
2641
2634
  // co-view: share the pointer with peer charts (leave events bypass throttle)
2642
2635
  if (this._coviewCh) {
@@ -2678,7 +2671,7 @@ class HabChart extends HTMLElementBase {
2678
2671
  if (!name || !this._connected || typeof BroadcastChannel === 'undefined') return;
2679
2672
  if (!this._coviewPeer) this._coviewPeer = 'p' + Math.random().toString(36).slice(2, 8);
2680
2673
  try {
2681
- const ch = new BroadcastChannel('hab-co-view:' + name);
2674
+ const ch = new BroadcastChannel('wick-co-view:' + name);
2682
2675
  ch.onmessage = (ev) => this._onCoMessage(ev.data);
2683
2676
  this._coviewCh = ch;
2684
2677
  } catch (_) {}
@@ -2703,7 +2696,7 @@ class HabChart extends HTMLElementBase {
2703
2696
  }
2704
2697
  if (!isNum(m.time) || !this._data.length) return;
2705
2698
  this._ghost = {
2706
- index: HabChart._indexForTime(this._data, m.time),
2699
+ index: WickChart._indexForTime(this._data, m.time),
2707
2700
  yFrac: isNum(m.yFrac) ? clamp(m.yFrac, 0, 1) : null,
2708
2701
  at: Date.now(),
2709
2702
  };
@@ -2715,15 +2708,31 @@ class HabChart extends HTMLElementBase {
2715
2708
  this._invalidate();
2716
2709
  }
2717
2710
 
2711
+ /** Dispatch `wick:name` (canonical) plus the deprecated `hab:name` alias,
2712
+ * so 0.x listeners keep working until 2.0. */
2713
+ _fire(name, detail) {
2714
+ this.dispatchEvent(new CustomEvent('wick:' + name, { detail }));
2715
+ this.dispatchEvent(new CustomEvent('hab:' + name, { detail }));
2716
+ }
2717
+
2718
2718
  _emitRange() {
2719
2719
  const r = this.getVisibleRange();
2720
2720
  if (!r) return;
2721
- this.dispatchEvent(new CustomEvent('hab:range', { detail: r }));
2721
+ this._fire('range', r);
2722
2722
  }
2723
2723
  }
2724
2724
 
2725
- if (typeof customElements !== 'undefined' && !customElements.get('hab-chart')) {
2726
- customElements.define('hab-chart', HabChart);
2725
+ if (typeof customElements !== 'undefined') {
2726
+ if (!customElements.get('wick-chart')) {
2727
+ customElements.define('wick-chart', WickChart);
2728
+ }
2729
+ // 0.x alias: same element under its old tag name (deprecated, removed in 2.0)
2730
+ if (!customElements.get('hab-chart')) {
2731
+ /** @deprecated use <wick-chart> */
2732
+ class HabChart extends WickChart {}
2733
+ customElements.define('hab-chart', HabChart);
2734
+ }
2727
2735
  }
2728
2736
 
2729
- export default HabChart;
2737
+ export default WickChart;
2738
+ export { WickChart };
@@ -1,10 +1,10 @@
1
1
  /* ==========================================================================
2
- * <hab-feed> — declarative data feeds for <hab-chart>.
2
+ * <wick-feed> — declarative data feeds for <wick-chart>.
3
3
  *
4
- * <script type="module" src="https://unpkg.com/hab-view/feed"></script>
4
+ * <script type="module" src="https://unpkg.com/wickchart/feed"></script>
5
5
  *
6
- * <hab-feed for="chart" binance="BTCUSDT" tf="1h"></hab-feed>
7
- * <hab-chart id="chart" indicators="sma:20 volume"></hab-chart>
6
+ * <wick-feed for="chart" binance="BTCUSDT" tf="1h"></wick-feed>
7
+ * <wick-chart id="chart" indicators="sma:20 volume"></wick-chart>
8
8
  *
9
9
  * A fully live chart with zero JavaScript written. Sources:
10
10
  * binance="SYMBOL" live via WebSocket (REST klines + backfill; falls back
@@ -17,11 +17,12 @@
17
17
  * Attributes: for (chart id; auto-pairs with the first chart otherwise),
18
18
  * tf (1m…1w), limit (initial bars, default 500), live="false" to disable
19
19
  * streaming. Status is reflected in the `status` attribute and via
20
- * `hab-feed:status` events (loading / live / polling / fallback / loaded /
21
- * waiting / idle). `hab-feed:fallback` fires when a live source degrades.
20
+ * `wick-feed:status` events (loading / live / polling / fallback / loaded /
21
+ * waiting / idle). `wick-feed:fallback` fires when a live source degrades.
22
+ * (The 0.x event names `hab-feed:*` still fire as deprecated aliases.)
22
23
  * ========================================================================== */
23
24
 
24
- import './hab-chart.js';
25
+ import './wick-chart.js';
25
26
  import {
26
27
  genSynthetic,
27
28
  makeSynthStream,
@@ -35,7 +36,7 @@ const LIVE_TICK_MS = 650;
35
36
 
36
37
  const HTMLElementBase = typeof HTMLElement !== 'undefined' ? HTMLElement : class {};
37
38
 
38
- class HabFeed extends HTMLElementBase {
39
+ class WickFeed extends HTMLElementBase {
39
40
  static get observedAttributes() {
40
41
  return ['for', 'binance', 'demo', 'url', 'tf', 'limit', 'poll', 'live'];
41
42
  }
@@ -86,17 +87,24 @@ class HabFeed extends HTMLElementBase {
86
87
  _setStatus(status, detail) {
87
88
  if (!this.isConnected) return;
88
89
  this.setAttribute('status', status);
89
- this.dispatchEvent(new CustomEvent('hab-feed:status', { detail: { status, ...detail } }));
90
+ this._fire('status', { status, ...detail });
90
91
  }
91
92
 
92
- /** Resolve the target chart (by `for` id, else the first <hab-chart>). */
93
+ /** Dispatch `wick-feed:name` plus the deprecated `hab-feed:name` alias. */
94
+ _fire(name, detail) {
95
+ this.dispatchEvent(new CustomEvent('wick-feed:' + name, { detail }));
96
+ this.dispatchEvent(new CustomEvent('hab-feed:' + name, { detail }));
97
+ }
98
+
99
+ /** Resolve the target chart (by `for` id, else the first chart element —
100
+ * <wick-chart> or the deprecated <hab-chart>). */
93
101
  _resolveChart() {
94
102
  const id = this.getAttribute('for');
95
103
  if (id) {
96
104
  const el = document.getElementById(id);
97
- return el && el.tagName === 'HAB-CHART' ? el : null;
105
+ return el && (el.tagName === 'WICK-CHART' || el.tagName === 'HAB-CHART') ? el : null;
98
106
  }
99
- return document.querySelector('hab-chart');
107
+ return document.querySelector('wick-chart') || document.querySelector('hab-chart');
100
108
  }
101
109
 
102
110
  _restart() {
@@ -105,7 +113,7 @@ class HabFeed extends HTMLElementBase {
105
113
  if (!chart || typeof chart.setData !== 'function') {
106
114
  // chart not in the DOM yet (or not upgraded) — watch for it
107
115
  this._setStatus('waiting');
108
- customElements.whenDefined('hab-chart').then(() => {
116
+ customElements.whenDefined('wick-chart').then(() => {
109
117
  if (!this.isConnected) return;
110
118
  this._observer = this._observer || new MutationObserver(() => {
111
119
  const c = this._resolveChart();
@@ -208,9 +216,7 @@ class HabFeed extends HTMLElementBase {
208
216
  }
209
217
 
210
218
  _degrade(gen, chart, sym, tfId, limit, live, err) {
211
- this.dispatchEvent(
212
- new CustomEvent('hab-feed:fallback', { detail: { reason: err && err.message } })
213
- );
219
+ this._fire('fallback', { reason: err && err.message });
214
220
  this._synthetic(gen, chart, sym, tfId, limit, live, 'fallback');
215
221
  }
216
222
 
@@ -248,8 +254,17 @@ class HabFeed extends HTMLElementBase {
248
254
  }
249
255
  }
250
256
 
251
- if (typeof customElements !== 'undefined' && !customElements.get('hab-feed')) {
252
- customElements.define('hab-feed', HabFeed);
257
+ if (typeof customElements !== 'undefined') {
258
+ if (!customElements.get('wick-feed')) {
259
+ customElements.define('wick-feed', WickFeed);
260
+ }
261
+ // 0.x alias: same element under its old tag name (deprecated, removed in 2.0)
262
+ if (!customElements.get('hab-feed')) {
263
+ /** @deprecated use <wick-feed> */
264
+ class HabFeed extends WickFeed {}
265
+ customElements.define('hab-feed', HabFeed);
266
+ }
253
267
  }
254
268
 
255
- export default HabFeed;
269
+ export default WickFeed;
270
+ export { WickFeed };
package/types/core.d.ts CHANGED
@@ -512,7 +512,7 @@ export declare const BUILTIN_INDICATORS: Map<string, {
512
512
  /**
513
513
  * Parse an `indicators` attribute string against a registry.
514
514
  * Token: `name[:param[/param…]][@color]`, the `volume` keyword, and
515
- * HabScript blobs `expr:{…}` (overlay) / `pexpr:{…}` (separate pane).
515
+ * WickScript blobs `expr:{…}` (overlay) / `pexpr:{…}` (separate pane).
516
516
  * @param {string|null|undefined} str
517
517
  * @param {Map<string, IndicatorDef>} registry
518
518
  * @returns {{overlays: IndicatorEntry[], panes: IndicatorEntry[], volume: boolean, unknown: string[]}}
@@ -533,7 +533,7 @@ export declare function parseIndicators(str: string | null | undefined, registry
533
533
  */
534
534
  export declare function splitIndicatorTokens(str: string | null | undefined): string[];
535
535
  /**
536
- * Compile a HabScript expression. Throws a descriptive error on any syntax
536
+ * Compile a WickScript expression. Throws a descriptive error on any syntax
537
537
  * or semantic problem — never evaluates strings at runtime.
538
538
  * @param {string} src
539
539
  * @returns {{src: string, ast: object}}
@@ -553,7 +553,7 @@ export declare function evalScript(compiled: {
553
553
  ast: object;
554
554
  } | string, bars: Bar[]): number[];
555
555
  /**
556
- * Build an indicator definition from a HabScript expression — used inline by
556
+ * Build an indicator definition from a WickScript expression — used inline by
557
557
  * `indicators="expr:{…}"` / `pexpr:{…}"`, or register it under a name:
558
558
  * `HabChart.registerIndicator('myspread', scriptIndicator('close - ema(close,21)'))`.
559
559
  * @param {string} src
@@ -1,7 +1,7 @@
1
1
  declare const HTMLElementBase: {
2
2
  new (): {};
3
3
  };
4
- declare class HabChart extends HTMLElementBase {
4
+ declare class WickChart extends HTMLElementBase {
5
5
  _canvas: any;
6
6
  _ctx: any;
7
7
  _legend: any;
@@ -172,13 +172,93 @@ declare class HabChart extends HTMLElementBase {
172
172
  connectedCallback(): void;
173
173
  disconnectedCallback(): void;
174
174
  attributeChangedCallback(name: any, _old: any, val: any): void;
175
- static _registryMap: any;
176
- /** Lazily-built registry, seeded with the built-in indicators. */
177
- static _registry(): any;
175
+ /** Indicator registry (module scope — shared with the legacy alias tag). */
176
+ static _registry(): Map<string, {
177
+ kind: string;
178
+ params: {
179
+ period: number;
180
+ mult?: undefined;
181
+ fast?: undefined;
182
+ slow?: undefined;
183
+ signal?: undefined;
184
+ };
185
+ compute: (bars: any, p: any) => number[];
186
+ range?: undefined;
187
+ color?: undefined;
188
+ guides?: undefined;
189
+ fmt?: undefined;
190
+ } | {
191
+ kind: string;
192
+ params: {
193
+ period: number;
194
+ mult?: undefined;
195
+ fast?: undefined;
196
+ slow?: undefined;
197
+ signal?: undefined;
198
+ };
199
+ compute: (bars: any, p: any) => number[];
200
+ range?: undefined;
201
+ color?: undefined;
202
+ guides?: undefined;
203
+ fmt?: undefined;
204
+ } | {
205
+ kind: string;
206
+ params: {
207
+ period: number;
208
+ mult: number;
209
+ fast?: undefined;
210
+ slow?: undefined;
211
+ signal?: undefined;
212
+ };
213
+ compute: (bars: any, p: any) => {
214
+ lines: {
215
+ name: string;
216
+ values: number[];
217
+ }[];
218
+ };
219
+ range?: undefined;
220
+ color?: undefined;
221
+ guides?: undefined;
222
+ fmt?: undefined;
223
+ } | {
224
+ kind: string;
225
+ params: {
226
+ mult?: undefined;
227
+ period: number;
228
+ fast?: undefined;
229
+ slow?: undefined;
230
+ signal?: undefined;
231
+ };
232
+ guides: number[];
233
+ range: number[];
234
+ fmt: string;
235
+ color: string;
236
+ compute: (bars: any, p: any) => number[];
237
+ } | {
238
+ range?: undefined;
239
+ color?: undefined;
240
+ kind: string;
241
+ params: {
242
+ mult?: undefined;
243
+ period?: undefined;
244
+ fast: number;
245
+ slow: number;
246
+ signal: number;
247
+ };
248
+ guides: number[];
249
+ fmt: string;
250
+ compute: (bars: any, p: any) => {
251
+ lines: {
252
+ name: string;
253
+ values: number[];
254
+ }[];
255
+ histogram: number[];
256
+ };
257
+ }>;
178
258
  /**
179
259
  * Register a custom indicator.
180
260
  *
181
- * HabChart.registerIndicator('vwap', {
261
+ * WickChart.registerIndicator('vwap', {
182
262
  * kind: 'overlay', // or 'pane'
183
263
  * params: { period: 20 }, // defaults; settable via name:period
184
264
  * compute(bars, params) { // bars: normalized {time,o,h,l,c,v}
@@ -269,7 +349,8 @@ declare class HabChart extends HTMLElementBase {
269
349
  removePosition(id: any): void;
270
350
  clearPositions(): void;
271
351
  /**
272
- * Price alert. Fires `hab:alert` ({id, price, bar}) on an edge crossing
352
+ * Price alert. Fires `wick:alert` ({id, price, bar}) on an edge crossing
353
+ * (plus the deprecated `hab:alert` alias)
273
354
  * during streaming updates.
274
355
  * @param {{id?: string, price: number, direction?: 'above'|'below'|'cross',
275
356
  * once?: boolean}} alert
@@ -386,6 +467,10 @@ declare class HabChart extends HTMLElementBase {
386
467
  _setupCoView(): void;
387
468
  _coviewSend(msg: any): void;
388
469
  _onCoMessage(m: any): void;
470
+ /** Dispatch `wick:name` (canonical) plus the deprecated `hab:name` alias,
471
+ * so 0.x listeners keep working until 2.0. */
472
+ _fire(name: any, detail: any): void;
389
473
  _emitRange(): void;
390
474
  }
391
- export default HabChart;
475
+ export default WickChart;
476
+ export { WickChart };
@@ -1,8 +1,8 @@
1
- import './hab-chart.js';
1
+ import './wick-chart.js';
2
2
  declare const HTMLElementBase: {
3
3
  new (): {};
4
4
  };
5
- declare class HabFeed extends HTMLElementBase {
5
+ declare class WickFeed extends HTMLElementBase {
6
6
  _gen: number;
7
7
  _closers: any[];
8
8
  _timer: number;
@@ -15,7 +15,10 @@ declare class HabFeed extends HTMLElementBase {
15
15
  _scheduleRestart(): void;
16
16
  _teardown(): void;
17
17
  _setStatus(status: any, detail: any): void;
18
- /** Resolve the target chart (by `for` id, else the first <hab-chart>). */
18
+ /** Dispatch `wick-feed:name` plus the deprecated `hab-feed:name` alias. */
19
+ _fire(name: any, detail: any): void;
20
+ /** Resolve the target chart (by `for` id, else the first chart element —
21
+ * <wick-chart> or the deprecated <hab-chart>). */
19
22
  _resolveChart(): Element;
20
23
  _restart(): void;
21
24
  _synthetic(gen: any, chart: any, key: any, tfId: any, limit: any, live: any, status?: string): void;
@@ -24,4 +27,5 @@ declare class HabFeed extends HTMLElementBase {
24
27
  _degrade(gen: any, chart: any, sym: any, tfId: any, limit: any, live: any, err: any): void;
25
28
  _rest(gen: any, chart: any, url: any, limit: any, live: any): Promise<void>;
26
29
  }
27
- export default HabFeed;
30
+ export default WickFeed;
31
+ export { WickFeed };