@tscircuit/core 0.0.33 → 0.0.34

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 CHANGED
@@ -3438,80 +3438,76 @@ declare class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
3438
3438
  doInitialPcbPrimitiveRender(): void;
3439
3439
  }
3440
3440
 
3441
+ declare const edgeSpecifiers: readonly ["leftedge", "rightedge", "topedge", "bottomedge", "center"];
3442
+ type EdgeSpecifier = (typeof edgeSpecifiers)[number];
3441
3443
  declare class Constraint extends PrimitiveComponent<typeof constraintProps> {
3442
3444
  get config(): {
3443
3445
  zodProps: z.ZodUnion<[z.ZodObject<{
3444
3446
  pcb: z.ZodOptional<z.ZodLiteral<true>>;
3445
- type: z.ZodOptional<z.ZodLiteral<"xdist">>;
3446
- xdist: z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, number, string | number>;
3447
+ xDist: z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, number, string | number>;
3447
3448
  left: z.ZodString;
3448
3449
  right: z.ZodString;
3449
3450
  edgeToEdge: z.ZodOptional<z.ZodLiteral<true>>;
3450
3451
  centerToCenter: z.ZodOptional<z.ZodLiteral<true>>;
3451
- fromLeftEdge: z.ZodOptional<z.ZodLiteral<true>>;
3452
- fromLeftCenter: z.ZodOptional<z.ZodLiteral<true>>;
3453
- toRightEdge: z.ZodOptional<z.ZodLiteral<true>>;
3454
- toRightCenter: z.ZodOptional<z.ZodLiteral<true>>;
3455
3452
  }, "strip", z.ZodTypeAny, {
3456
3453
  left: string;
3457
3454
  right: string;
3458
- xdist: number;
3459
- type?: "xdist" | undefined;
3455
+ xDist: number;
3460
3456
  pcb?: true | undefined;
3461
3457
  edgeToEdge?: true | undefined;
3462
3458
  centerToCenter?: true | undefined;
3463
- fromLeftEdge?: true | undefined;
3464
- fromLeftCenter?: true | undefined;
3465
- toRightEdge?: true | undefined;
3466
- toRightCenter?: true | undefined;
3467
3459
  }, {
3468
3460
  left: string;
3469
3461
  right: string;
3470
- xdist: string | number;
3471
- type?: "xdist" | undefined;
3462
+ xDist: string | number;
3472
3463
  pcb?: true | undefined;
3473
3464
  edgeToEdge?: true | undefined;
3474
3465
  centerToCenter?: true | undefined;
3475
- fromLeftEdge?: true | undefined;
3476
- fromLeftCenter?: true | undefined;
3477
- toRightEdge?: true | undefined;
3478
- toRightCenter?: true | undefined;
3479
3466
  }>, z.ZodObject<{
3480
3467
  pcb: z.ZodOptional<z.ZodLiteral<true>>;
3481
- type: z.ZodOptional<z.ZodLiteral<"ydist">>;
3482
- ydist: z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, number, string | number>;
3468
+ yDist: z.ZodEffects<z.ZodUnion<[z.ZodString, z.ZodNumber]>, number, string | number>;
3483
3469
  top: z.ZodString;
3484
3470
  bottom: z.ZodString;
3485
3471
  edgeToEdge: z.ZodOptional<z.ZodLiteral<true>>;
3486
3472
  centerToCenter: z.ZodOptional<z.ZodLiteral<true>>;
3487
- fromTopEdge: z.ZodOptional<z.ZodLiteral<true>>;
3488
- fromTopCenter: z.ZodOptional<z.ZodLiteral<true>>;
3489
- toBottomEdge: z.ZodOptional<z.ZodLiteral<true>>;
3490
- toBottomCenter: z.ZodOptional<z.ZodLiteral<true>>;
3491
3473
  }, "strip", z.ZodTypeAny, {
3492
3474
  top: string;
3493
3475
  bottom: string;
3494
- ydist: number;
3495
- type?: "ydist" | undefined;
3476
+ yDist: number;
3496
3477
  pcb?: true | undefined;
3497
3478
  edgeToEdge?: true | undefined;
3498
3479
  centerToCenter?: true | undefined;
3499
- fromTopEdge?: true | undefined;
3500
- fromTopCenter?: true | undefined;
3501
- toBottomEdge?: true | undefined;
3502
- toBottomCenter?: true | undefined;
3503
3480
  }, {
3504
3481
  top: string;
3505
3482
  bottom: string;
3506
- ydist: string | number;
3507
- type?: "ydist" | undefined;
3483
+ yDist: string | number;
3508
3484
  pcb?: true | undefined;
3509
3485
  edgeToEdge?: true | undefined;
3510
3486
  centerToCenter?: true | undefined;
3511
- fromTopEdge?: true | undefined;
3512
- fromTopCenter?: true | undefined;
3513
- toBottomEdge?: true | undefined;
3514
- toBottomCenter?: true | undefined;
3487
+ }>, z.ZodObject<{
3488
+ pcb: z.ZodOptional<z.ZodLiteral<true>>;
3489
+ sameY: z.ZodOptional<z.ZodLiteral<true>>;
3490
+ for: z.ZodArray<z.ZodString, "many">;
3491
+ }, "strip", z.ZodTypeAny, {
3492
+ for: string[];
3493
+ pcb?: true | undefined;
3494
+ sameY?: true | undefined;
3495
+ }, {
3496
+ for: string[];
3497
+ pcb?: true | undefined;
3498
+ sameY?: true | undefined;
3499
+ }>, z.ZodObject<{
3500
+ pcb: z.ZodOptional<z.ZodLiteral<true>>;
3501
+ sameX: z.ZodOptional<z.ZodLiteral<true>>;
3502
+ for: z.ZodArray<z.ZodString, "many">;
3503
+ }, "strip", z.ZodTypeAny, {
3504
+ for: string[];
3505
+ pcb?: true | undefined;
3506
+ sameX?: true | undefined;
3507
+ }, {
3508
+ for: string[];
3509
+ pcb?: true | undefined;
3510
+ sameX?: true | undefined;
3515
3511
  }>]>;
3516
3512
  };
3517
3513
  constructor(props: z.input<typeof constraintProps>);
@@ -3519,6 +3515,8 @@ declare class Constraint extends PrimitiveComponent<typeof constraintProps> {
3519
3515
  componentsWithSelectors: Array<{
3520
3516
  component: PrimitiveComponent<any>;
3521
3517
  selector: string;
3518
+ componentSelector: string;
3519
+ edge: EdgeSpecifier | undefined;
3522
3520
  }>;
3523
3521
  };
3524
3522
  }
package/dist/index.js CHANGED
@@ -522,11 +522,18 @@ var Footprint = class extends PrimitiveComponent {
522
522
  if (constraints.length === 0) return;
523
523
  const involvedComponents = constraints.flatMap(
524
524
  (constraint) => constraint._getAllReferencedComponents().componentsWithSelectors
525
- ).map(({ component, selector }) => ({
525
+ ).map(({ component, selector, componentSelector, edge }) => ({
526
526
  component,
527
527
  selector,
528
+ componentSelector,
529
+ edge,
528
530
  bounds: component._getCircuitJsonBounds()
529
531
  }));
532
+ if (involvedComponents.some((c) => c.edge)) {
533
+ throw new Error(
534
+ "edge constraints not implemented yet for footprint layout, contributions welcome!"
535
+ );
536
+ }
530
537
  function getComponentDetails(selector) {
531
538
  return involvedComponents.find(({ selector: s }) => s === selector);
532
539
  }
@@ -547,8 +554,8 @@ var Footprint = class extends PrimitiveComponent {
547
554
  }
548
555
  for (const constraint of constraints) {
549
556
  const props = constraint._parsedProps;
550
- if ("xdist" in props) {
551
- const { xdist, left, right, edgeToEdge, centerToCenter } = props;
557
+ if ("xDist" in props) {
558
+ const { xDist, left, right, edgeToEdge, centerToCenter } = props;
552
559
  const leftVar = getKVar(`${left}_x`);
553
560
  const rightVar = getKVar(`${right}_x`);
554
561
  const leftBounds = getComponentDetails(left)?.bounds;
@@ -559,7 +566,7 @@ var Footprint = class extends PrimitiveComponent {
559
566
  new kiwi.Constraint(
560
567
  expr,
561
568
  kiwi.Operator.Eq,
562
- props.xdist,
569
+ props.xDist,
563
570
  kiwi.Strength.required
564
571
  )
565
572
  );
@@ -574,13 +581,13 @@ var Footprint = class extends PrimitiveComponent {
574
581
  new kiwi.Constraint(
575
582
  expr,
576
583
  kiwi.Operator.Eq,
577
- props.xdist,
584
+ props.xDist,
578
585
  kiwi.Strength.required
579
586
  )
580
587
  );
581
588
  }
582
- } else if ("ydist" in props) {
583
- const { ydist, top, bottom, edgeToEdge, centerToCenter } = props;
589
+ } else if ("yDist" in props) {
590
+ const { yDist, top, bottom, edgeToEdge, centerToCenter } = props;
584
591
  const topVar = getKVar(`${top}_y`);
585
592
  const bottomVar = getKVar(`${bottom}_y`);
586
593
  const topBounds = getComponentDetails(top)?.bounds;
@@ -591,7 +598,7 @@ var Footprint = class extends PrimitiveComponent {
591
598
  new kiwi.Constraint(
592
599
  expr,
593
600
  kiwi.Operator.Eq,
594
- props.ydist,
601
+ props.yDist,
595
602
  kiwi.Strength.required
596
603
  )
597
604
  );
@@ -606,11 +613,37 @@ var Footprint = class extends PrimitiveComponent {
606
613
  new kiwi.Constraint(
607
614
  expr,
608
615
  kiwi.Operator.Eq,
609
- props.ydist,
616
+ props.yDist,
610
617
  kiwi.Strength.required
611
618
  )
612
619
  );
613
620
  }
621
+ } else if ("sameY" in props) {
622
+ const { for: selectors } = props;
623
+ if (selectors.length < 2) continue;
624
+ const vars = selectors.map((selector) => getKVar(`${selector}_y`));
625
+ const expr = new kiwi.Expression(...vars.slice(1));
626
+ solver.addConstraint(
627
+ new kiwi.Constraint(
628
+ expr,
629
+ kiwi.Operator.Eq,
630
+ vars[0],
631
+ kiwi.Strength.required
632
+ )
633
+ );
634
+ } else if ("sameX" in props) {
635
+ const { for: selectors } = props;
636
+ if (selectors.length < 2) continue;
637
+ const vars = selectors.map((selector) => getKVar(`${selector}_x`));
638
+ const expr = new kiwi.Expression(...vars.slice(1));
639
+ solver.addConstraint(
640
+ new kiwi.Constraint(
641
+ expr,
642
+ kiwi.Operator.Eq,
643
+ vars[0],
644
+ kiwi.Strength.required
645
+ )
646
+ );
614
647
  }
615
648
  }
616
649
  solver.updateVariables();
@@ -1236,7 +1269,6 @@ var PlatedHole = class extends PrimitiveComponent {
1236
1269
  doInitialPcbPrimitiveRender() {
1237
1270
  const { db } = this.root;
1238
1271
  const { _parsedProps: props } = this;
1239
- if (!props.portHints) return;
1240
1272
  const position = this._getGlobalPcbPositionBeforeLayout();
1241
1273
  if (props.shape === "circle") {
1242
1274
  const pcb_plated_hole = db.pcb_plated_hole.insert({
@@ -2942,6 +2974,13 @@ var Jumper = class extends NormalComponent {
2942
2974
  // lib/components/primitive-components/Constraint.ts
2943
2975
  import { constraintProps } from "@tscircuit/props";
2944
2976
  import "zod";
2977
+ var edgeSpecifiers = [
2978
+ "leftedge",
2979
+ "rightedge",
2980
+ "topedge",
2981
+ "bottomedge",
2982
+ "center"
2983
+ ];
2945
2984
  var Constraint2 = class extends PrimitiveComponent {
2946
2985
  get config() {
2947
2986
  return {
@@ -2953,23 +2992,38 @@ var Constraint2 = class extends PrimitiveComponent {
2953
2992
  if ("xdist" in props || "ydist" in props) {
2954
2993
  if (!("edgeToEdge" in props) && !("centerToCenter" in props)) {
2955
2994
  throw new Error(
2956
- "edgeToEdge, centerToCenter (or from*/to* props) must be set for xdist or ydist for <constraint />"
2995
+ `edgeToEdge, centerToCenter must be set for xDist or yDist for ${this}`
2957
2996
  );
2958
2997
  }
2959
2998
  }
2999
+ if ("for" in props && props.for.length < 2) {
3000
+ throw new Error(`"for" must have at least two selectors for ${this}`);
3001
+ }
2960
3002
  }
2961
3003
  _getAllReferencedComponents() {
2962
3004
  const componentsWithSelectors = [];
3005
+ const subcircuit = this.getSubcircuit();
3006
+ function addComponentFromSelector(selector) {
3007
+ const component = subcircuit.selectOne(selector);
3008
+ if (component) {
3009
+ const maybeEdge = selector.split(" ").pop();
3010
+ const edge = edgeSpecifiers.includes(maybeEdge) ? maybeEdge : void 0;
3011
+ componentsWithSelectors.push({
3012
+ selector,
3013
+ component,
3014
+ componentSelector: edge ? selector.replace(` ${edge}`, "") : selector,
3015
+ edge
3016
+ });
3017
+ }
3018
+ }
2963
3019
  for (const key of ["left", "right", "top", "bottom"]) {
2964
3020
  if (key in this._parsedProps) {
2965
- const selector = this._parsedProps[key];
2966
- const component = this.getSubcircuit().selectOne(selector);
2967
- if (component) {
2968
- componentsWithSelectors.push({
2969
- selector,
2970
- component
2971
- });
2972
- }
3021
+ addComponentFromSelector(this._parsedProps[key]);
3022
+ }
3023
+ }
3024
+ if ("for" in this._parsedProps) {
3025
+ for (const selector of this._parsedProps.for) {
3026
+ addComponentFromSelector(selector);
2973
3027
  }
2974
3028
  }
2975
3029
  return { componentsWithSelectors };
@@ -2,6 +2,16 @@ import { constraintProps } from "@tscircuit/props"
2
2
  import { z } from "zod"
3
3
  import { PrimitiveComponent } from "../base-components/PrimitiveComponent"
4
4
 
5
+ const edgeSpecifiers = [
6
+ "leftedge",
7
+ "rightedge",
8
+ "topedge",
9
+ "bottomedge",
10
+ "center",
11
+ ] as const
12
+
13
+ export type EdgeSpecifier = (typeof edgeSpecifiers)[number]
14
+
5
15
  export class Constraint extends PrimitiveComponent<typeof constraintProps> {
6
16
  get config() {
7
17
  return {
@@ -13,34 +23,60 @@ export class Constraint extends PrimitiveComponent<typeof constraintProps> {
13
23
  super(props)
14
24
  if ("xdist" in props || "ydist" in props) {
15
25
  if (!("edgeToEdge" in props) && !("centerToCenter" in props)) {
26
+ // TODO don't throw an error if the selectors specify an edge
16
27
  throw new Error(
17
- "edgeToEdge, centerToCenter (or from*/to* props) must be set for xdist or ydist for <constraint />",
28
+ `edgeToEdge, centerToCenter must be set for xDist or yDist for ${this}`,
18
29
  )
19
30
  }
20
31
  }
32
+ if ("for" in props && props.for.length < 2) {
33
+ throw new Error(`"for" must have at least two selectors for ${this}`)
34
+ }
21
35
  }
22
36
 
23
37
  _getAllReferencedComponents(): {
24
38
  componentsWithSelectors: Array<{
25
39
  component: PrimitiveComponent<any>
26
40
  selector: string
41
+ componentSelector: string
42
+ edge: EdgeSpecifier | undefined
27
43
  }>
28
44
  } {
29
45
  const componentsWithSelectors: Array<{
30
46
  component: PrimitiveComponent<any>
31
47
  selector: string
48
+ componentSelector: string
49
+ edge: EdgeSpecifier | undefined
32
50
  }> = []
33
51
 
52
+ const subcircuit = this.getSubcircuit()
53
+
54
+ function addComponentFromSelector(selector: string) {
55
+ // TODO this selector has to be modified in case it contains a leftedge,
56
+ // center/topedge/rightedge indicator
57
+ const component = subcircuit.selectOne(selector)
58
+ if (component) {
59
+ const maybeEdge = selector.split(" ").pop() as EdgeSpecifier
60
+ const edge = edgeSpecifiers.includes(maybeEdge) ? maybeEdge : undefined
61
+
62
+ componentsWithSelectors.push({
63
+ selector,
64
+ component,
65
+ componentSelector: edge ? selector.replace(` ${edge}`, "") : selector,
66
+ edge,
67
+ })
68
+ }
69
+ }
70
+
34
71
  for (const key of ["left", "right", "top", "bottom"]) {
35
72
  if (key in this._parsedProps) {
36
- const selector = (this._parsedProps as any)[key] as string
37
- const component = this.getSubcircuit().selectOne(selector)
38
- if (component) {
39
- componentsWithSelectors.push({
40
- selector,
41
- component,
42
- })
43
- }
73
+ addComponentFromSelector((this._parsedProps as any)[key] as string)
74
+ }
75
+ }
76
+
77
+ if ("for" in this._parsedProps) {
78
+ for (const selector of this._parsedProps.for) {
79
+ addComponentFromSelector(selector)
44
80
  }
45
81
  }
46
82
 
@@ -23,12 +23,20 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
23
23
  (constraint) =>
24
24
  constraint._getAllReferencedComponents().componentsWithSelectors,
25
25
  )
26
- .map(({ component, selector }) => ({
26
+ .map(({ component, selector, componentSelector, edge }) => ({
27
27
  component,
28
28
  selector,
29
+ componentSelector,
30
+ edge,
29
31
  bounds: component._getCircuitJsonBounds(),
30
32
  }))
31
33
 
34
+ if (involvedComponents.some((c) => c.edge)) {
35
+ throw new Error(
36
+ "edge constraints not implemented yet for footprint layout, contributions welcome!",
37
+ )
38
+ }
39
+
32
40
  function getComponentDetails(selector: string) {
33
41
  return involvedComponents.find(({ selector: s }) => s === selector)
34
42
  }
@@ -56,8 +64,8 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
56
64
  for (const constraint of constraints) {
57
65
  const props = constraint._parsedProps
58
66
 
59
- if ("xdist" in props) {
60
- const { xdist, left, right, edgeToEdge, centerToCenter } = props
67
+ if ("xDist" in props) {
68
+ const { xDist, left, right, edgeToEdge, centerToCenter } = props
61
69
  const leftVar = getKVar(`${left}_x`)
62
70
  const rightVar = getKVar(`${right}_x`)
63
71
  const leftBounds = getComponentDetails(left)?.bounds!
@@ -70,7 +78,7 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
70
78
  new kiwi.Constraint(
71
79
  expr,
72
80
  kiwi.Operator.Eq,
73
- props.xdist,
81
+ props.xDist,
74
82
  kiwi.Strength.required,
75
83
  ),
76
84
  )
@@ -87,13 +95,13 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
87
95
  new kiwi.Constraint(
88
96
  expr,
89
97
  kiwi.Operator.Eq,
90
- props.xdist,
98
+ props.xDist,
91
99
  kiwi.Strength.required,
92
100
  ),
93
101
  )
94
102
  }
95
- } else if ("ydist" in props) {
96
- const { ydist, top, bottom, edgeToEdge, centerToCenter } = props
103
+ } else if ("yDist" in props) {
104
+ const { yDist, top, bottom, edgeToEdge, centerToCenter } = props
97
105
  const topVar = getKVar(`${top}_y`)
98
106
  const bottomVar = getKVar(`${bottom}_y`)
99
107
  const topBounds = getComponentDetails(top)?.bounds!
@@ -108,7 +116,7 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
108
116
  new kiwi.Constraint(
109
117
  expr,
110
118
  kiwi.Operator.Eq,
111
- props.ydist,
119
+ props.yDist,
112
120
  kiwi.Strength.required,
113
121
  ),
114
122
  )
@@ -125,11 +133,38 @@ export class Footprint extends PrimitiveComponent<typeof footprintProps> {
125
133
  new kiwi.Constraint(
126
134
  expr,
127
135
  kiwi.Operator.Eq,
128
- props.ydist,
136
+ props.yDist,
129
137
  kiwi.Strength.required,
130
138
  ),
131
139
  )
132
140
  }
141
+ } else if ("sameY" in props) {
142
+ const { for: selectors } = props
143
+ if (selectors.length < 2) continue
144
+ const vars = selectors.map((selector) => getKVar(`${selector}_y`))
145
+ const expr = new kiwi.Expression(...vars.slice(1))
146
+
147
+ solver.addConstraint(
148
+ new kiwi.Constraint(
149
+ expr,
150
+ kiwi.Operator.Eq,
151
+ vars[0],
152
+ kiwi.Strength.required,
153
+ ),
154
+ )
155
+ } else if ("sameX" in props) {
156
+ const { for: selectors } = props
157
+ if (selectors.length < 2) continue
158
+ const vars = selectors.map((selector) => getKVar(`${selector}_x`))
159
+ const expr = new kiwi.Expression(...vars.slice(1))
160
+ solver.addConstraint(
161
+ new kiwi.Constraint(
162
+ expr,
163
+ kiwi.Operator.Eq,
164
+ vars[0],
165
+ kiwi.Strength.required,
166
+ ),
167
+ )
133
168
  }
134
169
  }
135
170
 
@@ -79,7 +79,6 @@ export class PlatedHole extends PrimitiveComponent<typeof platedHoleProps> {
79
79
  doInitialPcbPrimitiveRender(): void {
80
80
  const { db } = this.root!
81
81
  const { _parsedProps: props } = this
82
- if (!props.portHints) return
83
82
  const position = this._getGlobalPcbPositionBeforeLayout()
84
83
  if (props.shape === "circle") {
85
84
  const pcb_plated_hole = db.pcb_plated_hole.insert({
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@tscircuit/core",
3
3
  "module": "index.ts",
4
4
  "type": "module",
5
- "version": "0.0.33",
5
+ "version": "0.0.34",
6
6
  "types": "dist/index.d.ts",
7
7
  "main": "dist/index.js",
8
8
  "files": [
@@ -35,7 +35,7 @@
35
35
  "dependencies": {
36
36
  "@lume/kiwi": "^0.4.3",
37
37
  "@tscircuit/infgrid-ijump-astar": "^0.0.6",
38
- "@tscircuit/props": "^0.0.61",
38
+ "@tscircuit/props": "^0.0.62",
39
39
  "@tscircuit/soup": "^0.0.66",
40
40
  "@tscircuit/soup-util": "0.0.18",
41
41
  "footprinter": "^0.0.44",