@pradeepjadhav/trading-reload-chart 1.0.3 → 1.1.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
@@ -18,7 +18,7 @@ For architecture, conventions, and agent guidelines, see [AGENTS.md](./AGENTS.md
18
18
 
19
19
  ## Quick start (local development)
20
20
 
21
- 1. **Clone and install**
21
+ ### 1. Clone and install
22
22
 
23
23
  ```bash
24
24
  git clone <repository-url>
@@ -26,7 +26,9 @@ cd trading-reload-chart
26
26
  npm install
27
27
  ```
28
28
 
29
- 2. **Run the demo** (hot reload, port **8999** by default)
29
+ ### 2. Run the demo
30
+
31
+ Hot reload, port **8999** by default.
30
32
 
31
33
  ```bash
32
34
  npm run dev
@@ -34,12 +36,12 @@ npm run dev
34
36
 
35
37
  Open the URL Vite prints (typically `http://localhost:8999`). The demo mounts `TradingReload` with sample API/WebSocket wiring in `demo/`.
36
38
 
37
- 3. **Optional checks**
39
+ ### 3. Optional checks
38
40
 
39
41
  ```bash
40
- npm run typecheck # TypeScript
41
- npm run lint # Biome
42
- npm run format # Biome format
42
+ npm run typecheck
43
+ npm run lint
44
+ npm run format
43
45
  ```
44
46
 
45
47
  ---
@@ -75,16 +77,111 @@ npm run preview
75
77
 
76
78
  ---
77
79
 
80
+ ## Publishing to npm
81
+
82
+ ### 1. Login to npm
83
+
84
+ ```bash
85
+ npm login
86
+ ```
87
+
88
+ Verify the active account:
89
+
90
+ ```bash
91
+ npm whoami
92
+ ```
93
+
94
+ The username should match the npm account that owns the package scope.
95
+
96
+ ### 2. Authenticate in your browser
97
+
98
+ If npm prompts for browser-based authentication:
99
+
100
+ 1. Open the URL shown in the terminal.
101
+ 2. Sign in to npm.
102
+ 3. Complete the verification flow.
103
+ 4. Return to the terminal.
104
+
105
+ Verify authentication:
106
+
107
+ ```bash
108
+ npm whoami
109
+ ```
110
+
111
+ ### 3. Build the package
112
+
113
+ ```bash
114
+ npm run build
115
+ ```
116
+
117
+ ### 4. Verify package contents
118
+
119
+ ```bash
120
+ npm pack --dry-run
121
+ ```
122
+
123
+ Ensure only the intended files are included.
124
+
125
+ ### 5. Publish
126
+
127
+ For a public scoped package:
128
+
129
+ ```bash
130
+ npm publish --access public
131
+ ```
132
+
133
+ ### Publishing a new version
134
+
135
+ Update the version:
136
+
137
+ ```bash
138
+ npm version patch
139
+ ```
140
+
141
+ or
142
+
143
+ ```bash
144
+ npm version minor
145
+ ```
146
+
147
+ or
148
+
149
+ ```bash
150
+ npm version major
151
+ ```
152
+
153
+ Then publish:
154
+
155
+ ```bash
156
+ npm publish --access public
157
+ ```
158
+
159
+ ### Useful commands
160
+
161
+ Check the currently authenticated npm user:
162
+
163
+ ```bash
164
+ npm whoami
165
+ ```
166
+
167
+ View package information:
168
+
169
+ ```bash
170
+ npm view @pradeepjadhav/trading-reload-chart
171
+ ```
172
+
173
+ ---
174
+
78
175
  ## Using the library in React / Next.js
79
176
 
80
177
  The chart is **client-only** (canvas + DOM). It does **not** support SSR.
81
178
 
82
179
  ### 1. Install the package
83
180
 
84
- **From npm** (after publish):
181
+ **From npm**:
85
182
 
86
183
  ```bash
87
- npm install trading-reload-chart react react-dom
184
+ npm install @pradeepjadhav/trading-reload-chart react react-dom
88
185
  ```
89
186
 
90
187
  **Directly from GitHub**:
@@ -99,6 +196,7 @@ npm install git+https://github.com/Pradeep17Jadhav/trading-reload-chart.git#main
99
196
  # In trading-reload-chart repo
100
197
  npm run build
101
198
  npm pack
199
+
102
200
  # In your app
103
201
  npm install /path/to/trading-reload-chart/trading-reload-chart-1.0.0.tgz
104
202
  ```
@@ -107,7 +205,7 @@ Or link during development:
107
205
 
108
206
  ```bash
109
207
  cd trading-reload-chart && npm run build && npm link
110
- cd your-app && npm link trading-reload-chart
208
+ cd your-app && npm link @pradeepjadhav/trading-reload-chart
111
209
  ```
112
210
 
113
211
  ### 2. Next.js App Router
@@ -124,7 +222,7 @@ import {
124
222
  type Shape,
125
223
  type ShapeToolType,
126
224
  type OpenTrade,
127
- } from "trading-reload-chart";
225
+ } from "@pradeepjadhav/trading-reload-chart";
128
226
 
129
227
  export function ChartPanel() {
130
228
  const [candles, setCandles] = useState<Candle[]>([]);
@@ -151,15 +249,17 @@ export function ChartPanel() {
151
249
  }
152
250
  ```
153
251
 
154
- - Give the parent a **defined height** (flex child, `h-full`, or fixed `min-height`). `TradingReload` fills **100%** of that container.
252
+ - Give the parent a **defined height** (flex child, `h-full`, or fixed `min-height`).
253
+ - `TradingReload` fills **100%** of that container.
155
254
  - Do **not** import chart CSS manually; styles ship with the component (`src/styles/chart.css`).
156
255
 
157
256
  ### 3. Vite / Create React App
158
257
 
159
- Same import; wrap the chart in a sized container:
160
-
161
258
  ```tsx
162
- import { TradingReload, type Candle } from "trading-reload-chart";
259
+ import {
260
+ TradingReload,
261
+ type Candle,
262
+ } from "@pradeepjadhav/trading-reload-chart";
163
263
 
164
264
  export function App() {
165
265
  return (
@@ -188,9 +288,23 @@ Import from the package root:
188
288
  | `ChartConfig`, `CHART_CONFIG`, `DeepPartial` | Configuration |
189
289
  | `ClosedTradeIndicator`, trade handle types | Trade overlay types |
190
290
 
191
- Controlled props (parent owns state): `candles`, `liveCandle`, `openTrades`, `closedTrades`, `shapes`, `activeShapeTool`, `config`, `activeSymbol`.
291
+ Controlled props (parent owns state):
292
+
293
+ - `candles`
294
+ - `liveCandle`
295
+ - `openTrades`
296
+ - `closedTrades`
297
+ - `shapes`
298
+ - `activeShapeTool`
299
+ - `config`
300
+ - `activeSymbol`
192
301
 
193
- Callbacks: `onShapeAdded`, `onShapeModified`, `onActiveShapeToolChange`, `onTradeModify`.
302
+ Callbacks:
303
+
304
+ - `onShapeAdded`
305
+ - `onShapeModified`
306
+ - `onActiveShapeToolChange`
307
+ - `onTradeModify`
194
308
 
195
309
  See [AGENTS.md](./AGENTS.md) for the full props contract.
196
310
 
@@ -213,10 +327,10 @@ trading-reload-chart/
213
327
  │ └── styles/ # chart.css
214
328
  ├── dist/ # Library build output
215
329
  ├── AGENTS.md
216
- └── vite.config.ts # `dev` = demo; `build --mode library` = package
330
+ └── vite.config.ts # dev = demo; build --mode library = package
217
331
  ```
218
332
 
219
- Type declarations live in **`*.types.ts`** files next to implementation code (see AGENTS.md).
333
+ Type declarations live in `*.types.ts` files next to implementation code (see AGENTS.md).
220
334
 
221
335
  ---
222
336
 
@@ -251,6 +365,6 @@ Modern evergreen browsers with Canvas 2D (Chrome, Edge, Firefox, Safari).
251
365
 
252
366
  ## License
253
367
 
254
- Commercial, proprietary license. Use of this library requires a paid license,
255
- subscription, or other written authorization from Pradeep Jadhav. See
256
- [LICENSE](./LICENSE).
368
+ Commercial, proprietary license. Use of this library requires a paid license, subscription, or other written authorization from Pradeep Jadhav.
369
+
370
+ See [LICENSE](./LICENSE).
@@ -15,7 +15,7 @@ export declare class FibRetracementShape {
15
15
  converter: ShapeCoordinateConverter;
16
16
  config?: FibRetracementConfig;
17
17
  }): void;
18
- static getHandles(shape: FibRetracementShapeData, converter: ShapeCoordinateConverter, config?: FibRetracementConfig): ShapeHandleHitbox[];
18
+ static getHandles(shape: FibRetracementShapeData, converter: ShapeCoordinateConverter): ShapeHandleHitbox[];
19
19
  static hitTest({ point, shape, converter, tolerance, config, }: {
20
20
  point: ShapePoint;
21
21
  shape: FibRetracementShapeData;
@@ -15,7 +15,7 @@ export declare class LineShape {
15
15
  converter: ShapeCoordinateConverter;
16
16
  config?: CommonShapeConfig;
17
17
  }): void;
18
- static getHandles(shape: TrendlineShape, converter: ShapeCoordinateConverter, config?: CommonShapeConfig): ShapeHandleHitbox[];
18
+ static getHandles(shape: TrendlineShape, converter: ShapeCoordinateConverter): ShapeHandleHitbox[];
19
19
  static hitTest({ point, shape, converter, tolerance, }: {
20
20
  point: ShapePoint;
21
21
  shape: TrendlineShape;
@@ -16,7 +16,7 @@ export declare class PathShape {
16
16
  converter: ShapeCoordinateConverter;
17
17
  config?: CommonShapeConfig;
18
18
  }): void;
19
- static getHandles(shape: PathShapeData, converter: ShapeCoordinateConverter, config?: CommonShapeConfig): ShapeHandleHitbox[];
19
+ static getHandles(shape: PathShapeData, converter: ShapeCoordinateConverter): ShapeHandleHitbox[];
20
20
  static hitTest({ point, shape, converter, tolerance, }: {
21
21
  point: ShapePoint;
22
22
  shape: PathShapeData;
@@ -15,7 +15,7 @@ export declare class RectangleShape {
15
15
  converter: ShapeCoordinateConverter;
16
16
  config?: RectangleShapeConfig;
17
17
  }): void;
18
- static getHandles(shape: RectangleShapeData, converter: ShapeCoordinateConverter, config?: RectangleShapeConfig): ShapeHandleHitbox[];
18
+ static getHandles(shape: RectangleShapeData, converter: ShapeCoordinateConverter): ShapeHandleHitbox[];
19
19
  static hitTest({ point, shape, converter, tolerance, }: {
20
20
  point: ShapePoint;
21
21
  shape: RectangleShapeData;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Fixed visual constants for shape drag handles.
3
+ * These are chart-internal rendering properties and are not user-configurable.
4
+ */
5
+ export declare const SHAPE_HANDLE_CONFIG: {
6
+ readonly handleColor: "#0F0F0F";
7
+ readonly handleBorderColor: "#2962FF";
8
+ readonly handleBorderThickness: 1.5;
9
+ readonly handleRadius: 5;
10
+ };
@@ -15,9 +15,12 @@ export declare class ShapesLayer {
15
15
  handleHitboxes: ShapeHandleHitbox[];
16
16
  private draft;
17
17
  private dragState;
18
+ private lastTapTime;
19
+ private lastTapShapeId;
18
20
  private onShapeAdded?;
19
21
  private onShapeModified?;
20
22
  private onShapeSelected?;
23
+ private onShapeDoubleClicked?;
21
24
  private onToolChange?;
22
25
  constructor(options: ShapesLayerOptions);
23
26
  setCandles(candles: Candle[]): void;
@@ -29,9 +32,17 @@ export declare class ShapesLayer {
29
32
  render(): void;
30
33
  handlePointerEvent(event: PointerEvent | MouseEvent): boolean;
31
34
  handleKeyboardEvent(event: KeyboardEvent): boolean;
35
+ private getArrowKeyDelta;
32
36
  private handlePointerDown;
33
37
  private handlePointerMove;
34
38
  private handlePointerUp;
39
+ private handleDoubleClick;
40
+ /**
41
+ * Tracks touch taps and fires `onShapeDoubleClicked` on a double-tap.
42
+ * Only runs for touch pointer events; mouse/stylus use the `dblclick` DOM
43
+ * event path instead to avoid firing twice.
44
+ */
45
+ private checkTouchDoubleTap;
35
46
  private handleContextMenu;
36
47
  private handleToolPointerDown;
37
48
  private handleTwoPointDraft;
@@ -72,10 +72,6 @@ export type ShapeLineStyle = "solid" | "dashed" | "dotted";
72
72
  * lineColor: "#4ade80",
73
73
  * lineOpacity: 1,
74
74
  * lineStyle: "solid",
75
- * handleColor: "#ffffff",
76
- * handleBorderColor: "#111827",
77
- * handleBorderThickness: 1,
78
- * handleRadius: 4,
79
75
  * };
80
76
  * ```
81
77
  */
@@ -86,12 +82,6 @@ export type CommonShapeConfig = {
86
82
  lineStyle: ShapeLineStyle;
87
83
  fillColor?: string;
88
84
  fillOpacity?: number;
89
- handleColor: string;
90
- handleBorderColor: string;
91
- handleBorderThickness: number;
92
- handleRadius: number;
93
- hoverLineWidth?: number;
94
- selectedLineWidth?: number;
95
85
  };
96
86
  export type RectangleShapeConfig = CommonShapeConfig & {
97
87
  textColor: string;
@@ -112,12 +102,6 @@ export type FibRetracementConfig = {
112
102
  levels: FibLevelConfig[];
113
103
  fillColor?: string;
114
104
  fillOpacity?: number;
115
- handleColor: string;
116
- handleBorderColor: string;
117
- handleBorderThickness: number;
118
- handleRadius: number;
119
- hoverLineWidth: number;
120
- selectedLineWidth: number;
121
105
  };
122
106
  export type PositionShapeConfig = {
123
107
  defaultWidthCandles: number;
@@ -135,12 +119,6 @@ export type PositionShapeConfig = {
135
119
  midLineOpacity: number;
136
120
  midLineWidth: number;
137
121
  midLineStyle: ShapeLineStyle;
138
- handleColor: string;
139
- handleBorderColor: string;
140
- handleBorderThickness: number;
141
- handleRadius: number;
142
- hoverLineWidth: number;
143
- selectedLineWidth: number;
144
122
  };
145
123
  /**
146
124
  * Trendline shape defined by two vertices.
@@ -293,12 +271,12 @@ export type Shape = TrendlineShape | RectangleShapeData | PathShapeData | FibRet
293
271
  * @example
294
272
  * ```ts
295
273
  * const config: ShapeConfig = {
296
- * trendline: { lineWidth: 2, lineColor: "#4ade80", lineOpacity: 1, lineStyle: "solid", handleColor: "#fff", handleBorderColor: "#111827", handleBorderThickness: 1, handleRadius: 4 },
297
- * rectangle: { lineWidth: 2, lineColor: "#60a5fa", lineOpacity: 1, lineStyle: "solid", handleColor: "#fff", handleBorderColor: "#111827", handleBorderThickness: 1, handleRadius: 4, textColor: "#fff", textOpacity: 1, textFontFamily: "Arial", textFontSize: 12 },
298
- * path: { lineWidth: 2, lineColor: "#f59e0b", lineOpacity: 1, lineStyle: "solid", handleColor: "#fff", handleBorderColor: "#111827", handleBorderThickness: 1, handleRadius: 4 },
299
- * fibRetracement: { levels: [], handleColor: "#fff", handleBorderColor: "#111827", handleBorderThickness: 1, handleRadius: 4, hoverLineWidth: 3, selectedLineWidth: 3 },
300
- * shortPosition: { defaultWidthCandles: 20, defaultStopLossPercent: 0.25, defaultRiskRewardRatio: 2, profitFillColor: "#16a34a", profitFillOpacity: 0.2, lossFillColor: "#dc2626", lossFillOpacity: 0.2, borderColor: "#fff", borderOpacity: 1, borderWidth: 1, borderStyle: "solid", midLineColor: "#fff", midLineOpacity: 0.8, midLineWidth: 1, midLineStyle: "dashed", handleColor: "#fff", handleBorderColor: "#111827", handleBorderThickness: 1, handleRadius: 4, hoverLineWidth: 2, selectedLineWidth: 2 },
301
- * longPosition: { defaultWidthCandles: 20, defaultStopLossPercent: 0.25, defaultRiskRewardRatio: 2, profitFillColor: "#16a34a", profitFillOpacity: 0.2, lossFillColor: "#dc2626", lossFillOpacity: 0.2, borderColor: "#fff", borderOpacity: 1, borderWidth: 1, borderStyle: "solid", midLineColor: "#fff", midLineOpacity: 0.8, midLineWidth: 1, midLineStyle: "dashed", handleColor: "#fff", handleBorderColor: "#111827", handleBorderThickness: 1, handleRadius: 4, hoverLineWidth: 2, selectedLineWidth: 2 },
274
+ * trendline: { lineWidth: 2, lineColor: "#4ade80", lineOpacity: 1, lineStyle: "solid" },
275
+ * rectangle: { lineWidth: 2, lineColor: "#60a5fa", lineOpacity: 1, lineStyle: "solid", textColor: "#fff", textOpacity: 1, textFontFamily: "Arial", textFontSize: 12 },
276
+ * path: { lineWidth: 2, lineColor: "#f59e0b", lineOpacity: 1, lineStyle: "solid" },
277
+ * fibRetracement: { levels: [] },
278
+ * shortPosition: { defaultWidthCandles: 20, defaultStopLossPercent: 0.25, defaultRiskRewardRatio: 2, profitFillColor: "#16a34a", profitFillOpacity: 0.2, lossFillColor: "#dc2626", lossFillOpacity: 0.2, borderColor: "#fff", borderOpacity: 1, borderWidth: 1, borderStyle: "solid", midLineColor: "#fff", midLineOpacity: 0.8, midLineWidth: 1, midLineStyle: "dashed" },
279
+ * longPosition: { defaultWidthCandles: 20, defaultStopLossPercent: 0.25, defaultRiskRewardRatio: 2, profitFillColor: "#16a34a", profitFillOpacity: 0.2, lossFillColor: "#dc2626", lossFillOpacity: 0.2, borderColor: "#fff", borderOpacity: 1, borderWidth: 1, borderStyle: "solid", midLineColor: "#fff", midLineOpacity: 0.8, midLineWidth: 1, midLineStyle: "dashed" },
302
280
  * };
303
281
  * ```
304
282
  */
@@ -462,6 +440,7 @@ export type ShapesLayerOptions = {
462
440
  onShapeAdded?: (payload: ShapeAddedPayload) => void;
463
441
  onShapeModified?: (payload: ShapeModifiedPayload) => void;
464
442
  onShapeSelected?: (payload: ShapeSelectedPayload | null) => void;
443
+ onShapeDoubleClicked?: (payload: ShapeSelectedPayload) => void;
465
444
  onToolChange?: (tool: ShapeToolType | null) => void;
466
445
  };
467
446
  export type InternalDragState = {
@@ -20,12 +20,11 @@ export declare class ShortLongPosition {
20
20
  config?: PositionShapeConfig;
21
21
  }): PositionShapeData;
22
22
  static getGeometry(shape: PositionShapeData, converter: ShapeCoordinateConverter): PositionGeometry;
23
- static getHandles(shape: PositionShapeData, converter: ShapeCoordinateConverter, config?: PositionShapeConfig): ShapeHandleHitbox[];
24
- static hitTest({ point, shape, converter, config, }: {
23
+ static getHandles(shape: PositionShapeData, converter: ShapeCoordinateConverter): ShapeHandleHitbox[];
24
+ static hitTest({ point, shape, converter, }: {
25
25
  point: ShapePoint;
26
26
  shape: PositionShapeData;
27
27
  converter: ShapeCoordinateConverter;
28
- config?: PositionShapeConfig;
29
28
  }): boolean;
30
29
  static move(shape: PositionShapeData, delta: ShapeVertex): PositionShapeData;
31
30
  static resize({ shape, handleType, vertex, converter, }: {
@@ -193,6 +193,18 @@ export type ChartControllerProps = {
193
193
  * ```
194
194
  */
195
195
  onShapeSelected?: (payload: ShapeSelectedPayload | null) => void;
196
+ /**
197
+ * Called when the user double-clicks on a shape.
198
+ *
199
+ * Fires with the same payload as {@link onShapeSelected} but only on a
200
+ * double-click gesture. Does not affect shape selection state.
201
+ *
202
+ * @example
203
+ * ```ts
204
+ * onShapeDoubleClicked: (payload) => openShapeEditor(payload.shapeId)
205
+ * ```
206
+ */
207
+ onShapeDoubleClicked?: (payload: ShapeSelectedPayload) => void;
196
208
  /**
197
209
  * Called when the chart wants the parent to change the active drawing tool.
198
210
  *