@tscircuit/core 0.0.28 → 0.0.29
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 +18 -2
- package/dist/index.js +57 -5
- package/lib/components/base-components/NormalComponent.ts +31 -4
- package/lib/components/base-components/PrimitiveComponent.ts +3 -0
- package/lib/components/base-components/Renderable.ts +1 -1
- package/lib/components/primitive-components/PlatedHole.ts +13 -0
- package/lib/components/primitive-components/SmtPad.ts +13 -0
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -36,7 +36,7 @@ declare class Circuit {
|
|
|
36
36
|
}
|
|
37
37
|
declare const Project: typeof Circuit;
|
|
38
38
|
|
|
39
|
-
declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "CreateNetsFromProps", "CreateTracesFromProps", "SourceRender", "SourceParentAttachment", "PortDiscovery", "PortMatching", "SourceTraceRender", "SchematicComponentRender", "SchematicLayout", "SchematicPortRender", "SchematicTraceRender", "PcbComponentRender", "PcbPortRender", "PcbPrimitiveRender", "PcbParentAttachment", "PcbLayout", "PcbTraceRender", "PcbRouteNetIslands", "
|
|
39
|
+
declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "CreateNetsFromProps", "CreateTracesFromProps", "SourceRender", "SourceParentAttachment", "PortDiscovery", "PortMatching", "SourceTraceRender", "SchematicComponentRender", "SchematicLayout", "SchematicPortRender", "SchematicTraceRender", "PcbComponentRender", "PcbPortRender", "PcbPrimitiveRender", "PcbParentAttachment", "PcbLayout", "PcbTraceRender", "PcbRouteNetIslands", "PcbComponentSizeCalculation", "CadModelRender"];
|
|
40
40
|
type RenderPhase = (typeof orderedRenderPhases)[number];
|
|
41
41
|
type RenderPhaseFn<K extends RenderPhase = RenderPhase> = `doInitial${K}` | `update${K}` | `remove${K}`;
|
|
42
42
|
type RenderPhaseStates = Record<RenderPhase, {
|
|
@@ -170,6 +170,10 @@ declare abstract class PrimitiveComponent<ZodProps extends ZodType = any> extend
|
|
|
170
170
|
getNameAndAliases(): string[];
|
|
171
171
|
isMatchingNameOrAlias(name: string): boolean;
|
|
172
172
|
isMatchingAnyOf(aliases: Array<string | number>): boolean;
|
|
173
|
+
getPcbSize(): {
|
|
174
|
+
width: number;
|
|
175
|
+
height: number;
|
|
176
|
+
};
|
|
173
177
|
doesSelectorMatch(selector: string): boolean;
|
|
174
178
|
getSubcircuit(): PrimitiveComponent;
|
|
175
179
|
selectAll(selector: string): PrimitiveComponent[];
|
|
@@ -548,7 +552,11 @@ declare class NormalComponent<ZodProps extends ZodType = any, PortNames extends
|
|
|
548
552
|
*/
|
|
549
553
|
doInitialSchematicComponentRender(): void;
|
|
550
554
|
doInitialPcbComponentRender(): void;
|
|
551
|
-
|
|
555
|
+
/**
|
|
556
|
+
* At this stage, the smtpads/pcb primitives are placed, so we can compute
|
|
557
|
+
* the width/height of the component
|
|
558
|
+
*/
|
|
559
|
+
doInitialPcbComponentSizeCalculation(): void;
|
|
552
560
|
_renderReactSubtree(element: ReactElement): ReactSubtree;
|
|
553
561
|
doInitialReactSubtreesRender(): void;
|
|
554
562
|
add(componentOrElm: PrimitiveComponent | ReactElement): void;
|
|
@@ -705,6 +713,10 @@ declare class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
|
|
|
705
713
|
height?: string | number | undefined;
|
|
706
714
|
}>]>;
|
|
707
715
|
};
|
|
716
|
+
getPcbSize(): {
|
|
717
|
+
width: number;
|
|
718
|
+
height: number;
|
|
719
|
+
};
|
|
708
720
|
doInitialPortMatching(): void;
|
|
709
721
|
doInitialPcbPrimitiveRender(): void;
|
|
710
722
|
}
|
|
@@ -3329,6 +3341,10 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
3329
3341
|
portHints?: (string | number)[] | undefined;
|
|
3330
3342
|
}>]>;
|
|
3331
3343
|
};
|
|
3344
|
+
getPcbSize(): {
|
|
3345
|
+
width: number;
|
|
3346
|
+
height: number;
|
|
3347
|
+
};
|
|
3332
3348
|
doInitialPortMatching(): void;
|
|
3333
3349
|
doInitialPcbPrimitiveRender(): void;
|
|
3334
3350
|
}
|
package/dist/index.js
CHANGED
|
@@ -56,8 +56,8 @@ var orderedRenderPhases = [
|
|
|
56
56
|
"PcbLayout",
|
|
57
57
|
"PcbTraceRender",
|
|
58
58
|
"PcbRouteNetIslands",
|
|
59
|
-
"
|
|
60
|
-
"
|
|
59
|
+
"PcbComponentSizeCalculation",
|
|
60
|
+
"CadModelRender"
|
|
61
61
|
];
|
|
62
62
|
var globalRenderCounter = 0;
|
|
63
63
|
var Renderable = class {
|
|
@@ -370,6 +370,9 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
370
370
|
(a) => aliases.map((a2) => a2.toString()).includes(a)
|
|
371
371
|
);
|
|
372
372
|
}
|
|
373
|
+
getPcbSize() {
|
|
374
|
+
throw new Error(`getPcbSize not implemented for ${this.componentName}`);
|
|
375
|
+
}
|
|
373
376
|
doesSelectorMatch(selector) {
|
|
374
377
|
const myTypeNames = [this.componentName, this.lowercaseComponentName];
|
|
375
378
|
const myClassNames = [this._parsedProps.name].filter(Boolean);
|
|
@@ -840,6 +843,18 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
840
843
|
zodProps: smtPadProps
|
|
841
844
|
};
|
|
842
845
|
}
|
|
846
|
+
getPcbSize() {
|
|
847
|
+
const { _parsedProps: props } = this;
|
|
848
|
+
if (props.shape === "circle") {
|
|
849
|
+
return { width: props.radius * 2, height: props.radius * 2 };
|
|
850
|
+
}
|
|
851
|
+
if (props.shape === "rect") {
|
|
852
|
+
return { width: props.width, height: props.height };
|
|
853
|
+
}
|
|
854
|
+
throw new Error(
|
|
855
|
+
`getPcbSize for shape "${props.shape}" not implemented for ${this.componentName}`
|
|
856
|
+
);
|
|
857
|
+
}
|
|
843
858
|
doInitialPortMatching() {
|
|
844
859
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
845
860
|
(c) => c.componentName === "Port"
|
|
@@ -944,6 +959,18 @@ var PlatedHole = class extends PrimitiveComponent {
|
|
|
944
959
|
zodProps: platedHoleProps
|
|
945
960
|
};
|
|
946
961
|
}
|
|
962
|
+
getPcbSize() {
|
|
963
|
+
const { _parsedProps: props } = this;
|
|
964
|
+
if (props.shape === "circle") {
|
|
965
|
+
return { width: props.outerDiameter, height: props.outerDiameter };
|
|
966
|
+
}
|
|
967
|
+
if (props.shape === "oval") {
|
|
968
|
+
return { width: props.outerWidth, height: props.outerHeight };
|
|
969
|
+
}
|
|
970
|
+
throw new Error(
|
|
971
|
+
`getPcbSize for shape "${props.shape}" not implemented for ${this.componentName}`
|
|
972
|
+
);
|
|
973
|
+
}
|
|
947
974
|
doInitialPortMatching() {
|
|
948
975
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
949
976
|
(c) => c.componentName === "Port"
|
|
@@ -1317,8 +1344,8 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1317
1344
|
const { db } = this.project;
|
|
1318
1345
|
const { _parsedProps: props } = this;
|
|
1319
1346
|
const pcb_component = db.pcb_component.insert({
|
|
1320
|
-
center:
|
|
1321
|
-
// width/height are computed in the
|
|
1347
|
+
center: this.getGlobalPcbPosition(),
|
|
1348
|
+
// width/height are computed in the PcbComponentSizeCalculation phase
|
|
1322
1349
|
width: 0,
|
|
1323
1350
|
height: 0,
|
|
1324
1351
|
layer: props.layer ?? "top",
|
|
@@ -1327,9 +1354,34 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
1327
1354
|
});
|
|
1328
1355
|
this.pcb_component_id = pcb_component.pcb_component_id;
|
|
1329
1356
|
}
|
|
1330
|
-
|
|
1357
|
+
/**
|
|
1358
|
+
* At this stage, the smtpads/pcb primitives are placed, so we can compute
|
|
1359
|
+
* the width/height of the component
|
|
1360
|
+
*/
|
|
1361
|
+
doInitialPcbComponentSizeCalculation() {
|
|
1362
|
+
if (!this.pcb_component_id) return;
|
|
1331
1363
|
const { db } = this.project;
|
|
1332
1364
|
const { _parsedProps: props } = this;
|
|
1365
|
+
let minX = Infinity;
|
|
1366
|
+
let minY = Infinity;
|
|
1367
|
+
let maxX = -Infinity;
|
|
1368
|
+
let maxY = -Infinity;
|
|
1369
|
+
for (const child of this.children) {
|
|
1370
|
+
if (child.isPcbPrimitive) {
|
|
1371
|
+
const { x, y } = child.getGlobalPcbPosition();
|
|
1372
|
+
const { width: width2, height: height2 } = child.getPcbSize();
|
|
1373
|
+
minX = Math.min(minX, x - width2 / 2);
|
|
1374
|
+
minY = Math.min(minY, y - height2 / 2);
|
|
1375
|
+
maxX = Math.max(maxX, x + width2 / 2);
|
|
1376
|
+
maxY = Math.max(maxY, y + height2 / 2);
|
|
1377
|
+
}
|
|
1378
|
+
}
|
|
1379
|
+
const width = maxX - minX;
|
|
1380
|
+
const height = maxY - minY;
|
|
1381
|
+
db.pcb_component.update(this.pcb_component_id, {
|
|
1382
|
+
width,
|
|
1383
|
+
height
|
|
1384
|
+
});
|
|
1333
1385
|
}
|
|
1334
1386
|
_renderReactSubtree(element) {
|
|
1335
1387
|
return {
|
|
@@ -194,8 +194,8 @@ export class NormalComponent<
|
|
|
194
194
|
const { db } = this.project!
|
|
195
195
|
const { _parsedProps: props } = this
|
|
196
196
|
const pcb_component = db.pcb_component.insert({
|
|
197
|
-
center:
|
|
198
|
-
// width/height are computed in the
|
|
197
|
+
center: this.getGlobalPcbPosition(),
|
|
198
|
+
// width/height are computed in the PcbComponentSizeCalculation phase
|
|
199
199
|
width: 0,
|
|
200
200
|
height: 0,
|
|
201
201
|
layer: props.layer ?? "top",
|
|
@@ -205,11 +205,38 @@ export class NormalComponent<
|
|
|
205
205
|
this.pcb_component_id = pcb_component.pcb_component_id
|
|
206
206
|
}
|
|
207
207
|
|
|
208
|
-
|
|
208
|
+
/**
|
|
209
|
+
* At this stage, the smtpads/pcb primitives are placed, so we can compute
|
|
210
|
+
* the width/height of the component
|
|
211
|
+
*/
|
|
212
|
+
doInitialPcbComponentSizeCalculation(): void {
|
|
213
|
+
if (!this.pcb_component_id) return
|
|
209
214
|
const { db } = this.project!
|
|
210
215
|
const { _parsedProps: props } = this
|
|
211
216
|
|
|
212
|
-
|
|
217
|
+
let minX = Infinity
|
|
218
|
+
let minY = Infinity
|
|
219
|
+
let maxX = -Infinity
|
|
220
|
+
let maxY = -Infinity
|
|
221
|
+
|
|
222
|
+
for (const child of this.children) {
|
|
223
|
+
if (child.isPcbPrimitive) {
|
|
224
|
+
const { x, y } = child.getGlobalPcbPosition()
|
|
225
|
+
const { width, height } = child.getPcbSize()
|
|
226
|
+
minX = Math.min(minX, x - width / 2)
|
|
227
|
+
minY = Math.min(minY, y - height / 2)
|
|
228
|
+
maxX = Math.max(maxX, x + width / 2)
|
|
229
|
+
maxY = Math.max(maxY, y + height / 2)
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
const width = maxX - minX
|
|
234
|
+
const height = maxY - minY
|
|
235
|
+
|
|
236
|
+
db.pcb_component.update(this.pcb_component_id!, {
|
|
237
|
+
width,
|
|
238
|
+
height,
|
|
239
|
+
})
|
|
213
240
|
}
|
|
214
241
|
|
|
215
242
|
_renderReactSubtree(element: ReactElement): ReactSubtree {
|
|
@@ -298,6 +298,9 @@ export abstract class PrimitiveComponent<
|
|
|
298
298
|
aliases.map((a) => a.toString()).includes(a),
|
|
299
299
|
)
|
|
300
300
|
}
|
|
301
|
+
getPcbSize(): { width: number; height: number } {
|
|
302
|
+
throw new Error(`getPcbSize not implemented for ${this.componentName}`)
|
|
303
|
+
}
|
|
301
304
|
|
|
302
305
|
doesSelectorMatch(selector: string): boolean {
|
|
303
306
|
const myTypeNames = [this.componentName, this.lowercaseComponentName]
|
|
@@ -14,6 +14,19 @@ export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
|
14
14
|
}
|
|
15
15
|
}
|
|
16
16
|
|
|
17
|
+
getPcbSize(): { width: number; height: number } {
|
|
18
|
+
const { _parsedProps: props } = this
|
|
19
|
+
if (props.shape === "circle") {
|
|
20
|
+
return { width: props.outerDiameter, height: props.outerDiameter }
|
|
21
|
+
}
|
|
22
|
+
if (props.shape === "oval") {
|
|
23
|
+
return { width: props.outerWidth, height: props.outerHeight }
|
|
24
|
+
}
|
|
25
|
+
throw new Error(
|
|
26
|
+
`getPcbSize for shape "${(props as any).shape}" not implemented for ${this.componentName}`,
|
|
27
|
+
)
|
|
28
|
+
}
|
|
29
|
+
|
|
17
30
|
doInitialPortMatching(): void {
|
|
18
31
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
19
32
|
(c) => c.componentName === "Port",
|
|
@@ -18,6 +18,19 @@ export class SmtPad extends PrimitiveComponent<typeof smtPadProps> {
|
|
|
18
18
|
}
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
+
getPcbSize(): { width: number; height: number } {
|
|
22
|
+
const { _parsedProps: props } = this
|
|
23
|
+
if (props.shape === "circle") {
|
|
24
|
+
return { width: props.radius! * 2, height: props.radius! * 2 }
|
|
25
|
+
}
|
|
26
|
+
if (props.shape === "rect") {
|
|
27
|
+
return { width: props.width!, height: props.height! }
|
|
28
|
+
}
|
|
29
|
+
throw new Error(
|
|
30
|
+
`getPcbSize for shape "${(props as any).shape}" not implemented for ${this.componentName}`,
|
|
31
|
+
)
|
|
32
|
+
}
|
|
33
|
+
|
|
21
34
|
doInitialPortMatching(): void {
|
|
22
35
|
const parentPorts = (this.parent?.children ?? []).filter(
|
|
23
36
|
(c) => c.componentName === "Port",
|