@aiready/components 0.13.12 → 0.13.13

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.
@@ -0,0 +1,158 @@
1
+ import * as d3 from 'd3';
2
+
3
+ export interface SimulationNode extends d3.SimulationNodeDatum {
4
+ id: string;
5
+ [key: string]: any;
6
+ }
7
+
8
+ export interface SimulationLink extends d3.SimulationLinkDatum<SimulationNode> {
9
+ source: string | SimulationNode;
10
+ target: string | SimulationNode;
11
+ [key: string]: any;
12
+ }
13
+
14
+ export interface ForceSimulationOptions {
15
+ /**
16
+ * Strength of the charge force (repulsion between nodes)
17
+ * @default -300
18
+ */
19
+ chargeStrength?: number;
20
+
21
+ /**
22
+ * Distance for links between nodes
23
+ * @default 100
24
+ */
25
+ linkDistance?: number;
26
+
27
+ /**
28
+ * Strength of the link force
29
+ * @default 1
30
+ */
31
+ linkStrength?: number;
32
+
33
+ /**
34
+ * Strength of collision detection
35
+ * @default 1
36
+ */
37
+ collisionStrength?: number;
38
+
39
+ /**
40
+ * Radius for collision detection (node size)
41
+ * @default 10
42
+ */
43
+ collisionRadius?: number;
44
+
45
+ /**
46
+ * Strength of centering force
47
+ * @default 0.1
48
+ */
49
+ centerStrength?: number;
50
+
51
+ /**
52
+ * Width of the simulation space
53
+ */
54
+ width: number;
55
+
56
+ /**
57
+ * Height of the simulation space
58
+ */
59
+ height: number;
60
+
61
+ /**
62
+ * Alpha decay rate (how quickly the simulation cools down)
63
+ * @default 0.0228
64
+ */
65
+ alphaDecay?: number;
66
+
67
+ /**
68
+ * Alpha target controls the resting energy of the simulation. When set to 0
69
+ * the simulation will cool and stop moving once forces settle. Increase to
70
+ * keep the graph more dynamic.
71
+ * @default 0
72
+ */
73
+ alphaTarget?: number;
74
+
75
+ /**
76
+ * Warm alpha used when (re)starting the simulation to give it a small amount
77
+ * of energy. This mirrors the Observable example which sets a modest
78
+ * alphaTarget when dragging instead of forcing alpha to 1.
79
+ * @default 0.3
80
+ */
81
+ warmAlpha?: number;
82
+
83
+ /**
84
+ * Minimum alpha threshold below which the simulation is considered cooled
85
+ * and will stop. Increasing this makes the simulation stop earlier.
86
+ * @default 0.01
87
+ */
88
+ alphaMin?: number;
89
+
90
+ /**
91
+ * When true, zero node velocities and snap positions when the simulation
92
+ * stops to reduce residual jitter.
93
+ * @default true
94
+ */
95
+ stabilizeOnStop?: boolean;
96
+
97
+ /**
98
+ * Throttle for tick updates in milliseconds to reduce update frequency
99
+ * (helps avoid excessive React re-renders).
100
+ * @default 33
101
+ */
102
+ tickThrottleMs?: number;
103
+
104
+ /**
105
+ * Maximum time (ms) to allow the simulation to run after creation/restart.
106
+ * If the simulation hasn't cooled by this time, it will be force-stopped
107
+ * to prevent indefinite animation. Set to 0 to disable.
108
+ * @default 3000
109
+ */
110
+ maxSimulationTimeMs?: number;
111
+
112
+ /**
113
+ * Velocity decay (friction)
114
+ * @default 0.4
115
+ */
116
+ velocityDecay?: number;
117
+
118
+ /**
119
+ * Optional tick callback invoked on each simulation tick with current nodes/links and the simulation instance
120
+ */
121
+ onTick?: (
122
+ nodes: SimulationNode[],
123
+ links: SimulationLink[],
124
+ sim: d3.Simulation<SimulationNode, SimulationLink>
125
+ ) => void;
126
+ }
127
+
128
+ export interface UseForceSimulationReturn {
129
+ /**
130
+ * Current nodes with positions
131
+ */
132
+ nodes: SimulationNode[];
133
+
134
+ /**
135
+ * Current links
136
+ */
137
+ links: SimulationLink[];
138
+
139
+ /**
140
+ * Restart the simulation
141
+ */
142
+ restart: () => void;
143
+
144
+ /**
145
+ * Stop the simulation
146
+ */
147
+ stop: () => void;
148
+
149
+ /**
150
+ * Whether the simulation is currently running
151
+ */
152
+ isRunning: boolean;
153
+
154
+ /**
155
+ * Current alpha value (simulation heat)
156
+ */
157
+ alpha: number;
158
+ }
@@ -1,163 +1,23 @@
1
+ // Re-export types from separate module for backward compatibility
2
+ export {
3
+ type SimulationNode,
4
+ type SimulationLink,
5
+ type ForceSimulationOptions,
6
+ type UseForceSimulationReturn,
7
+ } from './simulation-types';
8
+
9
+ // Import helpers from separate module
10
+ import { stabilizeNodes, seedRandomPositions } from './simulation-helpers';
11
+ import type {
12
+ SimulationNode,
13
+ SimulationLink,
14
+ ForceSimulationOptions,
15
+ UseForceSimulationReturn,
16
+ } from './simulation-types';
17
+
1
18
  import { useEffect, useRef, useState } from 'react';
2
19
  import * as d3 from 'd3';
3
20
 
4
- export interface SimulationNode extends d3.SimulationNodeDatum {
5
- id: string;
6
- [key: string]: any;
7
- }
8
-
9
- export interface SimulationLink extends d3.SimulationLinkDatum<SimulationNode> {
10
- source: string | SimulationNode;
11
- target: string | SimulationNode;
12
- [key: string]: any;
13
- }
14
-
15
- export interface ForceSimulationOptions {
16
- /**
17
- * Strength of the charge force (repulsion between nodes)
18
- * @default -300
19
- */
20
- chargeStrength?: number;
21
-
22
- /**
23
- * Distance for links between nodes
24
- * @default 100
25
- */
26
- linkDistance?: number;
27
-
28
- /**
29
- * Strength of the link force
30
- * @default 1
31
- */
32
- linkStrength?: number;
33
-
34
- /**
35
- * Strength of collision detection
36
- * @default 1
37
- */
38
- collisionStrength?: number;
39
-
40
- /**
41
- * Radius for collision detection (node size)
42
- * @default 10
43
- */
44
- collisionRadius?: number;
45
-
46
- /**
47
- * Strength of centering force
48
- * @default 0.1
49
- */
50
- centerStrength?: number;
51
-
52
- /**
53
- * Width of the simulation space
54
- */
55
- width: number;
56
-
57
- /**
58
- * Height of the simulation space
59
- */
60
- height: number;
61
-
62
- /**
63
- * Alpha decay rate (how quickly the simulation cools down)
64
- * @default 0.0228
65
- */
66
- alphaDecay?: number;
67
-
68
- /**
69
- * Alpha target controls the resting energy of the simulation. When set to 0
70
- * the simulation will cool and stop moving once forces settle. Increase to
71
- * keep the graph more dynamic.
72
- * @default 0
73
- */
74
- alphaTarget?: number;
75
-
76
- /**
77
- * Warm alpha used when (re)starting the simulation to give it a small amount
78
- * of energy. This mirrors the Observable example which sets a modest
79
- * alphaTarget when dragging instead of forcing alpha to 1.
80
- * @default 0.3
81
- */
82
- warmAlpha?: number;
83
-
84
- /**
85
- * Minimum alpha threshold below which the simulation is considered cooled
86
- * and will stop. Increasing this makes the simulation stop earlier.
87
- * @default 0.01
88
- */
89
- alphaMin?: number;
90
-
91
- /**
92
- * When true, zero node velocities and snap positions when the simulation
93
- * stops to reduce residual jitter.
94
- * @default true
95
- */
96
- stabilizeOnStop?: boolean;
97
-
98
- /**
99
- * Throttle for tick updates in milliseconds to reduce update frequency
100
- * (helps avoid excessive React re-renders).
101
- * @default 33
102
- */
103
- tickThrottleMs?: number;
104
-
105
- /**
106
- * Maximum time (ms) to allow the simulation to run after creation/restart.
107
- * If the simulation hasn't cooled by this time, it will be force-stopped
108
- * to prevent indefinite animation. Set to 0 to disable.
109
- * @default 3000
110
- */
111
- maxSimulationTimeMs?: number;
112
-
113
- /**
114
- * Velocity decay (friction)
115
- * @default 0.4
116
- */
117
- velocityDecay?: number;
118
-
119
- /**
120
- * Optional tick callback invoked on each simulation tick with current nodes/links and the simulation instance
121
- */
122
- onTick?: (
123
- nodes: SimulationNode[],
124
- links: SimulationLink[],
125
- sim: d3.Simulation<SimulationNode, SimulationLink>
126
- ) => void;
127
- }
128
-
129
- export interface UseForceSimulationReturn {
130
- /**
131
- * Current nodes with positions
132
- */
133
- nodes: SimulationNode[];
134
-
135
- /**
136
- * Current links
137
- */
138
- links: SimulationLink[];
139
-
140
- /**
141
- * Restart the simulation
142
- */
143
- restart: () => void;
144
-
145
- /**
146
- * Stop the simulation
147
- */
148
- stop: () => void;
149
-
150
- /**
151
- * Whether the simulation is currently running
152
- */
153
- isRunning: boolean;
154
-
155
- /**
156
- * Current alpha value (simulation heat)
157
- */
158
- alpha: number;
159
- }
160
-
161
21
  /**
162
22
  * Hook for managing d3-force simulations
163
23
  * Automatically handles simulation lifecycle, tick updates, and cleanup
@@ -297,12 +157,7 @@ export function useForceSimulation(
297
157
  } catch (e) {
298
158
  void e;
299
159
  // If error, fall back to random positions
300
- nodesCopy.forEach((n) => {
301
- n.x = Math.random() * width;
302
- n.y = Math.random() * height;
303
- (n as any).vx = (Math.random() - 0.5) * 10;
304
- (n as any).vy = (Math.random() - 0.5) * 10;
305
- });
160
+ seedRandomPositions(nodesCopy, width, height);
306
161
  }
307
162
 
308
163
  // Create the simulation
@@ -393,12 +248,7 @@ export function useForceSimulation(
393
248
  stopTimeoutRef.current = (globalThis.setTimeout as any)(() => {
394
249
  try {
395
250
  if (stabilizeOnStop) {
396
- nodesCopy.forEach((n) => {
397
- (n as any).vx = 0;
398
- (n as any).vy = 0;
399
- if (typeof n.x === 'number') n.x = Number(n.x.toFixed(3));
400
- if (typeof n.y === 'number') n.y = Number(n.y.toFixed(3));
401
- });
251
+ stabilizeNodes(nodesCopy);
402
252
  }
403
253
  simulation.alpha(0);
404
254
  simulation.stop();
@@ -429,12 +279,7 @@ export function useForceSimulation(
429
279
  if (simulation.alpha() <= (alphaMin as number)) {
430
280
  try {
431
281
  if (stabilizeOnStop) {
432
- nodesCopy.forEach((n) => {
433
- (n as any).vx = 0;
434
- (n as any).vy = 0;
435
- if (typeof n.x === 'number') n.x = Number(n.x.toFixed(3));
436
- if (typeof n.y === 'number') n.y = Number(n.y.toFixed(3));
437
- });
282
+ stabilizeNodes(nodesCopy);
438
283
  }
439
284
  simulation.stop();
440
285
  } catch (e) {