@dwlf/charting 1.0.0 → 1.1.1

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 (50) hide show
  1. package/README.md +225 -19
  2. package/dist/charting/__tests__/chartSpec.test.d.ts +1 -0
  3. package/dist/charting/scales.d.ts +14 -0
  4. package/dist/charting/types.d.ts +454 -0
  5. package/dist/charting.css +1 -1
  6. package/dist/components/DWLFChart.d.ts +119 -0
  7. package/dist/components/index.d.ts +2 -0
  8. package/dist/components/overlays/AlertLineAnnotationView.d.ts +14 -0
  9. package/dist/components/overlays/AnnotationLayer.d.ts +55 -0
  10. package/dist/components/overlays/ArrowAnnotationView.d.ts +24 -0
  11. package/dist/components/overlays/BosLineAnnotationView.d.ts +22 -0
  12. package/dist/components/overlays/BrushAnnotationView.d.ts +20 -0
  13. package/dist/components/overlays/ChannelAnnotationView.d.ts +23 -0
  14. package/dist/components/overlays/CrossLineAnnotationView.d.ts +29 -0
  15. package/dist/components/overlays/DiagonalLineOverlay.d.ts +31 -0
  16. package/dist/components/overlays/EmojiAnnotationView.d.ts +22 -0
  17. package/dist/components/overlays/FairValueGapAnnotationView.d.ts +23 -0
  18. package/dist/components/overlays/FibExtensionAnnotationView.d.ts +19 -0
  19. package/dist/components/overlays/FibRetracementAnnotationView.d.ts +19 -0
  20. package/dist/components/overlays/HLineAnnotationView.d.ts +15 -0
  21. package/dist/components/overlays/HorizontalLineOverlay.d.ts +23 -0
  22. package/dist/components/overlays/MarkerOverlay.d.ts +66 -0
  23. package/dist/components/overlays/MeasureAnnotationView.d.ts +25 -0
  24. package/dist/components/overlays/MessageBubbleOverlay.d.ts +55 -0
  25. package/dist/components/overlays/OrderBlockAnnotationView.d.ts +23 -0
  26. package/dist/components/overlays/PitchforkAnnotationView.d.ts +19 -0
  27. package/dist/components/overlays/PositionOverlay.d.ts +52 -0
  28. package/dist/components/overlays/RayAnnotationView.d.ts +30 -0
  29. package/dist/components/overlays/RectangleAnnotationView.d.ts +23 -0
  30. package/dist/components/overlays/SMAOverlay.d.ts +20 -0
  31. package/dist/components/overlays/TextAnnotationView.d.ts +24 -0
  32. package/dist/components/overlays/TimeRangeAnnotationView.d.ts +22 -0
  33. package/dist/components/overlays/TrendLineAnnotationView.d.ts +23 -0
  34. package/dist/components/overlays/VLineAnnotationView.d.ts +26 -0
  35. package/dist/components/overlays/annotationConstants.d.ts +21 -0
  36. package/dist/components/overlays/annotationUtils.d.ts +13 -0
  37. package/dist/components/overlays/useAnnotationDrag.d.ts +18 -0
  38. package/dist/components/overlays/usePointAnnotationDrag.d.ts +23 -0
  39. package/dist/hooks/useCandlestickChart.d.ts +18 -0
  40. package/dist/hooks/useChartAnimations.d.ts +49 -0
  41. package/dist/hooks/useChartLayout.d.ts +12 -0
  42. package/dist/hooks/useChartPanZoom.d.ts +7 -0
  43. package/dist/hooks/useChartPanZoomVirtual.d.ts +24 -0
  44. package/dist/hooks/useContainerSize.d.ts +4 -0
  45. package/dist/hooks/useOverlayToggles.d.ts +19 -0
  46. package/dist/index.cjs +1 -1
  47. package/dist/index.d.ts +56 -0
  48. package/dist/index.js +13 -13
  49. package/dist/utils/indicators.d.ts +40 -0
  50. package/package.json +4 -1
@@ -0,0 +1,454 @@
1
+ export interface LinePoint {
2
+ t: number;
3
+ v: number;
4
+ }
5
+ export interface OhlcPoint {
6
+ t: number;
7
+ o: number;
8
+ h: number;
9
+ l: number;
10
+ c: number;
11
+ }
12
+ export type Candle = OhlcPoint;
13
+ export type SeriesType = 'line' | 'hist' | 'area' | 'ohlc' | 'marker' | 'position';
14
+ export interface SeriesStyle {
15
+ color?: string;
16
+ lineWidth?: number;
17
+ dashed?: boolean;
18
+ opacity?: number;
19
+ markerShape?: 'arrow-up' | 'arrow-down' | 'circle';
20
+ markerSize?: number;
21
+ markerOffsetY?: number;
22
+ markerFontSize?: number;
23
+ markerTextColor?: string;
24
+ markerTextOffsetY?: number;
25
+ riskColor?: string;
26
+ rewardColor?: string;
27
+ bubbleColor?: string;
28
+ textColor?: string;
29
+ fontSize?: number;
30
+ pointer?: boolean;
31
+ padding?: number;
32
+ }
33
+ export type TooltipFormatter = (point: any) => string;
34
+ export interface SeriesSpec {
35
+ key: string;
36
+ type: SeriesType;
37
+ data: any[];
38
+ /** Shorthand for style.color. If both are set, style.color takes precedence. */
39
+ color?: string;
40
+ style?: SeriesStyle;
41
+ tooltipFormatter?: TooltipFormatter;
42
+ showInTooltip?: boolean;
43
+ /**
44
+ * Optional click handler invoked when a point belonging to this series is
45
+ * clicked. The callback receives the raw datum found by the hit-testing
46
+ * logic (for markers this is typically the marker datum; for OHLC, the
47
+ * candle; for lines, the nearest LinePoint).
48
+ *
49
+ * Consumers should treat this as best-effort hit-testing around the
50
+ * current crosshair time.
51
+ */
52
+ onClick?: (raw: any) => void;
53
+ }
54
+ export interface PaneGuide {
55
+ y: number;
56
+ dashed?: boolean;
57
+ label?: string;
58
+ color?: string;
59
+ /**
60
+ * Optional start time for partial-width guides (e.g., S/R lines that start
61
+ * at their formation bar). If omitted, the guide extends from the left edge.
62
+ */
63
+ startTime?: number;
64
+ /**
65
+ * Optional end time for partial-width guides. If omitted, the guide extends
66
+ * to the right edge.
67
+ */
68
+ endTime?: number;
69
+ }
70
+ export interface PaneSpec {
71
+ id: string;
72
+ title?: string;
73
+ heightRatio: number;
74
+ yScale: {
75
+ mode: 'auto' | 'fixed';
76
+ min?: number;
77
+ max?: number;
78
+ };
79
+ series: SeriesSpec[];
80
+ guides?: PaneGuide[];
81
+ }
82
+ export interface ChartSpec {
83
+ panes: PaneSpec[];
84
+ timeFormatter?: (t: number) => string;
85
+ onCrosshairMove?: (t: number) => void;
86
+ /**
87
+ * When true, include all series (markers, positions, overlays) when deriving
88
+ * the automatic Y-domain for panes that contain OHLC data. By default only
89
+ * OHLC series influence the auto-scale, while panes without OHLC series
90
+ * continue to consider every series to avoid empty domains.
91
+ */
92
+ includeOverlaysInAutoScale?: boolean;
93
+ /**
94
+ * Optional global handler fired when the user clicks on the chart canvas
95
+ * and a nearest series/point has been resolved. This is useful for
96
+ * higher-level interactions (e.g. selecting a cycle-low marker) without
97
+ * requiring every series to declare its own onClick handler.
98
+ */
99
+ onSeriesPointClick?: (info: {
100
+ paneId: string;
101
+ seriesKey: string;
102
+ time: number;
103
+ raw: any;
104
+ }) => void;
105
+ }
106
+ export interface PaneComputedScale {
107
+ domain: [number, number];
108
+ scale: (value: number) => number;
109
+ invert: (value: number) => number;
110
+ }
111
+ /** X-axis scale function with optional invert/range accessors */
112
+ export type XScale = ((value: number) => number) & {
113
+ invert?: (value: number) => number | Date;
114
+ range?: () => [number, number];
115
+ };
116
+ export type AnnotationType = 'hline' | 'vline' | 'text' | 'trendline' | 'ray' | 'crossline' | 'rectangle' | 'emoji' | 'timerange' | 'arrow' | 'channel' | 'fibRetracement' | 'measure' | 'alert_line' | 'brush' | 'pitchfork' | 'fib_extension' | 'order_block' | 'fair_value_gap' | 'bos_line';
117
+ export type LineStyle = 'solid' | 'dashed' | 'dotted';
118
+ export interface AnnotationBase {
119
+ id: string;
120
+ type: AnnotationType;
121
+ symbol: string;
122
+ timeframe: string;
123
+ /** Timeframes this annotation is visible on. Null/undefined/empty = visible on all. */
124
+ visibleTimeframes?: string[];
125
+ createdAt: number;
126
+ updatedAt: number;
127
+ }
128
+ export interface HLineAnnotation extends AnnotationBase {
129
+ type: 'hline';
130
+ price: number;
131
+ color: string;
132
+ lineStyle: LineStyle;
133
+ lineWidth: number;
134
+ label?: string;
135
+ showPrice: boolean;
136
+ }
137
+ export interface VLineAnnotation extends AnnotationBase {
138
+ type: 'vline';
139
+ time: number;
140
+ color: string;
141
+ lineStyle: LineStyle;
142
+ lineWidth: number;
143
+ label?: string;
144
+ showTime: boolean;
145
+ }
146
+ export interface TextAnnotation extends AnnotationBase {
147
+ type: 'text';
148
+ time: number;
149
+ price: number;
150
+ text: string;
151
+ color: string;
152
+ backgroundColor?: string;
153
+ fontSize: number;
154
+ }
155
+ /** A single point in a freehand brush stroke (chart coordinates). */
156
+ export type BrushPoint = LinePoint;
157
+ /** Standard Fibonacci retracement level ratios */
158
+ export declare const FIB_LEVELS_DEFAULT: readonly [0, 0.236, 0.382, 0.5, 0.618, 0.786, 1];
159
+ /** Optional extension levels beyond the 0–100% range */
160
+ export declare const FIB_EXTENSIONS_DEFAULT: readonly [1.272, 1.618, 2, 2.618];
161
+ export interface TrendLineAnnotation extends AnnotationBase {
162
+ type: 'trendline';
163
+ time1: number;
164
+ price1: number;
165
+ time2: number;
166
+ price2: number;
167
+ color?: string;
168
+ lineWidth?: number;
169
+ lineStyle?: LineStyle;
170
+ label?: string;
171
+ extendLeft: boolean;
172
+ extendRight: boolean;
173
+ }
174
+ export interface ChannelAnnotation extends AnnotationBase {
175
+ type: 'channel';
176
+ /** First anchor point of the base line */
177
+ time1: number;
178
+ price1: number;
179
+ /** Second anchor point of the base line */
180
+ time2: number;
181
+ price2: number;
182
+ /**
183
+ * Price offset for the parallel line. Positive = above the base line,
184
+ * negative = below. The parallel line runs through
185
+ * (time1, price1 + priceOffset) → (time2, price2 + priceOffset).
186
+ */
187
+ priceOffset: number;
188
+ color: string;
189
+ lineStyle: LineStyle;
190
+ lineWidth: number;
191
+ label?: string;
192
+ /** Opacity of the fill between the two parallel lines (0–1) */
193
+ fillOpacity: number;
194
+ extendLeft: boolean;
195
+ extendRight: boolean;
196
+ }
197
+ export interface RayAnnotation extends AnnotationBase {
198
+ type: 'ray';
199
+ time1: number;
200
+ price1: number;
201
+ time2: number;
202
+ price2: number;
203
+ color: string;
204
+ lineStyle: LineStyle;
205
+ lineWidth: number;
206
+ label?: string;
207
+ }
208
+ export interface RectangleAnnotation extends AnnotationBase {
209
+ type: 'rectangle';
210
+ time1: number;
211
+ price1: number;
212
+ time2: number;
213
+ price2: number;
214
+ color: string;
215
+ fillOpacity: number;
216
+ lineStyle: LineStyle;
217
+ lineWidth: number;
218
+ label?: string;
219
+ }
220
+ export interface TimeRangeAnnotation extends AnnotationBase {
221
+ type: 'timerange';
222
+ time1: number;
223
+ time2: number;
224
+ color: string;
225
+ fillOpacity: number;
226
+ lineStyle: LineStyle;
227
+ lineWidth: number;
228
+ label?: string;
229
+ }
230
+ export interface CrossLineAnnotation extends AnnotationBase {
231
+ type: 'crossline';
232
+ time: number;
233
+ price: number;
234
+ color: string;
235
+ lineStyle: LineStyle;
236
+ lineWidth: number;
237
+ label?: string;
238
+ showPrice: boolean;
239
+ showTime: boolean;
240
+ }
241
+ export interface AlertLineAnnotation extends AnnotationBase {
242
+ type: 'alert_line';
243
+ price: number;
244
+ color: string;
245
+ lineStyle: LineStyle;
246
+ lineWidth: number;
247
+ label?: string;
248
+ showPrice: boolean;
249
+ /** Whether the alert has been triggered */
250
+ triggered: boolean;
251
+ /** Direction: 'above' = alert when price crosses above, 'below' = crosses below */
252
+ direction: 'above' | 'below';
253
+ /** Server-side alert ID from POST /v2/alerts (set after sync) */
254
+ alertId?: string;
255
+ }
256
+ export interface EmojiAnnotation extends AnnotationBase {
257
+ type: 'emoji';
258
+ time: number;
259
+ price: number;
260
+ emoji: string;
261
+ size: number;
262
+ }
263
+ export interface ArrowAnnotation extends AnnotationBase {
264
+ type: 'arrow';
265
+ /** Text box / callout origin point */
266
+ time1: number;
267
+ price1: number;
268
+ /** Arrow target point (arrowhead rendered here) */
269
+ time2: number;
270
+ price2: number;
271
+ text: string;
272
+ color: string;
273
+ lineStyle: LineStyle;
274
+ lineWidth: number;
275
+ fontSize: number;
276
+ }
277
+ export interface FibRetracementAnnotation extends AnnotationBase {
278
+ type: 'fibRetracement' | 'measure';
279
+ /** Swing point 1 (typically the high or low where the move starts) */
280
+ time1: number;
281
+ price1: number;
282
+ /** Swing point 2 (the other extreme of the move) */
283
+ time2: number;
284
+ price2: number;
285
+ color: string;
286
+ lineStyle: LineStyle;
287
+ lineWidth: number;
288
+ label?: string;
289
+ /** Opacity of the fill bands between adjacent levels (0–1) */
290
+ fillOpacity: number;
291
+ /** Fib ratios to display. Defaults to FIB_LEVELS_DEFAULT. */
292
+ levels: number[];
293
+ /** Whether to show extension levels beyond 100% */
294
+ showExtensions: boolean;
295
+ /** Whether to extend level lines to the right edge of the chart */
296
+ extendRight: boolean;
297
+ }
298
+ export interface MeasureAnnotation extends AnnotationBase {
299
+ type: 'measure';
300
+ /** First anchor point */
301
+ time1: number;
302
+ price1: number;
303
+ /** Second anchor point */
304
+ time2: number;
305
+ price2: number;
306
+ color: string;
307
+ }
308
+ export interface BrushAnnotation extends AnnotationBase {
309
+ type: 'brush';
310
+ /** Ordered array of points forming the freehand path. */
311
+ points: BrushPoint[];
312
+ color: string;
313
+ lineWidth: number;
314
+ }
315
+ /**
316
+ * Andrew's Pitchfork — three-point tool.
317
+ * P1 is the pivot (start of the median line).
318
+ * P2 and P3 define the swing high/low.
319
+ * The median line extends from P1 through the midpoint of P2–P3.
320
+ * Upper parallel runs through P2; lower parallel runs through P3.
321
+ */
322
+ export interface PitchforkAnnotation extends AnnotationBase {
323
+ type: 'pitchfork';
324
+ /** Pivot point (start of median line) */
325
+ time1: number;
326
+ price1: number;
327
+ /** Second anchor (e.g., swing high) */
328
+ time2: number;
329
+ price2: number;
330
+ /** Third anchor (e.g., swing low) */
331
+ time3: number;
332
+ price3: number;
333
+ color: string;
334
+ lineStyle: LineStyle;
335
+ lineWidth: number;
336
+ label?: string;
337
+ /** Opacity of the fill between upper and lower parallels (0–1) */
338
+ fillOpacity: number;
339
+ /** Extend lines to chart edges */
340
+ extendRight: boolean;
341
+ }
342
+ /**
343
+ * Fibonacci Extension — three-point tool for projecting price targets.
344
+ * P1 is the start of the initial move (e.g., swing low).
345
+ * P2 is the end of the initial move (e.g., swing high).
346
+ * P3 is the end of the retracement (e.g., pullback low).
347
+ * Extension levels are projected from P3 using the P1→P2 move distance.
348
+ */
349
+ export interface FibExtensionAnnotation extends AnnotationBase {
350
+ type: 'fib_extension';
351
+ /** Start of initial move */
352
+ time1: number;
353
+ price1: number;
354
+ /** End of initial move */
355
+ time2: number;
356
+ price2: number;
357
+ /** End of retracement */
358
+ time3: number;
359
+ price3: number;
360
+ color: string;
361
+ lineStyle: LineStyle;
362
+ lineWidth: number;
363
+ label?: string;
364
+ /** Extension levels to display (e.g., [0, 0.618, 1, 1.272, 1.618, 2, 2.618]) */
365
+ levels: number[];
366
+ /** Opacity of the fill between levels (0–1) */
367
+ fillOpacity: number;
368
+ /** Show price labels on each level */
369
+ showPrices: boolean;
370
+ }
371
+ /**
372
+ * SMC Order Block — a zone where institutional activity occurred.
373
+ * Rendered as a shaded price zone between low and high of the block candle.
374
+ */
375
+ export interface OrderBlockAnnotation extends AnnotationBase {
376
+ type: 'order_block';
377
+ /** Time of the order block candle */
378
+ time: number;
379
+ /** High price of the order block candle */
380
+ high: number;
381
+ /** Low price of the order block candle */
382
+ low: number;
383
+ /** Direction: bullish (green) or bearish (red) */
384
+ direction: 'bullish' | 'bearish';
385
+ /** Current state of the order block */
386
+ state: 'active' | 'tested' | 'mitigated';
387
+ /** Color (auto-computed from direction if not provided) */
388
+ color?: string;
389
+ /** Fill opacity (0-1) */
390
+ fillOpacity: number;
391
+ /** Border line style */
392
+ lineStyle: LineStyle;
393
+ /** Border line width */
394
+ lineWidth: number;
395
+ /** Optional label (e.g., "OB", "Buy OB") */
396
+ label?: string;
397
+ }
398
+ /**
399
+ * SMC Fair Value Gap — the unfilled gap between three consecutive candles.
400
+ * The gap is between the low of the middle candle and high of the adjacent candle.
401
+ */
402
+ export interface FairValueGapAnnotation extends AnnotationBase {
403
+ type: 'fair_value_gap';
404
+ /** Time of the first candle (left side of gap) */
405
+ time1: number;
406
+ /** Time of the third candle (right side of gap) */
407
+ time2: number;
408
+ /** Top of the FVG zone (high of candle1 vs candle3, whichever is higher) */
409
+ top: number;
410
+ /** Bottom of the FVG zone (low of candle1 vs candle3, whichever is lower) */
411
+ bottom: number;
412
+ /** Direction: bullish (green) or bearish (red) */
413
+ direction: 'bullish' | 'bearish';
414
+ /** Whether the FVG has been filled (mitigated) */
415
+ filled: boolean;
416
+ /** Color (auto-computed from direction if not provided) */
417
+ color?: string;
418
+ /** Fill opacity (0-1) */
419
+ fillOpacity: number;
420
+ /** Border line style */
421
+ lineStyle: LineStyle;
422
+ /** Border line width */
423
+ lineWidth: number;
424
+ /** Optional label (e.g., "FVG") */
425
+ label?: string;
426
+ }
427
+ /**
428
+ * SMC BOS (Break of Structure) or ChoCH (Change of Character) level line.
429
+ * A horizontal line at the level where price broke a structure.
430
+ */
431
+ export interface BosLineAnnotation extends AnnotationBase {
432
+ type: 'bos_line';
433
+ /** Time at which the break occurred */
434
+ time: number;
435
+ /** Price level of the break */
436
+ price: number;
437
+ /** Type: BOS or ChoCH */
438
+ bosType: 'BOS' | 'ChoCH';
439
+ /** Direction: bullish (green) or bearish (red) */
440
+ direction: 'bullish' | 'bearish';
441
+ /** Whether this is a confirmed break (vs pending) */
442
+ confirmed: boolean;
443
+ /** Color (auto-computed from direction if not provided) */
444
+ color?: string;
445
+ /** Line style */
446
+ lineStyle: LineStyle;
447
+ /** Line width */
448
+ lineWidth: number;
449
+ /** Show price label */
450
+ showPrice: boolean;
451
+ /** Show type label (BOS/ChoCH) */
452
+ showLabel: boolean;
453
+ }
454
+ export type Annotation = HLineAnnotation | VLineAnnotation | TextAnnotation | TrendLineAnnotation | RayAnnotation | CrossLineAnnotation | RectangleAnnotation | EmojiAnnotation | TimeRangeAnnotation | ArrowAnnotation | ChannelAnnotation | FibRetracementAnnotation | MeasureAnnotation | AlertLineAnnotation | BrushAnnotation | PitchforkAnnotation | FibExtensionAnnotation | OrderBlockAnnotation | FairValueGapAnnotation | BosLineAnnotation;
package/dist/charting.css CHANGED
@@ -1 +1 @@
1
- .dwlf-chart-container{font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;color:#1a202c}.dwlf-chart-svg{display:block}.dwlf-pane-tooltip{position:absolute;padding:6px 10px;background:#111827d9;color:#f7fafc;border-radius:6px;border:1px solid rgba(148,163,184,.2);font-size:11px;pointer-events:none;max-width:220px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.dwlf-pane-tooltip__title{font-weight:600;margin-bottom:2px}.dwlf-pane-tooltip__content{display:flex;flex-direction:column;gap:2px}.dwlf-pane-tooltip__row{display:flex;justify-content:space-between;gap:8px;white-space:nowrap}.dwlf-candles path{shape-rendering:crispEdges}.dwlf-y-axis text{text-anchor:end}.dwlf-x-axis text{pointer-events:none;font-variant-numeric:tabular-nums}.dwlf-chart-container.fade-transition{transition:opacity .5s ease-out,background-color .3s ease-out}.dwlf-chart-container.fade-transition.loading,.dwlf-chart-container.fade-transition.background{opacity:1}.dwlf-chart-container.fade-transition .dwlf-chart-svg g{transition:opacity .3s ease-out}.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles{transition:opacity .2s ease-out}.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area{transition:opacity .4s ease-out}@media(prefers-reduced-motion:reduce){.dwlf-chart-container,.dwlf-chart-container.fade-transition,.dwlf-chart-container.fade-transition .dwlf-chart-svg g,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area{transition:none!important;@keyframes marker-drop{0%{opacity:0;transform:translateY(-20px)}60%{opacity:.8;transform:translateY(2px)}80%{opacity:1;transform:translateY(-1px)}to{opacity:1;transform:translateY(0)}}// charting styles}.dwlf-chart-container .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg g .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area .marker-overlay-animated .dwlf-marker-drop{animation:marker-drop .6s ease-out forwards;opacity:0;transform:translateY(-20px)}.dwlf-chart-container .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg g .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line .marker-overlay-animated .dwlf-marker-drop,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area .marker-overlay-animated .dwlf-marker-drop{animation:none!important;opacity:1!important;transform:none!important}.dwlf-chart-container .annotation-layer,.dwlf-chart-container.fade-transition .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg g .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area .annotation-layer{transition:opacity .4s ease-in-out}.dwlf-chart-container .annotation-layer,.dwlf-chart-container.fade-transition .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg g .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line .annotation-layer,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area .annotation-layer{transition:none!important}}
1
+ .dwlf-chart-container{font-family:Inter,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,sans-serif;color:#1a202c}.dwlf-chart-svg{display:block}.dwlf-pane-tooltip{position:absolute;padding:6px 10px;background:#111827d9;color:#f7fafc;border-radius:6px;border:1px solid rgba(148,163,184,.2);font-size:11px;pointer-events:none;max-width:220px;-webkit-backdrop-filter:blur(4px);backdrop-filter:blur(4px)}.dwlf-pane-tooltip__title{font-weight:600;margin-bottom:2px}.dwlf-pane-tooltip__content{display:flex;flex-direction:column;gap:2px}.dwlf-pane-tooltip__row{display:flex;justify-content:space-between;gap:8px;white-space:nowrap}.dwlf-candles path{shape-rendering:crispEdges}.dwlf-y-axis text{text-anchor:end}.dwlf-x-axis text{pointer-events:none;font-variant-numeric:tabular-nums}.dwlf-chart-container.fade-transition{transition:opacity .5s ease-out,background-color .3s ease-out}.dwlf-chart-container.fade-transition.loading,.dwlf-chart-container.fade-transition.background{opacity:1}.dwlf-chart-container.fade-transition .dwlf-chart-svg g{transition:opacity .3s ease-out}.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles{transition:opacity .2s ease-out}.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area{transition:opacity .4s ease-out}@media(prefers-reduced-motion:reduce){.dwlf-chart-container,.dwlf-chart-container.fade-transition,.dwlf-chart-container.fade-transition .dwlf-chart-svg g,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-candles,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-line,.dwlf-chart-container.fade-transition .dwlf-chart-svg .dwlf-series-area{transition:none!important}}.marker-overlay-animated .dwlf-marker-drop{animation:marker-drop .6s ease-out forwards;opacity:0;transform:translateY(-20px)}@keyframes marker-drop{0%{opacity:0;transform:translateY(-20px)}60%{opacity:.8;transform:translateY(2px)}80%{opacity:1;transform:translateY(-1px)}to{opacity:1;transform:translateY(0)}}@media(prefers-reduced-motion:reduce){.marker-overlay-animated .dwlf-marker-drop{animation:none!important;opacity:1!important;transform:none!important}}.annotation-layer{transition:opacity .4s ease-in-out}@media(prefers-reduced-motion:reduce){.annotation-layer{transition:none!important}}
@@ -0,0 +1,119 @@
1
+ import { default as React } from 'react';
2
+ import { Annotation, ChartSpec, PaneGuide, PaneSpec, SeriesSpec } from '../charting/types';
3
+ import { ChartAnimationState } from '../hooks/useChartAnimations';
4
+ type HoverSeries = {
5
+ key: string;
6
+ color?: string;
7
+ value: number | null;
8
+ display: string;
9
+ raw: any;
10
+ };
11
+ declare const computeSeriesHover: (series: SeriesSpec, time: number) => HoverSeries;
12
+ export interface AxisColorConfig {
13
+ light?: string;
14
+ dark?: string;
15
+ }
16
+ export interface DWLFChartProps {
17
+ spec?: ChartSpec;
18
+ darkMode?: boolean;
19
+ showGrid?: boolean;
20
+ className?: string;
21
+ style?: React.CSSProperties;
22
+ enablePanZoom?: boolean;
23
+ timeframe?: string;
24
+ initialVisibleCount?: number;
25
+ extraRightSlots?: number;
26
+ compressGaps?: boolean;
27
+ axisColors?: AxisColorConfig;
28
+ crosshairSnapMode?: 'series' | 'pointer';
29
+ /**
30
+ * When true, draw a small price label on the right-hand axis that tracks
31
+ * the crosshair position for each pane.
32
+ *
33
+ * This mirrors the old Chart.js behaviour used in the portfolio frontend
34
+ * and is wired to the global "Crosshair Price Label" user preference.
35
+ */
36
+ showCrosshairPriceLabel?: boolean;
37
+ /**
38
+ * Chart annotations (horizontal lines, text labels) for the price pane.
39
+ * Rendered as an overlay layer above series but below crosshair.
40
+ */
41
+ annotations?: Annotation[];
42
+ /**
43
+ * Currently selected annotation ID (shows selection handles).
44
+ */
45
+ selectedAnnotationId?: string | null;
46
+ /**
47
+ * Callback when an annotation is clicked/selected.
48
+ */
49
+ onAnnotationSelect?: (id: string | null) => void;
50
+ /**
51
+ * Callback when an annotation is moved (drag).
52
+ */
53
+ onAnnotationMove?: (id: string, update: Partial<Annotation>) => void;
54
+ /**
55
+ * Callback when text annotation requests edit (double-click).
56
+ */
57
+ onAnnotationTextEdit?: (id: string) => void;
58
+ /**
59
+ * Callback when an annotation is double-clicked.
60
+ */
61
+ onAnnotationDoubleClick?: (id: string) => void;
62
+ /**
63
+ * Callback when user clicks on chart canvas (for placing annotations).
64
+ * Receives { time, price, paneId, screenX, screenY }.
65
+ */
66
+ onChartCanvasClick?: (info: {
67
+ time: number;
68
+ price: number;
69
+ paneId: string;
70
+ screenX: number;
71
+ screenY: number;
72
+ }) => void;
73
+ /**
74
+ * Callback when user moves mouse over chart canvas (for annotation previews).
75
+ * Only fires when the prop is provided to avoid unnecessary overhead.
76
+ * Receives { time, price, paneId, screenX, screenY }.
77
+ */
78
+ onCanvasMouseMove?: (info: {
79
+ time: number;
80
+ price: number;
81
+ paneId: string;
82
+ screenX: number;
83
+ screenY: number;
84
+ }) => void;
85
+ /**
86
+ * Alias for onCanvasMouseMove - callback when user hovers over chart canvas.
87
+ * Receives { time, price } coordinates for annotation preview generation.
88
+ */
89
+ onChartCanvasHover?: (info: {
90
+ time: number;
91
+ price: number;
92
+ }) => void;
93
+ /**
94
+ * Optional animation state for controlling chart reveal animations.
95
+ * When provided, the chart will render based on the current animation phase.
96
+ */
97
+ animationState?: ChartAnimationState;
98
+ }
99
+ export interface DwlfChartHandle {
100
+ setSpec(spec: ChartSpec): void;
101
+ addPane(pane: PaneSpec): void;
102
+ removePane(paneId: string): void;
103
+ updatePane(paneId: string, patch: Partial<PaneSpec>): void;
104
+ addSeries(paneId: string, series: SeriesSpec): void;
105
+ updateSeries(paneId: string, key: string, data: any[]): void;
106
+ removeSeries(paneId: string, key: string): void;
107
+ addGuide(paneId: string, guide: PaneGuide): void;
108
+ removeGuide(paneId: string, y: number): void;
109
+ enableSharedCrosshair(enabled: boolean): void;
110
+ zoomIn(): void;
111
+ zoomOut(): void;
112
+ resetView(): void;
113
+ panToStart(): void;
114
+ panToEnd(): void;
115
+ }
116
+ declare const DWLFChart: React.ForwardRefExoticComponent<DWLFChartProps & React.RefAttributes<DwlfChartHandle>>;
117
+ export { computeSeriesHover as __computeSeriesHoverForTests };
118
+ export type { DwlfChartHandle, DWLFChartProps };
119
+ export default DWLFChart;
@@ -0,0 +1,2 @@
1
+ export { default as DWLFChart, __computeSeriesHoverForTests } from './DWLFChart';
2
+ export type { DwlfChartHandle, DWLFChartProps } from './DWLFChart';
@@ -0,0 +1,14 @@
1
+ import { default as React } from 'react';
2
+ import { AlertLineAnnotation, PaneComputedScale } from '../../charting/types';
3
+ export interface AlertLineAnnotationViewProps {
4
+ annotation: AlertLineAnnotation;
5
+ yScale: PaneComputedScale;
6
+ chartWidth: number;
7
+ paneHeight: number;
8
+ darkMode?: boolean;
9
+ selected?: boolean;
10
+ onSelect?: (id: string | null) => void;
11
+ onMove?: (id: string, newPrice: number) => void;
12
+ }
13
+ declare const AlertLineAnnotationView: React.FC<AlertLineAnnotationViewProps>;
14
+ export default AlertLineAnnotationView;
@@ -0,0 +1,55 @@
1
+ import { default as React } from 'react';
2
+ import { Annotation, HLineAnnotation, VLineAnnotation, TextAnnotation, TrendLineAnnotation, RayAnnotation, CrossLineAnnotation, RectangleAnnotation, EmojiAnnotation, TimeRangeAnnotation, ArrowAnnotation, ChannelAnnotation, FibRetracementAnnotation, MeasureAnnotation, AlertLineAnnotation, BrushAnnotation, PitchforkAnnotation, FibExtensionAnnotation, OrderBlockAnnotation, FairValueGapAnnotation, BosLineAnnotation, PaneComputedScale, XScale } from '../../charting/types';
3
+ export interface AnnotationLayerProps {
4
+ annotations: Annotation[];
5
+ xScale: XScale;
6
+ yScale: PaneComputedScale;
7
+ chartWidth: number;
8
+ paneHeight: number;
9
+ darkMode?: boolean;
10
+ selectedAnnotationId?: string | null;
11
+ onAnnotationSelect?: (id: string | null) => void;
12
+ onAnnotationDoubleClick?: (id: string) => void;
13
+ onAnnotationMove?: (id: string, update: Partial<Annotation>) => void;
14
+ onAnnotationTextEdit?: (id: string) => void;
15
+ /** Convert raw timestamp to index when compressGaps is enabled */
16
+ timeToIndex?: (time: number) => number | undefined;
17
+ /** Convert index back to raw timestamp when compressGaps is enabled */
18
+ indexToTime?: (index: number) => number;
19
+ /** Number of data points (required for closest index search when compressGaps enabled) */
20
+ dataLength?: number;
21
+ /** Pre-computed compressed times array (avoids redundant reconstruction from indexToTime) */
22
+ compressedTimes?: number[];
23
+ /** Optional time formatter for vertical line labels */
24
+ timeFormatter?: (t: number) => string;
25
+ /** Current chart timeframe — used to filter annotations by visibleTimeframes */
26
+ currentTimeframe?: string;
27
+ /** Animation phase for controlling fade-in transitions */
28
+ animationPhase?: string;
29
+ }
30
+ declare const AnnotationLayer: React.FC<AnnotationLayerProps>;
31
+ export default AnnotationLayer;
32
+ export declare const createHLineAnnotation: (symbol: string, timeframe: string, price: number, options?: Partial<Omit<HLineAnnotation, "id" | "type" | "symbol" | "timeframe" | "price" | "createdAt" | "updatedAt">>) => HLineAnnotation;
33
+ export declare const createVLineAnnotation: (symbol: string, timeframe: string, time: number, options?: Partial<Omit<VLineAnnotation, "id" | "type" | "symbol" | "timeframe" | "time" | "createdAt" | "updatedAt">>) => VLineAnnotation;
34
+ export declare const createTextAnnotation: (symbol: string, timeframe: string, time: number, price: number, text: string, options?: Partial<Omit<TextAnnotation, "id" | "type" | "symbol" | "timeframe" | "time" | "price" | "text" | "createdAt" | "updatedAt">>) => TextAnnotation;
35
+ export declare const createTrendLineAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, options?: Partial<Omit<TrendLineAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "createdAt" | "updatedAt">>) => TrendLineAnnotation;
36
+ export declare const createRayAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, options?: Partial<Omit<RayAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "createdAt" | "updatedAt">>) => RayAnnotation;
37
+ export declare const createCrossLineAnnotation: (symbol: string, timeframe: string, time: number, price: number, options?: Partial<Omit<CrossLineAnnotation, "id" | "type" | "symbol" | "timeframe" | "time" | "price" | "createdAt" | "updatedAt">>) => CrossLineAnnotation;
38
+ export declare const createRectangleAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, options?: Partial<Omit<RectangleAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "createdAt" | "updatedAt">>) => RectangleAnnotation;
39
+ export declare const createEmojiAnnotation: (symbol: string, timeframe: string, time: number, price: number, emoji: string, options?: Partial<Omit<EmojiAnnotation, "id" | "type" | "symbol" | "timeframe" | "time" | "price" | "emoji" | "createdAt" | "updatedAt">>) => EmojiAnnotation;
40
+ export declare const createTimeRangeAnnotation: (symbol: string, timeframe: string, time1: number, time2: number, options?: Partial<Omit<TimeRangeAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "time2" | "createdAt" | "updatedAt">>) => TimeRangeAnnotation;
41
+ export declare const createArrowAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, text: string, options?: Partial<Omit<ArrowAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "text" | "createdAt" | "updatedAt">>) => ArrowAnnotation;
42
+ export declare const createChannelAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, priceOffset: number, options?: Partial<Omit<ChannelAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "priceOffset" | "createdAt" | "updatedAt">>) => ChannelAnnotation;
43
+ export declare const createFibRetracementAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, options?: Partial<Omit<FibRetracementAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "createdAt" | "updatedAt">>) => FibRetracementAnnotation;
44
+ export declare const createMeasureAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, options?: Partial<Omit<MeasureAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "createdAt" | "updatedAt">>) => MeasureAnnotation;
45
+ export declare const createAlertLineAnnotation: (symbol: string, timeframe: string, price: number, options?: Partial<Omit<AlertLineAnnotation, "id" | "type" | "symbol" | "timeframe" | "price" | "createdAt" | "updatedAt">>) => AlertLineAnnotation;
46
+ export declare const createBrushAnnotation: (symbol: string, timeframe: string, points: {
47
+ t: number;
48
+ v: number;
49
+ }[], options?: Partial<Omit<BrushAnnotation, "id" | "type" | "symbol" | "timeframe" | "points" | "createdAt" | "updatedAt">>) => BrushAnnotation;
50
+ export declare const createPitchforkAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, time3: number, price3: number, options?: Partial<Omit<PitchforkAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "time3" | "price3" | "createdAt" | "updatedAt">>) => PitchforkAnnotation;
51
+ export declare const createFibExtensionAnnotation: (symbol: string, timeframe: string, time1: number, price1: number, time2: number, price2: number, time3: number, price3: number, options?: Partial<Omit<FibExtensionAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "price1" | "time2" | "price2" | "time3" | "price3" | "createdAt" | "updatedAt">>) => FibExtensionAnnotation;
52
+ export declare const createOrderBlockAnnotation: (symbol: string, timeframe: string, time: number, high: number, low: number, direction: "bullish" | "bearish", options?: Partial<Omit<OrderBlockAnnotation, "id" | "type" | "symbol" | "timeframe" | "time" | "high" | "low" | "direction" | "createdAt" | "updatedAt">>) => OrderBlockAnnotation;
53
+ export declare const createFairValueGapAnnotation: (symbol: string, timeframe: string, time1: number, time2: number, top: number, bottom: number, direction: "bullish" | "bearish", options?: Partial<Omit<FairValueGapAnnotation, "id" | "type" | "symbol" | "timeframe" | "time1" | "time2" | "top" | "bottom" | "direction" | "createdAt" | "updatedAt">>) => FairValueGapAnnotation;
54
+ export declare const createBosLineAnnotation: (symbol: string, timeframe: string, time: number, price: number, bosType: "BOS" | "ChoCH", direction: "bullish" | "bearish", options?: Partial<Omit<BosLineAnnotation, "id" | "type" | "symbol" | "timeframe" | "time" | "price" | "bosType" | "direction" | "createdAt" | "updatedAt">>) => BosLineAnnotation;
55
+ export declare const ANNOTATION_COLORS: readonly ["#ef4444", "#f97316", "#eab308", "#22c55e", "#06b6d4", "#3b82f6", "#8b5cf6", "#ec4899", "#64748b", "#ffffff"];