@tscircuit/core 0.0.992 → 0.0.994

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
@@ -123664,7 +123664,7 @@ declare class SchematicPath extends PrimitiveComponent<typeof schematicPathProps
123664
123664
  get config(): {
123665
123665
  componentName: string;
123666
123666
  zodProps: zod.ZodObject<{
123667
- points: zod.ZodArray<zod.ZodObject<{
123667
+ points: zod.ZodOptional<zod.ZodArray<zod.ZodObject<{
123668
123668
  x: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
123669
123669
  y: zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>;
123670
123670
  }, "strip", zod.ZodTypeAny, {
@@ -123673,28 +123673,28 @@ declare class SchematicPath extends PrimitiveComponent<typeof schematicPathProps
123673
123673
  }, {
123674
123674
  x: string | number;
123675
123675
  y: string | number;
123676
- }>, "many">;
123676
+ }>, "many">>;
123677
123677
  svgPath: zod.ZodOptional<zod.ZodString>;
123678
123678
  strokeWidth: zod.ZodOptional<zod.ZodEffects<zod.ZodUnion<[zod.ZodString, zod.ZodNumber]>, number, string | number>>;
123679
123679
  strokeColor: zod.ZodOptional<zod.ZodString>;
123680
123680
  isFilled: zod.ZodDefault<zod.ZodOptional<zod.ZodBoolean>>;
123681
123681
  fillColor: zod.ZodOptional<zod.ZodEnum<["red", "blue"]>>;
123682
123682
  }, "strip", zod.ZodTypeAny, {
123683
- points: {
123684
- x: number;
123685
- y: number;
123686
- }[];
123687
123683
  isFilled: boolean;
123688
123684
  strokeWidth?: number | undefined;
123685
+ points?: {
123686
+ x: number;
123687
+ y: number;
123688
+ }[] | undefined;
123689
123689
  fillColor?: "red" | "blue" | undefined;
123690
123690
  svgPath?: string | undefined;
123691
123691
  strokeColor?: string | undefined;
123692
123692
  }, {
123693
- points: {
123693
+ strokeWidth?: string | number | undefined;
123694
+ points?: {
123694
123695
  x: string | number;
123695
123696
  y: string | number;
123696
- }[];
123697
- strokeWidth?: string | number | undefined;
123697
+ }[] | undefined;
123698
123698
  isFilled?: boolean | undefined;
123699
123699
  fillColor?: "red" | "blue" | undefined;
123700
123700
  svgPath?: string | undefined;
package/dist/index.js CHANGED
@@ -17065,6 +17065,19 @@ var Panel = class extends Group6 {
17065
17065
  }
17066
17066
  }
17067
17067
  }
17068
+ if (layoutMode === "none" && childBoardInstances.length > 1) {
17069
+ const boardsWithoutPosition = childBoardInstances.filter((board) => {
17070
+ const hasPcbX = board._parsedProps.pcbX !== void 0;
17071
+ const hasPcbY = board._parsedProps.pcbY !== void 0;
17072
+ return !hasPcbX && !hasPcbY;
17073
+ });
17074
+ if (boardsWithoutPosition.length > 1) {
17075
+ this.root.db.pcb_placement_error.insert({
17076
+ error_type: "pcb_placement_error",
17077
+ message: `Multiple boards in panel without pcbX/pcbY positions. When layoutMode="none", each board must have explicit pcbX and pcbY coordinates to avoid overlapping. Either set pcbX/pcbY on each board, or use layoutMode="grid" for automatic positioning.`
17078
+ });
17079
+ }
17080
+ }
17068
17081
  if (layoutMode !== "grid") return;
17069
17082
  const tabWidth = this._parsedProps.tabWidth ?? DEFAULT_TAB_WIDTH;
17070
17083
  const boardGap = this._parsedProps.boardGap ?? tabWidth;
@@ -20340,6 +20353,136 @@ var SchematicCircle = class extends PrimitiveComponent2 {
20340
20353
 
20341
20354
  // lib/components/primitive-components/SchematicPath.ts
20342
20355
  import { schematicPathProps } from "@tscircuit/props";
20356
+
20357
+ // lib/utils/schematic/svgPathToPoints.ts
20358
+ import SVGPathCommander from "svg-path-commander";
20359
+ function sampleCurveSegment(segmentPath, samplesPerUnit) {
20360
+ const commander = new SVGPathCommander(segmentPath);
20361
+ const length7 = commander.getTotalLength();
20362
+ const numSamples = Math.max(2, Math.ceil(length7 * samplesPerUnit));
20363
+ const points = [];
20364
+ for (let i = 1; i <= numSamples; i++) {
20365
+ const t = i / numSamples * length7;
20366
+ const point6 = commander.getPointAtLength(t);
20367
+ points.push({ x: point6.x, y: point6.y });
20368
+ }
20369
+ return points;
20370
+ }
20371
+ function svgPathToPoints(svgPath, samplesPerUnit = 10) {
20372
+ const pathCommander = new SVGPathCommander(svgPath);
20373
+ pathCommander.toAbsolute();
20374
+ const segments = pathCommander.segments;
20375
+ const result = [];
20376
+ let currentPoints = [];
20377
+ let currentX = 0;
20378
+ let currentY = 0;
20379
+ let subpathStartX = 0;
20380
+ let subpathStartY = 0;
20381
+ for (const segment2 of segments) {
20382
+ const cmd = segment2[0];
20383
+ switch (cmd) {
20384
+ case "M": {
20385
+ if (currentPoints.length > 0) {
20386
+ result.push(currentPoints);
20387
+ }
20388
+ currentX = segment2[1];
20389
+ currentY = segment2[2];
20390
+ subpathStartX = currentX;
20391
+ subpathStartY = currentY;
20392
+ currentPoints = [{ x: currentX, y: currentY }];
20393
+ break;
20394
+ }
20395
+ case "L": {
20396
+ currentX = segment2[1];
20397
+ currentY = segment2[2];
20398
+ currentPoints.push({ x: currentX, y: currentY });
20399
+ break;
20400
+ }
20401
+ case "H": {
20402
+ currentX = segment2[1];
20403
+ currentPoints.push({ x: currentX, y: currentY });
20404
+ break;
20405
+ }
20406
+ case "V": {
20407
+ currentY = segment2[1];
20408
+ currentPoints.push({ x: currentX, y: currentY });
20409
+ break;
20410
+ }
20411
+ case "Z": {
20412
+ if (currentX !== subpathStartX || currentY !== subpathStartY) {
20413
+ currentPoints.push({ x: subpathStartX, y: subpathStartY });
20414
+ }
20415
+ currentX = subpathStartX;
20416
+ currentY = subpathStartY;
20417
+ break;
20418
+ }
20419
+ case "C": {
20420
+ const endX = segment2[5];
20421
+ const endY = segment2[6];
20422
+ const segmentPath = `M ${currentX} ${currentY} C ${segment2[1]} ${segment2[2]} ${segment2[3]} ${segment2[4]} ${endX} ${endY}`;
20423
+ const sampledPoints = sampleCurveSegment(segmentPath, samplesPerUnit);
20424
+ currentPoints.push(...sampledPoints);
20425
+ currentX = endX;
20426
+ currentY = endY;
20427
+ break;
20428
+ }
20429
+ case "S": {
20430
+ const endX = segment2[3];
20431
+ const endY = segment2[4];
20432
+ const segmentPath = `M ${currentX} ${currentY} S ${segment2[1]} ${segment2[2]} ${endX} ${endY}`;
20433
+ const sampledPoints = sampleCurveSegment(segmentPath, samplesPerUnit);
20434
+ currentPoints.push(...sampledPoints);
20435
+ currentX = endX;
20436
+ currentY = endY;
20437
+ break;
20438
+ }
20439
+ case "Q": {
20440
+ const endX = segment2[3];
20441
+ const endY = segment2[4];
20442
+ const segmentPath = `M ${currentX} ${currentY} Q ${segment2[1]} ${segment2[2]} ${endX} ${endY}`;
20443
+ const sampledPoints = sampleCurveSegment(segmentPath, samplesPerUnit);
20444
+ currentPoints.push(...sampledPoints);
20445
+ currentX = endX;
20446
+ currentY = endY;
20447
+ break;
20448
+ }
20449
+ case "T": {
20450
+ const endX = segment2[1];
20451
+ const endY = segment2[2];
20452
+ const segmentPath = `M ${currentX} ${currentY} T ${endX} ${endY}`;
20453
+ const sampledPoints = sampleCurveSegment(segmentPath, samplesPerUnit);
20454
+ currentPoints.push(...sampledPoints);
20455
+ currentX = endX;
20456
+ currentY = endY;
20457
+ break;
20458
+ }
20459
+ case "A": {
20460
+ const endX = segment2[6];
20461
+ const endY = segment2[7];
20462
+ const segmentPath = `M ${currentX} ${currentY} A ${segment2[1]} ${segment2[2]} ${segment2[3]} ${segment2[4]} ${segment2[5]} ${endX} ${endY}`;
20463
+ const sampledPoints = sampleCurveSegment(segmentPath, samplesPerUnit);
20464
+ currentPoints.push(...sampledPoints);
20465
+ currentX = endX;
20466
+ currentY = endY;
20467
+ break;
20468
+ }
20469
+ }
20470
+ }
20471
+ if (currentPoints.length > 0) {
20472
+ result.push(currentPoints);
20473
+ }
20474
+ return result.map((points) => {
20475
+ const deduped = [];
20476
+ for (const point6 of points) {
20477
+ if (deduped.length === 0 || Math.abs(deduped[deduped.length - 1].x - point6.x) > 1e-9 || Math.abs(deduped[deduped.length - 1].y - point6.y) > 1e-9) {
20478
+ deduped.push(point6);
20479
+ }
20480
+ }
20481
+ return deduped;
20482
+ });
20483
+ }
20484
+
20485
+ // lib/components/primitive-components/SchematicPath.ts
20343
20486
  var SchematicPath = class extends PrimitiveComponent2 {
20344
20487
  isSchematicPrimitive = true;
20345
20488
  get config() {
@@ -20354,19 +20497,37 @@ var SchematicPath = class extends PrimitiveComponent2 {
20354
20497
  const { _parsedProps: props } = this;
20355
20498
  const globalPos = this._getGlobalSchematicPositionBeforeLayout();
20356
20499
  const schematic_component_id = this.getPrimitiveContainer()?.parent?.schematic_component_id;
20357
- db.schematic_path.insert({
20358
- schematic_component_id,
20359
- points: props.points.map((point6) => ({
20360
- x: point6.x + globalPos.x,
20361
- y: point6.y + globalPos.y
20362
- })),
20363
- is_filled: props.isFilled,
20364
- fill_color: props.fillColor,
20365
- stroke_color: props.strokeColor,
20366
- stroke_width: props.strokeWidth,
20367
- svg_path: props.svgPath,
20368
- subcircuit_id: this.getSubcircuit().subcircuit_id ?? void 0
20369
- });
20500
+ const subcircuit_id = this.getSubcircuit().subcircuit_id ?? void 0;
20501
+ if (props.svgPath) {
20502
+ const subpaths = svgPathToPoints(props.svgPath);
20503
+ for (const subpathPoints of subpaths) {
20504
+ db.schematic_path.insert({
20505
+ schematic_component_id,
20506
+ points: subpathPoints.map((point6) => ({
20507
+ x: point6.x + globalPos.x,
20508
+ y: point6.y + globalPos.y
20509
+ })),
20510
+ is_filled: props.isFilled,
20511
+ fill_color: props.fillColor,
20512
+ stroke_color: props.strokeColor,
20513
+ stroke_width: props.strokeWidth,
20514
+ subcircuit_id
20515
+ });
20516
+ }
20517
+ } else if (props.points && props.points.length > 0) {
20518
+ db.schematic_path.insert({
20519
+ schematic_component_id,
20520
+ points: props.points.map((point6) => ({
20521
+ x: point6.x + globalPos.x,
20522
+ y: point6.y + globalPos.y
20523
+ })),
20524
+ is_filled: props.isFilled,
20525
+ fill_color: props.fillColor,
20526
+ stroke_color: props.strokeColor,
20527
+ stroke_width: props.strokeWidth,
20528
+ subcircuit_id
20529
+ });
20530
+ }
20370
20531
  }
20371
20532
  };
20372
20533
 
@@ -21036,7 +21197,7 @@ import { identity as identity5 } from "transformation-matrix";
21036
21197
  var package_default = {
21037
21198
  name: "@tscircuit/core",
21038
21199
  type: "module",
21039
- version: "0.0.991",
21200
+ version: "0.0.993",
21040
21201
  types: "dist/index.d.ts",
21041
21202
  main: "dist/index.js",
21042
21203
  module: "dist/index.js",
@@ -21079,7 +21240,7 @@ var package_default = {
21079
21240
  "@tscircuit/math-utils": "^0.0.29",
21080
21241
  "@tscircuit/miniflex": "^0.0.4",
21081
21242
  "@tscircuit/ngspice-spice-engine": "^0.0.8",
21082
- "@tscircuit/props": "^0.0.455",
21243
+ "@tscircuit/props": "^0.0.456",
21083
21244
  "@tscircuit/schematic-match-adapt": "^0.0.16",
21084
21245
  "@tscircuit/schematic-trace-solver": "^v0.0.45",
21085
21246
  "@tscircuit/solver-utils": "^0.0.3",
@@ -21092,7 +21253,7 @@ var package_default = {
21092
21253
  "bun-match-svg": "0.0.12",
21093
21254
  "calculate-elbow": "^0.0.12",
21094
21255
  "chokidar-cli": "^3.0.0",
21095
- "circuit-json": "^0.0.363",
21256
+ "circuit-json": "^0.0.364",
21096
21257
  "circuit-json-to-bpc": "^0.0.13",
21097
21258
  "circuit-json-to-connectivity-map": "^0.0.23",
21098
21259
  "circuit-json-to-gltf": "^0.0.31",
@@ -21145,6 +21306,7 @@ var package_default = {
21145
21306
  nanoid: "^5.0.7",
21146
21307
  "performance-now": "^2.1.0",
21147
21308
  "react-reconciler": "^0.32.0",
21309
+ "svg-path-commander": "^2.1.11",
21148
21310
  "transformation-matrix": "^2.16.1",
21149
21311
  zod: "^3.25.67"
21150
21312
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@tscircuit/core",
3
3
  "type": "module",
4
- "version": "0.0.992",
4
+ "version": "0.0.994",
5
5
  "types": "dist/index.d.ts",
6
6
  "main": "dist/index.js",
7
7
  "module": "dist/index.js",
@@ -44,7 +44,7 @@
44
44
  "@tscircuit/math-utils": "^0.0.29",
45
45
  "@tscircuit/miniflex": "^0.0.4",
46
46
  "@tscircuit/ngspice-spice-engine": "^0.0.8",
47
- "@tscircuit/props": "^0.0.455",
47
+ "@tscircuit/props": "^0.0.456",
48
48
  "@tscircuit/schematic-match-adapt": "^0.0.16",
49
49
  "@tscircuit/schematic-trace-solver": "^v0.0.45",
50
50
  "@tscircuit/solver-utils": "^0.0.3",
@@ -57,7 +57,7 @@
57
57
  "bun-match-svg": "0.0.12",
58
58
  "calculate-elbow": "^0.0.12",
59
59
  "chokidar-cli": "^3.0.0",
60
- "circuit-json": "^0.0.363",
60
+ "circuit-json": "^0.0.364",
61
61
  "circuit-json-to-bpc": "^0.0.13",
62
62
  "circuit-json-to-connectivity-map": "^0.0.23",
63
63
  "circuit-json-to-gltf": "^0.0.31",
@@ -110,6 +110,7 @@
110
110
  "nanoid": "^5.0.7",
111
111
  "performance-now": "^2.1.0",
112
112
  "react-reconciler": "^0.32.0",
113
+ "svg-path-commander": "^2.1.11",
113
114
  "transformation-matrix": "^2.16.1",
114
115
  "zod": "^3.25.67"
115
116
  }