@tscircuit/core 0.0.203 → 0.0.205

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
@@ -41,6 +41,8 @@ declare abstract class Renderable implements IRenderable {
41
41
  constructor(props: any);
42
42
  protected _markDirty(phase: RenderPhase): void;
43
43
  protected _queueAsyncEffect(effect: () => Promise<void>): void;
44
+ protected _emitRenderLifecycleEvent(phase: RenderPhase, eventType: "start" | "end"): void;
45
+ getString(): string;
44
46
  _hasIncompleteAsyncEffects(): boolean;
45
47
  getCurrentRenderPhase(): RenderPhase | null;
46
48
  getRenderGraph(): Record<string, any>;
@@ -79,7 +81,7 @@ interface SchematicBoxDimensions {
79
81
  };
80
82
  }
81
83
 
82
- type RootCircuitEventName = "asyncEffectComplete";
84
+ type RootCircuitEventName = "asyncEffectComplete" | "renderable:renderLifecycle:anyEvent" | `renderable:renderLifecycle:${RenderPhase}:start` | `renderable:renderLifecycle:${RenderPhase}:end`;
83
85
  declare class Circuit {
84
86
  firstChild: PrimitiveComponent | null;
85
87
  children: PrimitiveComponent[];
@@ -937,7 +939,7 @@ declare class Board extends Group<typeof boardProps> {
937
939
  serverUrl?: string | undefined;
938
940
  inputFormat?: "simplified" | "circuit-json" | undefined;
939
941
  cache?: _tscircuit_props.PcbRouteCache | undefined;
940
- }>, z.ZodLiteral<"auto">, z.ZodLiteral<"auto-local">, z.ZodLiteral<"auto-cloud">]>>;
942
+ }>, z.ZodLiteral<"sequential-trace">, z.ZodLiteral<"subcircuit">, z.ZodLiteral<"auto">, z.ZodLiteral<"auto-local">, z.ZodLiteral<"auto-cloud">]>>;
941
943
  }>, {
942
944
  width: z.ZodOptional<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, number, string | number>>;
943
945
  height: z.ZodOptional<z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, number, string | number>>;
@@ -970,7 +972,7 @@ declare class Board extends Group<typeof boardProps> {
970
972
  defaultTraceWidth?: number | undefined;
971
973
  minTraceWidth?: number | undefined;
972
974
  pcbRouteCache?: _tscircuit_props.PcbRouteCache | undefined;
973
- autorouter?: "auto" | "auto-local" | "auto-cloud" | {
975
+ autorouter?: "sequential-trace" | "subcircuit" | "auto" | "auto-local" | "auto-cloud" | {
974
976
  serverUrl?: string | undefined;
975
977
  inputFormat?: "simplified" | "circuit-json" | undefined;
976
978
  cache?: _tscircuit_props.PcbRouteCache | undefined;
@@ -1002,7 +1004,7 @@ declare class Board extends Group<typeof boardProps> {
1002
1004
  defaultTraceWidth?: string | number | undefined;
1003
1005
  minTraceWidth?: string | number | undefined;
1004
1006
  pcbRouteCache?: _tscircuit_props.PcbRouteCache | undefined;
1005
- autorouter?: "auto" | "auto-local" | "auto-cloud" | {
1007
+ autorouter?: "sequential-trace" | "subcircuit" | "auto" | "auto-local" | "auto-cloud" | {
1006
1008
  serverUrl?: string | undefined;
1007
1009
  inputFormat?: "simplified" | "circuit-json" | undefined;
1008
1010
  cache?: _tscircuit_props.PcbRouteCache | undefined;
package/dist/index.js CHANGED
@@ -143,6 +143,27 @@ var Renderable = class {
143
143
  }
144
144
  });
145
145
  }
146
+ _emitRenderLifecycleEvent(phase, eventType) {
147
+ const eventPayload = {
148
+ renderId: this._renderId,
149
+ componentDisplayName: this.getString()
150
+ };
151
+ const eventName = `renderable:renderLifecycle:${phase}:${eventType}`;
152
+ if ("root" in this && this.root) {
153
+ ;
154
+ this.root.emit(eventName, {
155
+ ...eventPayload,
156
+ type: eventName
157
+ });
158
+ this.root.emit("renderable:renderLifecycle:anyEvent", {
159
+ ...eventPayload,
160
+ type: eventName
161
+ });
162
+ }
163
+ }
164
+ getString() {
165
+ return this.constructor.name;
166
+ }
146
167
  _hasIncompleteAsyncEffects() {
147
168
  return this._asyncEffects.some((effect) => !effect.complete);
148
169
  }
@@ -150,7 +171,7 @@ var Renderable = class {
150
171
  return this._currentRenderPhase;
151
172
  }
152
173
  getRenderGraph() {
153
- const graph = {
174
+ return {
154
175
  id: this._renderId,
155
176
  currentPhase: this._currentRenderPhase,
156
177
  renderPhaseStates: this.renderPhaseStates,
@@ -159,7 +180,6 @@ var Renderable = class {
159
180
  (child) => child.getRenderGraph()
160
181
  )
161
182
  };
162
- return graph;
163
183
  }
164
184
  runRenderCycle() {
165
185
  for (const renderPhase of orderedRenderPhases) {
@@ -181,10 +201,11 @@ var Renderable = class {
181
201
  const isDirty = phaseState.dirty;
182
202
  if (!isInitialized && this.shouldBeRemoved) return;
183
203
  if (this.shouldBeRemoved && isInitialized) {
184
- ;
204
+ this._emitRenderLifecycleEvent(phase, "start");
185
205
  this?.[`remove${phase}`]?.();
186
206
  phaseState.initialized = false;
187
207
  phaseState.dirty = false;
208
+ this._emitRenderLifecycleEvent(phase, "end");
188
209
  return;
189
210
  }
190
211
  const prevPhaseIndex = orderedRenderPhases.indexOf(phase) - 1;
@@ -193,17 +214,20 @@ var Renderable = class {
193
214
  const hasIncompleteEffects = this._asyncEffects.filter((e) => e.phase === prevPhase).some((e) => !e.complete);
194
215
  if (hasIncompleteEffects) return;
195
216
  }
217
+ this._emitRenderLifecycleEvent(phase, "start");
196
218
  if (isInitialized) {
197
219
  if (isDirty) {
198
220
  ;
199
221
  this?.[`update${phase}`]?.();
200
222
  phaseState.dirty = false;
201
223
  }
224
+ this._emitRenderLifecycleEvent(phase, "end");
202
225
  return;
203
226
  }
204
227
  phaseState.dirty = false;
205
228
  this?.[`doInitial${phase}`]?.();
206
229
  phaseState.initialized = true;
230
+ this._emitRenderLifecycleEvent(phase, "end");
207
231
  }
208
232
  runRenderPhaseForChildren(phase) {
209
233
  for (const child of this.children) {
@@ -1243,6 +1267,7 @@ var SmtPad = class extends PrimitiveComponent {
1243
1267
  );
1244
1268
  const isRotated90 = Math.abs(decomposedMat.rotation.angle * (180 / Math.PI) - 90) % 180 < 0.01;
1245
1269
  const { maybeFlipLayer } = this._getPcbPrimitiveFlippedHelpers();
1270
+ const parentRotation = container?._parsedProps.pcbRotation ?? 0;
1246
1271
  let pcb_smtpad = null;
1247
1272
  const pcb_component_id = this.parent?.pcb_component_id ?? this.getPrimitiveContainer()?.pcb_component_id;
1248
1273
  if (props.shape === "circle") {
@@ -1269,16 +1294,28 @@ var SmtPad = class extends PrimitiveComponent {
1269
1294
  pcb_smtpad_id: pcb_smtpad.pcb_smtpad_id
1270
1295
  });
1271
1296
  } else if (props.shape === "rect") {
1272
- pcb_smtpad = db.pcb_smtpad.insert({
1297
+ pcb_smtpad = parentRotation === 0 ? db.pcb_smtpad.insert({
1273
1298
  pcb_component_id,
1274
1299
  pcb_port_id: this.matchedPort?.pcb_port_id,
1275
1300
  // port likely isn't matched
1276
1301
  layer: maybeFlipLayer(props.layer ?? "top"),
1277
1302
  shape: "rect",
1278
- ...isRotated90 ? { width: props.height, height: props.width } : { width: props.width, height: props.height },
1303
+ ...{
1304
+ width: isRotated90 ? props.height : props.width,
1305
+ height: isRotated90 ? props.width : props.height
1306
+ },
1279
1307
  port_hints: props.portHints.map((ph) => ph.toString()),
1280
1308
  x: position.x,
1281
1309
  y: position.y
1310
+ }) : db.pcb_smtpad.insert({
1311
+ pcb_component_id,
1312
+ layer: props.layer ?? "top",
1313
+ shape: "rotated_rect",
1314
+ ...{ width: props.width, height: props.height },
1315
+ x: position.x,
1316
+ y: position.y,
1317
+ ccw_rotation: parentRotation,
1318
+ port_hints: props.portHints.map((ph) => ph.toString())
1282
1319
  });
1283
1320
  if (pcb_smtpad.shape === "rect")
1284
1321
  db.pcb_solder_paste.insert({
@@ -1319,6 +1356,26 @@ var SmtPad = class extends PrimitiveComponent {
1319
1356
  height: smtpad.height
1320
1357
  };
1321
1358
  }
1359
+ if (smtpad.shape === "rotated_rect") {
1360
+ const angleRad = smtpad.ccw_rotation * Math.PI / 180;
1361
+ const cosAngle = Math.cos(angleRad);
1362
+ const sinAngle = Math.sin(angleRad);
1363
+ const w2 = smtpad.width / 2;
1364
+ const h2 = smtpad.height / 2;
1365
+ const xExtent = Math.abs(w2 * cosAngle) + Math.abs(h2 * sinAngle);
1366
+ const yExtent = Math.abs(w2 * sinAngle) + Math.abs(h2 * cosAngle);
1367
+ return {
1368
+ center: { x: smtpad.x, y: smtpad.y },
1369
+ bounds: {
1370
+ left: smtpad.x - xExtent,
1371
+ right: smtpad.x + xExtent,
1372
+ top: smtpad.y - yExtent,
1373
+ bottom: smtpad.y + yExtent
1374
+ },
1375
+ width: xExtent * 2,
1376
+ height: yExtent * 2
1377
+ };
1378
+ }
1322
1379
  if (smtpad.shape === "circle") {
1323
1380
  return {
1324
1381
  center: { x: smtpad.x, y: smtpad.y },
@@ -5580,7 +5637,7 @@ var Circuit = class {
5580
5637
  this._guessRootComponent();
5581
5638
  return this.firstChild?.selectOne(selector, opts) ?? null;
5582
5639
  }
5583
- _eventListeners = { asyncEffectComplete: [] };
5640
+ _eventListeners = {};
5584
5641
  emit(event, ...args) {
5585
5642
  if (!this._eventListeners[event]) return;
5586
5643
  for (const listener of this._eventListeners[event]) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.203",
4
+ "version": "0.0.205",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -41,11 +41,12 @@
41
41
  "@tscircuit/footprinter": "^0.0.89",
42
42
  "@tscircuit/infgrid-ijump-astar": "^0.0.24",
43
43
  "@tscircuit/math-utils": "^0.0.5",
44
- "@tscircuit/props": "^0.0.105",
45
- "@tscircuit/schematic-autolayout": "^0.0.6",
46
- "@tscircuit/soup-util": "^0.0.40",
47
44
  "circuit-json": "^0.0.108",
48
45
  "circuit-json-to-connectivity-map": "^0.0.17",
46
+ "@tscircuit/props": "^0.0.106",
47
+ "@tscircuit/schematic-autolayout": "^0.0.6",
48
+ "@tscircuit/soup-util": "^0.0.41",
49
+ "circuit-to-svg": "0.0.84",
49
50
  "format-si-unit": "^0.0.2",
50
51
  "nanoid": "^5.0.7",
51
52
  "performance-now": "^2.1.0",