@tscircuit/core 0.0.73 → 0.0.74
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/package.json +2 -4
- package/index.ts +0 -1
- package/lib/Project.ts +0 -131
- package/lib/components/base-components/NormalComponent.ts +0 -419
- package/lib/components/base-components/PrimitiveComponent.ts +0 -478
- package/lib/components/base-components/Renderable.ts +0 -126
- package/lib/components/index.ts +0 -25
- package/lib/components/normal-components/Board.ts +0 -49
- package/lib/components/normal-components/Capacitor.ts +0 -70
- package/lib/components/normal-components/Chip.ts +0 -98
- package/lib/components/normal-components/Diode.ts +0 -27
- package/lib/components/normal-components/Jumper.ts +0 -101
- package/lib/components/normal-components/Led.ts +0 -27
- package/lib/components/normal-components/Resistor.ts +0 -59
- package/lib/components/primitive-components/Constraint.ts +0 -91
- package/lib/components/primitive-components/FabricationNotePath.ts +0 -50
- package/lib/components/primitive-components/FabricationNoteText.ts +0 -26
- package/lib/components/primitive-components/Footprint.ts +0 -239
- package/lib/components/primitive-components/Group.ts +0 -42
- package/lib/components/primitive-components/Hole.ts +0 -65
- package/lib/components/primitive-components/Keepout.ts +0 -58
- package/lib/components/primitive-components/Net.ts +0 -171
- package/lib/components/primitive-components/PlatedHole.ts +0 -116
- package/lib/components/primitive-components/Port.ts +0 -236
- package/lib/components/primitive-components/SilkscreenPath.ts +0 -48
- package/lib/components/primitive-components/SilkscreenText.ts +0 -25
- package/lib/components/primitive-components/SmtPad.ts +0 -162
- package/lib/components/primitive-components/Trace.ts +0 -635
- package/lib/components/primitive-components/TraceHint.ts +0 -71
- package/lib/fiber/catalogue.ts +0 -22
- package/lib/fiber/create-instance-from-react-element.ts +0 -179
- package/lib/fiber/intrinsic-jsx.ts +0 -48
- package/lib/index.ts +0 -5
- package/lib/register-catalogue.ts +0 -12
- package/lib/soup/underscorifyPinStyles.ts +0 -25
- package/lib/soup/underscorifyPortArrangement.ts +0 -51
- package/lib/utils/autorouting/SimpleRouteJson.ts +0 -48
- package/lib/utils/autorouting/computeObstacleBounds.ts +0 -10
- package/lib/utils/autorouting/findPossibleTraceLayerCombinations.ts +0 -102
- package/lib/utils/autorouting/mergeRoutes.ts +0 -71
- package/lib/utils/components/createNetsFromProps.ts +0 -15
- package/lib/utils/constants.ts +0 -35
- package/lib/utils/createComponentsFromSoup.ts +0 -79
- package/lib/utils/extend-aliases.ts +0 -12
- package/lib/utils/get-bounds-of-pcb-components.ts +0 -41
- package/lib/utils/get-relative-direction.ts +0 -14
- package/lib/utils/getClosest.ts +0 -35
- package/lib/utils/getPortFromHints.ts +0 -10
- package/lib/utils/pairs.ts +0 -10
- package/lib/utils/projectPointInDirection.ts +0 -18
- package/lib/utils/range.ts +0 -8
- package/lib/utils/schematic/getAllDimensionsForSchematicBox.ts +0 -330
- package/lib/utils/schematic/getSizeOfSidesFromPortArrangement.ts +0 -47
- package/lib/utils/selector-matching/index.ts +0 -2
- package/lib/utils/selector-matching/is-matching-path-selector.ts +0 -32
- package/lib/utils/selector-matching/is-matching-selector.ts +0 -64
- package/lib/utils/try-now.ts +0 -7
|
@@ -1,478 +0,0 @@
|
|
|
1
|
-
import type { AnySoupElement, AnySourceComponent } from "@tscircuit/soup"
|
|
2
|
-
import type { Circuit } from "../../Project"
|
|
3
|
-
import type { ZodType } from "zod"
|
|
4
|
-
import { z } from "zod"
|
|
5
|
-
import { symbols, type SchSymbol, type BaseSymbolName } from "schematic-symbols"
|
|
6
|
-
import { isValidElement as isReactElement, type ReactElement } from "react"
|
|
7
|
-
import type { Port } from "../primitive-components/Port"
|
|
8
|
-
import { Renderable, type RenderPhase } from "./Renderable"
|
|
9
|
-
import {
|
|
10
|
-
applyToPoint,
|
|
11
|
-
compose,
|
|
12
|
-
identity,
|
|
13
|
-
rotate,
|
|
14
|
-
translate,
|
|
15
|
-
type Matrix,
|
|
16
|
-
} from "transformation-matrix"
|
|
17
|
-
import { isMatchingSelector } from "lib/utils/selector-matching"
|
|
18
|
-
import type { LayoutBuilder } from "@tscircuit/layout"
|
|
19
|
-
|
|
20
|
-
export interface BaseComponentConfig {
|
|
21
|
-
schematicSymbolName?: BaseSymbolName | null
|
|
22
|
-
zodProps: ZodType
|
|
23
|
-
sourceFtype?: AnySourceComponent["ftype"] | null
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* A PrimitiveComponent (SmtPad, Port etc.) doesn't have the ability to contain
|
|
28
|
-
* React subtrees or explicit handling of the "footprint" prop. But otherwise
|
|
29
|
-
* has most of the features of a NormalComponent.
|
|
30
|
-
*/
|
|
31
|
-
export abstract class PrimitiveComponent<
|
|
32
|
-
ZodProps extends ZodType = any,
|
|
33
|
-
> extends Renderable {
|
|
34
|
-
parent: PrimitiveComponent | null = null
|
|
35
|
-
children: PrimitiveComponent[]
|
|
36
|
-
childrenPendingRemoval: PrimitiveComponent[]
|
|
37
|
-
|
|
38
|
-
get config(): BaseComponentConfig {
|
|
39
|
-
return {
|
|
40
|
-
zodProps: z.object({}).passthrough(),
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
props: z.input<ZodProps>
|
|
45
|
-
_parsedProps: z.infer<ZodProps>
|
|
46
|
-
|
|
47
|
-
componentName = ""
|
|
48
|
-
lowercaseComponentName = ""
|
|
49
|
-
|
|
50
|
-
externallyAddedAliases: string[]
|
|
51
|
-
|
|
52
|
-
/**
|
|
53
|
-
* An subcircuit is self-contained. All the selectors inside
|
|
54
|
-
* a subcircuit are relative to the subcircuit group. You can have multiple
|
|
55
|
-
* subcircuits and their selectors will not interact with each other (even if the
|
|
56
|
-
* components share the same names) unless you explicitly break out some ports
|
|
57
|
-
*/
|
|
58
|
-
get isSubcircuit() {
|
|
59
|
-
return (
|
|
60
|
-
Boolean(this.props.subcircuit) ||
|
|
61
|
-
// Implied opaque group for top-level group
|
|
62
|
-
(this.lowercaseComponentName === "group" && (this?.parent as any)?.isRoot)
|
|
63
|
-
)
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/**
|
|
67
|
-
* A primitive container is a component that contains one or more ports and
|
|
68
|
-
* primitive components that are designed to interact.
|
|
69
|
-
*
|
|
70
|
-
* For example a resistor contains ports and smtpads that interact, so the
|
|
71
|
-
* resistor is a primitive container. Inside a primitive container, the ports
|
|
72
|
-
* and pads are likely to reference each other and look for eachother during
|
|
73
|
-
* the port matching phase.
|
|
74
|
-
*
|
|
75
|
-
*/
|
|
76
|
-
isPrimitiveContainer = false
|
|
77
|
-
|
|
78
|
-
source_group_id: string | null = null
|
|
79
|
-
source_component_id: string | null = null
|
|
80
|
-
schematic_component_id: string | null = null
|
|
81
|
-
pcb_component_id: string | null = null
|
|
82
|
-
cad_component_id: string | null = null
|
|
83
|
-
|
|
84
|
-
constructor(props: z.input<ZodProps>) {
|
|
85
|
-
super(props)
|
|
86
|
-
this.children = []
|
|
87
|
-
this.childrenPendingRemoval = []
|
|
88
|
-
this.props = props ?? {}
|
|
89
|
-
this.externallyAddedAliases = []
|
|
90
|
-
this._parsedProps = this.config.zodProps.parse(
|
|
91
|
-
props ?? {},
|
|
92
|
-
) as z.infer<ZodProps>
|
|
93
|
-
if (!this.componentName) {
|
|
94
|
-
this.componentName = this.constructor.name
|
|
95
|
-
}
|
|
96
|
-
this.lowercaseComponentName = this.componentName.toLowerCase()
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
setProps(props: Partial<z.input<ZodProps>>) {
|
|
100
|
-
const newProps = this.config.zodProps.parse({
|
|
101
|
-
...this.props,
|
|
102
|
-
...props,
|
|
103
|
-
}) as z.infer<ZodProps>
|
|
104
|
-
const oldProps = this.props
|
|
105
|
-
this.props = newProps
|
|
106
|
-
this._parsedProps = this.config.zodProps.parse(props) as z.infer<ZodProps>
|
|
107
|
-
this.onPropsChange({
|
|
108
|
-
oldProps,
|
|
109
|
-
newProps,
|
|
110
|
-
changedProps: Object.keys(props),
|
|
111
|
-
})
|
|
112
|
-
this.parent?.onChildChanged(this)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/**
|
|
116
|
-
* Computes a transformation matrix from the props of this component for PCB
|
|
117
|
-
* components
|
|
118
|
-
*/
|
|
119
|
-
computePcbPropsTransform(): Matrix {
|
|
120
|
-
const { _parsedProps: props } = this
|
|
121
|
-
|
|
122
|
-
const matrix = compose(
|
|
123
|
-
translate(props.pcbX ?? 0, props.pcbY ?? 0),
|
|
124
|
-
rotate(((props.pcbRotation ?? 0) * Math.PI) / 180),
|
|
125
|
-
)
|
|
126
|
-
|
|
127
|
-
return matrix
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
/**
|
|
131
|
-
* Compute a transformation matrix combining all parent transforms for PCB
|
|
132
|
-
* components, including this component's translation and rotation.
|
|
133
|
-
*
|
|
134
|
-
* This is used to compute this component's position as well as all children
|
|
135
|
-
* components positions before layout is applied
|
|
136
|
-
*/
|
|
137
|
-
_computePcbGlobalTransformBeforeLayout(): Matrix {
|
|
138
|
-
const { _parsedProps: props } = this
|
|
139
|
-
const manualPlacement =
|
|
140
|
-
this.getSubcircuit()._getManualPlacementForComponent(this)
|
|
141
|
-
|
|
142
|
-
// pcbX or pcbY will override the manual placement
|
|
143
|
-
if (
|
|
144
|
-
manualPlacement &&
|
|
145
|
-
this.props.pcbX === undefined &&
|
|
146
|
-
this.props.pcbY === undefined
|
|
147
|
-
) {
|
|
148
|
-
return compose(
|
|
149
|
-
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
|
|
150
|
-
compose(
|
|
151
|
-
translate(manualPlacement.x, manualPlacement.y),
|
|
152
|
-
rotate(((props.pcbRotation ?? 0) * Math.PI) / 180),
|
|
153
|
-
),
|
|
154
|
-
)
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
return compose(
|
|
158
|
-
this.parent?._computePcbGlobalTransformBeforeLayout() ?? identity(),
|
|
159
|
-
this.computePcbPropsTransform(),
|
|
160
|
-
)
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
getPrimitiveContainer(): PrimitiveComponent | null {
|
|
164
|
-
if (this.isPrimitiveContainer) return this
|
|
165
|
-
return this.parent?.getPrimitiveContainer?.() ?? null
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Compute the PCB bounds of this component the circuit json elements
|
|
170
|
-
* associated with it.
|
|
171
|
-
*/
|
|
172
|
-
_getPcbCircuitJsonBounds(): {
|
|
173
|
-
center: { x: number; y: number }
|
|
174
|
-
bounds: { left: number; top: number; right: number; bottom: number }
|
|
175
|
-
width: number
|
|
176
|
-
height: number
|
|
177
|
-
} {
|
|
178
|
-
return {
|
|
179
|
-
center: { x: 0, y: 0 },
|
|
180
|
-
bounds: { left: 0, top: 0, right: 0, bottom: 0 },
|
|
181
|
-
width: 0,
|
|
182
|
-
height: 0,
|
|
183
|
-
}
|
|
184
|
-
}
|
|
185
|
-
|
|
186
|
-
/**
|
|
187
|
-
* Set the position of this component from the layout solver. This method
|
|
188
|
-
* should operate using CircuitJson associated with this component, like
|
|
189
|
-
* _getPcbCircuitJsonBounds it can be called multiple times as different
|
|
190
|
-
* parents apply layout to their children.
|
|
191
|
-
*/
|
|
192
|
-
_setPositionFromLayout(newCenter: { x: number; y: number }) {
|
|
193
|
-
throw new Error(
|
|
194
|
-
`_setPositionFromLayout not implemented for ${this.componentName}`,
|
|
195
|
-
)
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
/**
|
|
199
|
-
* Computes a transformation matrix from the props of this component for
|
|
200
|
-
* schematic components
|
|
201
|
-
*/
|
|
202
|
-
computeSchematicPropsTransform(): Matrix {
|
|
203
|
-
return compose(translate(this.props.schX ?? 0, this.props.schY ?? 0))
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
/**
|
|
207
|
-
* Compute a transformation matrix combining all parent transforms for this
|
|
208
|
-
* component
|
|
209
|
-
*/
|
|
210
|
-
computeSchematicGlobalTransform(): Matrix {
|
|
211
|
-
return compose(
|
|
212
|
-
this.parent?.computeSchematicGlobalTransform?.() ?? identity(),
|
|
213
|
-
this.computeSchematicPropsTransform(),
|
|
214
|
-
)
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
getSchematicSymbol(variant: "horz" | "vert" | null = null): SchSymbol | null {
|
|
218
|
-
if (variant === null) {
|
|
219
|
-
return this.getSchematicSymbol(
|
|
220
|
-
this.props.schRotation % 90 === 0 ? "vert" : "horz",
|
|
221
|
-
)
|
|
222
|
-
}
|
|
223
|
-
const { config } = this
|
|
224
|
-
if (!config.schematicSymbolName) return null
|
|
225
|
-
return (
|
|
226
|
-
symbols[
|
|
227
|
-
`${config.schematicSymbolName}_${variant}` as keyof typeof symbols
|
|
228
|
-
] ?? null
|
|
229
|
-
)
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
/**
|
|
233
|
-
* Subcircuit groups have a prop called "layout" that can include manual
|
|
234
|
-
* placements for pcb components. These are typically added from an IDE
|
|
235
|
-
*/
|
|
236
|
-
_getManualPlacementForComponent(
|
|
237
|
-
component: PrimitiveComponent,
|
|
238
|
-
): { x: number; y: number } | null {
|
|
239
|
-
if (!this.isSubcircuit) return null
|
|
240
|
-
|
|
241
|
-
const layout: LayoutBuilder = this.props.layout
|
|
242
|
-
if (!layout) return null
|
|
243
|
-
|
|
244
|
-
const placementConfig = layout.manual_pcb_placement_config
|
|
245
|
-
if (!placementConfig) return null
|
|
246
|
-
|
|
247
|
-
for (const position of placementConfig.positions) {
|
|
248
|
-
if (isMatchingSelector(component, position.selector)) {
|
|
249
|
-
const center = applyToPoint(
|
|
250
|
-
this._computePcbGlobalTransformBeforeLayout(),
|
|
251
|
-
position.center,
|
|
252
|
-
)
|
|
253
|
-
return center
|
|
254
|
-
}
|
|
255
|
-
}
|
|
256
|
-
|
|
257
|
-
return null
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
_getGlobalPcbPositionBeforeLayout(): { x: number; y: number } {
|
|
261
|
-
return applyToPoint(this._computePcbGlobalTransformBeforeLayout(), {
|
|
262
|
-
x: 0,
|
|
263
|
-
y: 0,
|
|
264
|
-
})
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
_getGlobalSchematicPositionBeforeLayout(): { x: number; y: number } {
|
|
268
|
-
return applyToPoint(this.computeSchematicGlobalTransform(), { x: 0, y: 0 })
|
|
269
|
-
}
|
|
270
|
-
|
|
271
|
-
get root(): Circuit | null {
|
|
272
|
-
return this.parent?.root ?? null
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
onAddToParent(parent: PrimitiveComponent) {
|
|
276
|
-
this.parent = parent
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
/**
|
|
280
|
-
* Called whenever the props change
|
|
281
|
-
*/
|
|
282
|
-
onPropsChange(params: {
|
|
283
|
-
oldProps: z.infer<ZodProps>
|
|
284
|
-
newProps: z.infer<ZodProps>
|
|
285
|
-
changedProps: string[]
|
|
286
|
-
}) {}
|
|
287
|
-
|
|
288
|
-
onChildChanged(child: PrimitiveComponent) {
|
|
289
|
-
this.parent?.onChildChanged(child)
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
add(component: PrimitiveComponent) {
|
|
293
|
-
component.onAddToParent(this)
|
|
294
|
-
component.parent = this
|
|
295
|
-
this.children.push(component)
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
addAll(components: PrimitiveComponent[]) {
|
|
299
|
-
for (const component of components) {
|
|
300
|
-
this.add(component)
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
remove(component: PrimitiveComponent) {
|
|
305
|
-
this.children = this.children.filter((c) => c !== component)
|
|
306
|
-
this.childrenPendingRemoval.push(component)
|
|
307
|
-
component.shouldBeRemoved = true
|
|
308
|
-
}
|
|
309
|
-
|
|
310
|
-
getSubcircuitSelector(): string {
|
|
311
|
-
const name = this._parsedProps.name
|
|
312
|
-
const endPart = name
|
|
313
|
-
? `${this.lowercaseComponentName}.${name}`
|
|
314
|
-
: this.lowercaseComponentName
|
|
315
|
-
|
|
316
|
-
if (!this.parent) return endPart
|
|
317
|
-
if (this.parent.isSubcircuit) return endPart
|
|
318
|
-
return `${this.parent.getSubcircuitSelector()} > ${endPart}`
|
|
319
|
-
}
|
|
320
|
-
|
|
321
|
-
getFullPathSelector(): string {
|
|
322
|
-
const name = this._parsedProps.name
|
|
323
|
-
const endPart = name
|
|
324
|
-
? `${this.lowercaseComponentName}.${name}`
|
|
325
|
-
: this.lowercaseComponentName
|
|
326
|
-
const parentSelector = this.parent?.getFullPathSelector?.()
|
|
327
|
-
if (!parentSelector) return endPart
|
|
328
|
-
return `${parentSelector} > ${endPart}`
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
getNameAndAliases(): string[] {
|
|
332
|
-
return [
|
|
333
|
-
this._parsedProps.name,
|
|
334
|
-
...(this._parsedProps.portHints ?? []),
|
|
335
|
-
].filter(Boolean)
|
|
336
|
-
}
|
|
337
|
-
isMatchingNameOrAlias(name: string) {
|
|
338
|
-
return this.getNameAndAliases().includes(name)
|
|
339
|
-
}
|
|
340
|
-
isMatchingAnyOf(aliases: Array<string | number>) {
|
|
341
|
-
return this.getNameAndAliases().some((a) =>
|
|
342
|
-
aliases.map((a) => a.toString()).includes(a),
|
|
343
|
-
)
|
|
344
|
-
}
|
|
345
|
-
getPcbSize(): { width: number; height: number } {
|
|
346
|
-
throw new Error(`getPcbSize not implemented for ${this.componentName}`)
|
|
347
|
-
}
|
|
348
|
-
|
|
349
|
-
doesSelectorMatch(selector: string): boolean {
|
|
350
|
-
const myTypeNames = [this.componentName, this.lowercaseComponentName]
|
|
351
|
-
const myClassNames = [this._parsedProps.name].filter(Boolean)
|
|
352
|
-
|
|
353
|
-
const parts = selector.trim().split(/\> /)[0]
|
|
354
|
-
const firstPart = parts[0]
|
|
355
|
-
|
|
356
|
-
if (parts.length > 1) return false
|
|
357
|
-
if (selector === "*") return true
|
|
358
|
-
if (selector[0] === "#" && selector.slice(1) === this.props.id) return true
|
|
359
|
-
if (selector[0] === "." && myClassNames.includes(selector.slice(1)))
|
|
360
|
-
return true
|
|
361
|
-
if (/^[a-zA-Z0-9_]/.test(firstPart) && myTypeNames.includes(firstPart))
|
|
362
|
-
return true
|
|
363
|
-
|
|
364
|
-
return false
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
getSubcircuit(): PrimitiveComponent {
|
|
368
|
-
if (this.isSubcircuit) return this
|
|
369
|
-
const group = this.parent?.getSubcircuit()
|
|
370
|
-
if (!group)
|
|
371
|
-
throw new Error("Component is not inside an opaque group (no board?)")
|
|
372
|
-
return group
|
|
373
|
-
}
|
|
374
|
-
|
|
375
|
-
selectAll(selector: string): PrimitiveComponent[] {
|
|
376
|
-
const parts = selector.trim().split(/\s+/)
|
|
377
|
-
let results: PrimitiveComponent[] = [this]
|
|
378
|
-
|
|
379
|
-
let onlyDirectChildren = false
|
|
380
|
-
for (const part of parts) {
|
|
381
|
-
if (part === ">") {
|
|
382
|
-
onlyDirectChildren = true
|
|
383
|
-
} else {
|
|
384
|
-
results = results.flatMap((component) => {
|
|
385
|
-
return (
|
|
386
|
-
onlyDirectChildren ? component.children : component.getDescendants()
|
|
387
|
-
).filter((descendant) => isMatchingSelector(descendant, part))
|
|
388
|
-
})
|
|
389
|
-
onlyDirectChildren = false
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
return results.filter((component) => component !== this)
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
selectOne(
|
|
397
|
-
selector: string,
|
|
398
|
-
options?: {
|
|
399
|
-
type?: string
|
|
400
|
-
port?: boolean
|
|
401
|
-
pcbPrimitive?: boolean
|
|
402
|
-
schematicPrimitive?: boolean
|
|
403
|
-
},
|
|
404
|
-
): PrimitiveComponent | null {
|
|
405
|
-
let type = options?.type?.toLowerCase()
|
|
406
|
-
if (options?.port) type = "port"
|
|
407
|
-
if (type) {
|
|
408
|
-
return (
|
|
409
|
-
this.selectAll(selector).find(
|
|
410
|
-
(c) => c.lowercaseComponentName === type,
|
|
411
|
-
) ?? null
|
|
412
|
-
)
|
|
413
|
-
}
|
|
414
|
-
if (options?.pcbPrimitive) {
|
|
415
|
-
return this.selectAll(selector).find((c) => c.isPcbPrimitive) ?? null
|
|
416
|
-
}
|
|
417
|
-
if (options?.schematicPrimitive) {
|
|
418
|
-
return (
|
|
419
|
-
this.selectAll(selector).find((c) => c.isSchematicPrimitive) ?? null
|
|
420
|
-
)
|
|
421
|
-
}
|
|
422
|
-
return this.selectAll(selector)[0] ?? null
|
|
423
|
-
}
|
|
424
|
-
|
|
425
|
-
getAvailablePcbLayers(): string[] {
|
|
426
|
-
if (this.isPcbPrimitive) {
|
|
427
|
-
if (this.props.layer) return [this.props.layer]
|
|
428
|
-
if (this.componentName === "PlatedHole") {
|
|
429
|
-
return ["top", "bottom"] // TODO derive layers from parent
|
|
430
|
-
}
|
|
431
|
-
return []
|
|
432
|
-
}
|
|
433
|
-
return []
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
getDescendants(): PrimitiveComponent[] {
|
|
437
|
-
const descendants: PrimitiveComponent[] = []
|
|
438
|
-
for (const child of this.children) {
|
|
439
|
-
descendants.push(child)
|
|
440
|
-
descendants.push(...child.getDescendants())
|
|
441
|
-
}
|
|
442
|
-
return descendants
|
|
443
|
-
}
|
|
444
|
-
|
|
445
|
-
// TODO we shouldn't need to override this, errors can be rendered and handled
|
|
446
|
-
// by the Renderable class, however, the Renderable class currently doesn't
|
|
447
|
-
// have access to the database or cleanup
|
|
448
|
-
renderError(message: Parameters<typeof Renderable.prototype.renderError>[0]) {
|
|
449
|
-
if (typeof message === "string") {
|
|
450
|
-
return super.renderError(message)
|
|
451
|
-
}
|
|
452
|
-
// TODO this needs to be cleaned up at some point!
|
|
453
|
-
this.root?.db.pcb_error.insert(message)
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
getString(): string {
|
|
457
|
-
const { lowercaseComponentName: cname, _parsedProps: props, parent } = this
|
|
458
|
-
if (parent?.props?.name && props?.name) {
|
|
459
|
-
return `<${cname}#${this._renderId}(.${parent?.props.name}>.${props?.name}) />`
|
|
460
|
-
}
|
|
461
|
-
if (props?.from && props?.to) {
|
|
462
|
-
return `<${cname}#${this._renderId}(from:${props.from} to:${props?.to}) />`
|
|
463
|
-
}
|
|
464
|
-
if (props?.name) {
|
|
465
|
-
return `<${cname}#${this._renderId} name=".${props?.name}" />`
|
|
466
|
-
}
|
|
467
|
-
if (props?.portHints) {
|
|
468
|
-
return `<${cname}#${this._renderId}(${props.portHints.map((ph: string) => `.${ph}`).join(", ")}) />`
|
|
469
|
-
}
|
|
470
|
-
return `<${cname}#${this._renderId} />`
|
|
471
|
-
}
|
|
472
|
-
get [Symbol.toStringTag](): string {
|
|
473
|
-
return this.getString()
|
|
474
|
-
}
|
|
475
|
-
[Symbol.for("nodejs.util.inspect.custom")]() {
|
|
476
|
-
return this.getString()
|
|
477
|
-
}
|
|
478
|
-
}
|
|
@@ -1,126 +0,0 @@
|
|
|
1
|
-
import type { PCBPlacementError, PCBTraceError } from "@tscircuit/soup"
|
|
2
|
-
import { Component, createElement, type ReactElement } from "react"
|
|
3
|
-
|
|
4
|
-
export const orderedRenderPhases = [
|
|
5
|
-
"ReactSubtreesRender",
|
|
6
|
-
"InitializePortsFromChildren",
|
|
7
|
-
"CreateNetsFromProps",
|
|
8
|
-
"CreateTracesFromProps",
|
|
9
|
-
"CreateTraceHintsFromProps",
|
|
10
|
-
"SourceRender",
|
|
11
|
-
"SourceParentAttachment",
|
|
12
|
-
"PortDiscovery",
|
|
13
|
-
"PortMatching",
|
|
14
|
-
"SourceTraceRender",
|
|
15
|
-
"SchematicComponentRender",
|
|
16
|
-
"SchematicLayout",
|
|
17
|
-
"SchematicPortRender",
|
|
18
|
-
"SchematicTraceRender",
|
|
19
|
-
"PcbComponentRender",
|
|
20
|
-
"PcbPrimitiveRender",
|
|
21
|
-
"PcbFootprintLayout",
|
|
22
|
-
"PcbPortRender",
|
|
23
|
-
"PcbPortAttachment",
|
|
24
|
-
"PcbLayout",
|
|
25
|
-
"PcbTraceRender",
|
|
26
|
-
"PcbTraceHintRender",
|
|
27
|
-
"PcbRouteNetIslands",
|
|
28
|
-
"PcbComponentSizeCalculation",
|
|
29
|
-
"CadModelRender",
|
|
30
|
-
] as const
|
|
31
|
-
|
|
32
|
-
export type RenderPhase = (typeof orderedRenderPhases)[number]
|
|
33
|
-
|
|
34
|
-
export type RenderPhaseFn<K extends RenderPhase = RenderPhase> =
|
|
35
|
-
| `doInitial${K}`
|
|
36
|
-
| `update${K}`
|
|
37
|
-
| `remove${K}`
|
|
38
|
-
|
|
39
|
-
export type RenderPhaseStates = Record<RenderPhase, { initialized: boolean }>
|
|
40
|
-
|
|
41
|
-
export type RenderPhaseFunctions = {
|
|
42
|
-
[T in RenderPhaseFn]?: () => void
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
export type IRenderable = RenderPhaseFunctions & {
|
|
46
|
-
renderPhaseStates: RenderPhaseStates
|
|
47
|
-
runRenderPhase(phase: RenderPhase): void
|
|
48
|
-
runRenderPhaseForChildren(phase: RenderPhase): void
|
|
49
|
-
shouldBeRemoved: boolean
|
|
50
|
-
children: IRenderable[]
|
|
51
|
-
runRenderCycle(): void
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
let globalRenderCounter = 0
|
|
55
|
-
export abstract class Renderable implements IRenderable {
|
|
56
|
-
renderPhaseStates: RenderPhaseStates
|
|
57
|
-
shouldBeRemoved = false
|
|
58
|
-
children: IRenderable[]
|
|
59
|
-
|
|
60
|
-
/** PCB-only SMTPads, PlatedHoles, Holes, Silkscreen elements etc. */
|
|
61
|
-
isPcbPrimitive = false
|
|
62
|
-
/** Schematic-only, lines, boxes, indicators etc. */
|
|
63
|
-
isSchematicPrimitive = false
|
|
64
|
-
|
|
65
|
-
_renderId: string
|
|
66
|
-
|
|
67
|
-
constructor(props: any) {
|
|
68
|
-
this._renderId = `${globalRenderCounter++}`
|
|
69
|
-
this.children = []
|
|
70
|
-
this.renderPhaseStates = {} as RenderPhaseStates
|
|
71
|
-
for (const phase of orderedRenderPhases) {
|
|
72
|
-
this.renderPhaseStates[phase] = { initialized: false }
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
runRenderCycle() {
|
|
77
|
-
for (const renderPhase of orderedRenderPhases) {
|
|
78
|
-
this.runRenderPhaseForChildren(renderPhase)
|
|
79
|
-
this.runRenderPhase(renderPhase)
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
/**
|
|
84
|
-
* This runs all the render methods for a given phase, calling one of:
|
|
85
|
-
* - doInitial*
|
|
86
|
-
* - update*
|
|
87
|
-
* -remove*
|
|
88
|
-
* ...depending on the current state of the component.
|
|
89
|
-
*/
|
|
90
|
-
runRenderPhase(phase: RenderPhase) {
|
|
91
|
-
const isInitialized = this.renderPhaseStates[phase].initialized
|
|
92
|
-
if (!isInitialized && this.shouldBeRemoved) return
|
|
93
|
-
if (this.shouldBeRemoved && isInitialized) {
|
|
94
|
-
;(this as any)?.[`remove${phase}`]?.()
|
|
95
|
-
this.renderPhaseStates[phase].initialized = false
|
|
96
|
-
return
|
|
97
|
-
}
|
|
98
|
-
if (isInitialized) {
|
|
99
|
-
;(this as any)?.[`update${phase}`]?.()
|
|
100
|
-
return
|
|
101
|
-
}
|
|
102
|
-
;(this as any)?.[`doInitial${phase}`]?.()
|
|
103
|
-
this.renderPhaseStates[phase].initialized = true
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
runRenderPhaseForChildren(phase: RenderPhase): void {
|
|
107
|
-
for (const child of this.children) {
|
|
108
|
-
child.runRenderPhaseForChildren(phase)
|
|
109
|
-
child.runRenderPhase(phase)
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
renderError(
|
|
114
|
-
message:
|
|
115
|
-
| string
|
|
116
|
-
| Omit<PCBTraceError, "pcb_error_id">
|
|
117
|
-
| Omit<PCBPlacementError, "pcb_error_id">,
|
|
118
|
-
) {
|
|
119
|
-
// TODO add to render phase error list and try to add position or
|
|
120
|
-
// relationships etc.
|
|
121
|
-
if (typeof message === "string") {
|
|
122
|
-
throw new Error(message)
|
|
123
|
-
}
|
|
124
|
-
throw new Error(JSON.stringify(message, null, 2))
|
|
125
|
-
}
|
|
126
|
-
}
|
package/lib/components/index.ts
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
export { NormalComponent } from "./base-components/NormalComponent"
|
|
2
|
-
export { PrimitiveComponent } from "./base-components/PrimitiveComponent"
|
|
3
|
-
export { Renderable, type IRenderable } from "./base-components/Renderable"
|
|
4
|
-
export { Board } from "./normal-components/Board"
|
|
5
|
-
export { Footprint } from "./primitive-components/Footprint"
|
|
6
|
-
export { SmtPad } from "./primitive-components/SmtPad"
|
|
7
|
-
export { Port } from "./primitive-components/Port"
|
|
8
|
-
export { Resistor } from "./normal-components/Resistor"
|
|
9
|
-
export { Led } from "./normal-components/Led"
|
|
10
|
-
export { Diode } from "./normal-components/Diode"
|
|
11
|
-
export { Capacitor } from "./normal-components/Capacitor"
|
|
12
|
-
export { Net } from "./primitive-components/Net"
|
|
13
|
-
export { Trace } from "./primitive-components/Trace"
|
|
14
|
-
export { TraceHint } from "./primitive-components/TraceHint"
|
|
15
|
-
export { Group } from "./primitive-components/Group"
|
|
16
|
-
export { Chip } from "./normal-components/Chip"
|
|
17
|
-
export { Jumper } from "./normal-components/Jumper"
|
|
18
|
-
export { SilkscreenPath } from "./primitive-components/SilkscreenPath"
|
|
19
|
-
export { PlatedHole } from "./primitive-components/PlatedHole"
|
|
20
|
-
export { Constraint } from "./primitive-components/Constraint"
|
|
21
|
-
export { Hole } from "./primitive-components/Hole"
|
|
22
|
-
export { SilkscreenText } from "./primitive-components/SilkscreenText"
|
|
23
|
-
export { Keepout } from "./primitive-components/Keepout"
|
|
24
|
-
export { FabricationNoteText } from "./primitive-components/FabricationNoteText"
|
|
25
|
-
export { FabricationNotePath } from "./primitive-components/FabricationNotePath"
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import { boardProps } from "@tscircuit/props"
|
|
2
|
-
import type { z } from "zod"
|
|
3
|
-
import { NormalComponent } from "../base-components/NormalComponent"
|
|
4
|
-
import { identity, type Matrix } from "transformation-matrix"
|
|
5
|
-
import { Group } from "../primitive-components/Group"
|
|
6
|
-
|
|
7
|
-
export class Board extends Group<typeof boardProps> {
|
|
8
|
-
pcb_board_id: string | null = null
|
|
9
|
-
|
|
10
|
-
get isSubcircuit() {
|
|
11
|
-
return true
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
get config() {
|
|
15
|
-
return {
|
|
16
|
-
zodProps: boardProps,
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
doInitialPcbComponentRender(): void {
|
|
21
|
-
const { db } = this.root!
|
|
22
|
-
const { _parsedProps: props } = this
|
|
23
|
-
|
|
24
|
-
if (!props.width || !props.height) {
|
|
25
|
-
throw new Error("Board width and height or an outline are required")
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const pcb_board = db.pcb_board.insert({
|
|
29
|
-
center: { x: props.pcbX, y: props.pcbY },
|
|
30
|
-
|
|
31
|
-
width: props.width,
|
|
32
|
-
height: props.height,
|
|
33
|
-
outline: props.outline,
|
|
34
|
-
})
|
|
35
|
-
|
|
36
|
-
this.pcb_board_id = pcb_board.pcb_board_id!
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
removePcbComponentRender(): void {
|
|
40
|
-
const { db } = this.root!
|
|
41
|
-
if (!this.pcb_board_id) return
|
|
42
|
-
db.pcb_board.delete(this.pcb_board_id!)
|
|
43
|
-
this.pcb_board_id = null
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
_computePcbGlobalTransformBeforeLayout(): Matrix {
|
|
47
|
-
return identity()
|
|
48
|
-
}
|
|
49
|
-
}
|