@coderyo/renderer-lite 1.0.3 → 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.
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
+ import * as lightweight_charts from 'lightweight-charts';
2
+ import { IChartApi, LineData, UTCTimestamp, LogicalRange } from 'lightweight-charts';
1
3
  import { Interval, Bar } from '@coderyo/data';
2
4
  import { IndicatorConfig } from '@coderyo/indicators';
3
- import { IChartApi, LineData, UTCTimestamp } from 'lightweight-charts';
4
5
 
5
6
  interface ChartVisibleRange {
6
7
  fromMs: number;
@@ -21,6 +22,7 @@ declare class TimeScaleBus {
21
22
  visibleFromMs: number;
22
23
  visibleToMs: number;
23
24
  register(chart: IChartApi): void;
25
+ unregister(chart: IChartApi): void;
24
26
  subscribeTransform(listener: TransformListener): () => void;
25
27
  setBarsTimeRange(fromMs: number, toMs: number): void;
26
28
  getVisibleRange(): ChartVisibleRange | null;
@@ -28,10 +30,45 @@ declare class TimeScaleBus {
28
30
  setBarSpacing(spacing: number): void;
29
31
  setVisibleTimeRange(range: ChartVisibleRange): void;
30
32
  scrollToLogicalPosition(position: number, animated?: boolean): void;
33
+ /**
34
+ * DESIGN §10.4.1: after historical prepend, shift every pane's logical range by Δ
35
+ * so canonical `visibleFromMs` / `visibleToMs` (and crosshair time mapping) stay fixed.
36
+ */
37
+ compensatePrependLogicalRange(delta: number, referenceChart?: IChartApi, sliceTimes?: readonly number[]): void;
31
38
  private syncFrom;
32
39
  private emit;
33
40
  }
34
41
 
42
+ /** Trim; empty / whitespace → independent pane (no cross-pane sync). */
43
+ declare function normalizeSyncGroupId(id?: string | null): string | null;
44
+ type PaneSyncKey = 'main' | 'volume' | 'indicator';
45
+ declare function independentBusKey(pane: PaneSyncKey): string;
46
+ declare function resolveBusMapKey(groupId: string | null | undefined, pane: PaneSyncKey): string;
47
+ interface PaneSyncGroupPatch {
48
+ main?: string | null;
49
+ volume?: string | null;
50
+ indicator?: string | null;
51
+ }
52
+ /**
53
+ * One {@link TimeScaleBus} per sync group id; empty group id → per-pane independent bus.
54
+ */
55
+ declare class TimeScaleBusRegistry {
56
+ private readonly buses;
57
+ private readonly paneKeys;
58
+ private activeKey;
59
+ constructor();
60
+ getOrCreateBus(key: string): TimeScaleBus;
61
+ getBusKeyForPane(pane: PaneSyncKey): string;
62
+ getBusForPane(pane: PaneSyncKey): TimeScaleBus;
63
+ /** Active bus for IChart viewport APIs (follows last-focused chart pane). */
64
+ get activeBus(): TimeScaleBus;
65
+ getActiveBusKey(): string;
66
+ setActivePane(pane: PaneSyncKey): void;
67
+ setPaneSyncGroup(pane: PaneSyncKey, groupId: string | null | undefined): string;
68
+ forEachBus(fn: (key: string, bus: TimeScaleBus) => void): void;
69
+ moveChart(chart: IChartApi, fromKey: string, toKey: string, copyRange?: boolean): void;
70
+ }
71
+
35
72
  type ScaleMode = 'linear' | 'log';
36
73
  interface CrosshairPayload {
37
74
  time: number;
@@ -49,8 +86,18 @@ interface PinePlotLine {
49
86
  color?: string;
50
87
  values: (number | null)[];
51
88
  }
89
+ type ChartPaneId = 'main' | 'volume' | 'indicator';
90
+ declare function isLayeredPaneMount(opts: Pick<PaneOrchestratorOptions, 'volumeMount'>): boolean;
91
+ declare function shouldResizeChartPane(focus: Set<ChartPaneId> | null, pane: ChartPaneId): boolean;
52
92
  interface PaneOrchestratorOptions {
93
+ /** Main candlestick mount (required). */
53
94
  container: HTMLElement;
95
+ /**
96
+ * P2: separate volume layer host; when set, no flex column in container.
97
+ * Mount order: create empty `chartMain` + `chartVolume` nodes first, pass to compositor widgets,
98
+ * then `createChart(chartMain, { volumeMount: chartVolume })` so LWC mounts after layer frames apply.
99
+ */
100
+ volumeMount?: HTMLElement;
54
101
  indicatorRoot?: HTMLElement;
55
102
  theme?: 'dark' | 'light';
56
103
  scaleMode?: ScaleMode;
@@ -68,9 +115,22 @@ interface PaneOrchestratorOptions {
68
115
  /** When true (default), set bar spacing on interval reload — does not change visible bar count. */
69
116
  autoBarSpacingOnInterval?: boolean;
70
117
  barSpacingByInterval?: Partial<Record<Interval, number>>;
118
+ /**
119
+ * When false, do not listen for `tradview:pane-resize` (ChartController owns that path).
120
+ * @default true for standalone orchestrator use; ChartController passes false.
121
+ */
122
+ listenPaneResizeEvents?: boolean;
71
123
  }
72
124
  declare class PaneOrchestrator {
73
- readonly bus: TimeScaleBus;
125
+ readonly busRegistry: TimeScaleBusRegistry;
126
+ /** Active sync group bus (last-focused pane); used by ChartController viewport APIs. */
127
+ get bus(): TimeScaleBus;
128
+ private readonly layeredPanes;
129
+ private readonly mainEl;
130
+ private readonly volWrap;
131
+ private detachMainVolResizer;
132
+ private resizeFocusPanes;
133
+ private readonly listenPaneResizeEvents;
74
134
  private readonly mainChart;
75
135
  private readonly volumeChart;
76
136
  private readonly mainSeries;
@@ -93,6 +153,9 @@ declare class PaneOrchestrator {
93
153
  private barTimesOrdered;
94
154
  private didInitialFit;
95
155
  private skipNextInitialFit;
156
+ /** setBars ran before the pane had layout size; refit on first real resize. */
157
+ private pendingViewportFit;
158
+ private pendingViewportBars;
96
159
  private indicatorConfig;
97
160
  private onIndicatorConfigChange?;
98
161
  private currentInterval;
@@ -102,6 +165,7 @@ declare class PaneOrchestrator {
102
165
  private barAnimator;
103
166
  private smoothPriceDurationMs;
104
167
  constructor(opts: PaneOrchestratorOptions);
168
+ private readonly onPaneResize;
105
169
  setSmoothPriceUpdate(enabled: boolean, durationMs?: number): void;
106
170
  /** Update the last candle (and price line); optional smooth interpolation. */
107
171
  updateLastBar(target: Bar, opts?: {
@@ -113,12 +177,27 @@ declare class PaneOrchestrator {
113
177
  setIntervalContext(interval: Interval): void;
114
178
  setTheme(theme: 'dark' | 'light'): void;
115
179
  setIndicatorConfig(config: IndicatorConfig | null): void;
180
+ private isVolumeVisible;
181
+ private closeVolumePane;
182
+ private applyVolumeVisibility;
183
+ /** Assign per-pane sync group ids (`''` / omit = independent). Re-registers LWC charts on group change. */
184
+ setPaneSyncGroups(patch: PaneSyncGroupPatch): void;
185
+ setActiveSyncPane(pane: ChartPaneId): void;
186
+ /** P2: when set, only these panes get LWC resize (panes in the same sync group still share TimeScaleBus). */
187
+ setResizeFocusPanes(panes: ChartPaneId[] | null): void;
188
+ /** Current resize focus (null = all panes). @internal — not part of public package API. */
189
+ getResizeFocusPanes(): ChartPaneId[] | null;
190
+ private shouldResizePane;
191
+ private rebuildMainVolumeResizer;
116
192
  setPinePlots(plots: PinePlotLine[] | null): void;
117
193
  private teardownIndicatorStack;
118
194
  private applyMainOverlays;
119
195
  private syncPinePlotSeries;
120
196
  setShowGrid(show: boolean): void;
121
197
  setBars(bars: Bar[], gaps?: number[]): void;
198
+ private mainPaneHasSize;
199
+ private tryInitialViewportFit;
200
+ private flushPendingViewportFit;
122
201
  subscribeCrosshair(listener: (payload: CrosshairPayload | null) => void): () => void;
123
202
  private findNearestBar;
124
203
  private createIndicatorStack;
@@ -133,6 +212,11 @@ declare class PaneOrchestrator {
133
212
  resetViewState(): void;
134
213
  /** Skip the next automatic fitContent after setBars (used by reloadHistory). */
135
214
  preserveViewportOnNextSetBars(): void;
215
+ /**
216
+ * DESIGN §10.4.1: after `mergeBars(..., prepend)` shift logical ranges on every sync bus
217
+ * so canonical ms viewport and crosshair `t` stay stable.
218
+ */
219
+ compensatePrependForBuses(sortedTimesBefore: readonly number[], sortedTimesAfter: readonly number[], interval: Interval): void;
136
220
  getVisibleRange(): ChartVisibleRange | null;
137
221
  getBarSpace(): number;
138
222
  setBarSpace(px: number): void;
@@ -144,6 +228,11 @@ declare class PaneOrchestrator {
144
228
  scrollToRealtime(): void;
145
229
  setLogScale(enabled: boolean): void;
146
230
  resize(): void;
231
+ /**
232
+ * Resize every LWC pane once for viewport fit; does **not** change {@link resizeFocusPanes}.
233
+ * @internal Used by ChartController data refresh paths.
234
+ */
235
+ resizeAllPanes(): void;
147
236
  getOverlayCanvas(): HTMLCanvasElement | null;
148
237
  timeToX(tMs: number): number | null;
149
238
  priceToY(price: number): number | null;
@@ -158,6 +247,12 @@ declare class PaneOrchestrator {
158
247
  private layoutForTheme;
159
248
  }
160
249
 
250
+ declare function attachPaneResizer(topPane: HTMLElement, bottomPane: HTMLElement, opts?: {
251
+ minTopPx?: number;
252
+ minBottomPx?: number;
253
+ storageKey?: string;
254
+ }): () => void;
255
+
161
256
  type IndicatorPaneId = 'macd' | 'rsi' | 'kdj';
162
257
  interface IndicatorPaneStackOptions {
163
258
  theme?: 'dark' | 'light';
@@ -192,6 +287,8 @@ declare class IndicatorPaneStack {
192
287
  setConfig(config: IndicatorConfig): void;
193
288
  private closePane;
194
289
  private applyPaneVisibility;
290
+ /** Rebuild flex children and drag handles only between visible panes. */
291
+ private rebuildPaneLayout;
195
292
  clearBars(): void;
196
293
  private warmupLookback;
197
294
  private detectBarMutation;
@@ -206,6 +303,8 @@ declare class IndicatorPaneStack {
206
303
  destroy(): void;
207
304
  private createPaneWrap;
208
305
  private layoutForTheme;
306
+ /** LWC instances for sync-group reassignment. */
307
+ getCharts(): IChartApi[];
209
308
  }
210
309
  declare function maOverlayLine(bars: Bar[], period?: number, source?: IndicatorConfig['source']): LineData<UTCTimestamp>[];
211
310
  declare function volMaOverlayLine(bars: Bar[], period?: number): LineData<UTCTimestamp>[];
@@ -216,6 +315,46 @@ declare function bollOverlayLines(bars: Bar[], period: number, mult: number, sou
216
315
  lower: LineData<UTCTimestamp>[];
217
316
  };
218
317
 
318
+ /** Slice of loaded bar open times for the current render window (DESIGN §10.4.1). */
319
+ declare function buildSliceTimes(sortedTimes: readonly number[], renderFromMs: number, renderToMs: number): number[];
320
+ /** Count bars newly present in slice after prepend merge. */
321
+ declare function countPrependSliceDelta(beforeSlice: readonly number[], afterSlice: readonly number[]): number;
322
+ /** Map LWC logical index (position in slice) to canonical bar time `t` (ms). */
323
+ declare function logicalIndexToBarTimeMs(sliceTimes: readonly number[], logicalIndex: number): number | null;
324
+ /** Mirrors {@link VirtualWindow.getRenderRange} for prepend slice math. */
325
+ declare function deriveRenderRange(visibleFromMs: number, visibleToMs: number, sortedTimes: readonly number[], intervalMs: number): {
326
+ renderFromMs: number;
327
+ renderToMs: number;
328
+ };
329
+ /** Logical range covering canonical visible ms within a slice (DESIGN §10.4.1 fallback). */
330
+ declare function logicalRangeForVisibleWindow(sliceTimes: readonly number[], visibleFromMs: number, visibleToMs: number): LogicalRange | null;
331
+ interface PrependSliceDeltaInput {
332
+ sortedTimesBefore: readonly number[];
333
+ sortedTimesAfter: readonly number[];
334
+ visibleFromMs: number;
335
+ visibleToMs: number;
336
+ intervalMs: number;
337
+ }
338
+ /** Δ new bars in render slice after historical prepend (canonical ms window unchanged). */
339
+ declare function computePrependSliceDeltaForViewport(input: PrependSliceDeltaInput): number;
340
+ interface CompensatePrependOnRegistryOptions {
341
+ registry: TimeScaleBusRegistry;
342
+ sortedTimesBefore: readonly number[];
343
+ sortedTimesAfter: readonly number[];
344
+ intervalMs: number;
345
+ /** Reference chart for logical range read (e.g. main pane). */
346
+ referenceChart?: lightweight_charts.IChartApi;
347
+ }
348
+ /** Apply §10.4.1 logicalRange offset on every bus with an initialized visible window. */
349
+ declare function compensatePrependOnRegistry(opts: CompensatePrependOnRegistryOptions): void;
350
+ interface CompensatePrependOnBusOptions {
351
+ sortedTimesBefore: readonly number[];
352
+ sortedTimesAfter: readonly number[];
353
+ intervalMs: number;
354
+ referenceChart?: lightweight_charts.IChartApi;
355
+ }
356
+ declare function compensatePrependOnBus(bus: TimeScaleBus, opts: CompensatePrependOnBusOptions): void;
357
+
219
358
  /**
220
359
  * Default horizontal bar spacing (px) per interval so candle width feels consistent
221
360
  * when the integrator controls how many bars are loaded / visible.
@@ -223,4 +362,4 @@ declare function bollOverlayLines(bars: Bar[], period: number, mult: number, sou
223
362
  declare function defaultBarSpacingForInterval(interval: Interval): number;
224
363
  declare function resolveBarSpacingForInterval(interval: Interval, overrides?: Partial<Record<Interval, number>>): number;
225
364
 
226
- export { type ChartVisibleRange, type CrosshairPayload, type IndicatorPaneId, IndicatorPaneStack, type IndicatorPaneStackOptions, PaneOrchestrator, type PaneOrchestratorOptions, type PinePlotLine, type ScaleMode, TimeScaleBus, type TransformState, bollOverlayLines, defaultBarSpacingForInterval, detectIndicatorBarMutation, emaOverlayLine, maOverlayLine, resolveBarSpacingForInterval, volMaOverlayLine };
365
+ export { type ChartPaneId, type ChartVisibleRange, type CompensatePrependOnBusOptions, type CompensatePrependOnRegistryOptions, type CrosshairPayload, type IndicatorPaneId, IndicatorPaneStack, type IndicatorPaneStackOptions, PaneOrchestrator, type PaneOrchestratorOptions, type PaneSyncGroupPatch, type PaneSyncKey, type PinePlotLine, type PrependSliceDeltaInput, type ScaleMode, TimeScaleBus, TimeScaleBusRegistry, type TransformState, attachPaneResizer, bollOverlayLines, buildSliceTimes, compensatePrependOnBus, compensatePrependOnRegistry, computePrependSliceDeltaForViewport, countPrependSliceDelta, defaultBarSpacingForInterval, deriveRenderRange, detectIndicatorBarMutation, emaOverlayLine, independentBusKey, isLayeredPaneMount, logicalIndexToBarTimeMs, logicalRangeForVisibleWindow, maOverlayLine, normalizeSyncGroupId, resolveBarSpacingForInterval, resolveBusMapKey, shouldResizeChartPane, volMaOverlayLine };