@tscircuit/core 0.0.148 → 0.0.150

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 +17 -17
  2. package/dist/index.js +341 -276
  3. package/package.json +2 -2
package/dist/index.d.ts CHANGED
@@ -60,6 +60,23 @@ type ReactSubtree = {
60
60
  component: NormalComponent;
61
61
  };
62
62
 
63
+ type SchematicBoxPortPositionWithMetadata = {
64
+ trueIndex: number;
65
+ pinNumber: number;
66
+ side: "left" | "right" | "top" | "bottom";
67
+ distanceFromOrthogonalEdge: number;
68
+ x: number;
69
+ y: number;
70
+ };
71
+ interface SchematicBoxDimensions {
72
+ pinCount: number;
73
+ getPortPositionByPinNumber(pinNumber: number): SchematicBoxPortPositionWithMetadata | null;
74
+ getSize(): {
75
+ width: number;
76
+ height: number;
77
+ };
78
+ }
79
+
63
80
  type RootCircuitEventName = "asyncEffectComplete";
64
81
  declare class Circuit {
65
82
  firstChild: PrimitiveComponent | null;
@@ -111,23 +128,6 @@ interface ISubcircuit extends PrimitiveComponent {
111
128
  _shouldUseTraceByTraceRouting(): boolean;
112
129
  }
113
130
 
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
-
131
131
  interface BaseComponentConfig {
132
132
  componentName: string;
133
133
  schematicSymbolName?: BaseSymbolName | null;
package/dist/index.js CHANGED
@@ -355,6 +355,53 @@ var createInstanceFromReactElement = (reactElm) => {
355
355
  return rootContainer.children[0];
356
356
  };
357
357
 
358
+ // lib/soup/underscorifyPinStyles.ts
359
+ import "circuit-json";
360
+ import "zod";
361
+ var underscorifyPinStyles = (pinStyles) => {
362
+ if (!pinStyles) return void 0;
363
+ const underscorePinStyles = {};
364
+ for (const [pinName, pinStyle] of Object.entries(pinStyles)) {
365
+ underscorePinStyles[pinName] = {
366
+ bottom_margin: pinStyle.bottomMargin,
367
+ left_margin: pinStyle.leftMargin,
368
+ right_margin: pinStyle.rightMargin,
369
+ top_margin: pinStyle.topMargin
370
+ };
371
+ }
372
+ return underscorePinStyles;
373
+ };
374
+
375
+ // lib/soup/underscorifyPortArrangement.ts
376
+ var underscorifyPortArrangement = (portArrangement) => {
377
+ if (!portArrangement) return void 0;
378
+ if ("leftSide" in portArrangement || "rightSide" in portArrangement || "topSide" in portArrangement || "bottomSide" in portArrangement) {
379
+ return {
380
+ left_side: portArrangement.leftSide,
381
+ right_side: portArrangement.rightSide,
382
+ top_side: portArrangement.topSide,
383
+ bottom_side: portArrangement.bottomSide
384
+ };
385
+ }
386
+ if ("leftPinCount" in portArrangement || "rightPinCount" in portArrangement || "topPinCount" in portArrangement || "bottomPinCount" in portArrangement) {
387
+ return {
388
+ left_size: portArrangement.leftPinCount,
389
+ right_size: portArrangement.rightPinCount,
390
+ top_size: portArrangement.topPinCount,
391
+ bottom_size: portArrangement.bottomPinCount
392
+ };
393
+ }
394
+ if ("leftSize" in portArrangement || "rightSize" in portArrangement || "topSize" in portArrangement || "bottomSize" in portArrangement) {
395
+ return {
396
+ left_size: portArrangement.leftSize,
397
+ right_size: portArrangement.rightSize,
398
+ top_size: portArrangement.topSize,
399
+ bottom_size: portArrangement.bottomSize
400
+ };
401
+ }
402
+ return void 0;
403
+ };
404
+
358
405
  // lib/errors/InvalidProps.ts
359
406
  var InvalidProps = class extends Error {
360
407
  constructor(componentName, originalProps, formattedError) {
@@ -421,7 +468,7 @@ import {
421
468
  rotate,
422
469
  translate
423
470
  } from "transformation-matrix";
424
- import { z } from "zod";
471
+ import { z as z2 } from "zod";
425
472
  var PrimitiveComponent = class extends Renderable {
426
473
  parent = null;
427
474
  children;
@@ -429,7 +476,7 @@ var PrimitiveComponent = class extends Renderable {
429
476
  get config() {
430
477
  return {
431
478
  componentName: "",
432
- zodProps: z.object({}).passthrough()
479
+ zodProps: z2.object({}).passthrough()
433
480
  };
434
481
  }
435
482
  props;
@@ -841,7 +888,7 @@ var PrimitiveComponent = class extends Renderable {
841
888
  };
842
889
 
843
890
  // lib/components/primitive-components/Net.ts
844
- import { z as z2 } from "zod";
891
+ import { z as z3 } from "zod";
845
892
 
846
893
  // lib/utils/pairs.ts
847
894
  function pairs(arr) {
@@ -854,8 +901,8 @@ function pairs(arr) {
854
901
 
855
902
  // lib/components/primitive-components/Net.ts
856
903
  import { autoroute } from "@tscircuit/infgrid-ijump-astar";
857
- var netProps = z2.object({
858
- name: z2.string()
904
+ var netProps = z3.object({
905
+ name: z3.string()
859
906
  });
860
907
  var Net = class extends PrimitiveComponent {
861
908
  source_net_id;
@@ -1571,11 +1618,11 @@ function getRelativeDirection(pointA, pointB) {
1571
1618
  // lib/components/primitive-components/Port.ts
1572
1619
  import "schematic-symbols";
1573
1620
  import { applyToPoint as applyToPoint4, compose as compose3, translate as translate3 } from "transformation-matrix";
1574
- import { z as z3 } from "zod";
1575
- var portProps = z3.object({
1576
- name: z3.string().optional(),
1577
- pinNumber: z3.number().optional(),
1578
- aliases: z3.array(z3.string()).optional()
1621
+ import { z as z4 } from "zod";
1622
+ var portProps = z4.object({
1623
+ name: z4.string().optional(),
1624
+ pinNumber: z4.number().optional(),
1625
+ aliases: z4.array(z4.string()).optional()
1579
1626
  });
1580
1627
  var Port = class extends PrimitiveComponent {
1581
1628
  source_port_id = null;
@@ -1821,223 +1868,6 @@ function getPortFromHints(hints) {
1821
1868
  });
1822
1869
  }
1823
1870
 
1824
- // lib/components/base-components/NormalComponent.ts
1825
- import {
1826
- isValidElement as isReactElement,
1827
- isValidElement
1828
- } from "react";
1829
- import { symbols as symbols2 } from "schematic-symbols";
1830
- import { z as z5 } from "zod";
1831
-
1832
- // lib/components/primitive-components/Footprint.ts
1833
- import { footprintProps } from "@tscircuit/props";
1834
- import * as kiwi from "@lume/kiwi";
1835
- import Debug from "debug";
1836
- var debug = Debug("tscircuit:core:footprint");
1837
- var Footprint = class extends PrimitiveComponent {
1838
- get config() {
1839
- return {
1840
- componentName: "Footprint",
1841
- zodProps: footprintProps
1842
- };
1843
- }
1844
- /**
1845
- * A footprint is a constrainedlayout, the db elements are adjusted according
1846
- * to any constraints that are defined.
1847
- */
1848
- doInitialPcbFootprintLayout() {
1849
- const constraints = this.children.filter(
1850
- (child) => child.componentName === "Constraint"
1851
- );
1852
- if (constraints.length === 0) return;
1853
- const { isFlipped } = this._getPcbPrimitiveFlippedHelpers();
1854
- const maybeFlipLeftRight = (props) => {
1855
- if (isFlipped) {
1856
- if ("left" in props && "right" in props) {
1857
- return {
1858
- ...props,
1859
- left: props.right,
1860
- right: props.left
1861
- };
1862
- }
1863
- }
1864
- return props;
1865
- };
1866
- const involvedComponents = constraints.flatMap(
1867
- (constraint) => constraint._getAllReferencedComponents().componentsWithSelectors
1868
- ).map(({ component, selector, componentSelector, edge }) => ({
1869
- component,
1870
- selector,
1871
- componentSelector,
1872
- edge,
1873
- bounds: component._getPcbCircuitJsonBounds()
1874
- }));
1875
- if (involvedComponents.some((c) => c.edge)) {
1876
- throw new Error(
1877
- "edge constraints not implemented yet for footprint layout, contributions welcome!"
1878
- );
1879
- }
1880
- function getComponentDetails(selector) {
1881
- return involvedComponents.find(({ selector: s }) => s === selector);
1882
- }
1883
- const solver = new kiwi.Solver();
1884
- const kVars = {};
1885
- function getKVar(name) {
1886
- if (!(name in kVars)) {
1887
- kVars[name] = new kiwi.Variable(name);
1888
- solver.addEditVariable(kVars[name], kiwi.Strength.weak);
1889
- }
1890
- return kVars[name];
1891
- }
1892
- for (const { selector, bounds: bounds2 } of involvedComponents) {
1893
- const kvx = getKVar(`${selector}_x`);
1894
- const kvy = getKVar(`${selector}_y`);
1895
- solver.suggestValue(kvx, bounds2.center.x);
1896
- solver.suggestValue(kvy, bounds2.center.y);
1897
- }
1898
- for (const constraint of constraints) {
1899
- const props = constraint._parsedProps;
1900
- if ("xDist" in props) {
1901
- const { xDist, left, right, edgeToEdge, centerToCenter } = maybeFlipLeftRight(props);
1902
- const leftVar = getKVar(`${left}_x`);
1903
- const rightVar = getKVar(`${right}_x`);
1904
- const leftBounds = getComponentDetails(left)?.bounds;
1905
- const rightBounds = getComponentDetails(right)?.bounds;
1906
- if (centerToCenter) {
1907
- const expr = new kiwi.Expression(rightVar, [-1, leftVar]);
1908
- solver.addConstraint(
1909
- new kiwi.Constraint(
1910
- expr,
1911
- kiwi.Operator.Eq,
1912
- props.xDist,
1913
- kiwi.Strength.required
1914
- )
1915
- );
1916
- } else if (edgeToEdge) {
1917
- const expr = new kiwi.Expression(
1918
- rightVar,
1919
- -rightBounds.width / 2,
1920
- [-1, leftVar],
1921
- -leftBounds.width / 2
1922
- );
1923
- solver.addConstraint(
1924
- new kiwi.Constraint(
1925
- expr,
1926
- kiwi.Operator.Eq,
1927
- props.xDist,
1928
- kiwi.Strength.required
1929
- )
1930
- );
1931
- }
1932
- } else if ("yDist" in props) {
1933
- const { yDist, top, bottom, edgeToEdge, centerToCenter } = props;
1934
- const topVar = getKVar(`${top}_y`);
1935
- const bottomVar = getKVar(`${bottom}_y`);
1936
- const topBounds = getComponentDetails(top)?.bounds;
1937
- const bottomBounds = getComponentDetails(bottom)?.bounds;
1938
- if (centerToCenter) {
1939
- const expr = new kiwi.Expression(topVar, [-1, bottomVar]);
1940
- solver.addConstraint(
1941
- new kiwi.Constraint(
1942
- expr,
1943
- kiwi.Operator.Eq,
1944
- props.yDist,
1945
- kiwi.Strength.required
1946
- )
1947
- );
1948
- } else if (edgeToEdge) {
1949
- const expr = new kiwi.Expression(
1950
- topVar,
1951
- topBounds.height / 2,
1952
- [-1, bottomVar],
1953
- -bottomBounds.height / 2
1954
- );
1955
- solver.addConstraint(
1956
- new kiwi.Constraint(
1957
- expr,
1958
- kiwi.Operator.Eq,
1959
- props.yDist,
1960
- kiwi.Strength.required
1961
- )
1962
- );
1963
- }
1964
- } else if ("sameY" in props) {
1965
- const { for: selectors } = props;
1966
- if (selectors.length < 2) continue;
1967
- const vars = selectors.map((selector) => getKVar(`${selector}_y`));
1968
- const expr = new kiwi.Expression(...vars.slice(1));
1969
- solver.addConstraint(
1970
- new kiwi.Constraint(
1971
- expr,
1972
- kiwi.Operator.Eq,
1973
- vars[0],
1974
- kiwi.Strength.required
1975
- )
1976
- );
1977
- } else if ("sameX" in props) {
1978
- const { for: selectors } = props;
1979
- if (selectors.length < 2) continue;
1980
- const vars = selectors.map((selector) => getKVar(`${selector}_x`));
1981
- const expr = new kiwi.Expression(...vars.slice(1));
1982
- solver.addConstraint(
1983
- new kiwi.Constraint(
1984
- expr,
1985
- kiwi.Operator.Eq,
1986
- vars[0],
1987
- kiwi.Strength.required
1988
- )
1989
- );
1990
- }
1991
- }
1992
- solver.updateVariables();
1993
- if (debug.enabled) {
1994
- console.log("Solution to layout constraints:");
1995
- console.table(
1996
- Object.entries(kVars).map(([key, kvar]) => ({
1997
- var: key,
1998
- val: kvar.value()
1999
- }))
2000
- );
2001
- }
2002
- const bounds = {
2003
- left: Infinity,
2004
- right: -Infinity,
2005
- top: -Infinity,
2006
- bottom: Infinity
2007
- };
2008
- for (const {
2009
- selector,
2010
- bounds: { width, height }
2011
- } of involvedComponents) {
2012
- const kvx = getKVar(`${selector}_x`);
2013
- const kvy = getKVar(`${selector}_y`);
2014
- const newLeft = kvx.value() - width / 2;
2015
- const newRight = kvx.value() + width / 2;
2016
- const newTop = kvy.value() + height / 2;
2017
- const newBottom = kvy.value() - height / 2;
2018
- bounds.left = Math.min(bounds.left, newLeft);
2019
- bounds.right = Math.max(bounds.right, newRight);
2020
- bounds.top = Math.max(bounds.top, newTop);
2021
- bounds.bottom = Math.min(bounds.bottom, newBottom);
2022
- }
2023
- const globalOffset = {
2024
- x: -(bounds.right + bounds.left) / 2,
2025
- y: -(bounds.top + bounds.bottom) / 2
2026
- };
2027
- const containerPos = this.getPrimitiveContainer()._getGlobalPcbPositionBeforeLayout();
2028
- globalOffset.x += containerPos.x;
2029
- globalOffset.y += containerPos.y;
2030
- for (const { component, selector } of involvedComponents) {
2031
- const kvx = getKVar(`${selector}_x`);
2032
- const kvy = getKVar(`${selector}_y`);
2033
- component._setPositionFromLayout({
2034
- x: kvx.value() + globalOffset.x,
2035
- y: kvy.value() + globalOffset.y
2036
- });
2037
- }
2038
- }
2039
- };
2040
-
2041
1871
  // lib/utils/schematic/getSizeOfSidesFromPortArrangement.ts
2042
1872
  var hasExplicitPinMapping = (pa) => {
2043
1873
  for (const side of [
@@ -2272,51 +2102,221 @@ var getAllDimensionsForSchematicBox = (params) => {
2272
2102
  };
2273
2103
  };
2274
2104
 
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) {
2105
+ // lib/components/base-components/NormalComponent.ts
2106
+ import {
2107
+ isValidElement as isReactElement,
2108
+ isValidElement
2109
+ } from "react";
2110
+ import { symbols as symbols2 } from "schematic-symbols";
2111
+ import { z as z5 } from "zod";
2112
+
2113
+ // lib/components/primitive-components/Footprint.ts
2114
+ import { footprintProps } from "@tscircuit/props";
2115
+ import * as kiwi from "@lume/kiwi";
2116
+ import Debug from "debug";
2117
+ var debug = Debug("tscircuit:core:footprint");
2118
+ var Footprint = class extends PrimitiveComponent {
2119
+ get config() {
2279
2120
  return {
2280
- left_side: portArrangement.leftSide,
2281
- right_side: portArrangement.rightSide,
2282
- top_side: portArrangement.topSide,
2283
- bottom_side: portArrangement.bottomSide
2121
+ componentName: "Footprint",
2122
+ zodProps: footprintProps
2284
2123
  };
2285
2124
  }
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
2125
+ /**
2126
+ * A footprint is a constrainedlayout, the db elements are adjusted according
2127
+ * to any constraints that are defined.
2128
+ */
2129
+ doInitialPcbFootprintLayout() {
2130
+ const constraints = this.children.filter(
2131
+ (child) => child.componentName === "Constraint"
2132
+ );
2133
+ if (constraints.length === 0) return;
2134
+ const { isFlipped } = this._getPcbPrimitiveFlippedHelpers();
2135
+ const maybeFlipLeftRight = (props) => {
2136
+ if (isFlipped) {
2137
+ if ("left" in props && "right" in props) {
2138
+ return {
2139
+ ...props,
2140
+ left: props.right,
2141
+ right: props.left
2142
+ };
2143
+ }
2144
+ }
2145
+ return props;
2292
2146
  };
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
2147
+ const involvedComponents = constraints.flatMap(
2148
+ (constraint) => constraint._getAllReferencedComponents().componentsWithSelectors
2149
+ ).map(({ component, selector, componentSelector, edge }) => ({
2150
+ component,
2151
+ selector,
2152
+ componentSelector,
2153
+ edge,
2154
+ bounds: component._getPcbCircuitJsonBounds()
2155
+ }));
2156
+ if (involvedComponents.some((c) => c.edge)) {
2157
+ throw new Error(
2158
+ "edge constraints not implemented yet for footprint layout, contributions welcome!"
2159
+ );
2160
+ }
2161
+ function getComponentDetails(selector) {
2162
+ return involvedComponents.find(({ selector: s }) => s === selector);
2163
+ }
2164
+ const solver = new kiwi.Solver();
2165
+ const kVars = {};
2166
+ function getKVar(name) {
2167
+ if (!(name in kVars)) {
2168
+ kVars[name] = new kiwi.Variable(name);
2169
+ solver.addEditVariable(kVars[name], kiwi.Strength.weak);
2170
+ }
2171
+ return kVars[name];
2172
+ }
2173
+ for (const { selector, bounds: bounds2 } of involvedComponents) {
2174
+ const kvx = getKVar(`${selector}_x`);
2175
+ const kvy = getKVar(`${selector}_y`);
2176
+ solver.suggestValue(kvx, bounds2.center.x);
2177
+ solver.suggestValue(kvy, bounds2.center.y);
2178
+ }
2179
+ for (const constraint of constraints) {
2180
+ const props = constraint._parsedProps;
2181
+ if ("xDist" in props) {
2182
+ const { xDist, left, right, edgeToEdge, centerToCenter } = maybeFlipLeftRight(props);
2183
+ const leftVar = getKVar(`${left}_x`);
2184
+ const rightVar = getKVar(`${right}_x`);
2185
+ const leftBounds = getComponentDetails(left)?.bounds;
2186
+ const rightBounds = getComponentDetails(right)?.bounds;
2187
+ if (centerToCenter) {
2188
+ const expr = new kiwi.Expression(rightVar, [-1, leftVar]);
2189
+ solver.addConstraint(
2190
+ new kiwi.Constraint(
2191
+ expr,
2192
+ kiwi.Operator.Eq,
2193
+ props.xDist,
2194
+ kiwi.Strength.required
2195
+ )
2196
+ );
2197
+ } else if (edgeToEdge) {
2198
+ const expr = new kiwi.Expression(
2199
+ rightVar,
2200
+ -rightBounds.width / 2,
2201
+ [-1, leftVar],
2202
+ -leftBounds.width / 2
2203
+ );
2204
+ solver.addConstraint(
2205
+ new kiwi.Constraint(
2206
+ expr,
2207
+ kiwi.Operator.Eq,
2208
+ props.xDist,
2209
+ kiwi.Strength.required
2210
+ )
2211
+ );
2212
+ }
2213
+ } else if ("yDist" in props) {
2214
+ const { yDist, top, bottom, edgeToEdge, centerToCenter } = props;
2215
+ const topVar = getKVar(`${top}_y`);
2216
+ const bottomVar = getKVar(`${bottom}_y`);
2217
+ const topBounds = getComponentDetails(top)?.bounds;
2218
+ const bottomBounds = getComponentDetails(bottom)?.bounds;
2219
+ if (centerToCenter) {
2220
+ const expr = new kiwi.Expression(topVar, [-1, bottomVar]);
2221
+ solver.addConstraint(
2222
+ new kiwi.Constraint(
2223
+ expr,
2224
+ kiwi.Operator.Eq,
2225
+ props.yDist,
2226
+ kiwi.Strength.required
2227
+ )
2228
+ );
2229
+ } else if (edgeToEdge) {
2230
+ const expr = new kiwi.Expression(
2231
+ topVar,
2232
+ topBounds.height / 2,
2233
+ [-1, bottomVar],
2234
+ -bottomBounds.height / 2
2235
+ );
2236
+ solver.addConstraint(
2237
+ new kiwi.Constraint(
2238
+ expr,
2239
+ kiwi.Operator.Eq,
2240
+ props.yDist,
2241
+ kiwi.Strength.required
2242
+ )
2243
+ );
2244
+ }
2245
+ } else if ("sameY" in props) {
2246
+ const { for: selectors } = props;
2247
+ if (selectors.length < 2) continue;
2248
+ const vars = selectors.map((selector) => getKVar(`${selector}_y`));
2249
+ const expr = new kiwi.Expression(...vars.slice(1));
2250
+ solver.addConstraint(
2251
+ new kiwi.Constraint(
2252
+ expr,
2253
+ kiwi.Operator.Eq,
2254
+ vars[0],
2255
+ kiwi.Strength.required
2256
+ )
2257
+ );
2258
+ } else if ("sameX" in props) {
2259
+ const { for: selectors } = props;
2260
+ if (selectors.length < 2) continue;
2261
+ const vars = selectors.map((selector) => getKVar(`${selector}_x`));
2262
+ const expr = new kiwi.Expression(...vars.slice(1));
2263
+ solver.addConstraint(
2264
+ new kiwi.Constraint(
2265
+ expr,
2266
+ kiwi.Operator.Eq,
2267
+ vars[0],
2268
+ kiwi.Strength.required
2269
+ )
2270
+ );
2271
+ }
2272
+ }
2273
+ solver.updateVariables();
2274
+ if (debug.enabled) {
2275
+ console.log("Solution to layout constraints:");
2276
+ console.table(
2277
+ Object.entries(kVars).map(([key, kvar]) => ({
2278
+ var: key,
2279
+ val: kvar.value()
2280
+ }))
2281
+ );
2282
+ }
2283
+ const bounds = {
2284
+ left: Infinity,
2285
+ right: -Infinity,
2286
+ top: -Infinity,
2287
+ bottom: Infinity
2300
2288
  };
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
2289
+ for (const {
2290
+ selector,
2291
+ bounds: { width, height }
2292
+ } of involvedComponents) {
2293
+ const kvx = getKVar(`${selector}_x`);
2294
+ const kvy = getKVar(`${selector}_y`);
2295
+ const newLeft = kvx.value() - width / 2;
2296
+ const newRight = kvx.value() + width / 2;
2297
+ const newTop = kvy.value() + height / 2;
2298
+ const newBottom = kvy.value() - height / 2;
2299
+ bounds.left = Math.min(bounds.left, newLeft);
2300
+ bounds.right = Math.max(bounds.right, newRight);
2301
+ bounds.top = Math.max(bounds.top, newTop);
2302
+ bounds.bottom = Math.min(bounds.bottom, newBottom);
2303
+ }
2304
+ const globalOffset = {
2305
+ x: -(bounds.right + bounds.left) / 2,
2306
+ y: -(bounds.top + bounds.bottom) / 2
2317
2307
  };
2308
+ const containerPos = this.getPrimitiveContainer()._getGlobalPcbPositionBeforeLayout();
2309
+ globalOffset.x += containerPos.x;
2310
+ globalOffset.y += containerPos.y;
2311
+ for (const { component, selector } of involvedComponents) {
2312
+ const kvx = getKVar(`${selector}_x`);
2313
+ const kvy = getKVar(`${selector}_y`);
2314
+ component._setPositionFromLayout({
2315
+ x: kvx.value() + globalOffset.x,
2316
+ y: kvy.value() + globalOffset.y
2317
+ });
2318
+ }
2318
2319
  }
2319
- return underscorePinStyles;
2320
2320
  };
2321
2321
 
2322
2322
  // lib/components/base-components/NormalComponent.ts
@@ -2430,10 +2430,14 @@ var NormalComponent = class extends PrimitiveComponent {
2430
2430
  this.addAll(portsToCreate);
2431
2431
  return;
2432
2432
  }
2433
- const portsFromFootprint = this.getPortsFromFootprint();
2434
- for (const port of portsFromFootprint) {
2435
- if (!portsToCreate.some((p) => p.isMatchingAnyOf(port.getNameAndAliases()))) {
2436
- portsToCreate.push(port);
2433
+ if (!this._parsedProps.schPortArrangement) {
2434
+ const portsFromFootprint = this.getPortsFromFootprint();
2435
+ for (const port of portsFromFootprint) {
2436
+ if (!portsToCreate.some(
2437
+ (p) => p.isMatchingAnyOf(port.getNameAndAliases())
2438
+ )) {
2439
+ portsToCreate.push(port);
2440
+ }
2437
2441
  }
2438
2442
  }
2439
2443
  if (portsToCreate.length > 0) {
@@ -2723,10 +2727,14 @@ var NormalComponent = class extends PrimitiveComponent {
2723
2727
  *
2724
2728
  */
2725
2729
  doInitialPortDiscovery() {
2726
- const newPorts = [
2727
- ...this.getPortsFromFootprint(),
2728
- ...this.getPortsFromSchematicSymbol()
2729
- ];
2730
+ const { _parsedProps: props } = this;
2731
+ let newPorts = [];
2732
+ if (!props.schPortArrangement) {
2733
+ newPorts = [
2734
+ ...this.getPortsFromFootprint(),
2735
+ ...this.getPortsFromSchematicSymbol()
2736
+ ];
2737
+ }
2730
2738
  const existingPorts = this.children.filter(
2731
2739
  (c) => c.componentName === "Port"
2732
2740
  );
@@ -2762,9 +2770,10 @@ var NormalComponent = class extends PrimitiveComponent {
2762
2770
  }
2763
2771
  _getPinCount() {
2764
2772
  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;
2773
+ if (schPortArrangement) {
2774
+ return (schPortArrangement.leftSize ?? 0) + (schPortArrangement.rightSize ?? 0) + (schPortArrangement.topSize ?? 0) + (schPortArrangement.bottomSize ?? 0);
2775
+ }
2776
+ return this.getPortsFromFootprint().length;
2768
2777
  }
2769
2778
  /**
2770
2779
  * Override the schematic port arrangement if you want to customize where pins
@@ -3313,6 +3322,56 @@ function tryNow(fn) {
3313
3322
 
3314
3323
  // lib/components/primitive-components/Trace.ts
3315
3324
  import "zod";
3325
+
3326
+ // lib/utils/autorouting/getDominantDirection.ts
3327
+ function getDominantDirection(edge) {
3328
+ const delta = {
3329
+ x: edge.to.x - edge.from.x,
3330
+ y: edge.to.y - edge.from.y
3331
+ };
3332
+ const absX = Math.abs(delta.x);
3333
+ const absY = Math.abs(delta.y);
3334
+ if (absX > absY) {
3335
+ return delta.x > 0 ? "right" : "left";
3336
+ }
3337
+ return delta.y > 0 ? "down" : "up";
3338
+ }
3339
+
3340
+ // lib/utils/schematic/getStubEdges.ts
3341
+ var getStubEdges = ({
3342
+ lastEdge,
3343
+ lastEdgePort,
3344
+ lastDominantDirection
3345
+ }) => {
3346
+ const edges = [];
3347
+ if (lastEdge && lastEdgePort) {
3348
+ const intermediatePoint = { x: lastEdge.to.x, y: lastEdge.to.y };
3349
+ if (lastDominantDirection === "left" || lastDominantDirection === "right") {
3350
+ intermediatePoint.x = lastEdgePort.position.x;
3351
+ edges.push({
3352
+ from: lastEdge.to,
3353
+ to: { ...intermediatePoint }
3354
+ });
3355
+ edges.push({
3356
+ from: intermediatePoint,
3357
+ to: { ...lastEdgePort.position }
3358
+ });
3359
+ } else {
3360
+ intermediatePoint.y = lastEdgePort.position.y;
3361
+ edges.push({
3362
+ from: lastEdge.to,
3363
+ to: { ...intermediatePoint }
3364
+ });
3365
+ edges.push({
3366
+ from: intermediatePoint,
3367
+ to: { ...lastEdgePort.position }
3368
+ });
3369
+ }
3370
+ }
3371
+ return edges;
3372
+ };
3373
+
3374
+ // lib/components/primitive-components/Trace.ts
3316
3375
  var portToObjective = (port) => {
3317
3376
  const portPosition = port._getGlobalPcbPositionAfterLayout();
3318
3377
  return {
@@ -3789,6 +3848,12 @@ searched component ${targetComponent.getString()}, which has ports: ${targetComp
3789
3848
  to: route[i + 1]
3790
3849
  });
3791
3850
  }
3851
+ const lastEdge = edges[edges.length - 1];
3852
+ const lastEdgePort = portsWithPosition[portsWithPosition.length - 1];
3853
+ const lastDominantDirection = getDominantDirection(lastEdge);
3854
+ edges.push(
3855
+ ...getStubEdges({ lastEdge, lastEdgePort, lastDominantDirection })
3856
+ );
3792
3857
  const trace = db.schematic_trace.insert({
3793
3858
  source_trace_id: this.source_trace_id,
3794
3859
  edges
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.148",
4
+ "version": "0.0.150",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -45,7 +45,7 @@
45
45
  "@tscircuit/soup-util": "^0.0.33",
46
46
  "circuit-json": "^0.0.93",
47
47
  "circuit-json-to-connectivity-map": "^0.0.17",
48
- "circuit-to-svg": "^0.0.58",
48
+ "circuit-to-svg": "^0.0.59",
49
49
  "nanoid": "^5.0.7",
50
50
  "performance-now": "^2.1.0",
51
51
  "react": "^18.3.1",