@tscircuit/core 0.0.146 → 0.0.148

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 +46 -39
  2. package/dist/index.js +416 -484
  3. package/package.json +3 -3
package/dist/index.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import * as _tscircuit_props from '@tscircuit/props';
2
+ import { traceProps, SchematicPortArrangement, groupProps, boardProps, capacitorProps, chipProps, diodeProps, jumperProps, ledProps, powerSourceProps, resistorProps, constraintProps, fabricationNotePathProps, fabricationNoteTextProps, footprintProps, holeProps, pcbKeepoutProps, netAliasProps, platedHoleProps, silkscreenCircleProps, silkscreenPathProps, silkscreenRectProps, silkscreenTextProps, smtPadProps, traceHintProps, viaProps, batteryProps, pinHeaderProps, inductorProps, CapacitorProps, ChipProps, ResistorProps } from '@tscircuit/props';
1
3
  import React, { ReactElement } from 'react';
2
4
  import * as zod from 'zod';
3
5
  import { ZodType, z } from 'zod';
@@ -5,8 +7,6 @@ import { SchSymbol, BaseSymbolName } from 'schematic-symbols';
5
7
  import { PcbTraceError, PcbPlacementError, LayerRef, AnyCircuitElement, AnySourceComponent, RouteHintPoint } from 'circuit-json';
6
8
  import { Matrix } from 'transformation-matrix';
7
9
  import { SoupUtilObjects } from '@tscircuit/soup-util';
8
- import * as _tscircuit_props from '@tscircuit/props';
9
- import { traceProps, groupProps, boardProps, capacitorProps, chipProps, diodeProps, jumperProps, ledProps, powerSourceProps, resistorProps, constraintProps, fabricationNotePathProps, fabricationNoteTextProps, footprintProps, holeProps, pcbKeepoutProps, netAliasProps, platedHoleProps, silkscreenCircleProps, silkscreenPathProps, silkscreenRectProps, silkscreenTextProps, smtPadProps, traceHintProps, viaProps, batteryProps, pinHeaderProps, inductorProps, CapacitorProps, ChipProps, ResistorProps } from '@tscircuit/props';
10
10
  import * as _tscircuit_layout from '@tscircuit/layout';
11
11
 
12
12
  declare const orderedRenderPhases: readonly ["ReactSubtreesRender", "InitializePortsFromChildren", "CreateNetsFromProps", "CreateTracesFromProps", "CreateTraceHintsFromProps", "SourceRender", "SourceParentAttachment", "PortDiscovery", "PortMatching", "SourceTraceRender", "SchematicComponentRender", "SchematicPortRender", "SchematicLayout", "SchematicTraceRender", "PcbComponentRender", "PcbPrimitiveRender", "PcbFootprintLayout", "PcbPortRender", "PcbPortAttachment", "PcbLayout", "PcbTraceRender", "PcbTraceHintRender", "PcbRouteNetIslands", "PcbComponentSizeCalculation", "CadModelRender"];
@@ -111,11 +111,29 @@ interface ISubcircuit extends PrimitiveComponent {
111
111
  _shouldUseTraceByTraceRouting(): boolean;
112
112
  }
113
113
 
114
+ type SchematicBoxPortPositionWithMetadata = {
115
+ trueIndex: number;
116
+ pinNumber: number;
117
+ side: "left" | "right" | "top" | "bottom";
118
+ distanceFromOrthogonalEdge: number;
119
+ x: number;
120
+ y: number;
121
+ };
122
+ interface SchematicBoxDimensions {
123
+ pinCount: number;
124
+ getPortPositionByPinNumber(pinNumber: number): SchematicBoxPortPositionWithMetadata | null;
125
+ getSize(): {
126
+ width: number;
127
+ height: number;
128
+ };
129
+ }
130
+
114
131
  interface BaseComponentConfig {
115
132
  componentName: string;
116
133
  schematicSymbolName?: BaseSymbolName | null;
117
134
  zodProps: ZodType;
118
135
  sourceFtype?: AnySourceComponent["ftype"] | null;
136
+ shouldRenderAsSchematicBox?: boolean;
119
137
  }
120
138
  /**
121
139
  * A PrimitiveComponent (SmtPad, Port etc.) doesn't have the ability to contain
@@ -271,6 +289,16 @@ declare abstract class PrimitiveComponent<ZodProps extends ZodType = any> extend
271
289
  }): PrimitiveComponent | null;
272
290
  getAvailablePcbLayers(): string[];
273
291
  getDescendants(): PrimitiveComponent[];
292
+ /**
293
+ * Return the number of pins in this component, this is important for
294
+ * NormalComponents
295
+ */
296
+ _getPinCount(): number;
297
+ /**
298
+ * If this component represents a SchematicBox (like a Chip), return the
299
+ * dimensions of the box, which allows computing the position of ports etc.
300
+ */
301
+ _getSchematicBoxDimensions(): SchematicBoxDimensions | null;
274
302
  renderError(message: Parameters<typeof Renderable.prototype.renderError>[0]): void;
275
303
  getString(): string;
276
304
  get [Symbol.toStringTag](): string;
@@ -696,11 +724,14 @@ declare class NormalComponent<ZodProps extends ZodType = any, PortNames extends
696
724
  doInitialSourceRender(): void;
697
725
  /**
698
726
  * Render the schematic component for this NormalComponent using the
699
- * config.schematicSymbolName if it exists.
727
+ * config.schematicSymbolName if it exists, or create a generic box if
728
+ * no symbol is defined.
700
729
  *
701
730
  * You can override this method to do more complicated things.
702
731
  */
703
732
  doInitialSchematicComponentRender(): void;
733
+ _doInitialSchematicComponentRenderWithSymbol(): void;
734
+ _doInitialSchematicComponentRenderWithSchematicBoxDimensions(): void;
704
735
  doInitialPcbComponentRender(): void;
705
736
  /**
706
737
  * At this stage, the smtpads/pcb primitives are placed, so we can compute
@@ -739,6 +770,13 @@ declare class NormalComponent<ZodProps extends ZodType = any, PortNames extends
739
770
  width: number;
740
771
  height: number;
741
772
  };
773
+ _getPinCount(): number;
774
+ /**
775
+ * Override the schematic port arrangement if you want to customize where pins
776
+ * appear on a schematic box, e.g. for a pin header
777
+ */
778
+ _getSchematicPortArrangement(): SchematicPortArrangement | null;
779
+ _getSchematicBoxDimensions(): SchematicBoxDimensions | null;
742
780
  doInitialCadModelRender(): void;
743
781
  }
744
782
 
@@ -1310,39 +1348,8 @@ declare class Capacitor extends NormalComponent<typeof capacitorProps, PassivePo
1310
1348
  doInitialSourceRender(): void;
1311
1349
  }
1312
1350
 
1313
- type PortInfo = {
1314
- trueIndex: number;
1315
- pinNumber: number;
1316
- side: "left" | "right" | "top" | "bottom" | "center";
1317
- distanceFromEdge: number;
1318
- x: number;
1319
- y: number;
1320
- };
1321
- /**
1322
- * Get the dimensions of a schematic box based on the provided parameters.
1323
- *
1324
- * A schematic box is a rectangular box with a set of pins on the sides.
1325
- *
1326
- * The user can customize the position of the pins and the spacing between them,
1327
- * this makes computing the box fairly complicated.
1328
- *
1329
- * A note on the internals:
1330
- * * A "true port" refers to a pin/port before it's remapped by the user to a
1331
- * different position. True Pin 1 is guaranteed to be in the top-left corner
1332
- * * We basically iterate over each side and compute how far we are from the
1333
- * edge for that side by adding margins together
1334
- */
1335
- interface SchematicBoxDimensions {
1336
- pinCount: number;
1337
- getPortPositionByPinNumber(pinNumber: number): PortInfo;
1338
- getSize(): {
1339
- width: number;
1340
- height: number;
1341
- };
1342
- }
1343
-
1344
1351
  declare class Chip<PinLabels extends string = never> extends NormalComponent<typeof chipProps, PinLabels> {
1345
- schematicDimensions: SchematicBoxDimensions | null;
1352
+ schematicBoxDimensions: SchematicBoxDimensions | null;
1346
1353
  get config(): {
1347
1354
  componentName: string;
1348
1355
  zodProps: zod.ZodObject<zod.objectUtil.extendShape<zod.objectUtil.extendShape<zod.objectUtil.extendShape<{
@@ -1934,9 +1941,9 @@ declare class Chip<PinLabels extends string = never> extends NormalComponent<typ
1934
1941
  schWidth?: string | number | undefined;
1935
1942
  schHeight?: string | number | undefined;
1936
1943
  }>;
1944
+ shouldRenderAsSchematicBox: boolean;
1937
1945
  };
1938
1946
  doInitialSourceRender(): void;
1939
- doInitialSchematicComponentRender(): void;
1940
1947
  doInitialPcbComponentRender(): void;
1941
1948
  }
1942
1949
 
@@ -2942,9 +2949,9 @@ declare class Jumper<PinLabels extends string = never> extends NormalComponent<t
2942
2949
  schHeight?: string | number | undefined;
2943
2950
  schDirection?: "left" | "right" | undefined;
2944
2951
  }>;
2952
+ shouldRenderAsSchematicBox: boolean;
2945
2953
  };
2946
2954
  doInitialSourceRender(): void;
2947
- doInitialSchematicComponentRender(): void;
2948
2955
  doInitialPcbComponentRender(): void;
2949
2956
  }
2950
2957
 
@@ -6234,12 +6241,12 @@ declare class PinHeader extends NormalComponent<typeof pinHeaderProps> {
6234
6241
  doubleRow?: boolean | undefined;
6235
6242
  platedDiameter?: string | number | undefined;
6236
6243
  }>;
6237
- schematicSymbolName: BaseSymbolName;
6244
+ shouldRenderAsSchematicBox: boolean;
6238
6245
  };
6239
6246
  _getImpliedFootprintString(): string | null;
6240
6247
  initPorts(): void;
6248
+ _getSchematicPortArrangement(): SchematicPortArrangement | null;
6241
6249
  doInitialSourceRender(): void;
6242
- doInitialSchematicComponentRender(): void;
6243
6250
  }
6244
6251
 
6245
6252
  declare class Inductor extends NormalComponent<typeof inductorProps, PassivePorts> {
package/dist/index.js CHANGED
@@ -790,6 +790,20 @@ var PrimitiveComponent = class extends Renderable {
790
790
  }
791
791
  return descendants;
792
792
  }
793
+ /**
794
+ * Return the number of pins in this component, this is important for
795
+ * NormalComponents
796
+ */
797
+ _getPinCount() {
798
+ return 0;
799
+ }
800
+ /**
801
+ * If this component represents a SchematicBox (like a Chip), return the
802
+ * dimensions of the box, which allows computing the position of ports etc.
803
+ */
804
+ _getSchematicBoxDimensions() {
805
+ return null;
806
+ }
793
807
  // TODO we shouldn't need to override this, errors can be rendered and handled
794
808
  // by the Renderable class, however, the Renderable class currently doesn't
795
809
  // have access to the database or cleanup
@@ -1615,23 +1629,28 @@ var Port = class extends PrimitiveComponent {
1615
1629
  return this._getPcbCircuitJsonBounds().center;
1616
1630
  }
1617
1631
  _getGlobalSchematicPositionBeforeLayout() {
1618
- if (!this.schematicSymbolPortDef) {
1619
- return applyToPoint4(this.parent.computeSchematicGlobalTransform(), {
1620
- x: 0,
1621
- y: 0
1622
- });
1623
- }
1624
1632
  const symbol = this.parent?.getSchematicSymbol();
1625
- if (!symbol) {
1626
- console.warn(`Could not find parent symbol for ${this}`);
1627
- return { x: 0, y: 0 };
1628
- }
1629
- const offsetY = -0.045;
1630
- const transform = compose3(
1631
- this.parent.computeSchematicGlobalTransform(),
1632
- translate3(-symbol.center.x, -symbol.center.y + offsetY)
1633
- );
1634
- return applyToPoint4(transform, this.schematicSymbolPortDef);
1633
+ if (symbol && this.schematicSymbolPortDef) {
1634
+ const transform = compose3(
1635
+ this.parent.computeSchematicGlobalTransform(),
1636
+ translate3(-symbol.center.x, -symbol.center.y)
1637
+ );
1638
+ return applyToPoint4(transform, this.schematicSymbolPortDef);
1639
+ }
1640
+ const parentBoxDim = this?.parent?._getSchematicBoxDimensions();
1641
+ if (parentBoxDim && this.props.pinNumber !== void 0) {
1642
+ const localPortPosition = parentBoxDim.getPortPositionByPinNumber(
1643
+ this.props.pinNumber
1644
+ );
1645
+ if (!localPortPosition) {
1646
+ return { x: 0, y: 0 };
1647
+ }
1648
+ return applyToPoint4(
1649
+ this.parent.computeSchematicGlobalTransform(),
1650
+ localPortPosition
1651
+ );
1652
+ }
1653
+ return { x: 0, y: 0 };
1635
1654
  }
1636
1655
  _getGlobalSchematicPositionAfterLayout() {
1637
1656
  const { db } = this.root;
@@ -1749,17 +1768,16 @@ var Port = class extends PrimitiveComponent {
1749
1768
  const container = this.getPrimitiveContainer();
1750
1769
  if (!container) return;
1751
1770
  const containerCenter = container._getGlobalSchematicPositionBeforeLayout();
1752
- let center = this._getGlobalSchematicPositionBeforeLayout();
1753
- if ("schematicDimensions" in container && props.pinNumber !== void 0) {
1754
- const chipDims = container.schematicDimensions;
1755
- center = chipDims.getPortPositionByPinNumber(props.pinNumber);
1756
- center.x += containerCenter.x;
1757
- center.y += containerCenter.y;
1771
+ const portCenter = this._getGlobalSchematicPositionBeforeLayout();
1772
+ let localPortInfo = null;
1773
+ const containerDims = container._getSchematicBoxDimensions();
1774
+ if (containerDims && props.pinNumber !== void 0) {
1775
+ localPortInfo = containerDims.getPortPositionByPinNumber(props.pinNumber);
1758
1776
  }
1759
1777
  if (this.getSubcircuit().props._schDebugObjectsEnabled) {
1760
1778
  db.schematic_debug_object.insert({
1761
1779
  shape: "rect",
1762
- center,
1780
+ center: portCenter,
1763
1781
  size: {
1764
1782
  width: 0.1,
1765
1783
  height: 0.1
@@ -1767,12 +1785,16 @@ var Port = class extends PrimitiveComponent {
1767
1785
  label: "obstacle"
1768
1786
  });
1769
1787
  }
1770
- this.facingDirection = getRelativeDirection(containerCenter, center);
1788
+ this.facingDirection = getRelativeDirection(containerCenter, portCenter);
1771
1789
  const schematic_port = db.schematic_port.insert({
1772
1790
  schematic_component_id: this.parent?.schematic_component_id,
1773
- center,
1791
+ center: portCenter,
1774
1792
  source_port_id: this.source_port_id,
1775
- facing_direction: this.facingDirection
1793
+ facing_direction: this.facingDirection,
1794
+ distance_from_component_edge: 0.4,
1795
+ side_of_component: localPortInfo?.side,
1796
+ pin_number: props.pinNumber,
1797
+ true_ccw_index: localPortInfo?.trueIndex
1776
1798
  });
1777
1799
  this.schematic_port_id = schematic_port.schematic_port_id;
1778
1800
  }
@@ -1805,7 +1827,7 @@ import {
1805
1827
  isValidElement
1806
1828
  } from "react";
1807
1829
  import { symbols as symbols2 } from "schematic-symbols";
1808
- import { z as z4 } from "zod";
1830
+ import { z as z5 } from "zod";
1809
1831
 
1810
1832
  // lib/components/primitive-components/Footprint.ts
1811
1833
  import { footprintProps } from "@tscircuit/props";
@@ -2016,9 +2038,290 @@ var Footprint = class extends PrimitiveComponent {
2016
2038
  }
2017
2039
  };
2018
2040
 
2041
+ // lib/utils/schematic/getSizeOfSidesFromPortArrangement.ts
2042
+ var hasExplicitPinMapping = (pa) => {
2043
+ for (const side of [
2044
+ "leftSide",
2045
+ "rightSide",
2046
+ "topSide",
2047
+ "bottomSide"
2048
+ ]) {
2049
+ if (side in pa && typeof pa[side] === "number") {
2050
+ throw new Error(
2051
+ `A number was specified for "${side}", you probably meant to use "size" not "side"`
2052
+ );
2053
+ }
2054
+ }
2055
+ return "leftSide" in pa || "rightSide" in pa || "topSide" in pa || "bottomSide" in pa;
2056
+ };
2057
+ var getSizeOfSidesFromPortArrangement = (pa) => {
2058
+ if (hasExplicitPinMapping(pa)) {
2059
+ return {
2060
+ leftSize: pa.leftSide?.pins.length ?? 0,
2061
+ rightSize: pa.rightSide?.pins.length ?? 0,
2062
+ topSize: pa.topSide?.pins.length ?? 0,
2063
+ bottomSize: pa.bottomSide?.pins.length ?? 0
2064
+ };
2065
+ }
2066
+ const { leftSize = 0, rightSize = 0, topSize = 0, bottomSize = 0 } = pa;
2067
+ return { leftSize, rightSize, topSize, bottomSize };
2068
+ };
2069
+
2070
+ // lib/utils/schematic/getAllDimensionsForSchematicBox.ts
2071
+ function isExplicitPinMappingArrangement(arrangement) {
2072
+ return arrangement.leftSide !== void 0;
2073
+ }
2074
+ var getAllDimensionsForSchematicBox = (params) => {
2075
+ const portDistanceFromEdge = params.portDistanceFromEdge ?? 0.4;
2076
+ let sidePinCounts = params.schPortArrangement ? getSizeOfSidesFromPortArrangement(params.schPortArrangement) : null;
2077
+ const sideLengths = {
2078
+ left: 0,
2079
+ right: 0,
2080
+ top: 0,
2081
+ bottom: 0
2082
+ };
2083
+ let pinCount = params.pinCount ?? null;
2084
+ if (pinCount === null) {
2085
+ if (sidePinCounts) {
2086
+ pinCount = sidePinCounts.leftSize + sidePinCounts.rightSize + sidePinCounts.topSize;
2087
+ } else {
2088
+ throw new Error("Could not determine pin count for the schematic box");
2089
+ }
2090
+ }
2091
+ if (pinCount && !sidePinCounts) {
2092
+ const rightSize = Math.floor(pinCount / 2);
2093
+ sidePinCounts = {
2094
+ leftSize: pinCount - rightSize,
2095
+ rightSize,
2096
+ topSize: 0,
2097
+ bottomSize: 0
2098
+ };
2099
+ }
2100
+ if (!sidePinCounts) {
2101
+ sidePinCounts = {
2102
+ leftSize: 0,
2103
+ rightSize: 0,
2104
+ topSize: 0,
2105
+ bottomSize: 0
2106
+ };
2107
+ }
2108
+ const orderedTruePorts = [];
2109
+ let currentDistanceFromEdge = 0;
2110
+ let truePinIndex = 0;
2111
+ for (let sideIndex = 0; sideIndex < sidePinCounts.leftSize; sideIndex++) {
2112
+ const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement?.leftSide?.pins[sideIndex] : truePinIndex + 1;
2113
+ const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
2114
+ if (pinStyle?.topMargin) {
2115
+ currentDistanceFromEdge += pinStyle.topMargin;
2116
+ }
2117
+ orderedTruePorts.push({
2118
+ trueIndex: truePinIndex,
2119
+ pinNumber,
2120
+ side: "left",
2121
+ distanceFromOrthogonalEdge: currentDistanceFromEdge
2122
+ });
2123
+ if (pinStyle?.bottomMargin) {
2124
+ currentDistanceFromEdge += pinStyle.bottomMargin;
2125
+ }
2126
+ const isLastPinOnSide = sideIndex === sidePinCounts.leftSize - 1;
2127
+ if (!isLastPinOnSide) {
2128
+ currentDistanceFromEdge += params.schPinSpacing;
2129
+ } else {
2130
+ sideLengths.left = currentDistanceFromEdge;
2131
+ }
2132
+ truePinIndex++;
2133
+ }
2134
+ currentDistanceFromEdge = 0;
2135
+ for (let sideIndex = 0; sideIndex < sidePinCounts.bottomSize; sideIndex++) {
2136
+ const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement.bottomSide?.pins[sideIndex] : truePinIndex + 1;
2137
+ const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
2138
+ if (pinStyle?.leftMargin) {
2139
+ currentDistanceFromEdge += pinStyle.leftMargin;
2140
+ }
2141
+ orderedTruePorts.push({
2142
+ trueIndex: truePinIndex,
2143
+ pinNumber,
2144
+ side: "bottom",
2145
+ distanceFromOrthogonalEdge: currentDistanceFromEdge
2146
+ });
2147
+ if (pinStyle?.rightMargin) {
2148
+ currentDistanceFromEdge += pinStyle.rightMargin;
2149
+ }
2150
+ const isLastPinOnSide = sideIndex === sidePinCounts.bottomSize - 1;
2151
+ if (!isLastPinOnSide) {
2152
+ currentDistanceFromEdge += params.schPinSpacing;
2153
+ } else {
2154
+ sideLengths.bottom = currentDistanceFromEdge;
2155
+ }
2156
+ truePinIndex++;
2157
+ }
2158
+ currentDistanceFromEdge = 0;
2159
+ for (let sideIndex = 0; sideIndex < sidePinCounts.rightSize; sideIndex++) {
2160
+ const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement.rightSide?.pins[sideIndex] : truePinIndex + 1;
2161
+ const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
2162
+ if (pinStyle?.bottomMargin) {
2163
+ currentDistanceFromEdge += pinStyle.bottomMargin;
2164
+ }
2165
+ orderedTruePorts.push({
2166
+ trueIndex: truePinIndex,
2167
+ pinNumber,
2168
+ side: "right",
2169
+ distanceFromOrthogonalEdge: currentDistanceFromEdge
2170
+ });
2171
+ if (pinStyle?.topMargin) {
2172
+ currentDistanceFromEdge += pinStyle.topMargin;
2173
+ }
2174
+ const isLastPinOnSide = sideIndex === sidePinCounts.rightSize - 1;
2175
+ if (!isLastPinOnSide) {
2176
+ currentDistanceFromEdge += params.schPinSpacing;
2177
+ } else {
2178
+ sideLengths.right = currentDistanceFromEdge;
2179
+ }
2180
+ truePinIndex++;
2181
+ }
2182
+ currentDistanceFromEdge = 0;
2183
+ for (let sideIndex = 0; sideIndex < sidePinCounts.topSize; sideIndex++) {
2184
+ const pinNumber = params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement) ? params.schPortArrangement.topSide?.pins[sideIndex] : truePinIndex + 1;
2185
+ const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
2186
+ if (pinStyle?.rightMargin) {
2187
+ currentDistanceFromEdge += pinStyle.rightMargin;
2188
+ }
2189
+ orderedTruePorts.push({
2190
+ trueIndex: truePinIndex,
2191
+ pinNumber,
2192
+ side: "top",
2193
+ distanceFromOrthogonalEdge: currentDistanceFromEdge
2194
+ });
2195
+ if (pinStyle?.leftMargin) {
2196
+ currentDistanceFromEdge += pinStyle.leftMargin;
2197
+ }
2198
+ const isLastPinOnSide = sideIndex === sidePinCounts.topSize - 1;
2199
+ if (!isLastPinOnSide) {
2200
+ currentDistanceFromEdge += params.schPinSpacing;
2201
+ } else {
2202
+ sideLengths.top = currentDistanceFromEdge;
2203
+ }
2204
+ truePinIndex++;
2205
+ }
2206
+ let schWidth = params.schWidth;
2207
+ if (!schWidth) {
2208
+ schWidth = Math.max(
2209
+ sideLengths.top + params.schPinSpacing * 2,
2210
+ sideLengths.bottom + params.schPinSpacing * 2
2211
+ );
2212
+ }
2213
+ let schHeight = params.schHeight;
2214
+ if (!schHeight) {
2215
+ schHeight = Math.max(
2216
+ sideLengths.left + params.schPinSpacing * 2,
2217
+ sideLengths.right + params.schPinSpacing * 2
2218
+ );
2219
+ }
2220
+ const trueEdgePositions = {
2221
+ // Top left corner
2222
+ left: {
2223
+ x: -schWidth / 2 - portDistanceFromEdge,
2224
+ y: sideLengths.left / 2
2225
+ },
2226
+ // bottom left corner
2227
+ bottom: {
2228
+ x: -sideLengths.bottom / 2,
2229
+ y: -schHeight / 2 - portDistanceFromEdge
2230
+ },
2231
+ // bottom right corner
2232
+ right: {
2233
+ x: schWidth / 2 + portDistanceFromEdge,
2234
+ y: -sideLengths.right / 2
2235
+ },
2236
+ // top right corner
2237
+ top: {
2238
+ x: sideLengths.top / 2,
2239
+ y: schHeight / 2 + portDistanceFromEdge
2240
+ }
2241
+ };
2242
+ const trueEdgeTraversalDirections = {
2243
+ left: { x: 0, y: -1 },
2244
+ right: { x: 0, y: 1 },
2245
+ top: { x: -1, y: 0 },
2246
+ bottom: { x: 1, y: 0 }
2247
+ };
2248
+ const truePortsWithPositions = orderedTruePorts.map((p) => {
2249
+ const { distanceFromOrthogonalEdge, side } = p;
2250
+ const edgePos = trueEdgePositions[side];
2251
+ const edgeDir = trueEdgeTraversalDirections[side];
2252
+ return {
2253
+ x: edgePos.x + distanceFromOrthogonalEdge * edgeDir.x,
2254
+ y: edgePos.y + distanceFromOrthogonalEdge * edgeDir.y,
2255
+ ...p
2256
+ };
2257
+ });
2258
+ return {
2259
+ getPortPositionByPinNumber(pinNumber) {
2260
+ const port = truePortsWithPositions.find(
2261
+ (p) => p.pinNumber.toString() === pinNumber.toString()
2262
+ );
2263
+ if (!port) {
2264
+ return null;
2265
+ }
2266
+ return port;
2267
+ },
2268
+ getSize() {
2269
+ return { width: schWidth, height: schHeight };
2270
+ },
2271
+ pinCount
2272
+ };
2273
+ };
2274
+
2275
+ // lib/soup/underscorifyPortArrangement.ts
2276
+ var underscorifyPortArrangement = (portArrangement) => {
2277
+ if (!portArrangement) return void 0;
2278
+ if ("leftSide" in portArrangement || "rightSide" in portArrangement || "topSide" in portArrangement || "bottomSide" in portArrangement) {
2279
+ return {
2280
+ left_side: portArrangement.leftSide,
2281
+ right_side: portArrangement.rightSide,
2282
+ top_side: portArrangement.topSide,
2283
+ bottom_side: portArrangement.bottomSide
2284
+ };
2285
+ }
2286
+ if ("leftPinCount" in portArrangement || "rightPinCount" in portArrangement || "topPinCount" in portArrangement || "bottomPinCount" in portArrangement) {
2287
+ return {
2288
+ left_size: portArrangement.leftPinCount,
2289
+ right_size: portArrangement.rightPinCount,
2290
+ top_size: portArrangement.topPinCount,
2291
+ bottom_size: portArrangement.bottomPinCount
2292
+ };
2293
+ }
2294
+ if ("leftSize" in portArrangement || "rightSize" in portArrangement || "topSize" in portArrangement || "bottomSize" in portArrangement) {
2295
+ return {
2296
+ left_size: portArrangement.leftSize,
2297
+ right_size: portArrangement.rightSize,
2298
+ top_size: portArrangement.topSize,
2299
+ bottom_size: portArrangement.bottomSize
2300
+ };
2301
+ }
2302
+ return void 0;
2303
+ };
2304
+
2305
+ // lib/soup/underscorifyPinStyles.ts
2306
+ import "circuit-json";
2307
+ import "zod";
2308
+ var underscorifyPinStyles = (pinStyles) => {
2309
+ if (!pinStyles) return void 0;
2310
+ const underscorePinStyles = {};
2311
+ for (const [pinName, pinStyle] of Object.entries(pinStyles)) {
2312
+ underscorePinStyles[pinName] = {
2313
+ bottom_margin: pinStyle.bottomMargin,
2314
+ left_margin: pinStyle.leftMargin,
2315
+ right_margin: pinStyle.rightMargin,
2316
+ top_margin: pinStyle.topMargin
2317
+ };
2318
+ }
2319
+ return underscorePinStyles;
2320
+ };
2321
+
2019
2322
  // lib/components/base-components/NormalComponent.ts
2020
2323
  var debug2 = Debug2("tscircuit:core");
2021
- var rotation3 = z4.object({
2324
+ var rotation3 = z5.object({
2022
2325
  x: rotation,
2023
2326
  y: rotation,
2024
2327
  z: rotation
@@ -2189,14 +2492,23 @@ var NormalComponent = class extends PrimitiveComponent {
2189
2492
  }
2190
2493
  /**
2191
2494
  * Render the schematic component for this NormalComponent using the
2192
- * config.schematicSymbolName if it exists.
2495
+ * config.schematicSymbolName if it exists, or create a generic box if
2496
+ * no symbol is defined.
2193
2497
  *
2194
2498
  * You can override this method to do more complicated things.
2195
2499
  */
2196
2500
  doInitialSchematicComponentRender() {
2197
- const { db } = this.root;
2198
2501
  const { schematicSymbolName } = this.config;
2199
- if (!schematicSymbolName) return;
2502
+ if (schematicSymbolName) {
2503
+ return this._doInitialSchematicComponentRenderWithSymbol();
2504
+ }
2505
+ const dimensions = this._getSchematicBoxDimensions();
2506
+ if (dimensions) {
2507
+ return this._doInitialSchematicComponentRenderWithSchematicBoxDimensions();
2508
+ }
2509
+ }
2510
+ _doInitialSchematicComponentRenderWithSymbol() {
2511
+ const { db } = this.root;
2200
2512
  const base_symbol_name = this.config.schematicSymbolName;
2201
2513
  const symbol_name_horz = `${base_symbol_name}_horz`;
2202
2514
  let symbol_name;
@@ -2213,15 +2525,37 @@ var NormalComponent = class extends PrimitiveComponent {
2213
2525
  throw new Error(`Could not find schematic-symbol: "${base_symbol_name}"`);
2214
2526
  }
2215
2527
  const symbol = symbols2[symbol_name];
2216
- if (!symbol) {
2217
- throw new Error(`Could not find schematic-symbol "${symbol_name}"`);
2528
+ if (symbol) {
2529
+ const schematic_component2 = db.schematic_component.insert({
2530
+ center: { x: this.props.schX ?? 0, y: this.props.schY ?? 0 },
2531
+ rotation: this.props.schRotation ?? 0,
2532
+ size: symbol.size,
2533
+ source_component_id: this.source_component_id,
2534
+ symbol_name
2535
+ });
2536
+ this.schematic_component_id = schematic_component2.schematic_component_id;
2537
+ }
2538
+ }
2539
+ _doInitialSchematicComponentRenderWithSchematicBoxDimensions() {
2540
+ const { db } = this.root;
2541
+ const { _parsedProps: props } = this;
2542
+ const dimensions = this._getSchematicBoxDimensions();
2543
+ const primaryPortLabels = {};
2544
+ for (const [port, label] of Object.entries(props.pinLabels ?? {})) {
2545
+ primaryPortLabels[port] = Array.isArray(label) ? label[0] : label;
2218
2546
  }
2219
2547
  const schematic_component2 = db.schematic_component.insert({
2220
- center: { x: this.props.schX ?? 0, y: this.props.schY ?? 0 },
2221
- rotation: this.props.schRotation ?? 0,
2222
- size: symbol.size,
2223
- source_component_id: this.source_component_id,
2224
- symbol_name
2548
+ center: { x: props.schX ?? 0, y: props.schY ?? 0 },
2549
+ rotation: props.schRotation ?? 0,
2550
+ size: dimensions.getSize(),
2551
+ port_arrangement: underscorifyPortArrangement(
2552
+ props.schPortArrangement
2553
+ ),
2554
+ pin_spacing: props.schPinSpacing ?? 0.2,
2555
+ // @ts-ignore soup needs to support distance for pin_styles
2556
+ pin_styles: underscorifyPinStyles(props.schPinStyle),
2557
+ port_labels: primaryPortLabels,
2558
+ source_component_id: this.source_component_id
2225
2559
  });
2226
2560
  this.schematic_component_id = schematic_component2.schematic_component_id;
2227
2561
  }
@@ -2426,6 +2760,35 @@ var NormalComponent = class extends PrimitiveComponent {
2426
2760
  height: pcb_component.height
2427
2761
  };
2428
2762
  }
2763
+ _getPinCount() {
2764
+ const schPortArrangement = this._getSchematicPortArrangement();
2765
+ const pinCountFromSchArrangement = (schPortArrangement?.leftSize ?? 0) + (schPortArrangement?.rightSize ?? 0) + (schPortArrangement?.topSize ?? 0) + (schPortArrangement?.bottomSize ?? 0);
2766
+ const pinCount = pinCountFromSchArrangement || this.getPortsFromFootprint().length;
2767
+ return pinCount;
2768
+ }
2769
+ /**
2770
+ * Override the schematic port arrangement if you want to customize where pins
2771
+ * appear on a schematic box, e.g. for a pin header
2772
+ */
2773
+ _getSchematicPortArrangement() {
2774
+ return this._parsedProps.schPortArrangement;
2775
+ }
2776
+ _getSchematicBoxDimensions() {
2777
+ if (this.getSchematicSymbol()) return null;
2778
+ if (!this.config.shouldRenderAsSchematicBox) return null;
2779
+ const { _parsedProps: props } = this;
2780
+ const pinCount = this._getPinCount();
2781
+ const pinSpacing = props.schPinSpacing ?? 0.2;
2782
+ const dimensions = getAllDimensionsForSchematicBox({
2783
+ schWidth: props.schWidth,
2784
+ schHeight: props.schHeight,
2785
+ schPinSpacing: pinSpacing,
2786
+ schPinStyle: props.schPinStyle,
2787
+ pinCount,
2788
+ schPortArrangement: this._getSchematicPortArrangement()
2789
+ });
2790
+ return dimensions;
2791
+ }
2429
2792
  doInitialCadModelRender() {
2430
2793
  const { db } = this.root;
2431
2794
  const { boardThickness = 0 } = this.root?._getBoard() ?? {};
@@ -2939,38 +3302,6 @@ function getClosest(point, candidates) {
2939
3302
  return closest;
2940
3303
  }
2941
3304
 
2942
- // lib/utils/projectPointInDirection.ts
2943
- var projectPointInDirection = (point, direction, distance) => {
2944
- switch (direction) {
2945
- case "up":
2946
- return { x: point.x, y: point.y + distance };
2947
- case "down":
2948
- return { x: point.x, y: point.y - distance };
2949
- case "left":
2950
- return { x: point.x + distance, y: point.y };
2951
- case "right":
2952
- return { x: point.x - distance, y: point.y };
2953
- default:
2954
- throw new Error(`Unknown direction "${direction}"`);
2955
- }
2956
- };
2957
-
2958
- // lib/utils/projectPointInOppositeDirection.ts
2959
- var projectPointInOppositeDirection = (point, direction, distance) => {
2960
- switch (direction) {
2961
- case "up":
2962
- return { x: point.x, y: point.y + distance };
2963
- case "down":
2964
- return { x: point.x, y: point.y - distance };
2965
- case "left":
2966
- return { x: point.x + distance, y: point.y };
2967
- case "right":
2968
- return { x: point.x - distance, y: point.y };
2969
- default:
2970
- throw new Error(`Unknown direction "${direction}"`);
2971
- }
2972
- };
2973
-
2974
3305
  // lib/utils/try-now.ts
2975
3306
  function tryNow(fn) {
2976
3307
  try {
@@ -3389,7 +3720,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
3389
3720
  const { db } = this.root;
3390
3721
  const { _parsedProps: props, parent } = this;
3391
3722
  if (!parent) throw new Error("Trace has no parent");
3392
- const { allPortsFound, portsWithSelectors: ports } = this._findConnectedPorts();
3723
+ const { allPortsFound, portsWithSelectors: connectedPorts } = this._findConnectedPorts();
3393
3724
  if (!allPortsFound) return;
3394
3725
  const obstacles = [];
3395
3726
  const connection = {
@@ -3418,7 +3749,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
3418
3749
  });
3419
3750
  }
3420
3751
  }
3421
- const portsWithPosition = ports.map(({ port }) => ({
3752
+ const portsWithPosition = connectedPorts.map(({ port }) => ({
3422
3753
  port,
3423
3754
  position: port._getGlobalSchematicPositionAfterLayout(),
3424
3755
  schematic_port_id: port.schematic_port_id ?? void 0,
@@ -3450,8 +3781,7 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
3450
3781
  });
3451
3782
  const results = autorouter.solveAndMapToTraces();
3452
3783
  if (results.length === 0) return;
3453
- const [result] = results;
3454
- const { route } = result;
3784
+ const [{ route }] = results;
3455
3785
  const edges = [];
3456
3786
  for (let i = 0; i < route.length - 1; i++) {
3457
3787
  edges.push({
@@ -3459,29 +3789,6 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
3459
3789
  to: route[i + 1]
3460
3790
  });
3461
3791
  }
3462
- const STUB_LENGTH = 0.15;
3463
- edges.unshift({
3464
- from: {
3465
- ...projectPointInDirection(
3466
- route[0],
3467
- portsWithPosition[0].facingDirection,
3468
- STUB_LENGTH
3469
- )
3470
- },
3471
- to: route[0],
3472
- from_schematic_port_id: portsWithPosition[0].schematic_port_id
3473
- });
3474
- edges.push({
3475
- from: route[route.length - 1],
3476
- to: {
3477
- ...projectPointInOppositeDirection(
3478
- route[route.length - 1],
3479
- portsWithPosition[1].facingDirection,
3480
- STUB_LENGTH
3481
- )
3482
- },
3483
- from_schematic_port_id: portsWithPosition[1].schematic_port_id
3484
- });
3485
3792
  const trace = db.schematic_trace.insert({
3486
3793
  source_trace_id: this.source_trace_id,
3487
3794
  edges
@@ -3544,308 +3851,13 @@ var Capacitor = class extends NormalComponent {
3544
3851
 
3545
3852
  // lib/components/normal-components/Chip.ts
3546
3853
  import { chipProps } from "@tscircuit/props";
3547
-
3548
- // lib/soup/underscorifyPinStyles.ts
3549
- import "circuit-json";
3550
- import "zod";
3551
- var underscorifyPinStyles = (pinStyles) => {
3552
- if (!pinStyles) return void 0;
3553
- const underscorePinStyles = {};
3554
- for (const [pinName, pinStyle] of Object.entries(pinStyles)) {
3555
- underscorePinStyles[pinName] = {
3556
- bottom_margin: pinStyle.bottomMargin,
3557
- left_margin: pinStyle.leftMargin,
3558
- right_margin: pinStyle.rightMargin,
3559
- top_margin: pinStyle.topMargin
3560
- };
3561
- }
3562
- return underscorePinStyles;
3563
- };
3564
-
3565
- // lib/soup/underscorifyPortArrangement.ts
3566
- var underscorifyPortArrangement = (portArrangement) => {
3567
- if (!portArrangement) return void 0;
3568
- if ("leftSide" in portArrangement || "rightSide" in portArrangement || "topSide" in portArrangement || "bottomSide" in portArrangement) {
3569
- return {
3570
- left_side: portArrangement.leftSide,
3571
- right_side: portArrangement.rightSide,
3572
- top_side: portArrangement.topSide,
3573
- bottom_side: portArrangement.bottomSide
3574
- };
3575
- }
3576
- if ("leftPinCount" in portArrangement || "rightPinCount" in portArrangement || "topPinCount" in portArrangement || "bottomPinCount" in portArrangement) {
3577
- return {
3578
- left_size: portArrangement.leftPinCount,
3579
- right_size: portArrangement.rightPinCount,
3580
- top_size: portArrangement.topPinCount,
3581
- bottom_size: portArrangement.bottomPinCount
3582
- };
3583
- }
3584
- if ("leftSize" in portArrangement || "rightSize" in portArrangement || "topSize" in portArrangement || "bottomSize" in portArrangement) {
3585
- return {
3586
- left_size: portArrangement.leftSize,
3587
- right_size: portArrangement.rightSize,
3588
- top_size: portArrangement.topSize,
3589
- bottom_size: portArrangement.bottomSize
3590
- };
3591
- }
3592
- return void 0;
3593
- };
3594
-
3595
- // lib/utils/schematic/getSizeOfSidesFromPortArrangement.ts
3596
- var hasExplicitPinMapping = (pa) => {
3597
- for (const side of [
3598
- "leftSide",
3599
- "rightSide",
3600
- "topSide",
3601
- "bottomSide"
3602
- ]) {
3603
- if (side in pa && typeof pa[side] === "number") {
3604
- throw new Error(
3605
- `A number was specified for "${side}", you probably meant to use "size" not "side"`
3606
- );
3607
- }
3608
- }
3609
- return "leftSide" in pa || "rightSide" in pa || "topSide" in pa || "bottomSide" in pa;
3610
- };
3611
- var getSizeOfSidesFromPortArrangement = (pa) => {
3612
- if (hasExplicitPinMapping(pa)) {
3613
- return {
3614
- leftSize: pa.leftSide?.pins.length ?? 0,
3615
- rightSize: pa.rightSide?.pins.length ?? 0,
3616
- topSize: pa.topSide?.pins.length ?? 0,
3617
- bottomSize: pa.bottomSide?.pins.length ?? 0
3618
- };
3619
- }
3620
- const { leftSize = 0, rightSize = 0, topSize = 0, bottomSize = 0 } = pa;
3621
- return { leftSize, rightSize, topSize, bottomSize };
3622
- };
3623
-
3624
- // lib/utils/schematic/getAllDimensionsForSchematicBox.ts
3625
- function isExplicitPinMappingArrangement(arrangement) {
3626
- return arrangement.leftSide !== void 0;
3627
- }
3628
- var getAllDimensionsForSchematicBox = (params) => {
3629
- const componentMargin = params.schPinSpacing;
3630
- let sidePinCounts = params.schPortArrangement ? getSizeOfSidesFromPortArrangement(params.schPortArrangement) : null;
3631
- const sideLengths = {
3632
- left: 0,
3633
- right: 0,
3634
- top: 0,
3635
- bottom: 0
3636
- };
3637
- let pinCount = params.pinCount ?? null;
3638
- if (pinCount === null) {
3639
- if (sidePinCounts) {
3640
- pinCount = sidePinCounts.leftSize + sidePinCounts.rightSize + sidePinCounts.topSize + sidePinCounts.bottomSize;
3641
- } else {
3642
- throw new Error("Could not determine pin count for the schematic box");
3643
- }
3644
- }
3645
- if (pinCount && !sidePinCounts) {
3646
- const rightSize = Math.floor(pinCount / 2);
3647
- sidePinCounts = {
3648
- leftSize: pinCount - rightSize,
3649
- rightSize,
3650
- topSize: 0,
3651
- bottomSize: 0
3652
- };
3653
- }
3654
- if (!sidePinCounts) {
3655
- sidePinCounts = {
3656
- leftSize: 0,
3657
- rightSize: 0,
3658
- topSize: 0,
3659
- bottomSize: 0
3660
- };
3661
- }
3662
- const schWidth = params.schWidth ?? Math.max(sidePinCounts.topSize, sidePinCounts.bottomSize) * params.schPinSpacing + 2 * componentMargin;
3663
- const schHeight = params.schHeight ?? Math.max(sidePinCounts.leftSize, sidePinCounts.rightSize) * params.schPinSpacing + 2 * componentMargin;
3664
- const distributePorts = (sideSize, sideLength, totalMargin) => {
3665
- if (sideSize <= 1) return 0;
3666
- return (sideLength - totalMargin) / (sideSize - 1);
3667
- };
3668
- const orderedTruePorts = [];
3669
- let truePinIndex = 0;
3670
- const processSide = (side, pins, direction) => {
3671
- const isVertical = side === "left" || side === "right";
3672
- const sideLength = isVertical ? schHeight : schWidth;
3673
- let totalMargin = 0;
3674
- for (const pin of pins) {
3675
- const pinStyle = params.schPinStyle?.[`pin${pin}`] ?? params.schPinStyle?.[pin];
3676
- if (pinStyle) {
3677
- if (isVertical) {
3678
- totalMargin += (pinStyle.topMargin ?? 0) + (pinStyle.bottomMargin ?? 0);
3679
- } else {
3680
- totalMargin += (pinStyle.leftMargin ?? 0) + (pinStyle.rightMargin ?? 0);
3681
- }
3682
- }
3683
- }
3684
- const spacing = distributePorts(
3685
- pins.length,
3686
- sideLength - 2 * componentMargin,
3687
- totalMargin
3688
- );
3689
- let currentDistanceFromEdge = componentMargin;
3690
- pins.forEach((pinNumber, index) => {
3691
- const pinStyle = params.schPinStyle?.[`pin${pinNumber}`] ?? params.schPinStyle?.[pinNumber];
3692
- if (pinStyle) {
3693
- if (isVertical) {
3694
- if (side === "left") {
3695
- currentDistanceFromEdge += direction === "top-to-bottom" ? pinStyle.topMargin ?? 0 : pinStyle.bottomMargin ?? 0;
3696
- } else {
3697
- currentDistanceFromEdge += direction === "top-to-bottom" ? pinStyle.bottomMargin ?? 0 : pinStyle.topMargin ?? 0;
3698
- }
3699
- } else {
3700
- if (side === "top") {
3701
- currentDistanceFromEdge += direction === "left-to-right" ? pinStyle.leftMargin ?? 0 : pinStyle.rightMargin ?? 0;
3702
- } else {
3703
- currentDistanceFromEdge += direction === "left-to-right" ? pinStyle.rightMargin ?? 0 : pinStyle.leftMargin ?? 0;
3704
- }
3705
- }
3706
- }
3707
- orderedTruePorts.push({
3708
- trueIndex: truePinIndex,
3709
- pinNumber,
3710
- side,
3711
- distanceFromEdge: currentDistanceFromEdge,
3712
- x: 0,
3713
- y: 0
3714
- });
3715
- if (pinStyle) {
3716
- if (isVertical) {
3717
- if (side === "left") {
3718
- currentDistanceFromEdge += direction === "top-to-bottom" ? pinStyle.bottomMargin ?? 0 : pinStyle.topMargin ?? 0;
3719
- } else {
3720
- currentDistanceFromEdge += direction === "top-to-bottom" ? pinStyle.topMargin ?? 0 : pinStyle.bottomMargin ?? 0;
3721
- }
3722
- } else {
3723
- if (side === "top") {
3724
- currentDistanceFromEdge += direction === "left-to-right" ? pinStyle.rightMargin ?? 0 : pinStyle.leftMargin ?? 0;
3725
- } else {
3726
- currentDistanceFromEdge += direction === "left-to-right" ? pinStyle.leftMargin ?? 0 : pinStyle.rightMargin ?? 0;
3727
- }
3728
- }
3729
- }
3730
- currentDistanceFromEdge += spacing;
3731
- truePinIndex++;
3732
- });
3733
- sideLengths[side] = sideLength;
3734
- };
3735
- if (params.schPortArrangement && isExplicitPinMappingArrangement(params.schPortArrangement)) {
3736
- if (params.schPortArrangement.leftSide) {
3737
- processSide(
3738
- "left",
3739
- params.schPortArrangement.leftSide.pins,
3740
- params.schPortArrangement.leftSide.direction ?? "top-to-bottom"
3741
- );
3742
- }
3743
- if (params.schPortArrangement.rightSide) {
3744
- processSide(
3745
- "right",
3746
- params.schPortArrangement.rightSide.pins,
3747
- params.schPortArrangement.rightSide.direction ?? "bottom-to-top"
3748
- );
3749
- }
3750
- if (params.schPortArrangement.topSide) {
3751
- processSide(
3752
- "top",
3753
- params.schPortArrangement.topSide.pins,
3754
- params.schPortArrangement.topSide.direction ?? "left-to-right"
3755
- );
3756
- }
3757
- if (params.schPortArrangement.bottomSide) {
3758
- processSide(
3759
- "bottom",
3760
- params.schPortArrangement.bottomSide.pins,
3761
- params.schPortArrangement.bottomSide.direction ?? "left-to-right"
3762
- );
3763
- }
3764
- } else {
3765
- const leftSide = Array.from(
3766
- { length: sidePinCounts.leftSize },
3767
- (_, i) => i + 1
3768
- );
3769
- const rightSide = Array.from(
3770
- { length: sidePinCounts.rightSize },
3771
- (_, i) => i + sidePinCounts.leftSize + 1
3772
- );
3773
- const topSide = Array.from(
3774
- { length: sidePinCounts.topSize },
3775
- (_, i) => i + sidePinCounts.leftSize + sidePinCounts.rightSize + 1
3776
- );
3777
- const bottomSide = Array.from(
3778
- {
3779
- length: pinCount - sidePinCounts.leftSize - sidePinCounts.rightSize - sidePinCounts.topSize
3780
- },
3781
- (_, i) => i + sidePinCounts.leftSize + sidePinCounts.rightSize + sidePinCounts.topSize + 1
3782
- );
3783
- processSide("left", leftSide, "top-to-bottom");
3784
- processSide("right", rightSide, "top-to-bottom");
3785
- processSide("top", topSide, "left-to-right");
3786
- processSide("bottom", bottomSide, "left-to-right");
3787
- }
3788
- const trueEdgePositions = {
3789
- left: { x: -schWidth / 2 - 0.2, y: schHeight / 2 },
3790
- bottom: { x: -schWidth / 2, y: schHeight / 2 + 0.2 },
3791
- right: { x: schWidth / 2 + 0.2, y: -schHeight / 2 },
3792
- top: { x: schWidth / 2, y: -schHeight / 2 - 0.2 }
3793
- };
3794
- const trueEdgeTraversalDirections = {
3795
- left: { x: 0, y: -1 },
3796
- right: { x: 0, y: 1 },
3797
- top: { x: -1, y: 0 },
3798
- bottom: { x: 1, y: 0 }
3799
- };
3800
- const truePortsWithPositions = orderedTruePorts.map((p) => {
3801
- const { distanceFromEdge, side } = p;
3802
- if (side === "center") {
3803
- return {
3804
- ...p,
3805
- x: 0,
3806
- y: 0
3807
- };
3808
- }
3809
- const edgePos = trueEdgePositions[side];
3810
- const edgeDir = trueEdgeTraversalDirections[side];
3811
- return {
3812
- ...p,
3813
- x: edgePos.x + distanceFromEdge * edgeDir.x,
3814
- y: edgePos.y + distanceFromEdge * edgeDir.y
3815
- };
3816
- });
3817
- return {
3818
- getPortPositionByPinNumber(pinNumber) {
3819
- const port = truePortsWithPositions.find(
3820
- (p) => p.pinNumber.toString() === pinNumber.toString()
3821
- );
3822
- if (!port) {
3823
- return {
3824
- trueIndex: -1,
3825
- // Use -1 for non-existent ports
3826
- pinNumber,
3827
- side: "center",
3828
- distanceFromEdge: 0,
3829
- x: 0,
3830
- y: 0
3831
- };
3832
- }
3833
- return port;
3834
- },
3835
- getSize() {
3836
- return { width: schWidth, height: schHeight };
3837
- },
3838
- pinCount
3839
- };
3840
- };
3841
-
3842
- // lib/components/normal-components/Chip.ts
3843
3854
  var Chip = class extends NormalComponent {
3844
- schematicDimensions = null;
3855
+ schematicBoxDimensions = null;
3845
3856
  get config() {
3846
3857
  return {
3847
3858
  componentName: "Chip",
3848
- zodProps: chipProps
3859
+ zodProps: chipProps,
3860
+ shouldRenderAsSchematicBox: true
3849
3861
  };
3850
3862
  }
3851
3863
  doInitialSourceRender() {
@@ -3859,43 +3871,6 @@ var Chip = class extends NormalComponent {
3859
3871
  });
3860
3872
  this.source_component_id = source_component.source_component_id;
3861
3873
  }
3862
- doInitialSchematicComponentRender() {
3863
- const { db } = this.root;
3864
- const { _parsedProps: props } = this;
3865
- const pinCountFromSchArrangement = (props.schPortArrangement?.leftSize ?? 0) + (props.schPortArrangement?.rightSize ?? 0) + (props.schPortArrangement?.topSize ?? 0) + (props.schPortArrangement?.bottomSize ?? 0);
3866
- const pinCount = pinCountFromSchArrangement || this.getPortsFromFootprint().length;
3867
- const pinSpacing = props.schPinSpacing ?? 0.2;
3868
- const dimensions = getAllDimensionsForSchematicBox({
3869
- schWidth: props.schWidth,
3870
- schHeight: props.schHeight,
3871
- schPinSpacing: pinSpacing,
3872
- schPinStyle: props.schPinStyle,
3873
- pinCount,
3874
- // @ts-ignore there's a subtley in the definition difference with
3875
- // leftSide/rightSide/topSide/bottomSide in how the direction is defined
3876
- // that doesn't really matter
3877
- schPortArrangement: props.schPortArrangement
3878
- });
3879
- this.schematicDimensions = dimensions;
3880
- const primaryPortLabels = {};
3881
- for (const [port, label] of Object.entries(props.pinLabels ?? {})) {
3882
- primaryPortLabels[port] = Array.isArray(label) ? label[0] : label;
3883
- }
3884
- const schematic_component2 = db.schematic_component.insert({
3885
- center: { x: props.schX ?? 0, y: props.schY ?? 0 },
3886
- rotation: props.schRotation ?? 0,
3887
- size: dimensions.getSize(),
3888
- port_arrangement: underscorifyPortArrangement(
3889
- props.schPortArrangement
3890
- ),
3891
- pin_spacing: pinSpacing,
3892
- // @ts-ignore soup needs to support distance for pin_styles
3893
- pin_styles: underscorifyPinStyles(props.schPinStyle),
3894
- port_labels: primaryPortLabels,
3895
- source_component_id: this.source_component_id
3896
- });
3897
- this.schematic_component_id = schematic_component2.schematic_component_id;
3898
- }
3899
3874
  doInitialPcbComponentRender() {
3900
3875
  const { db } = this.root;
3901
3876
  const { _parsedProps: props } = this;
@@ -3946,7 +3921,8 @@ var Jumper = class extends NormalComponent {
3946
3921
  get config() {
3947
3922
  return {
3948
3923
  componentName: "Jumper",
3949
- zodProps: jumperProps
3924
+ zodProps: jumperProps,
3925
+ shouldRenderAsSchematicBox: true
3950
3926
  };
3951
3927
  }
3952
3928
  doInitialSourceRender() {
@@ -3961,41 +3937,6 @@ var Jumper = class extends NormalComponent {
3961
3937
  });
3962
3938
  this.source_component_id = source_component.source_component_id;
3963
3939
  }
3964
- doInitialSchematicComponentRender() {
3965
- const { db } = this.root;
3966
- const { _parsedProps: props } = this;
3967
- const ports = this.children.filter((child) => child instanceof Port);
3968
- const pinSpacing = props.schPinSpacing ?? 0.2;
3969
- const dimensions = getAllDimensionsForSchematicBox({
3970
- schWidth: props.schWidth,
3971
- schHeight: props.schHeight,
3972
- schPinSpacing: pinSpacing,
3973
- schPinStyle: props.schPinStyle,
3974
- pinCount: ports.length,
3975
- // @ts-ignore there's a subtley in the definition difference with
3976
- // leftSide/rightSide/topSide/bottomSide in how the direction is defined
3977
- // that doesn't really matter
3978
- schPortArrangement: {
3979
- // TODO use schematic direction or schPortArrangement
3980
- rightSize: ports.length
3981
- }
3982
- });
3983
- this.schematicDimensions = dimensions;
3984
- const schematic_component2 = db.schematic_component.insert({
3985
- center: { x: props.schX ?? 0, y: props.schY ?? 0 },
3986
- rotation: props.schRotation ?? 0,
3987
- size: dimensions.getSize(),
3988
- port_arrangement: underscorifyPortArrangement(
3989
- props.schPortArrangement
3990
- ),
3991
- pin_spacing: pinSpacing,
3992
- // @ts-ignore soup needs to support distance for pin_styles
3993
- pin_styles: underscorifyPinStyles(props.schPinStyle),
3994
- port_labels: props.pinLabels,
3995
- source_component_id: this.source_component_id
3996
- });
3997
- this.schematic_component_id = schematic_component2.schematic_component_id;
3998
- }
3999
3940
  doInitialPcbComponentRender() {
4000
3941
  const { db } = this.root;
4001
3942
  const { _parsedProps: props } = this;
@@ -4501,7 +4442,7 @@ var PinHeader = class extends NormalComponent {
4501
4442
  return {
4502
4443
  componentName: "PinHeader",
4503
4444
  zodProps: pinHeaderProps,
4504
- schematicSymbolName: "pinrow_horz"
4445
+ shouldRenderAsSchematicBox: true
4505
4446
  };
4506
4447
  }
4507
4448
  _getImpliedFootprintString() {
@@ -4529,6 +4470,12 @@ var PinHeader = class extends NormalComponent {
4529
4470
  );
4530
4471
  }
4531
4472
  }
4473
+ _getSchematicPortArrangement() {
4474
+ return {
4475
+ leftSize: 0,
4476
+ rightSize: this._parsedProps.pinCount ?? 1
4477
+ };
4478
+ }
4532
4479
  doInitialSourceRender() {
4533
4480
  const { db } = this.root;
4534
4481
  const { _parsedProps: props } = this;
@@ -4542,21 +4489,6 @@ var PinHeader = class extends NormalComponent {
4542
4489
  });
4543
4490
  this.source_component_id = source_component.source_component_id;
4544
4491
  }
4545
- doInitialSchematicComponentRender() {
4546
- const { db } = this.root;
4547
- const { _parsedProps: props } = this;
4548
- const schematic_component2 = db.schematic_component.insert({
4549
- center: { x: props.schX ?? 0, y: props.schY ?? 0 },
4550
- rotation: props.schRotation ?? 0,
4551
- size: { width: 2, height: props.pinCount ?? 1 },
4552
- source_component_id: this.source_component_id,
4553
- port_arrangement: {
4554
- left_size: 0,
4555
- right_size: props.pinCount ?? 1
4556
- }
4557
- });
4558
- this.schematic_component_id = schematic_component2.schematic_component_id;
4559
- }
4560
4492
  };
4561
4493
 
4562
4494
  // lib/components/normal-components/Inductor.ts
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.146",
4
+ "version": "0.0.148",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -43,9 +43,9 @@
43
43
  "@tscircuit/props": "^0.0.83",
44
44
  "@tscircuit/schematic-autolayout": "^0.0.5",
45
45
  "@tscircuit/soup-util": "^0.0.33",
46
- "circuit-json": "^0.0.91",
46
+ "circuit-json": "^0.0.93",
47
47
  "circuit-json-to-connectivity-map": "^0.0.17",
48
- "circuit-to-svg": "^0.0.56",
48
+ "circuit-to-svg": "^0.0.58",
49
49
  "nanoid": "^5.0.7",
50
50
  "performance-now": "^2.1.0",
51
51
  "react": "^18.3.1",