@adrienhobbs/candlekit 0.2.0 → 0.2.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 +12 -1
- package/dist/index.js +45 -3
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -166,8 +166,19 @@ interface ChartComponentProps {
|
|
|
166
166
|
trades?: ChartTrade[];
|
|
167
167
|
selectedTradeId?: string | null;
|
|
168
168
|
renderTradePopup?: (trade: ChartTrade) => ReactNode;
|
|
169
|
+
/**
|
|
170
|
+
* Fixed chart height in px. When omitted, the chart fills its container's
|
|
171
|
+
* height (observed via ResizeObserver) instead of a fixed default — so a
|
|
172
|
+
* flex/percent-sized parent gets a full-height chart.
|
|
173
|
+
*/
|
|
174
|
+
height?: number;
|
|
175
|
+
/**
|
|
176
|
+
* When set, recenter the time scale on this trade (by id) so it scrolls into
|
|
177
|
+
* view. Pairs with `selectedTradeId` to drive both selection and focus.
|
|
178
|
+
*/
|
|
179
|
+
focusTradeId?: string | null;
|
|
169
180
|
}
|
|
170
|
-
declare function ChartComponent({ bars, onLoadMoreData, indicators, lines, onBarUpdate, onNewBar, onDeleteLine, onAddLine, onClearAllLines, enableBarSelection, onBarClick, trades, selectedTradeId, renderTradePopup, }: ChartComponentProps): react_jsx_runtime.JSX.Element;
|
|
181
|
+
declare function ChartComponent({ bars, onLoadMoreData, indicators, lines, onBarUpdate, onNewBar, onDeleteLine, onAddLine, onClearAllLines, enableBarSelection, onBarClick, trades, selectedTradeId, renderTradePopup, height, focusTradeId, }: ChartComponentProps): react_jsx_runtime.JSX.Element;
|
|
171
182
|
|
|
172
183
|
interface IndicatorBrowserProps {
|
|
173
184
|
isOpen: boolean;
|
package/dist/index.js
CHANGED
|
@@ -299,7 +299,9 @@ function ChartComponent({
|
|
|
299
299
|
onBarClick,
|
|
300
300
|
trades = [],
|
|
301
301
|
selectedTradeId = null,
|
|
302
|
-
renderTradePopup
|
|
302
|
+
renderTradePopup,
|
|
303
|
+
height,
|
|
304
|
+
focusTradeId = null
|
|
303
305
|
}) {
|
|
304
306
|
const chartContainerRef = useRef(null);
|
|
305
307
|
const chartRef = useRef(null);
|
|
@@ -323,6 +325,8 @@ function ChartComponent({
|
|
|
323
325
|
const barsRef = useRef(bars);
|
|
324
326
|
const isDraggingRef = useRef(false);
|
|
325
327
|
const mouseDownPosRef = useRef(null);
|
|
328
|
+
const heightRef = useRef(height);
|
|
329
|
+
heightRef.current = height;
|
|
326
330
|
useEffect(() => {
|
|
327
331
|
if (!chartContainerRef.current) return;
|
|
328
332
|
chartContainerRef.current.style.position = "relative";
|
|
@@ -341,7 +345,10 @@ function ChartComponent({
|
|
|
341
345
|
horzLines: { color: "#1e293b" }
|
|
342
346
|
},
|
|
343
347
|
width: chartContainerRef.current.clientWidth,
|
|
344
|
-
height
|
|
348
|
+
// Auto-fill the container's height unless an explicit `height` is given.
|
|
349
|
+
// Fall back to 600 only when the container hasn't been laid out yet (a
|
|
350
|
+
// ResizeObserver below corrects it on first measure).
|
|
351
|
+
height: height ?? (chartContainerRef.current.clientHeight || 600),
|
|
345
352
|
timeScale: {
|
|
346
353
|
timeVisible: true,
|
|
347
354
|
secondsVisible: true,
|
|
@@ -396,9 +403,18 @@ function ChartComponent({
|
|
|
396
403
|
});
|
|
397
404
|
const handleResize = () => {
|
|
398
405
|
if (chartContainerRef.current && chart) {
|
|
399
|
-
|
|
406
|
+
const nextHeight = heightRef.current ?? chartContainerRef.current.clientHeight;
|
|
407
|
+
chart.applyOptions({
|
|
408
|
+
width: chartContainerRef.current.clientWidth,
|
|
409
|
+
// Only drive height when auto-filling and the container has a real
|
|
410
|
+
// measured height; otherwise leave the current height untouched.
|
|
411
|
+
...heightRef.current === void 0 && nextHeight > 0 ? { height: nextHeight } : {},
|
|
412
|
+
...heightRef.current !== void 0 ? { height: heightRef.current } : {}
|
|
413
|
+
});
|
|
400
414
|
}
|
|
401
415
|
};
|
|
416
|
+
const resizeObserver = new ResizeObserver(handleResize);
|
|
417
|
+
resizeObserver.observe(chartContainerRef.current);
|
|
402
418
|
const handleContextMenu = (e) => {
|
|
403
419
|
e.preventDefault();
|
|
404
420
|
e.stopPropagation();
|
|
@@ -490,6 +506,7 @@ function ChartComponent({
|
|
|
490
506
|
const container = chartContainerRef.current;
|
|
491
507
|
return () => {
|
|
492
508
|
window.removeEventListener("resize", handleResize);
|
|
509
|
+
resizeObserver.disconnect();
|
|
493
510
|
container.removeEventListener("contextmenu", handleContextMenu, true);
|
|
494
511
|
container.removeEventListener("mousedown", handleMouseDown, true);
|
|
495
512
|
container.removeEventListener("mousemove", handleMouseMove, true);
|
|
@@ -501,6 +518,31 @@ function ChartComponent({
|
|
|
501
518
|
useEffect(() => {
|
|
502
519
|
barsRef.current = bars;
|
|
503
520
|
}, [bars]);
|
|
521
|
+
useEffect(() => {
|
|
522
|
+
if (chartRef.current && height !== void 0) {
|
|
523
|
+
chartRef.current.applyOptions({ height });
|
|
524
|
+
}
|
|
525
|
+
}, [height]);
|
|
526
|
+
useEffect(() => {
|
|
527
|
+
if (!chartRef.current || !focusTradeId) return;
|
|
528
|
+
const trade = trades.find((t) => t.id === focusTradeId);
|
|
529
|
+
if (!trade) return;
|
|
530
|
+
const entrySec = trade.entryTime / 1e3;
|
|
531
|
+
const exitSec = trade.exitTime / 1e3;
|
|
532
|
+
const sorted = [...bars].sort((a, b) => a.timestamp - b.timestamp);
|
|
533
|
+
const stepSec = sorted.length > 1 ? (sorted[sorted.length - 1].timestamp - sorted[0].timestamp) / 1e3 / (sorted.length - 1) : 300;
|
|
534
|
+
const pad = Math.max(exitSec - entrySec, stepSec * 12);
|
|
535
|
+
const raf = requestAnimationFrame(() => {
|
|
536
|
+
try {
|
|
537
|
+
chartRef.current?.timeScale().setVisibleRange({
|
|
538
|
+
from: entrySec - pad,
|
|
539
|
+
to: exitSec + pad
|
|
540
|
+
});
|
|
541
|
+
} catch {
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
return () => cancelAnimationFrame(raf);
|
|
545
|
+
}, [focusTradeId, trades, bars]);
|
|
504
546
|
useEffect(() => {
|
|
505
547
|
if (!candlestickSeriesRef.current || !volumeSeriesRef.current) return;
|
|
506
548
|
const sortedBars = [...bars].sort((a, b) => a.timestamp - b.timestamp);
|