@tscircuit/core 0.0.16 → 0.0.18
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 +842 -43
- package/dist/index.js +211 -16
- package/lib/Project.ts +29 -0
- package/lib/components/base-components/NormalComponent.ts +16 -0
- package/lib/components/base-components/PrimitiveComponent.ts +3 -0
- package/lib/components/index.ts +3 -0
- package/lib/components/normal-components/Chip.ts +0 -19
- package/lib/components/normal-components/Jumper.ts +101 -0
- package/lib/components/primitive-components/PlatedHole.ts +60 -0
- package/lib/components/primitive-components/Port.ts +1 -0
- package/lib/components/primitive-components/SilkscreenPath.ts +35 -0
- package/lib/fiber/intrinsic-jsx.ts +1 -0
- package/lib/utils/createComponentsFromSoup.ts +23 -50
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -12,13 +12,16 @@ __export(components_exports, {
|
|
|
12
12
|
Chip: () => Chip,
|
|
13
13
|
Footprint: () => Footprint,
|
|
14
14
|
Group: () => Group,
|
|
15
|
+
Jumper: () => Jumper,
|
|
15
16
|
Led: () => Led,
|
|
16
17
|
Net: () => Net,
|
|
17
18
|
NormalComponent: () => NormalComponent,
|
|
19
|
+
PlatedHole: () => PlatedHole,
|
|
18
20
|
Port: () => Port,
|
|
19
21
|
PrimitiveComponent: () => PrimitiveComponent,
|
|
20
22
|
Renderable: () => Renderable,
|
|
21
23
|
Resistor: () => Resistor,
|
|
24
|
+
SilkscreenPath: () => SilkscreenPath,
|
|
22
25
|
SmtPad: () => SmtPad,
|
|
23
26
|
Trace: () => Trace,
|
|
24
27
|
TraceHint: () => TraceHint
|
|
@@ -167,6 +170,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
167
170
|
_parsedProps;
|
|
168
171
|
componentName = "";
|
|
169
172
|
lowercaseComponentName = "";
|
|
173
|
+
externallyAddedAliases;
|
|
170
174
|
source_group_id = null;
|
|
171
175
|
source_component_id = null;
|
|
172
176
|
schematic_component_id = null;
|
|
@@ -177,6 +181,7 @@ var PrimitiveComponent = class extends Renderable {
|
|
|
177
181
|
this.children = [];
|
|
178
182
|
this.childrenPendingRemoval = [];
|
|
179
183
|
this.props = props ?? {};
|
|
184
|
+
this.externallyAddedAliases = [];
|
|
180
185
|
this._parsedProps = this.config.zodProps.parse(
|
|
181
186
|
props ?? {}
|
|
182
187
|
);
|
|
@@ -466,7 +471,8 @@ var Port = class extends PrimitiveComponent {
|
|
|
466
471
|
/* @__PURE__ */ new Set([
|
|
467
472
|
...props.aliases ?? [],
|
|
468
473
|
props.name,
|
|
469
|
-
...typeof props.pinNumber === "number" ? [`pin${props.pinNumber}`, props.pinNumber.toString()] : []
|
|
474
|
+
...typeof props.pinNumber === "number" ? [`pin${props.pinNumber}`, props.pinNumber.toString()] : [],
|
|
475
|
+
...this.externallyAddedAliases
|
|
470
476
|
])
|
|
471
477
|
);
|
|
472
478
|
}
|
|
@@ -796,6 +802,83 @@ var SmtPad = class extends PrimitiveComponent {
|
|
|
796
802
|
}
|
|
797
803
|
};
|
|
798
804
|
|
|
805
|
+
// lib/components/primitive-components/SilkscreenPath.ts
|
|
806
|
+
import { silkscreenPathProps } from "@tscircuit/props";
|
|
807
|
+
var SilkscreenPath = class extends PrimitiveComponent {
|
|
808
|
+
pcb_silkscreen_path_id = null;
|
|
809
|
+
get config() {
|
|
810
|
+
return {
|
|
811
|
+
zodProps: silkscreenPathProps
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
doInitialPcbPrimitiveRender() {
|
|
815
|
+
const { db } = this.project;
|
|
816
|
+
const { _parsedProps: props } = this;
|
|
817
|
+
const layer = props.layer ?? "top";
|
|
818
|
+
if (layer !== "top" && layer !== "bottom") {
|
|
819
|
+
throw new Error(
|
|
820
|
+
`Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`
|
|
821
|
+
);
|
|
822
|
+
}
|
|
823
|
+
const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
|
|
824
|
+
pcb_component_id: this.parent?.pcb_component_id,
|
|
825
|
+
layer,
|
|
826
|
+
route: props.route,
|
|
827
|
+
stroke_width: props.strokeWidth ?? 0.1
|
|
828
|
+
});
|
|
829
|
+
this.pcb_silkscreen_path_id = pcb_silkscreen_path.pcb_silkscreen_path_id;
|
|
830
|
+
}
|
|
831
|
+
};
|
|
832
|
+
|
|
833
|
+
// lib/components/primitive-components/PlatedHole.ts
|
|
834
|
+
import { platedHoleProps } from "@tscircuit/props";
|
|
835
|
+
var PlatedHole = class extends PrimitiveComponent {
|
|
836
|
+
pcb_plated_hole_id = null;
|
|
837
|
+
matchedPort = null;
|
|
838
|
+
isPcbPrimitive = true;
|
|
839
|
+
get config() {
|
|
840
|
+
return {
|
|
841
|
+
zodProps: platedHoleProps
|
|
842
|
+
};
|
|
843
|
+
}
|
|
844
|
+
doInitialPortMatching() {
|
|
845
|
+
const parentPorts = (this.parent?.children ?? []).filter(
|
|
846
|
+
(c) => c.componentName === "Port"
|
|
847
|
+
);
|
|
848
|
+
if (!this.props.portHints) {
|
|
849
|
+
return;
|
|
850
|
+
}
|
|
851
|
+
for (const port of parentPorts) {
|
|
852
|
+
if (port.isMatchingAnyOf(this.props.portHints)) {
|
|
853
|
+
this.matchedPort = port;
|
|
854
|
+
port.registerMatch(this);
|
|
855
|
+
return;
|
|
856
|
+
}
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
doInitialPcbPrimitiveRender() {
|
|
860
|
+
const { db } = this.project;
|
|
861
|
+
const { _parsedProps: props } = this;
|
|
862
|
+
if (!props.portHints) return;
|
|
863
|
+
const position = this.getGlobalPcbPosition();
|
|
864
|
+
if (props.shape === "circle") {
|
|
865
|
+
const plated_hole_input = {
|
|
866
|
+
pcb_component_id: this.parent?.pcb_component_id,
|
|
867
|
+
pcb_port_id: this.matchedPort?.pcb_port_id,
|
|
868
|
+
layers: ["top", "bottom"],
|
|
869
|
+
outer_diameter: props.outerDiameter,
|
|
870
|
+
hole_diameter: props.holeDiameter,
|
|
871
|
+
shape: "circle",
|
|
872
|
+
port_hints: this.getNameAndAliases(),
|
|
873
|
+
x: position.x,
|
|
874
|
+
y: position.y,
|
|
875
|
+
type: "pcb_plated_hole"
|
|
876
|
+
};
|
|
877
|
+
const pcb_plated_hole = db.pcb_plated_hole.insert(plated_hole_input);
|
|
878
|
+
}
|
|
879
|
+
}
|
|
880
|
+
};
|
|
881
|
+
|
|
799
882
|
// lib/utils/createComponentsFromSoup.ts
|
|
800
883
|
var createComponentsFromSoup = (soup) => {
|
|
801
884
|
const components = [];
|
|
@@ -823,6 +906,27 @@ var createComponentsFromSoup = (soup) => {
|
|
|
823
906
|
portHints: elm.port_hints
|
|
824
907
|
})
|
|
825
908
|
);
|
|
909
|
+
} else if (elm.type === "pcb_silkscreen_path") {
|
|
910
|
+
components.push(
|
|
911
|
+
new SilkscreenPath({
|
|
912
|
+
layer: elm.layer,
|
|
913
|
+
route: elm.route,
|
|
914
|
+
strokeWidth: elm.stroke_width
|
|
915
|
+
})
|
|
916
|
+
);
|
|
917
|
+
} else if (elm.type === "pcb_plated_hole" && elm.shape === "circle") {
|
|
918
|
+
if (elm.shape === "circle") {
|
|
919
|
+
components.push(
|
|
920
|
+
new PlatedHole({
|
|
921
|
+
pcbX: elm.x,
|
|
922
|
+
pcbY: elm.y,
|
|
923
|
+
shape: "circle",
|
|
924
|
+
holeDiameter: elm.hole_diameter,
|
|
925
|
+
outerDiameter: elm.outer_diameter,
|
|
926
|
+
portHints: elm.port_hints
|
|
927
|
+
})
|
|
928
|
+
);
|
|
929
|
+
}
|
|
826
930
|
}
|
|
827
931
|
}
|
|
828
932
|
return components;
|
|
@@ -866,6 +970,20 @@ var NormalComponent = class extends PrimitiveComponent {
|
|
|
866
970
|
}
|
|
867
971
|
const portsFromFootprint = this.getPortsFromFootprint();
|
|
868
972
|
this.addAll(portsFromFootprint);
|
|
973
|
+
const pinLabels = this._parsedProps.pinLabels;
|
|
974
|
+
if (pinLabels) {
|
|
975
|
+
for (let [pinNumber, label] of Object.entries(pinLabels)) {
|
|
976
|
+
pinNumber = pinNumber.replace("pin", "");
|
|
977
|
+
const port = this.selectOne(`port[pinNumber='${pinNumber}']`);
|
|
978
|
+
if (!port) {
|
|
979
|
+
throw new Error(
|
|
980
|
+
`Could not find port for pin number ${pinNumber} in chip ${this.getString()}`
|
|
981
|
+
);
|
|
982
|
+
}
|
|
983
|
+
port.externallyAddedAliases.push(label);
|
|
984
|
+
port.props.name = label;
|
|
985
|
+
}
|
|
986
|
+
}
|
|
869
987
|
}
|
|
870
988
|
_addChildrenFromStringFootprint() {
|
|
871
989
|
const { footprint } = this.props;
|
|
@@ -1902,27 +2020,81 @@ var Chip = class extends NormalComponent {
|
|
|
1902
2020
|
zodProps: chipProps
|
|
1903
2021
|
};
|
|
1904
2022
|
}
|
|
1905
|
-
|
|
1906
|
-
|
|
2023
|
+
doInitialSourceRender() {
|
|
2024
|
+
const { db } = this.project;
|
|
1907
2025
|
const { _parsedProps: props } = this;
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
2026
|
+
const source_component = db.source_component.insert({
|
|
2027
|
+
ftype: "simple_chip",
|
|
2028
|
+
name: props.name,
|
|
2029
|
+
manufacturer_part_number: props.manufacturerPartNumber,
|
|
2030
|
+
supplier_part_numbers: props.supplierPartNumbers
|
|
2031
|
+
});
|
|
2032
|
+
this.source_component_id = source_component.source_component_id;
|
|
2033
|
+
}
|
|
2034
|
+
doInitialSchematicComponentRender() {
|
|
2035
|
+
const { db } = this.project;
|
|
2036
|
+
const { _parsedProps: props } = this;
|
|
2037
|
+
const ports = this.children.filter((child) => child instanceof Port);
|
|
2038
|
+
const pinSpacing = props.schPinSpacing ?? 0.2;
|
|
2039
|
+
const dimensions = getAllDimensionsForSchematicBox({
|
|
2040
|
+
schWidth: props.schWidth,
|
|
2041
|
+
schHeight: props.schHeight,
|
|
2042
|
+
schPinSpacing: pinSpacing,
|
|
2043
|
+
schPinStyle: props.schPinStyle,
|
|
2044
|
+
pinCount: ports.length,
|
|
2045
|
+
// @ts-ignore there's a subtley in the definition difference with
|
|
2046
|
+
// leftSide/rightSide/topSide/bottomSide in how the direction is defined
|
|
2047
|
+
// that doesn't really matter
|
|
2048
|
+
schPortArrangement: props.schPortArrangement
|
|
2049
|
+
});
|
|
2050
|
+
this.schematicDimensions = dimensions;
|
|
2051
|
+
const schematic_component2 = db.schematic_component.insert({
|
|
2052
|
+
center: { x: props.schX ?? 0, y: props.schY ?? 0 },
|
|
2053
|
+
rotation: props.schRotation ?? 0,
|
|
2054
|
+
size: dimensions.getSize(),
|
|
2055
|
+
port_arrangement: underscorifyPortArrangement(
|
|
2056
|
+
props.schPortArrangement
|
|
2057
|
+
),
|
|
2058
|
+
pin_spacing: pinSpacing,
|
|
2059
|
+
// @ts-ignore soup needs to support distance for pin_styles
|
|
2060
|
+
pin_styles: underscorifyPinStyles(props.schPinStyle),
|
|
2061
|
+
port_labels: props.pinLabels,
|
|
2062
|
+
source_component_id: this.source_component_id
|
|
2063
|
+
});
|
|
2064
|
+
this.schematic_component_id = schematic_component2.schematic_component_id;
|
|
2065
|
+
}
|
|
2066
|
+
doInitialPcbComponentRender() {
|
|
2067
|
+
const { db } = this.project;
|
|
2068
|
+
const { _parsedProps: props } = this;
|
|
2069
|
+
const pcb_component = db.pcb_component.insert({
|
|
2070
|
+
center: { x: props.pcbX ?? 0, y: props.pcbY ?? 0 },
|
|
2071
|
+
width: 2,
|
|
2072
|
+
// Default width, adjust as needed
|
|
2073
|
+
height: 3,
|
|
2074
|
+
// Default height, adjust as needed
|
|
2075
|
+
layer: props.layer ?? "top",
|
|
2076
|
+
rotation: props.pcbRotation ?? 0,
|
|
2077
|
+
source_component_id: this.source_component_id
|
|
2078
|
+
});
|
|
2079
|
+
this.pcb_component_id = pcb_component.pcb_component_id;
|
|
2080
|
+
}
|
|
2081
|
+
};
|
|
2082
|
+
|
|
2083
|
+
// lib/components/normal-components/Jumper.ts
|
|
2084
|
+
import { jumperProps } from "@tscircuit/props";
|
|
2085
|
+
var Jumper = class extends NormalComponent {
|
|
2086
|
+
schematicDimensions = null;
|
|
2087
|
+
get config() {
|
|
2088
|
+
return {
|
|
2089
|
+
zodProps: jumperProps
|
|
2090
|
+
};
|
|
1920
2091
|
}
|
|
1921
2092
|
doInitialSourceRender() {
|
|
1922
2093
|
const { db } = this.project;
|
|
1923
2094
|
const { _parsedProps: props } = this;
|
|
1924
2095
|
const source_component = db.source_component.insert({
|
|
1925
2096
|
ftype: "simple_chip",
|
|
2097
|
+
// TODO unknown or jumper
|
|
1926
2098
|
name: props.name,
|
|
1927
2099
|
manufacturer_part_number: props.manufacturerPartNumber,
|
|
1928
2100
|
supplier_part_numbers: props.supplierPartNumbers
|
|
@@ -1943,7 +2115,10 @@ var Chip = class extends NormalComponent {
|
|
|
1943
2115
|
// @ts-ignore there's a subtley in the definition difference with
|
|
1944
2116
|
// leftSide/rightSide/topSide/bottomSide in how the direction is defined
|
|
1945
2117
|
// that doesn't really matter
|
|
1946
|
-
schPortArrangement:
|
|
2118
|
+
schPortArrangement: {
|
|
2119
|
+
// TODO use schematic direction or schPortArrangement
|
|
2120
|
+
rightSize: ports.length
|
|
2121
|
+
}
|
|
1947
2122
|
});
|
|
1948
2123
|
this.schematicDimensions = dimensions;
|
|
1949
2124
|
const schematic_component2 = db.schematic_component.insert({
|
|
@@ -1986,6 +2161,7 @@ var Project = class {
|
|
|
1986
2161
|
rootComponent = null;
|
|
1987
2162
|
children;
|
|
1988
2163
|
db;
|
|
2164
|
+
_hasRenderedAtleastOnce = false;
|
|
1989
2165
|
constructor() {
|
|
1990
2166
|
this.children = [];
|
|
1991
2167
|
this.db = su([]);
|
|
@@ -2029,13 +2205,29 @@ var Project = class {
|
|
|
2029
2205
|
if (!rootComponent) throw new Error("Project has no root component");
|
|
2030
2206
|
rootComponent.setProject(this);
|
|
2031
2207
|
rootComponent.runRenderCycle();
|
|
2208
|
+
this._hasRenderedAtleastOnce = true;
|
|
2032
2209
|
}
|
|
2033
2210
|
getSoup() {
|
|
2211
|
+
if (!this._hasRenderedAtleastOnce) this.render();
|
|
2034
2212
|
return this.db.toArray();
|
|
2035
2213
|
}
|
|
2036
2214
|
getCircuitJson() {
|
|
2037
2215
|
return this.getSoup();
|
|
2038
2216
|
}
|
|
2217
|
+
async getSvg(options) {
|
|
2218
|
+
const circuitToSvg = await import("circuit-to-svg").catch((e) => {
|
|
2219
|
+
throw new Error(
|
|
2220
|
+
`To use project.getSvg, you must install the "circuit-to-svg" package.
|
|
2221
|
+
|
|
2222
|
+
"${e.message}"`
|
|
2223
|
+
);
|
|
2224
|
+
});
|
|
2225
|
+
return circuitToSvg.circuitJsonToPcbSvg(this.getSoup());
|
|
2226
|
+
}
|
|
2227
|
+
async preview(previewNameOrOpts) {
|
|
2228
|
+
const previewOpts = typeof previewNameOrOpts === "object" ? previewNameOrOpts : { previewName: previewNameOrOpts };
|
|
2229
|
+
throw new Error("project.preview is not yet implemented");
|
|
2230
|
+
}
|
|
2039
2231
|
computeGlobalSchematicTransform() {
|
|
2040
2232
|
return identity5();
|
|
2041
2233
|
}
|
|
@@ -2061,14 +2253,17 @@ export {
|
|
|
2061
2253
|
Chip,
|
|
2062
2254
|
Footprint,
|
|
2063
2255
|
Group,
|
|
2256
|
+
Jumper,
|
|
2064
2257
|
Led,
|
|
2065
2258
|
Net,
|
|
2066
2259
|
NormalComponent,
|
|
2260
|
+
PlatedHole,
|
|
2067
2261
|
Port,
|
|
2068
2262
|
PrimitiveComponent,
|
|
2069
2263
|
Project,
|
|
2070
2264
|
Renderable,
|
|
2071
2265
|
Resistor,
|
|
2266
|
+
SilkscreenPath,
|
|
2072
2267
|
SmtPad,
|
|
2073
2268
|
Trace,
|
|
2074
2269
|
TraceHint
|
package/lib/Project.ts
CHANGED
|
@@ -11,6 +11,8 @@ export class Project {
|
|
|
11
11
|
children: PrimitiveComponent[]
|
|
12
12
|
db: SoupUtilObjects
|
|
13
13
|
|
|
14
|
+
_hasRenderedAtleastOnce = false
|
|
15
|
+
|
|
14
16
|
constructor() {
|
|
15
17
|
this.children = []
|
|
16
18
|
this.db = su([])
|
|
@@ -64,9 +66,11 @@ export class Project {
|
|
|
64
66
|
rootComponent.setProject(this)
|
|
65
67
|
|
|
66
68
|
rootComponent.runRenderCycle()
|
|
69
|
+
this._hasRenderedAtleastOnce = true
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
getSoup(): AnySoupElement[] {
|
|
73
|
+
if (!this._hasRenderedAtleastOnce) this.render()
|
|
70
74
|
return this.db.toArray()
|
|
71
75
|
}
|
|
72
76
|
|
|
@@ -74,6 +78,31 @@ export class Project {
|
|
|
74
78
|
return this.getSoup()
|
|
75
79
|
}
|
|
76
80
|
|
|
81
|
+
async getSvg(options: { view: "pcb"; layer?: string }): Promise<string> {
|
|
82
|
+
const circuitToSvg = await import("circuit-to-svg").catch((e) => {
|
|
83
|
+
throw new Error(
|
|
84
|
+
`To use project.getSvg, you must install the "circuit-to-svg" package.\n\n"${e.message}"`,
|
|
85
|
+
)
|
|
86
|
+
})
|
|
87
|
+
|
|
88
|
+
return circuitToSvg.circuitJsonToPcbSvg(this.getSoup())
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async preview(
|
|
92
|
+
previewNameOrOpts:
|
|
93
|
+
| string
|
|
94
|
+
| {
|
|
95
|
+
previewName: string
|
|
96
|
+
tscircuitApiKey?: string
|
|
97
|
+
},
|
|
98
|
+
) {
|
|
99
|
+
const previewOpts =
|
|
100
|
+
typeof previewNameOrOpts === "object"
|
|
101
|
+
? previewNameOrOpts
|
|
102
|
+
: { previewName: previewNameOrOpts }
|
|
103
|
+
throw new Error("project.preview is not yet implemented")
|
|
104
|
+
}
|
|
105
|
+
|
|
77
106
|
computeGlobalSchematicTransform(): Matrix {
|
|
78
107
|
return identity()
|
|
79
108
|
}
|
|
@@ -87,6 +87,22 @@ export class NormalComponent<
|
|
|
87
87
|
const portsFromFootprint = this.getPortsFromFootprint()
|
|
88
88
|
|
|
89
89
|
this.addAll(portsFromFootprint)
|
|
90
|
+
|
|
91
|
+
const pinLabels: Record<string, string> | undefined =
|
|
92
|
+
this._parsedProps.pinLabels
|
|
93
|
+
if (pinLabels) {
|
|
94
|
+
for (let [pinNumber, label] of Object.entries(pinLabels)) {
|
|
95
|
+
pinNumber = pinNumber.replace("pin", "")
|
|
96
|
+
const port = this.selectOne(`port[pinNumber='${pinNumber}']`)
|
|
97
|
+
if (!port) {
|
|
98
|
+
throw new Error(
|
|
99
|
+
`Could not find port for pin number ${pinNumber} in chip ${this.getString()}`,
|
|
100
|
+
)
|
|
101
|
+
}
|
|
102
|
+
port.externallyAddedAliases.push(label)
|
|
103
|
+
port.props.name = label
|
|
104
|
+
}
|
|
105
|
+
}
|
|
90
106
|
}
|
|
91
107
|
|
|
92
108
|
_addChildrenFromStringFootprint() {
|
|
@@ -46,6 +46,8 @@ export abstract class PrimitiveComponent<
|
|
|
46
46
|
componentName = ""
|
|
47
47
|
lowercaseComponentName = ""
|
|
48
48
|
|
|
49
|
+
externallyAddedAliases: string[]
|
|
50
|
+
|
|
49
51
|
source_group_id: string | null = null
|
|
50
52
|
source_component_id: string | null = null
|
|
51
53
|
schematic_component_id: string | null = null
|
|
@@ -57,6 +59,7 @@ export abstract class PrimitiveComponent<
|
|
|
57
59
|
this.children = []
|
|
58
60
|
this.childrenPendingRemoval = []
|
|
59
61
|
this.props = props ?? {}
|
|
62
|
+
this.externallyAddedAliases = []
|
|
60
63
|
this._parsedProps = this.config.zodProps.parse(
|
|
61
64
|
props ?? {},
|
|
62
65
|
) as z.infer<ZodProps>
|
package/lib/components/index.ts
CHANGED
|
@@ -13,3 +13,6 @@ export { Trace } from "./primitive-components/Trace"
|
|
|
13
13
|
export { TraceHint } from "./primitive-components/TraceHint"
|
|
14
14
|
export { Group } from "./primitive-components/Group"
|
|
15
15
|
export { Chip } from "./normal-components/Chip"
|
|
16
|
+
export { Jumper } from "./normal-components/Jumper"
|
|
17
|
+
export { SilkscreenPath } from "./primitive-components/SilkscreenPath"
|
|
18
|
+
export { PlatedHole } from "./primitive-components/PlatedHole"
|
|
@@ -21,25 +21,6 @@ export class Chip<PinLabels extends string = never> extends NormalComponent<
|
|
|
21
21
|
}
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
initPorts() {
|
|
25
|
-
super.initPorts()
|
|
26
|
-
|
|
27
|
-
const { _parsedProps: props } = this
|
|
28
|
-
|
|
29
|
-
if (props.pinLabels) {
|
|
30
|
-
for (const [pinNumber, label] of Object.entries(props.pinLabels)) {
|
|
31
|
-
const port = this.selectOne(`port[pinNumber='${pinNumber}']`)
|
|
32
|
-
if (!port) {
|
|
33
|
-
throw new Error(
|
|
34
|
-
`Could not find port for pin number ${pinNumber} in chip ${this.getString()}`,
|
|
35
|
-
)
|
|
36
|
-
}
|
|
37
|
-
port.props.aliases.push(port.props.name)
|
|
38
|
-
port.props.name = label
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
24
|
doInitialSourceRender(): void {
|
|
44
25
|
const { db } = this.project!
|
|
45
26
|
const { _parsedProps: props } = this
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { NormalComponent } from "lib/components/base-components/NormalComponent"
|
|
2
|
+
import { jumperProps } from "@tscircuit/props"
|
|
3
|
+
import { Port } from "../primitive-components/Port"
|
|
4
|
+
import type { BaseSymbolName } from "lib/utils/constants"
|
|
5
|
+
import {
|
|
6
|
+
getAllDimensionsForSchematicBox,
|
|
7
|
+
type SchematicBoxDimensions,
|
|
8
|
+
} from "lib/utils/schematic/getAllDimensionsForSchematicBox"
|
|
9
|
+
import { underscorifyPortArrangement } from "lib/soup/underscorifyPortArrangement"
|
|
10
|
+
import { underscorifyPinStyles } from "lib/soup/underscorifyPinStyles"
|
|
11
|
+
|
|
12
|
+
export class Jumper<PinLabels extends string = never> extends NormalComponent<
|
|
13
|
+
typeof jumperProps,
|
|
14
|
+
PinLabels
|
|
15
|
+
> {
|
|
16
|
+
schematicDimensions: SchematicBoxDimensions | null = null
|
|
17
|
+
|
|
18
|
+
get config() {
|
|
19
|
+
return {
|
|
20
|
+
zodProps: jumperProps,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
doInitialSourceRender(): void {
|
|
25
|
+
const { db } = this.project!
|
|
26
|
+
const { _parsedProps: props } = this
|
|
27
|
+
|
|
28
|
+
const source_component = db.source_component.insert({
|
|
29
|
+
ftype: "simple_chip", // TODO unknown or jumper
|
|
30
|
+
name: props.name,
|
|
31
|
+
manufacturer_part_number: props.manufacturerPartNumber,
|
|
32
|
+
supplier_part_numbers: props.supplierPartNumbers,
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
this.source_component_id = source_component.source_component_id!
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
doInitialSchematicComponentRender() {
|
|
39
|
+
const { db } = this.project!
|
|
40
|
+
const { _parsedProps: props } = this
|
|
41
|
+
|
|
42
|
+
const ports = this.children.filter((child) => child instanceof Port)
|
|
43
|
+
|
|
44
|
+
const pinSpacing = props.schPinSpacing ?? 0.2
|
|
45
|
+
|
|
46
|
+
const dimensions = getAllDimensionsForSchematicBox({
|
|
47
|
+
schWidth: props.schWidth,
|
|
48
|
+
schHeight: props.schHeight,
|
|
49
|
+
schPinSpacing: pinSpacing,
|
|
50
|
+
schPinStyle: props.schPinStyle,
|
|
51
|
+
|
|
52
|
+
pinCount: ports.length,
|
|
53
|
+
|
|
54
|
+
// @ts-ignore there's a subtley in the definition difference with
|
|
55
|
+
// leftSide/rightSide/topSide/bottomSide in how the direction is defined
|
|
56
|
+
// that doesn't really matter
|
|
57
|
+
schPortArrangement: {
|
|
58
|
+
// TODO use schematic direction or schPortArrangement
|
|
59
|
+
rightSize: ports.length,
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
this.schematicDimensions = dimensions
|
|
63
|
+
|
|
64
|
+
const schematic_component = db.schematic_component.insert({
|
|
65
|
+
center: { x: props.schX ?? 0, y: props.schY ?? 0 },
|
|
66
|
+
rotation: props.schRotation ?? 0,
|
|
67
|
+
size: dimensions.getSize(),
|
|
68
|
+
|
|
69
|
+
port_arrangement: underscorifyPortArrangement(
|
|
70
|
+
props.schPortArrangement as any,
|
|
71
|
+
),
|
|
72
|
+
|
|
73
|
+
pin_spacing: pinSpacing,
|
|
74
|
+
|
|
75
|
+
// @ts-ignore soup needs to support distance for pin_styles
|
|
76
|
+
pin_styles: underscorifyPinStyles(props.schPinStyle),
|
|
77
|
+
|
|
78
|
+
port_labels: props.pinLabels,
|
|
79
|
+
|
|
80
|
+
source_component_id: this.source_component_id!,
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
this.schematic_component_id = schematic_component.schematic_component_id
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
doInitialPcbComponentRender() {
|
|
87
|
+
const { db } = this.project!
|
|
88
|
+
const { _parsedProps: props } = this
|
|
89
|
+
|
|
90
|
+
const pcb_component = db.pcb_component.insert({
|
|
91
|
+
center: { x: props.pcbX ?? 0, y: props.pcbY ?? 0 },
|
|
92
|
+
width: 2, // Default width, adjust as needed
|
|
93
|
+
height: 3, // Default height, adjust as needed
|
|
94
|
+
layer: props.layer ?? "top",
|
|
95
|
+
rotation: props.pcbRotation ?? 0,
|
|
96
|
+
source_component_id: this.source_component_id!,
|
|
97
|
+
})
|
|
98
|
+
|
|
99
|
+
this.pcb_component_id = pcb_component.pcb_component_id
|
|
100
|
+
}
|
|
101
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { PrimitiveComponent } from "../base-components/PrimitiveComponent"
|
|
2
|
+
import { platedHoleProps } from "@tscircuit/props"
|
|
3
|
+
import type { Port } from "./Port"
|
|
4
|
+
import type { PCBPlatedHoleInput } from "@tscircuit/soup"
|
|
5
|
+
|
|
6
|
+
export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
|
|
7
|
+
pcb_plated_hole_id: string | null = null
|
|
8
|
+
matchedPort: Port | null = null
|
|
9
|
+
isPcbPrimitive = true
|
|
10
|
+
|
|
11
|
+
get config() {
|
|
12
|
+
return {
|
|
13
|
+
zodProps: platedHoleProps,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
doInitialPortMatching(): void {
|
|
18
|
+
const parentPorts = (this.parent?.children ?? []).filter(
|
|
19
|
+
(c) => c.componentName === "Port",
|
|
20
|
+
) as Port[]
|
|
21
|
+
|
|
22
|
+
if (!this.props.portHints) {
|
|
23
|
+
return
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
for (const port of parentPorts) {
|
|
27
|
+
if (port.isMatchingAnyOf(this.props.portHints)) {
|
|
28
|
+
this.matchedPort = port
|
|
29
|
+
port.registerMatch(this)
|
|
30
|
+
return
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
doInitialPcbPrimitiveRender(): void {
|
|
36
|
+
const { db } = this.project!
|
|
37
|
+
const { _parsedProps: props } = this
|
|
38
|
+
if (!props.portHints) return
|
|
39
|
+
const position = this.getGlobalPcbPosition()
|
|
40
|
+
if (props.shape === "circle") {
|
|
41
|
+
const plated_hole_input: PCBPlatedHoleInput = {
|
|
42
|
+
pcb_component_id: this.parent?.pcb_component_id!,
|
|
43
|
+
pcb_port_id: this.matchedPort?.pcb_port_id!,
|
|
44
|
+
layers: ["top", "bottom"],
|
|
45
|
+
outer_diameter: props.outerDiameter,
|
|
46
|
+
hole_diameter: props.holeDiameter,
|
|
47
|
+
shape: "circle",
|
|
48
|
+
port_hints: this.getNameAndAliases(),
|
|
49
|
+
x: position.x,
|
|
50
|
+
y: position.y,
|
|
51
|
+
type: "pcb_plated_hole",
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// @ts-ignore - some issue with soup-util types it seems
|
|
55
|
+
const pcb_plated_hole = db.pcb_plated_hole.insert(plated_hole_input)
|
|
56
|
+
|
|
57
|
+
// this.pcb_plated_hole_id = pcb_plated_hole.pcb_plated_hole_id
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { silkscreenPathProps } from "@tscircuit/props"
|
|
2
|
+
import { PrimitiveComponent } from "../base-components/PrimitiveComponent"
|
|
3
|
+
|
|
4
|
+
export class SilkscreenPath extends PrimitiveComponent<
|
|
5
|
+
typeof silkscreenPathProps
|
|
6
|
+
> {
|
|
7
|
+
pcb_silkscreen_path_id: string | null = null
|
|
8
|
+
|
|
9
|
+
get config() {
|
|
10
|
+
return {
|
|
11
|
+
zodProps: silkscreenPathProps,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
doInitialPcbPrimitiveRender(): void {
|
|
16
|
+
const { db } = this.project!
|
|
17
|
+
const { _parsedProps: props } = this
|
|
18
|
+
|
|
19
|
+
const layer = props.layer ?? "top"
|
|
20
|
+
if (layer !== "top" && layer !== "bottom") {
|
|
21
|
+
throw new Error(
|
|
22
|
+
`Invalid layer "${layer}" for SilkscreenPath. Must be "top" or "bottom".`,
|
|
23
|
+
)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const pcb_silkscreen_path = db.pcb_silkscreen_path.insert({
|
|
27
|
+
pcb_component_id: this.parent?.pcb_component_id!,
|
|
28
|
+
layer,
|
|
29
|
+
route: props.route,
|
|
30
|
+
stroke_width: props.strokeWidth ?? 0.1,
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
this.pcb_silkscreen_path_id = pcb_silkscreen_path.pcb_silkscreen_path_id
|
|
34
|
+
}
|
|
35
|
+
}
|