@tscircuit/core 0.0.985 → 0.0.987

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 (3) hide show
  1. package/dist/index.d.ts +123 -109
  2. package/dist/index.js +214 -145
  3. package/package.json +1 -1
package/dist/index.d.ts CHANGED
@@ -16,115 +16,6 @@ import { CopperPourPipelineSolver } from '@tscircuit/copper-pour-solver';
16
16
  import { ConnectivityMap } from 'circuit-json-to-connectivity-map';
17
17
  import { GraphicsObject } from 'graphics-debug';
18
18
 
19
- declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "InflateSubcircuitCircuitJson", "SourceNameDuplicateComponentRemoval", "PcbFootprintStringRender", "InitializePortsFromChildren", "CreateNetsFromProps", "AssignFallbackProps", "CreateTracesFromProps", "CreateTracesFromNetLabels", "CreateTraceHintsFromProps", "SourceGroupRender", "AssignNameToUnnamedComponents", "SourceRender", "SourceParentAttachment", "PortMatching", "OptimizeSelectorCache", "SourceTraceRender", "SourceAddConnectivityMapKey", "SourceDesignRuleChecks", "SimulationRender", "SchematicComponentRender", "SchematicPortRender", "SchematicPrimitiveRender", "SchematicComponentSizeCalculation", "SchematicLayout", "SchematicTraceRender", "SchematicReplaceNetLabelsWithSymbols", "PanelBoardLayout", "PcbComponentRender", "PcbPrimitiveRender", "PcbFootprintLayout", "PcbPortRender", "PcbPortAttachment", "PcbComponentSizeCalculation", "PcbComponentAnchorAlignment", "PcbLayout", "PcbBoardAutoSize", "PanelLayout", "PcbTraceHintRender", "PcbManualTraceRender", "PcbTraceRender", "PcbRouteNetIslands", "PcbCopperPourRender", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "SimulationSpiceEngineRender"];
20
- type RenderPhase = (typeof orderedRenderPhases)[number];
21
- declare const renderPhaseIndexMap: Map<"ReactSubtreesRender" | "InflateSubcircuitCircuitJson" | "SourceNameDuplicateComponentRemoval" | "PcbFootprintStringRender" | "InitializePortsFromChildren" | "CreateNetsFromProps" | "AssignFallbackProps" | "CreateTracesFromProps" | "CreateTracesFromNetLabels" | "CreateTraceHintsFromProps" | "SourceGroupRender" | "AssignNameToUnnamedComponents" | "SourceRender" | "SourceParentAttachment" | "PortMatching" | "OptimizeSelectorCache" | "SourceTraceRender" | "SourceAddConnectivityMapKey" | "SourceDesignRuleChecks" | "SimulationRender" | "SchematicComponentRender" | "SchematicPortRender" | "SchematicPrimitiveRender" | "SchematicComponentSizeCalculation" | "SchematicLayout" | "SchematicTraceRender" | "SchematicReplaceNetLabelsWithSymbols" | "PanelBoardLayout" | "PcbComponentRender" | "PcbPrimitiveRender" | "PcbFootprintLayout" | "PcbPortRender" | "PcbPortAttachment" | "PcbComponentSizeCalculation" | "PcbComponentAnchorAlignment" | "PcbLayout" | "PcbBoardAutoSize" | "PanelLayout" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbCopperPourRender" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "SimulationSpiceEngineRender", number>;
22
- type RenderPhaseFn<K extends RenderPhase = RenderPhase> = `doInitial${K}` | `update${K}` | `remove${K}`;
23
- type RenderPhaseStates = Record<RenderPhase, {
24
- initialized: boolean;
25
- dirty: boolean;
26
- }>;
27
- type AsyncEffect = {
28
- effectName: string;
29
- promise: Promise<void>;
30
- phase: RenderPhase;
31
- complete: boolean;
32
- };
33
- type RenderPhaseFunctions = {
34
- [T in RenderPhaseFn]?: () => void;
35
- };
36
- type IRenderable = RenderPhaseFunctions & {
37
- renderPhaseStates: RenderPhaseStates;
38
- runRenderPhase(phase: RenderPhase): void;
39
- runRenderPhaseForChildren(phase: RenderPhase): void;
40
- shouldBeRemoved: boolean;
41
- children: IRenderable[];
42
- runRenderCycle(): void;
43
- };
44
- declare abstract class Renderable implements IRenderable {
45
- renderPhaseStates: RenderPhaseStates;
46
- shouldBeRemoved: boolean;
47
- children: IRenderable[];
48
- /** PCB-only SMTPads, PlatedHoles, Holes, Silkscreen elements etc. */
49
- isPcbPrimitive: boolean;
50
- /** Schematic-only, lines, boxes, indicators etc. */
51
- isSchematicPrimitive: boolean;
52
- _renderId: string;
53
- _currentRenderPhase: RenderPhase | null;
54
- private _asyncEffects;
55
- parent: Renderable | null;
56
- constructor(props: any);
57
- _markDirty(phase: RenderPhase): void;
58
- _queueAsyncEffect(effectName: string, effect: () => Promise<void>): void;
59
- protected _emitRenderLifecycleEvent(phase: RenderPhase, startOrEnd: "start" | "end"): void;
60
- getString(): string;
61
- _hasIncompleteAsyncEffects(): boolean;
62
- _hasIncompleteAsyncEffectsInSubtreeForPhase(phase: RenderPhase): boolean;
63
- getCurrentRenderPhase(): RenderPhase | null;
64
- getRenderGraph(): Record<string, any>;
65
- getTopLevelRenderable(): Renderable;
66
- runRenderCycle(): void;
67
- /**
68
- * This runs all the render methods for a given phase, calling one of:
69
- * - doInitial*
70
- * - update*
71
- * -remove*
72
- * ...depending on the current state of the component.
73
- */
74
- runRenderPhase(phase: RenderPhase): void;
75
- runRenderPhaseForChildren(phase: RenderPhase): void;
76
- renderError(message: string | Omit<PcbTraceError, "pcb_error_id"> | Omit<PcbPlacementError, "pcb_error_id"> | Omit<PcbManualEditConflictWarning, "pcb_error_id"> | Omit<PcbViaClearanceError, "pcb_error_id">): void;
77
- }
78
-
79
- /**
80
- * This is how we render in React. This can be a confusing part of the codebase,
81
- * but here are some helpful reference implementations:
82
- *
83
- * https://github.com/diegomura/react-pdf/blob/fabecc56727dfb6d590a3fa1e11f50250ecbbea1/packages/reconciler/src/reconciler-31.js
84
- * https://github.com/pmndrs/react-three-fiber/blob/ec4f00bb61cc4f6e28b3a12b1dca9daa5594f10e/packages/fiber/src/core/renderer.ts
85
- *
86
- *
87
- */
88
-
89
- type ReactSubtree = {
90
- element: ReactElement;
91
- component: NormalComponent;
92
- };
93
-
94
- type SchematicBoxPortPositionWithMetadata = {
95
- trueIndex: number;
96
- pinNumber: number;
97
- side: "left" | "right" | "top" | "bottom";
98
- distanceFromOrthogonalEdge: number;
99
- x: number;
100
- y: number;
101
- };
102
- interface SchematicBoxDimensions {
103
- pinCount: number;
104
- getPortPositionByPinNumber(pinNumber: number): SchematicBoxPortPositionWithMetadata | null;
105
- getSize(): {
106
- width: number;
107
- height: number;
108
- };
109
- getSizeIncludingPins(): {
110
- width: number;
111
- height: number;
112
- };
113
- }
114
- interface SchematicBoxComponentDimensions {
115
- schWidth: number;
116
- schHeight: number;
117
- }
118
-
119
- interface BoardI {
120
- componentName: string;
121
- boardThickness: number;
122
- _connectedSchematicPortPairs: Set<string>;
123
- allLayers: ReadonlyArray<LayerRef>;
124
- _getBoardCalcVariables(): Record<string, number>;
125
- pcb_board_id?: string | null;
126
- }
127
-
128
19
  declare const SOLVERS: {
129
20
  PackSolver2: typeof PackSolver2;
130
21
  AutoroutingPipelineSolver: typeof AutoroutingPipelineSolver;
@@ -271,6 +162,124 @@ interface DebugLogOutputEvent {
271
162
  content: any;
272
163
  }
273
164
 
165
+ interface IRootCircuit {
166
+ emit(event: RootCircuitEventName, ...args: any[]): void;
167
+ on(event: RootCircuitEventName, listener: (...args: any[]) => void): void;
168
+ _hasIncompleteAsyncEffectsForPhase(phase: RenderPhase): boolean;
169
+ }
170
+
171
+ declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "InflateSubcircuitCircuitJson", "SourceNameDuplicateComponentRemoval", "PcbFootprintStringRender", "InitializePortsFromChildren", "CreateNetsFromProps", "AssignFallbackProps", "CreateTracesFromProps", "CreateTracesFromNetLabels", "CreateTraceHintsFromProps", "SourceGroupRender", "AssignNameToUnnamedComponents", "SourceRender", "SourceParentAttachment", "PortMatching", "OptimizeSelectorCache", "SourceTraceRender", "SourceAddConnectivityMapKey", "SourceDesignRuleChecks", "SimulationRender", "SchematicComponentRender", "SchematicPortRender", "SchematicPrimitiveRender", "SchematicComponentSizeCalculation", "SchematicLayout", "SchematicTraceRender", "SchematicReplaceNetLabelsWithSymbols", "PanelBoardLayout", "PcbComponentRender", "PcbPrimitiveRender", "PcbFootprintLayout", "PcbPortRender", "PcbPortAttachment", "PcbComponentSizeCalculation", "PcbComponentAnchorAlignment", "PcbLayout", "PcbBoardAutoSize", "PanelLayout", "PcbTraceHintRender", "PcbManualTraceRender", "PcbTraceRender", "PcbRouteNetIslands", "PcbCopperPourRender", "PcbDesignRuleChecks", "SilkscreenOverlapAdjustment", "CadModelRender", "PartsEngineRender", "SimulationSpiceEngineRender"];
172
+ type RenderPhase = (typeof orderedRenderPhases)[number];
173
+ declare const renderPhaseIndexMap: Map<"ReactSubtreesRender" | "InflateSubcircuitCircuitJson" | "SourceNameDuplicateComponentRemoval" | "PcbFootprintStringRender" | "InitializePortsFromChildren" | "CreateNetsFromProps" | "AssignFallbackProps" | "CreateTracesFromProps" | "CreateTracesFromNetLabels" | "CreateTraceHintsFromProps" | "SourceGroupRender" | "AssignNameToUnnamedComponents" | "SourceRender" | "SourceParentAttachment" | "PortMatching" | "OptimizeSelectorCache" | "SourceTraceRender" | "SourceAddConnectivityMapKey" | "SourceDesignRuleChecks" | "SimulationRender" | "SchematicComponentRender" | "SchematicPortRender" | "SchematicPrimitiveRender" | "SchematicComponentSizeCalculation" | "SchematicLayout" | "SchematicTraceRender" | "SchematicReplaceNetLabelsWithSymbols" | "PanelBoardLayout" | "PcbComponentRender" | "PcbPrimitiveRender" | "PcbFootprintLayout" | "PcbPortRender" | "PcbPortAttachment" | "PcbComponentSizeCalculation" | "PcbComponentAnchorAlignment" | "PcbLayout" | "PcbBoardAutoSize" | "PanelLayout" | "PcbTraceHintRender" | "PcbManualTraceRender" | "PcbTraceRender" | "PcbRouteNetIslands" | "PcbCopperPourRender" | "PcbDesignRuleChecks" | "SilkscreenOverlapAdjustment" | "CadModelRender" | "PartsEngineRender" | "SimulationSpiceEngineRender", number>;
174
+ type RenderPhaseFn<K extends RenderPhase = RenderPhase> = `doInitial${K}` | `update${K}` | `remove${K}`;
175
+ type RenderPhaseStates = Record<RenderPhase, {
176
+ initialized: boolean;
177
+ dirty: boolean;
178
+ }>;
179
+ type AsyncEffect = {
180
+ asyncEffectId: string;
181
+ effectName: string;
182
+ promise: Promise<void>;
183
+ phase: RenderPhase;
184
+ complete: boolean;
185
+ };
186
+ type RenderPhaseFunctions = {
187
+ [T in RenderPhaseFn]?: () => void;
188
+ };
189
+ type IRenderable = RenderPhaseFunctions & {
190
+ renderPhaseStates: RenderPhaseStates;
191
+ runRenderPhase(phase: RenderPhase): void;
192
+ runRenderPhaseForChildren(phase: RenderPhase): void;
193
+ shouldBeRemoved: boolean;
194
+ children: IRenderable[];
195
+ runRenderCycle(): void;
196
+ };
197
+ declare abstract class Renderable implements IRenderable {
198
+ renderPhaseStates: RenderPhaseStates;
199
+ shouldBeRemoved: boolean;
200
+ children: IRenderable[];
201
+ /** PCB-only SMTPads, PlatedHoles, Holes, Silkscreen elements etc. */
202
+ isPcbPrimitive: boolean;
203
+ /** Schematic-only, lines, boxes, indicators etc. */
204
+ isSchematicPrimitive: boolean;
205
+ _renderId: string;
206
+ _currentRenderPhase: RenderPhase | null;
207
+ private _asyncEffects;
208
+ parent: Renderable | null;
209
+ constructor(props: any);
210
+ _markDirty(phase: RenderPhase): void;
211
+ _queueAsyncEffect(effectName: string, effect: () => Promise<void>): void;
212
+ protected _emitRenderLifecycleEvent(phase: RenderPhase, startOrEnd: "start" | "end"): void;
213
+ getString(): string;
214
+ _hasIncompleteAsyncEffects(): boolean;
215
+ _hasIncompleteAsyncEffectsInSubtreeForPhase(phase: RenderPhase): boolean;
216
+ _hasIncompleteAsyncEffectsForPhase(phase: RenderPhase): boolean;
217
+ getCurrentRenderPhase(): RenderPhase | null;
218
+ getRenderGraph(): Record<string, any>;
219
+ getTopLevelRenderable(): Renderable;
220
+ runRenderCycle(): void;
221
+ /**
222
+ * This runs all the render methods for a given phase, calling one of:
223
+ * - doInitial*
224
+ * - update*
225
+ * -remove*
226
+ * ...depending on the current state of the component.
227
+ */
228
+ runRenderPhase(phase: RenderPhase): void;
229
+ runRenderPhaseForChildren(phase: RenderPhase): void;
230
+ protected _getRootCircuit(): IRootCircuit | null;
231
+ renderError(message: string | Omit<PcbTraceError, "pcb_error_id"> | Omit<PcbPlacementError, "pcb_error_id"> | Omit<PcbManualEditConflictWarning, "pcb_error_id"> | Omit<PcbViaClearanceError, "pcb_error_id">): void;
232
+ }
233
+
234
+ /**
235
+ * This is how we render in React. This can be a confusing part of the codebase,
236
+ * but here are some helpful reference implementations:
237
+ *
238
+ * https://github.com/diegomura/react-pdf/blob/fabecc56727dfb6d590a3fa1e11f50250ecbbea1/packages/reconciler/src/reconciler-31.js
239
+ * https://github.com/pmndrs/react-three-fiber/blob/ec4f00bb61cc4f6e28b3a12b1dca9daa5594f10e/packages/fiber/src/core/renderer.ts
240
+ *
241
+ *
242
+ */
243
+
244
+ type ReactSubtree = {
245
+ element: ReactElement;
246
+ component: NormalComponent;
247
+ };
248
+
249
+ type SchematicBoxPortPositionWithMetadata = {
250
+ trueIndex: number;
251
+ pinNumber: number;
252
+ side: "left" | "right" | "top" | "bottom";
253
+ distanceFromOrthogonalEdge: number;
254
+ x: number;
255
+ y: number;
256
+ };
257
+ interface SchematicBoxDimensions {
258
+ pinCount: number;
259
+ getPortPositionByPinNumber(pinNumber: number): SchematicBoxPortPositionWithMetadata | null;
260
+ getSize(): {
261
+ width: number;
262
+ height: number;
263
+ };
264
+ getSizeIncludingPins(): {
265
+ width: number;
266
+ height: number;
267
+ };
268
+ }
269
+ interface SchematicBoxComponentDimensions {
270
+ schWidth: number;
271
+ schHeight: number;
272
+ }
273
+
274
+ interface BoardI {
275
+ componentName: string;
276
+ boardThickness: number;
277
+ _connectedSchematicPortPairs: Set<string>;
278
+ allLayers: ReadonlyArray<LayerRef>;
279
+ _getBoardCalcVariables(): Record<string, number>;
280
+ pcb_board_id?: string | null;
281
+ }
282
+
274
283
  declare function resolveStaticFileImport(path: string, platform?: PlatformConfig): Promise<string>;
275
284
 
276
285
  declare class RootCircuit {
@@ -299,6 +308,8 @@ declare class RootCircuit {
299
308
  */
300
309
  projectUrl?: string;
301
310
  _hasRenderedAtleastOnce: boolean;
311
+ private _asyncEffectIdsByPhase;
312
+ private _asyncEffectPhaseById;
302
313
  constructor({ platform, projectUrl, }?: {
303
314
  platform?: PlatformConfig;
304
315
  projectUrl?: string;
@@ -313,6 +324,7 @@ declare class RootCircuit {
313
324
  render(): void;
314
325
  renderUntilSettled(): Promise<void>;
315
326
  private _hasIncompleteAsyncEffects;
327
+ _hasIncompleteAsyncEffectsForPhase(phase: RenderPhase): boolean;
316
328
  getCircuitJson(): AnyCircuitElement[];
317
329
  toJson(): AnyCircuitElement[];
318
330
  getSvg(options: {
@@ -336,6 +348,8 @@ declare class RootCircuit {
336
348
  removeListener(event: RootCircuitEventName, listener: (...args: any[]) => void): void;
337
349
  enableDebug(debug: string | null | false): void;
338
350
  getClientOrigin(): string;
351
+ private _registerAsyncEffectStart;
352
+ private _registerAsyncEffectEnd;
339
353
  }
340
354
  /**
341
355
  * @deprecated
package/dist/index.js CHANGED
@@ -185,6 +185,7 @@ var asyncPhaseDependencies = {
185
185
  PcbComponentAnchorAlignment: ["PcbFootprintStringRender"]
186
186
  };
187
187
  var globalRenderCounter = 0;
188
+ var globalAsyncEffectCounter = 0;
188
189
  var Renderable = class _Renderable {
189
190
  renderPhaseStates;
190
191
  shouldBeRemoved = false;
@@ -219,7 +220,9 @@ var Renderable = class _Renderable {
219
220
  }
220
221
  }
221
222
  _queueAsyncEffect(effectName, effect) {
223
+ const asyncEffectId = `${this._renderId}:${globalAsyncEffectCounter++}`;
222
224
  const asyncEffect = {
225
+ asyncEffectId,
223
226
  promise: effect(),
224
227
  // TODO don't start effects until end of render cycle
225
228
  phase: this._currentRenderPhase,
@@ -227,9 +230,10 @@ var Renderable = class _Renderable {
227
230
  complete: false
228
231
  };
229
232
  this._asyncEffects.push(asyncEffect);
230
- if ("root" in this && this.root) {
231
- ;
232
- this.root.emit("asyncEffect:start", {
233
+ const root = this._getRootCircuit();
234
+ if (root) {
235
+ root.emit("asyncEffect:start", {
236
+ asyncEffectId,
233
237
  effectName,
234
238
  componentDisplayName: this.getString(),
235
239
  phase: asyncEffect.phase
@@ -237,9 +241,10 @@ var Renderable = class _Renderable {
237
241
  }
238
242
  asyncEffect.promise.then(() => {
239
243
  asyncEffect.complete = true;
240
- if ("root" in this && this.root) {
241
- ;
242
- this.root.emit("asyncEffect:end", {
244
+ const root2 = this._getRootCircuit();
245
+ if (root2) {
246
+ root2.emit("asyncEffect:end", {
247
+ asyncEffectId,
243
248
  effectName,
244
249
  componentDisplayName: this.getString(),
245
250
  phase: asyncEffect.phase
@@ -251,9 +256,10 @@ var Renderable = class _Renderable {
251
256
  ${error.stack}`
252
257
  );
253
258
  asyncEffect.complete = true;
254
- if ("root" in this && this.root) {
255
- ;
256
- this.root.emit("asyncEffect:end", {
259
+ const root2 = this._getRootCircuit();
260
+ if (root2) {
261
+ root2.emit("asyncEffect:end", {
262
+ asyncEffectId,
257
263
  effectName,
258
264
  componentDisplayName: this.getString(),
259
265
  phase: asyncEffect.phase,
@@ -270,10 +276,10 @@ ${error.stack}`
270
276
  componentDisplayName: this.getString(),
271
277
  type: granular_event_type
272
278
  };
273
- if ("root" in this && this.root) {
274
- ;
275
- this.root.emit(granular_event_type, eventPayload);
276
- this.root.emit("renderable:renderLifecycle:anyEvent", {
279
+ const root = this._getRootCircuit();
280
+ if (root) {
281
+ root.emit(granular_event_type, eventPayload);
282
+ root.emit("renderable:renderLifecycle:anyEvent", {
277
283
  ...eventPayload,
278
284
  type: granular_event_type
279
285
  });
@@ -299,6 +305,13 @@ ${error.stack}`
299
305
  }
300
306
  return false;
301
307
  }
308
+ _hasIncompleteAsyncEffectsForPhase(phase) {
309
+ const root = this._getRootCircuit();
310
+ if (root?._hasIncompleteAsyncEffectsForPhase) {
311
+ return root._hasIncompleteAsyncEffectsForPhase(phase);
312
+ }
313
+ return this._hasIncompleteAsyncEffectsInSubtreeForPhase(phase);
314
+ }
302
315
  getCurrentRenderPhase() {
303
316
  return this._currentRenderPhase;
304
317
  }
@@ -355,9 +368,8 @@ ${error.stack}`
355
368
  }
356
369
  const deps = asyncPhaseDependencies[phase] || [];
357
370
  if (deps.length > 0) {
358
- const root = this.getTopLevelRenderable();
359
371
  for (const depPhase of deps) {
360
- if (root._hasIncompleteAsyncEffectsInSubtreeForPhase(depPhase)) {
372
+ if (this._hasIncompleteAsyncEffectsForPhase(depPhase)) {
361
373
  return;
362
374
  }
363
375
  }
@@ -383,6 +395,12 @@ ${error.stack}`
383
395
  child.runRenderPhase(phase);
384
396
  }
385
397
  }
398
+ _getRootCircuit() {
399
+ if ("root" in this) {
400
+ return this.root ?? null;
401
+ }
402
+ return null;
403
+ }
386
404
  renderError(message) {
387
405
  if (typeof message === "string") {
388
406
  throw new Error(message);
@@ -2358,10 +2376,10 @@ var SmtPad = class extends PrimitiveComponent2 {
2358
2376
  pcb_group_id: this.getGroup()?.pcb_group_id ?? void 0
2359
2377
  });
2360
2378
  } else if (props.shape === "polygon") {
2361
- const transformedPoints = props.points.map((point4) => {
2379
+ const transformedPoints = props.points.map((point6) => {
2362
2380
  const transformed = applyToPoint2(globalTransform, {
2363
- x: distance.parse(point4.x),
2364
- y: distance.parse(point4.y)
2381
+ x: distance.parse(point6.x),
2382
+ y: distance.parse(point6.y)
2365
2383
  });
2366
2384
  return {
2367
2385
  x: transformed.x,
@@ -2593,18 +2611,18 @@ var SilkscreenPath = class extends PrimitiveComponent2 {
2593
2611
  if (!currentPath) return;
2594
2612
  let currentCenterX = 0;
2595
2613
  let currentCenterY = 0;
2596
- for (const point4 of currentPath.route) {
2597
- currentCenterX += point4.x;
2598
- currentCenterY += point4.y;
2614
+ for (const point6 of currentPath.route) {
2615
+ currentCenterX += point6.x;
2616
+ currentCenterY += point6.y;
2599
2617
  }
2600
2618
  currentCenterX /= currentPath.route.length;
2601
2619
  currentCenterY /= currentPath.route.length;
2602
2620
  const offsetX = newCenter.x - currentCenterX;
2603
2621
  const offsetY = newCenter.y - currentCenterY;
2604
- const newRoute = currentPath.route.map((point4) => ({
2605
- ...point4,
2606
- x: point4.x + offsetX,
2607
- y: point4.y + offsetY
2622
+ const newRoute = currentPath.route.map((point6) => ({
2623
+ ...point6,
2624
+ x: point6.x + offsetX,
2625
+ y: point6.y + offsetY
2608
2626
  }));
2609
2627
  db.pcb_silkscreen_path.update(this.pcb_silkscreen_path_id, {
2610
2628
  route: newRoute
@@ -2634,11 +2652,11 @@ var SilkscreenPath = class extends PrimitiveComponent2 {
2634
2652
  return { width: 0, height: 0 };
2635
2653
  }
2636
2654
  let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
2637
- for (const point4 of props.route) {
2638
- minX = Math.min(minX, point4.x);
2639
- maxX = Math.max(maxX, point4.x);
2640
- minY = Math.min(minY, point4.y);
2641
- maxY = Math.max(maxY, point4.y);
2655
+ for (const point6 of props.route) {
2656
+ minX = Math.min(minX, point6.x);
2657
+ maxX = Math.max(maxX, point6.x);
2658
+ minY = Math.min(minY, point6.y);
2659
+ maxY = Math.max(maxY, point6.y);
2642
2660
  }
2643
2661
  return {
2644
2662
  width: maxX - minX,
@@ -2674,14 +2692,14 @@ var PcbTrace = class extends PrimitiveComponent2 {
2674
2692
  const subcircuit = this.getSubcircuit();
2675
2693
  const { maybeFlipLayer } = this._getPcbPrimitiveFlippedHelpers();
2676
2694
  const parentTransform = this._computePcbGlobalTransformBeforeLayout();
2677
- const transformedRoute = props.route.map((point4) => {
2678
- const { x, y, ...restOfPoint } = point4;
2695
+ const transformedRoute = props.route.map((point6) => {
2696
+ const { x, y, ...restOfPoint } = point6;
2679
2697
  const transformedPoint = applyToPoint4(parentTransform, { x, y });
2680
- if (point4.route_type === "wire" && point4.layer) {
2698
+ if (point6.route_type === "wire" && point6.layer) {
2681
2699
  return {
2682
2700
  ...transformedPoint,
2683
2701
  ...restOfPoint,
2684
- layer: maybeFlipLayer(point4.layer)
2702
+ layer: maybeFlipLayer(point6.layer)
2685
2703
  };
2686
2704
  }
2687
2705
  return { ...transformedPoint, ...restOfPoint };
@@ -2701,16 +2719,16 @@ var PcbTrace = class extends PrimitiveComponent2 {
2701
2719
  return { width: 0, height: 0 };
2702
2720
  }
2703
2721
  let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
2704
- for (const point4 of props.route) {
2705
- minX = Math.min(minX, point4.x);
2706
- maxX = Math.max(maxX, point4.x);
2707
- minY = Math.min(minY, point4.y);
2708
- maxY = Math.max(maxY, point4.y);
2709
- if (point4.route_type === "wire") {
2710
- minX = Math.min(minX, point4.x - point4.width / 2);
2711
- maxX = Math.max(maxX, point4.x + point4.width / 2);
2712
- minY = Math.min(minY, point4.y - point4.width / 2);
2713
- maxY = Math.max(maxY, point4.y + point4.width / 2);
2722
+ for (const point6 of props.route) {
2723
+ minX = Math.min(minX, point6.x);
2724
+ maxX = Math.max(maxX, point6.x);
2725
+ minY = Math.min(minY, point6.y);
2726
+ maxY = Math.max(maxY, point6.y);
2727
+ if (point6.route_type === "wire") {
2728
+ minX = Math.min(minX, point6.x - point6.width / 2);
2729
+ maxX = Math.max(maxX, point6.x + point6.width / 2);
2730
+ minY = Math.min(minY, point6.y - point6.width / 2);
2731
+ maxY = Math.max(maxY, point6.y + point6.width / 2);
2714
2732
  }
2715
2733
  }
2716
2734
  if (minX === Infinity || maxX === -Infinity || minY === Infinity || maxY === -Infinity) {
@@ -2977,9 +2995,9 @@ var PlatedHole = class extends PrimitiveComponent2 {
2977
2995
  });
2978
2996
  this.pcb_plated_hole_id = pcb_plated_hole.pcb_plated_hole_id;
2979
2997
  } else if (props.shape === "hole_with_polygon_pad") {
2980
- const padOutline = (props.padOutline || []).map((point4) => {
2981
- const x = typeof point4.x === "number" ? point4.x : parseFloat(String(point4.x));
2982
- const y = typeof point4.y === "number" ? point4.y : parseFloat(String(point4.y));
2998
+ const padOutline = (props.padOutline || []).map((point6) => {
2999
+ const x = typeof point6.x === "number" ? point6.x : parseFloat(String(point6.x));
3000
+ const y = typeof point6.y === "number" ? point6.y : parseFloat(String(point6.y));
2983
3001
  return {
2984
3002
  x,
2985
3003
  y
@@ -3398,11 +3416,11 @@ var Cutout = class extends PrimitiveComponent2 {
3398
3416
  if (props.shape === "polygon") {
3399
3417
  if (props.points.length === 0) return { width: 0, height: 0 };
3400
3418
  let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
3401
- for (const point4 of props.points) {
3402
- minX = Math.min(minX, point4.x);
3403
- maxX = Math.max(maxX, point4.x);
3404
- minY = Math.min(minY, point4.y);
3405
- maxY = Math.max(maxY, point4.y);
3419
+ for (const point6 of props.points) {
3420
+ minX = Math.min(minX, point6.x);
3421
+ maxX = Math.max(maxX, point6.x);
3422
+ minY = Math.min(minY, point6.y);
3423
+ maxY = Math.max(maxY, point6.y);
3406
3424
  }
3407
3425
  return { width: maxX - minX, height: maxY - minY };
3408
3426
  }
@@ -3441,11 +3459,11 @@ var Cutout = class extends PrimitiveComponent2 {
3441
3459
  } else if (cutout.shape === "polygon") {
3442
3460
  if (cutout.points.length === 0) return super._getPcbCircuitJsonBounds();
3443
3461
  let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
3444
- for (const point4 of cutout.points) {
3445
- minX = Math.min(minX, point4.x);
3446
- maxX = Math.max(maxX, point4.x);
3447
- minY = Math.min(minY, point4.y);
3448
- maxY = Math.max(maxY, point4.y);
3462
+ for (const point6 of cutout.points) {
3463
+ minX = Math.min(minX, point6.x);
3464
+ maxX = Math.max(maxX, point6.x);
3465
+ minY = Math.min(minY, point6.y);
3466
+ maxY = Math.max(maxY, point6.y);
3449
3467
  }
3450
3468
  return {
3451
3469
  center: { x: (minX + maxX) / 2, y: (minY + maxY) / 2 },
@@ -5488,13 +5506,13 @@ var getDistance = (a, b) => {
5488
5506
  const bPos = "_getGlobalPcbPositionBeforeLayout" in b ? b._getGlobalPcbPositionBeforeLayout() : b;
5489
5507
  return Math.sqrt((aPos.x - bPos.x) ** 2 + (aPos.y - bPos.y) ** 2);
5490
5508
  };
5491
- function getClosest(point4, candidates) {
5509
+ function getClosest(point6, candidates) {
5492
5510
  if (candidates.length === 0)
5493
5511
  throw new Error("No candidates given to getClosest method");
5494
5512
  let closest = candidates[0];
5495
5513
  let closestDist = Infinity;
5496
5514
  for (const candidate of candidates) {
5497
- const dist = getDistance(point4, candidate);
5515
+ const dist = getDistance(point6, candidate);
5498
5516
  if (dist < closestDist) {
5499
5517
  closest = candidate;
5500
5518
  closestDist = dist;
@@ -5624,30 +5642,36 @@ function getTraceDisplayName({
5624
5642
  }
5625
5643
 
5626
5644
  // lib/utils/is-route-outside-board.ts
5627
- var isRouteOutsideBoard = (mergedRoute, { db }) => {
5628
- const pcbBoard = db.pcb_board.list()[0];
5629
- if (pcbBoard.outline) {
5630
- const boardOutline = pcbBoard.outline;
5631
- const isInsidePolygon = (point4, polygon) => {
5632
- let inside = false;
5633
- for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
5634
- const xi = polygon[i].x, yi = polygon[i].y;
5635
- const xj = polygon[j].x, yj = polygon[j].y;
5636
- const intersect = yi > point4.y !== yj > point4.y && point4.x < (xj - xi) * (point4.y - yi) / (yj - yi) + xi;
5637
- if (intersect) inside = !inside;
5638
- }
5639
- return inside;
5640
- };
5641
- return mergedRoute.some((point4) => !isInsidePolygon(point4, boardOutline));
5642
- }
5643
- const boardWidth = pcbBoard.width;
5644
- const boardHeight = pcbBoard.height;
5645
- const boardCenterX = pcbBoard.center.x;
5646
- const boardCenterY = pcbBoard.center.y;
5647
- const outsideBoard = mergedRoute.some((point4) => {
5648
- return point4.x < boardCenterX - boardWidth / 2 || point4.y < boardCenterY - boardHeight / 2 || point4.x > boardCenterX + boardWidth / 2 || point4.y > boardCenterY + boardHeight / 2;
5649
- });
5650
- return outsideBoard;
5645
+ import { point as point2 } from "@flatten-js/core";
5646
+
5647
+ // lib/utils/get-pcb-board-outline-polygon.ts
5648
+ import { Box, point, Polygon } from "@flatten-js/core";
5649
+ var getPcbBoardOutlinePolygon = (pcbBoard) => {
5650
+ if (pcbBoard.outline && pcbBoard.outline.length > 0) {
5651
+ return new Polygon(pcbBoard.outline.map((p) => point(p.x, p.y)));
5652
+ }
5653
+ return new Polygon(
5654
+ new Box(
5655
+ pcbBoard.center.x - pcbBoard.width / 2,
5656
+ pcbBoard.center.y - pcbBoard.height / 2,
5657
+ pcbBoard.center.x + pcbBoard.width / 2,
5658
+ pcbBoard.center.y + pcbBoard.height / 2
5659
+ ).toPoints()
5660
+ );
5661
+ };
5662
+
5663
+ // lib/utils/is-route-outside-board.ts
5664
+ var isRouteOutsideBoard = ({
5665
+ mergedRoute,
5666
+ db,
5667
+ pcbBoardId
5668
+ }) => {
5669
+ const pcbBoard = db.pcb_board.get(pcbBoardId);
5670
+ if (!pcbBoard) return false;
5671
+ const boardOutlinePolygon = getPcbBoardOutlinePolygon(pcbBoard);
5672
+ return !mergedRoute.flat().every(
5673
+ (routePoint) => boardOutlinePolygon.contains(point2(routePoint.x, routePoint.y))
5674
+ );
5651
5675
  };
5652
5676
 
5653
5677
  // lib/utils/obstacles/getObstaclesFromRoute.ts
@@ -6227,12 +6251,12 @@ var createSchematicTraceCrossingSegments = ({
6227
6251
 
6228
6252
  // lib/components/primitive-components/Trace/trace-utils/create-schematic-trace-junctions.ts
6229
6253
  var TOLERANCE = 1e-3;
6230
- var isPointWithinEdge = (point4, edge) => {
6254
+ var isPointWithinEdge = (point6, edge) => {
6231
6255
  const minX = Math.min(edge.from.x, edge.to.x);
6232
6256
  const maxX = Math.max(edge.from.x, edge.to.x);
6233
6257
  const minY = Math.min(edge.from.y, edge.to.y);
6234
6258
  const maxY = Math.max(edge.from.y, edge.to.y);
6235
- return point4.x >= minX && point4.x <= maxX && point4.y >= minY && point4.y <= maxY;
6259
+ return point6.x >= minX && point6.x <= maxX && point6.y >= minY && point6.y <= maxY;
6236
6260
  };
6237
6261
  var getEdgeOrientation = (edge) => {
6238
6262
  const isVertical = Math.abs(edge.from.x - edge.to.x) < TOLERANCE;
@@ -6840,15 +6864,15 @@ import { getFullConnectivityMapFromCircuitJson } from "circuit-json-to-connectiv
6840
6864
  function getTraceLength(route) {
6841
6865
  let totalLength = 0;
6842
6866
  for (let i = 0; i < route.length; i++) {
6843
- const point4 = route[i];
6844
- if (point4.route_type === "wire") {
6867
+ const point6 = route[i];
6868
+ if (point6.route_type === "wire") {
6845
6869
  const nextPoint = route[i + 1];
6846
6870
  if (nextPoint) {
6847
- const dx = nextPoint.x - point4.x;
6848
- const dy = nextPoint.y - point4.y;
6871
+ const dx = nextPoint.x - point6.x;
6872
+ const dy = nextPoint.y - point6.y;
6849
6873
  totalLength += Math.sqrt(dx * dx + dy * dy);
6850
6874
  }
6851
- } else if (point4.route_type === "via") {
6875
+ } else if (point6.route_type === "via") {
6852
6876
  totalLength += 1.6;
6853
6877
  }
6854
6878
  }
@@ -7158,17 +7182,17 @@ function Trace_doInitialPcbTraceRender(trace) {
7158
7182
  });
7159
7183
  trace._portsRoutedOnPcb = ports;
7160
7184
  trace.pcb_trace_id = pcb_trace.pcb_trace_id;
7161
- for (const point4 of mergedRoute) {
7162
- if (point4.route_type === "via") {
7185
+ for (const point6 of mergedRoute) {
7186
+ if (point6.route_type === "via") {
7163
7187
  db.pcb_via.insert({
7164
7188
  pcb_trace_id: pcb_trace.pcb_trace_id,
7165
- x: point4.x,
7166
- y: point4.y,
7189
+ x: point6.x,
7190
+ y: point6.y,
7167
7191
  hole_diameter: holeDiameter,
7168
7192
  outer_diameter: padDiameter,
7169
- layers: [point4.from_layer, point4.to_layer],
7170
- from_layer: point4.from_layer,
7171
- to_layer: point4.to_layer
7193
+ layers: [point6.from_layer, point6.to_layer],
7194
+ from_layer: point6.from_layer,
7195
+ to_layer: point6.to_layer
7172
7196
  });
7173
7197
  }
7174
7198
  }
@@ -7830,7 +7854,15 @@ var Trace3 = class extends PrimitiveComponent2 {
7830
7854
  }
7831
7855
  _insertErrorIfTraceIsOutsideBoard(mergedRoute, ports) {
7832
7856
  const { db } = this.root;
7833
- const isOutsideBoard = isRouteOutsideBoard(mergedRoute, { db });
7857
+ const board = this._getBoard();
7858
+ if (!board) return;
7859
+ const pcbBoardId = board.pcb_board_id;
7860
+ if (!pcbBoardId) return;
7861
+ const isOutsideBoard = isRouteOutsideBoard({
7862
+ mergedRoute,
7863
+ db,
7864
+ pcbBoardId
7865
+ });
7834
7866
  if (isOutsideBoard) {
7835
7867
  db.pcb_trace_error.insert({
7836
7868
  error_type: "pcb_trace_error",
@@ -10553,7 +10585,7 @@ var getSimpleRouteJsonFromCircuitJson = ({
10553
10585
  layerCount: board?.num_layers ?? 2,
10554
10586
  minTraceWidth,
10555
10587
  nominalTraceWidth,
10556
- outline: board?.outline?.map((point4) => ({ ...point4 }))
10588
+ outline: board?.outline?.map((point6) => ({ ...point6 }))
10557
10589
  },
10558
10590
  connMap
10559
10591
  };
@@ -14249,16 +14281,16 @@ function splitRouteAtJumperPads(route, padInfos) {
14249
14281
  const segments = [];
14250
14282
  let currentSegment = [];
14251
14283
  for (let i = 0; i < route.length; i++) {
14252
- const point4 = route[i];
14253
- currentSegment.push(point4);
14254
- if (point4.route_type === "wire" && i > 0 && i < route.length - 1) {
14255
- const padInfo = findJumperPortContainingPoint(padInfos, point4.x, point4.y);
14284
+ const point6 = route[i];
14285
+ currentSegment.push(point6);
14286
+ if (point6.route_type === "wire" && i > 0 && i < route.length - 1) {
14287
+ const padInfo = findJumperPortContainingPoint(padInfos, point6.x, point6.y);
14256
14288
  if (padInfo) {
14257
- if (!point4.end_pcb_port_id) {
14258
- point4.end_pcb_port_id = padInfo.pcb_port_id;
14289
+ if (!point6.end_pcb_port_id) {
14290
+ point6.end_pcb_port_id = padInfo.pcb_port_id;
14259
14291
  }
14260
14292
  segments.push(currentSegment);
14261
- const newStartPoint = { ...point4 };
14293
+ const newStartPoint = { ...point6 };
14262
14294
  delete newStartPoint.end_pcb_port_id;
14263
14295
  if (!newStartPoint.start_pcb_port_id) {
14264
14296
  newStartPoint.start_pcb_port_id = padInfo.pcb_port_id;
@@ -14396,9 +14428,9 @@ var Group6 = class extends NormalComponent3 {
14396
14428
  const { _parsedProps: props } = this;
14397
14429
  const groupProps2 = props;
14398
14430
  const hasOutline = groupProps2.outline && groupProps2.outline.length > 0;
14399
- const numericOutline = hasOutline ? groupProps2.outline.map((point4) => ({
14400
- x: distance8.parse(point4.x),
14401
- y: distance8.parse(point4.y)
14431
+ const numericOutline = hasOutline ? groupProps2.outline.map((point6) => ({
14432
+ x: distance8.parse(point6.x),
14433
+ y: distance8.parse(point6.y)
14402
14434
  })) : void 0;
14403
14435
  const ctx = this.props;
14404
14436
  const anchorPosition = this._getGlobalPcbPositionBeforeLayout();
@@ -14435,9 +14467,9 @@ var Group6 = class extends NormalComponent3 {
14435
14467
  const hasOutline = props.outline && props.outline.length > 0;
14436
14468
  const hasExplicitPositioning = this._parsedProps.pcbX !== void 0 || this._parsedProps.pcbY !== void 0;
14437
14469
  if (hasOutline) {
14438
- const numericOutline = props.outline.map((point4) => ({
14439
- x: distance8.parse(point4.x),
14440
- y: distance8.parse(point4.y)
14470
+ const numericOutline = props.outline.map((point6) => ({
14471
+ x: distance8.parse(point6.x),
14472
+ y: distance8.parse(point6.y)
14441
14473
  }));
14442
14474
  const outlineBounds = getBoundsFromPoints3(numericOutline);
14443
14475
  if (!outlineBounds) return;
@@ -14907,20 +14939,20 @@ var Group6 = class extends NormalComponent3 {
14907
14939
  continue;
14908
14940
  }
14909
14941
  if (pcb_trace.type === "pcb_trace") {
14910
- for (const point4 of pcb_trace.route) {
14911
- if (point4.route_type === "via") {
14942
+ for (const point6 of pcb_trace.route) {
14943
+ if (point6.route_type === "via") {
14912
14944
  db.pcb_via.insert({
14913
14945
  pcb_trace_id: pcb_trace.pcb_trace_id,
14914
- x: point4.x,
14915
- y: point4.y,
14946
+ x: point6.x,
14947
+ y: point6.y,
14916
14948
  hole_diameter: holeDiameter,
14917
14949
  outer_diameter: padDiameter,
14918
14950
  layers: [
14919
- point4.from_layer,
14920
- point4.to_layer
14951
+ point6.from_layer,
14952
+ point6.to_layer
14921
14953
  ],
14922
- from_layer: point4.from_layer,
14923
- to_layer: point4.to_layer
14954
+ from_layer: point6.from_layer,
14955
+ to_layer: point6.to_layer
14924
14956
  });
14925
14957
  }
14926
14958
  }
@@ -16410,9 +16442,9 @@ var Board = class extends Group6 {
16410
16442
  center
16411
16443
  };
16412
16444
  if (outline) {
16413
- update.outline = outline.map((point4) => ({
16414
- x: point4.x + (props.outlineOffsetX ?? 0),
16415
- y: point4.y + (props.outlineOffsetY ?? 0)
16445
+ update.outline = outline.map((point6) => ({
16446
+ x: point6.x + (props.outlineOffsetX ?? 0),
16447
+ y: point6.y + (props.outlineOffsetY ?? 0)
16416
16448
  }));
16417
16449
  }
16418
16450
  db.pcb_board.update(this.pcb_board_id, update);
@@ -16499,8 +16531,8 @@ var Board = class extends Group6 {
16499
16531
  });
16500
16532
  }
16501
16533
  if (props.outline) {
16502
- const xValues = props.outline.map((point4) => point4.x);
16503
- const yValues = props.outline.map((point4) => point4.y);
16534
+ const xValues = props.outline.map((point6) => point6.x);
16535
+ const yValues = props.outline.map((point6) => point6.y);
16504
16536
  const minX = Math.min(...xValues);
16505
16537
  const maxX = Math.max(...xValues);
16506
16538
  const minY = Math.min(...yValues);
@@ -16535,9 +16567,9 @@ var Board = class extends Group6 {
16535
16567
  num_layers: this.allLayers.length,
16536
16568
  width: computedWidth,
16537
16569
  height: computedHeight,
16538
- outline: outline?.map((point4) => ({
16539
- x: point4.x + (props.outlineOffsetX ?? 0) + outlineTranslation.x,
16540
- y: point4.y + (props.outlineOffsetY ?? 0) + outlineTranslation.y
16570
+ outline: outline?.map((point6) => ({
16571
+ x: point6.x + (props.outlineOffsetX ?? 0) + outlineTranslation.x,
16572
+ y: point6.y + (props.outlineOffsetY ?? 0) + outlineTranslation.y
16541
16573
  })),
16542
16574
  material: props.material
16543
16575
  });
@@ -16654,7 +16686,7 @@ import { distance as distance11 } from "circuit-json";
16654
16686
 
16655
16687
  // lib/utils/panels/generate-panel-tabs-and-mouse-bites.ts
16656
16688
  import * as Flatten from "@flatten-js/core";
16657
- import { point as point2, Polygon as Polygon2 } from "@flatten-js/core";
16689
+ import { point as point5, Polygon as Polygon3 } from "@flatten-js/core";
16658
16690
  var DEFAULT_TAB_LENGTH = 5;
16659
16691
  var DEFAULT_TAB_WIDTH = 2;
16660
16692
  var generateCutoutsAndMousebitesForOutline = (outline, options) => {
@@ -16790,8 +16822,8 @@ function generatePanelTabsAndMouseBites(boards, options) {
16790
16822
  if (board.width && board.height) {
16791
16823
  boardDimensions.push(Math.min(board.width, board.height));
16792
16824
  } else if (board.outline && board.outline.length > 0) {
16793
- const outlinePolygon = new Polygon2(
16794
- board.outline.map((p) => point2(p.x, p.y))
16825
+ const outlinePolygon = new Polygon3(
16826
+ board.outline.map((p) => point5(p.x, p.y))
16795
16827
  );
16796
16828
  const area = Math.abs(outlinePolygon.area());
16797
16829
  if (area > 0) {
@@ -18029,10 +18061,10 @@ var FabricationNotePath = class extends PrimitiveComponent2 {
18029
18061
  const { _parsedProps: props } = this;
18030
18062
  if (props.route.length === 0) return { width: 0, height: 0 };
18031
18063
  const xs = props.route.map(
18032
- (point4) => typeof point4.x === "string" ? parseFloat(point4.x) : point4.x
18064
+ (point6) => typeof point6.x === "string" ? parseFloat(point6.x) : point6.x
18033
18065
  );
18034
18066
  const ys = props.route.map(
18035
- (point4) => typeof point4.y === "string" ? parseFloat(point4.y) : point4.y
18067
+ (point6) => typeof point6.y === "string" ? parseFloat(point6.y) : point6.y
18036
18068
  );
18037
18069
  const minX = Math.min(...xs);
18038
18070
  const maxX = Math.max(...xs);
@@ -18450,8 +18482,8 @@ var PcbNotePath = class extends PrimitiveComponent2 {
18450
18482
  const subcircuit = this.getSubcircuit();
18451
18483
  const group = this.getGroup();
18452
18484
  const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id ?? void 0;
18453
- const transformedRoute = props.route.map((point4) => {
18454
- const { x, y, ...rest } = point4;
18485
+ const transformedRoute = props.route.map((point6) => {
18486
+ const { x, y, ...rest } = point6;
18455
18487
  const numericX = typeof x === "string" ? parseFloat(x) : x;
18456
18488
  const numericY = typeof y === "string" ? parseFloat(y) : y;
18457
18489
  const transformed = applyToPoint15(transform, { x: numericX, y: numericY });
@@ -18471,10 +18503,10 @@ var PcbNotePath = class extends PrimitiveComponent2 {
18471
18503
  const { _parsedProps: props } = this;
18472
18504
  if (props.route.length === 0) return { width: 0, height: 0 };
18473
18505
  const xs = props.route.map(
18474
- (point4) => typeof point4.x === "string" ? parseFloat(point4.x) : point4.x
18506
+ (point6) => typeof point6.x === "string" ? parseFloat(point6.x) : point6.x
18475
18507
  );
18476
18508
  const ys = props.route.map(
18477
- (point4) => typeof point4.y === "string" ? parseFloat(point4.y) : point4.y
18509
+ (point6) => typeof point6.y === "string" ? parseFloat(point6.y) : point6.y
18478
18510
  );
18479
18511
  const minX = Math.min(...xs);
18480
18512
  const maxX = Math.max(...xs);
@@ -18750,11 +18782,11 @@ var BreakoutPoint = class extends PrimitiveComponent2 {
18750
18782
  if (this.root?.pcbDisabled) return;
18751
18783
  const { db } = this.root;
18752
18784
  if (!this.pcb_breakout_point_id) return;
18753
- const point4 = db.pcb_breakout_point.get(this.pcb_breakout_point_id);
18754
- if (point4) {
18785
+ const point6 = db.pcb_breakout_point.get(this.pcb_breakout_point_id);
18786
+ if (point6) {
18755
18787
  db.pcb_breakout_point.update(this.pcb_breakout_point_id, {
18756
- x: point4.x + deltaX,
18757
- y: point4.y + deltaY
18788
+ x: point6.x + deltaX,
18789
+ y: point6.y + deltaY
18758
18790
  });
18759
18791
  }
18760
18792
  }
@@ -20325,9 +20357,9 @@ var SchematicPath = class extends PrimitiveComponent2 {
20325
20357
  const schematic_component_id = this.getPrimitiveContainer()?.parent?.schematic_component_id;
20326
20358
  db.schematic_path.insert({
20327
20359
  schematic_component_id,
20328
- points: props.points.map((point4) => ({
20329
- x: point4.x + globalPos.x,
20330
- y: point4.y + globalPos.y
20360
+ points: props.points.map((point6) => ({
20361
+ x: point6.x + globalPos.x,
20362
+ y: point6.y + globalPos.y
20331
20363
  })),
20332
20364
  is_filled: props.isFilled,
20333
20365
  fill_color: props.fillColor,
@@ -21002,7 +21034,7 @@ import { identity as identity5 } from "transformation-matrix";
21002
21034
  var package_default = {
21003
21035
  name: "@tscircuit/core",
21004
21036
  type: "module",
21005
- version: "0.0.984",
21037
+ version: "0.0.986",
21006
21038
  types: "dist/index.d.ts",
21007
21039
  main: "dist/index.js",
21008
21040
  module: "dist/index.js",
@@ -21152,6 +21184,8 @@ var RootCircuit = class {
21152
21184
  */
21153
21185
  projectUrl;
21154
21186
  _hasRenderedAtleastOnce = false;
21187
+ _asyncEffectIdsByPhase = /* @__PURE__ */ new Map();
21188
+ _asyncEffectPhaseById = /* @__PURE__ */ new Map();
21155
21189
  constructor({
21156
21190
  platform,
21157
21191
  projectUrl
@@ -21244,8 +21278,12 @@ var RootCircuit = class {
21244
21278
  this.emit("renderComplete");
21245
21279
  }
21246
21280
  _hasIncompleteAsyncEffects() {
21281
+ if (this._asyncEffectPhaseById.size > 0) return true;
21247
21282
  return this.children.some((child) => child._hasIncompleteAsyncEffects());
21248
21283
  }
21284
+ _hasIncompleteAsyncEffectsForPhase(phase) {
21285
+ return (this._asyncEffectIdsByPhase.get(phase)?.size ?? 0) > 0;
21286
+ }
21249
21287
  getCircuitJson() {
21250
21288
  if (!this._hasRenderedAtleastOnce) this.render();
21251
21289
  return this.db.toArray();
@@ -21295,6 +21333,11 @@ var RootCircuit = class {
21295
21333
  }
21296
21334
  _eventListeners = {};
21297
21335
  emit(event, ...args) {
21336
+ if (event === "asyncEffect:start") {
21337
+ this._registerAsyncEffectStart(args[0]);
21338
+ } else if (event === "asyncEffect:end") {
21339
+ this._registerAsyncEffectEnd(args[0]);
21340
+ }
21298
21341
  if (!this._eventListeners[event]) return;
21299
21342
  for (const listener of this._eventListeners[event]) {
21300
21343
  listener(...args);
@@ -21328,6 +21371,32 @@ var RootCircuit = class {
21328
21371
  }
21329
21372
  return "";
21330
21373
  }
21374
+ _registerAsyncEffectStart(payload) {
21375
+ if (!payload?.asyncEffectId || !payload.phase) return;
21376
+ const { asyncEffectId, phase } = payload;
21377
+ const existingPhase = this._asyncEffectPhaseById.get(asyncEffectId);
21378
+ if (existingPhase && existingPhase !== phase) {
21379
+ this._asyncEffectIdsByPhase.get(existingPhase)?.delete(asyncEffectId);
21380
+ }
21381
+ if (!this._asyncEffectIdsByPhase.has(phase)) {
21382
+ this._asyncEffectIdsByPhase.set(phase, /* @__PURE__ */ new Set());
21383
+ }
21384
+ this._asyncEffectIdsByPhase.get(phase).add(asyncEffectId);
21385
+ this._asyncEffectPhaseById.set(asyncEffectId, phase);
21386
+ }
21387
+ _registerAsyncEffectEnd(payload) {
21388
+ if (!payload?.asyncEffectId) return;
21389
+ const { asyncEffectId } = payload;
21390
+ const phase = this._asyncEffectPhaseById.get(asyncEffectId) ?? payload.phase;
21391
+ if (phase) {
21392
+ const phaseSet = this._asyncEffectIdsByPhase.get(phase);
21393
+ phaseSet?.delete(asyncEffectId);
21394
+ if (phaseSet && phaseSet.size === 0) {
21395
+ this._asyncEffectIdsByPhase.delete(phase);
21396
+ }
21397
+ }
21398
+ this._asyncEffectPhaseById.delete(asyncEffectId);
21399
+ }
21331
21400
  };
21332
21401
  var Project = RootCircuit;
21333
21402
  var Circuit = RootCircuit;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.985",
4
+ "version": "0.0.987",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",