@tscircuit/core 0.0.1037 → 0.0.1039

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.js CHANGED
@@ -33,7 +33,7 @@ __export(components_exports, {
33
33
  Fiducial: () => Fiducial,
34
34
  Footprint: () => Footprint,
35
35
  Fuse: () => Fuse,
36
- Group: () => Group,
36
+ Group: () => Group6,
37
37
  Hole: () => Hole,
38
38
  Inductor: () => Inductor,
39
39
  Interconnect: () => Interconnect,
@@ -296,6 +296,7 @@ import Debug from "debug";
296
296
  var debug = Debug("tscircuit:renderable");
297
297
  var orderedRenderPhases = [
298
298
  "ReactSubtreesRender",
299
+ "RenderIsolatedSubcircuits",
299
300
  "InflateSubcircuitCircuitJson",
300
301
  "SourceNameDuplicateComponentRemoval",
301
302
  "PcbFootprintStringRender",
@@ -351,6 +352,7 @@ var renderPhaseIndexMap = new Map(
351
352
  orderedRenderPhases.map((phase, index) => [phase, index])
352
353
  );
353
354
  var asyncPhaseDependencies = {
355
+ InflateSubcircuitCircuitJson: ["RenderIsolatedSubcircuits"],
354
356
  PcbFootprintLayout: ["PcbFootprintStringRender"],
355
357
  PcbComponentSizeCalculation: ["PcbFootprintStringRender"],
356
358
  PcbLayout: ["PcbFootprintStringRender"],
@@ -6943,6 +6945,17 @@ function getRelativeDirection(pointA, pointB) {
6943
6945
  return dy >= 0 ? "up" : "down";
6944
6946
  }
6945
6947
 
6948
+ // lib/utils/constants.ts
6949
+ var stringProxy = new Proxy(
6950
+ {},
6951
+ {
6952
+ get: (target, prop) => prop
6953
+ }
6954
+ );
6955
+ var FTYPE = stringProxy;
6956
+ var SCHEMATIC_COMPONENT_OUTLINE_COLOR = "rgba(132, 0, 0)";
6957
+ var SCHEMATIC_COMPONENT_OUTLINE_STROKE_WIDTH = 0.12;
6958
+
6946
6959
  // lib/components/primitive-components/Port/Port.ts
6947
6960
  import "schematic-symbols";
6948
6961
  import { applyToPoint as applyToPoint7, compose as compose3, translate as translate3 } from "transformation-matrix";
@@ -6999,6 +7012,7 @@ var getCenterOfPcbPrimitives = (pcbPrimitives) => {
6999
7012
  var portProps = z7.object({
7000
7013
  name: z7.string().optional(),
7001
7014
  pinNumber: z7.number().optional(),
7015
+ schStemLength: z7.number().optional(),
7002
7016
  aliases: z7.array(z7.string()).optional(),
7003
7017
  layer: z7.string().optional(),
7004
7018
  layers: z7.array(z7.string()).optional(),
@@ -7494,14 +7508,15 @@ var Port = class extends PrimitiveComponent2 {
7494
7508
  }
7495
7509
  const bestDisplayPinLabel = this._getBestDisplayPinLabel();
7496
7510
  const parentNormalComponent = this.getParentNormalComponent();
7511
+ const sideOfComponent = localPortInfo?.side ?? (props.direction === "up" ? "top" : props.direction === "down" ? "bottom" : props.direction);
7497
7512
  const schematicPortInsertProps = {
7498
7513
  type: "schematic_port",
7499
7514
  schematic_component_id: parentNormalComponent?.schematic_component_id,
7500
7515
  center: portCenter,
7501
7516
  source_port_id: this.source_port_id,
7502
7517
  facing_direction: this.facingDirection,
7503
- distance_from_component_edge: 0.4,
7504
- side_of_component: localPortInfo?.side,
7518
+ distance_from_component_edge: props.schStemLength ?? 0.4,
7519
+ side_of_component: sideOfComponent,
7505
7520
  pin_number: props.pinNumber,
7506
7521
  true_ccw_index: localPortInfo?.trueIndex,
7507
7522
  display_pin_label: bestDisplayPinLabel,
@@ -7517,6 +7532,25 @@ var Port = class extends PrimitiveComponent2 {
7517
7532
  }
7518
7533
  const schematic_port = db.schematic_port.insert(schematicPortInsertProps);
7519
7534
  this.schematic_port_id = schematic_port.schematic_port_id;
7535
+ if (props.schStemLength !== void 0 && props.schStemLength !== 0) {
7536
+ const { schStemLength, direction } = props;
7537
+ let x2 = portCenter.x;
7538
+ let y2 = portCenter.y;
7539
+ if (direction === "right") x2 -= schStemLength;
7540
+ else if (direction === "left") x2 += schStemLength;
7541
+ else if (direction === "up") y2 -= schStemLength;
7542
+ else if (direction === "down") y2 += schStemLength;
7543
+ db.schematic_line.insert({
7544
+ schematic_component_id: parentNormalComponent?.schematic_component_id,
7545
+ x1: portCenter.x,
7546
+ y1: portCenter.y,
7547
+ x2,
7548
+ y2,
7549
+ stroke_width: 0.02,
7550
+ color: SCHEMATIC_COMPONENT_OUTLINE_COLOR,
7551
+ is_dashed: false
7552
+ });
7553
+ }
7520
7554
  }
7521
7555
  _getSubcircuitConnectivityKey() {
7522
7556
  return this.root?.db.source_port.get(this.source_port_id)?.subcircuit_connectivity_map_key;
@@ -10128,7 +10162,7 @@ import {
10128
10162
  import {
10129
10163
  distance as distance8
10130
10164
  } from "circuit-json";
10131
- import Debug14 from "debug";
10165
+ import Debug13 from "debug";
10132
10166
 
10133
10167
  // lib/utils/autorouting/CapacityMeshAutorouter.ts
10134
10168
  import "@tscircuit/capacity-autorouter";
@@ -12537,464 +12571,59 @@ var Group_doInitialPcbLayoutPack = (group) => {
12537
12571
  });
12538
12572
  };
12539
12573
 
12540
- // lib/IsolatedCircuit.ts
12541
- import { su as su5 } from "@tscircuit/circuit-json-util";
12542
- import Debug7 from "debug";
12543
- import { isValidElement as isValidElement2 } from "react";
12544
- import { identity as identity4 } from "transformation-matrix";
12545
-
12546
- // package.json
12547
- var package_default = {
12548
- name: "@tscircuit/core",
12549
- type: "module",
12550
- version: "0.0.1036",
12551
- types: "dist/index.d.ts",
12552
- main: "dist/index.js",
12553
- module: "dist/index.js",
12554
- exports: {
12555
- ".": {
12556
- import: "./dist/index.js",
12557
- types: "./dist/index.d.ts"
12558
- }
12559
- },
12560
- files: [
12561
- "dist"
12562
- ],
12563
- repository: {
12564
- type: "git",
12565
- url: "https://github.com/tscircuit/core"
12566
- },
12567
- scripts: {
12568
- build: "tsup-node index.ts --format esm --dts",
12569
- format: "biome format . --write",
12570
- "measure-bundle": "howfat -r table .",
12571
- "pkg-pr-new-release": "bunx pkg-pr-new publish --comment=off --peerDeps",
12572
- "smoke-test:dist": "bun run scripts/smoke-tests/test-dist-simple-circuit.tsx",
12573
- "build:benchmarking": "bun build --experimental-html ./benchmarking/website/index.html --outdir ./benchmarking-dist",
12574
- "build:benchmarking:watch": `chokidar "./{benchmarking,lib}/**/*.{ts,tsx}" -c 'bun build --experimental-html ./benchmarking/website/index.html --outdir ./benchmarking-dist'`,
12575
- "start:benchmarking": 'concurrently "bun run build:benchmarking:watch" "live-server ./benchmarking-dist"',
12576
- "generate-test-plan": "bun run scripts/generate-test-plan.ts"
12577
- },
12578
- devDependencies: {
12579
- "@biomejs/biome": "^1.8.3",
12580
- "@resvg/resvg-js": "^2.6.2",
12581
- "@tscircuit/alphabet": "0.0.18",
12582
- "@tscircuit/capacity-autorouter": "^0.0.269",
12583
- "@tscircuit/checks": "^0.0.90",
12584
- "@tscircuit/circuit-json-util": "^0.0.77",
12585
- "@tscircuit/common": "^0.0.20",
12586
- "@tscircuit/copper-pour-solver": "^0.0.20",
12587
- "@tscircuit/footprinter": "^0.0.288",
12588
- "@tscircuit/infgrid-ijump-astar": "^0.0.35",
12589
- "@tscircuit/log-soup": "^1.0.2",
12590
- "@tscircuit/matchpack": "^0.0.16",
12591
- "@tscircuit/math-utils": "^0.0.29",
12592
- "@tscircuit/miniflex": "^0.0.4",
12593
- "@tscircuit/ngspice-spice-engine": "^0.0.8",
12594
- "@tscircuit/props": "^0.0.474",
12595
- "@tscircuit/schematic-match-adapt": "^0.0.16",
12596
- "@tscircuit/schematic-trace-solver": "^v0.0.45",
12597
- "@tscircuit/solver-utils": "^0.0.3",
12598
- "@tscircuit/soup-util": "^0.0.41",
12599
- "@types/bun": "^1.2.16",
12600
- "@types/debug": "^4.1.12",
12601
- "@types/react": "^19.1.8",
12602
- "@types/react-dom": "^19.1.6",
12603
- "@types/react-reconciler": "^0.28.9",
12604
- "bpc-graph": "^0.0.57",
12605
- "bun-match-svg": "0.0.12",
12606
- "calculate-elbow": "^0.0.12",
12607
- "chokidar-cli": "^3.0.0",
12608
- "circuit-json": "^0.0.379",
12609
- "circuit-json-to-bpc": "^0.0.13",
12610
- "circuit-json-to-connectivity-map": "^0.0.23",
12611
- "circuit-json-to-gltf": "^0.0.65",
12612
- "circuit-json-to-simple-3d": "^0.0.9",
12613
- "circuit-json-to-spice": "^0.0.34",
12614
- "circuit-to-svg": "^0.0.327",
12615
- concurrently: "^9.1.2",
12616
- "connectivity-map": "^1.0.0",
12617
- debug: "^4.3.6",
12618
- "eecircuit-engine": "^1.5.6",
12619
- flatbush: "^4.5.0",
12620
- "graphics-debug": "^0.0.60",
12621
- howfat: "^0.3.8",
12622
- "live-server": "^1.2.2",
12623
- "looks-same": "^9.0.1",
12624
- minicssgrid: "^0.0.9",
12625
- "pkg-pr-new": "^0.0.37",
12626
- poppygl: "^0.0.16",
12627
- react: "^19.1.0",
12628
- "react-dom": "^19.1.0",
12629
- "schematic-symbols": "^0.0.208",
12630
- spicey: "^0.0.14",
12631
- "ts-expect": "^1.3.0",
12632
- tsup: "^8.2.4"
12633
- },
12634
- peerDependencies: {
12635
- "@tscircuit/capacity-autorouter": "*",
12636
- "@tscircuit/checks": "*",
12637
- "@tscircuit/circuit-json-util": "*",
12638
- "@tscircuit/footprinter": "*",
12639
- "@tscircuit/infgrid-ijump-astar": "*",
12640
- "@tscircuit/math-utils": "*",
12641
- "@tscircuit/props": "*",
12642
- "@tscircuit/schematic-match-adapt": "*",
12643
- "circuit-json-to-bpc": "*",
12644
- "bpc-graph": "*",
12645
- "@tscircuit/matchpack": "*",
12646
- "circuit-json": "*",
12647
- "circuit-json-to-connectivity-map": "*",
12648
- "schematic-symbols": "*",
12649
- typescript: "^5.0.0"
12650
- },
12651
- dependencies: {
12652
- "@flatten-js/core": "^1.6.2",
12653
- "@lume/kiwi": "^0.4.3",
12654
- "calculate-packing": "0.0.68",
12655
- "css-select": "5.1.0",
12656
- "format-si-unit": "^0.0.3",
12657
- nanoid: "^5.0.7",
12658
- "performance-now": "^2.1.0",
12659
- "react-reconciler": "^0.32.0",
12660
- "svg-path-commander": "^2.1.11",
12661
- "transformation-matrix": "^2.16.1",
12662
- zod: "^3.25.67"
12574
+ // lib/components/primitive-components/Group/Group_doInitialSchematicLayoutFlex.ts
12575
+ import {
12576
+ getCircuitJsonTree,
12577
+ getMinimumFlexContainer as getMinimumFlexContainer2,
12578
+ repositionSchematicComponentTo,
12579
+ repositionSchematicGroupTo
12580
+ } from "@tscircuit/circuit-json-util";
12581
+ import { RootFlexBox as RootFlexBox2 } from "@tscircuit/miniflex";
12582
+ import { length as length4 } from "circuit-json";
12583
+ var getSizeOfTreeNodeChild = (db, child) => {
12584
+ const { sourceComponent, sourceGroup } = child;
12585
+ if (child.nodeType === "component") {
12586
+ const schComponent = db.schematic_component.getWhere({
12587
+ source_component_id: sourceComponent?.source_component_id
12588
+ });
12589
+ if (!schComponent?.size) return null;
12590
+ return {
12591
+ width: schComponent.size.width,
12592
+ height: schComponent.size.height
12593
+ };
12663
12594
  }
12664
- };
12665
-
12666
- // lib/IsolatedCircuit.ts
12667
- var IsolatedCircuit = class {
12668
- firstChild = null;
12669
- children;
12670
- db;
12671
- root = null;
12672
- isRootCircuit = false;
12673
- _schematicDisabledOverride;
12674
- get schematicDisabled() {
12675
- if (this._schematicDisabledOverride !== void 0) {
12676
- return this._schematicDisabledOverride;
12677
- }
12678
- if (this.platform?.schematicDisabled !== void 0) {
12679
- return this.platform.schematicDisabled;
12595
+ if (child.nodeType === "group") {
12596
+ const schGroup = db.schematic_group.getWhere({
12597
+ source_group_id: sourceGroup?.source_group_id
12598
+ });
12599
+ if (schGroup?.width && schGroup?.height) {
12600
+ return {
12601
+ width: schGroup.width,
12602
+ height: schGroup.height
12603
+ };
12680
12604
  }
12681
- const board = this._getBoard();
12682
- return board?._parsedProps?.schematicDisabled ?? false;
12683
- }
12684
- set schematicDisabled(value) {
12685
- this._schematicDisabledOverride = value;
12686
- }
12687
- pcbDisabled = false;
12688
- pcbRoutingDisabled = false;
12689
- _featureMspSchematicTraceRouting = true;
12690
- /**
12691
- * The IsolatedCircuit name is usually set by the platform, it's not required but
12692
- * if supplied can identify the circuit in certain effects, e.g. it is passed
12693
- * as the display_name parameter for autorouting effects.
12694
- */
12695
- name;
12696
- platform;
12697
- /**
12698
- * Optional URL pointing to where this project is hosted or documented.
12699
- * When provided it is stored in the source_project_metadata.project_url field
12700
- * of the generated Circuit JSON.
12701
- */
12702
- projectUrl;
12703
- _hasRenderedAtleastOnce = false;
12704
- _asyncEffectIdsByPhase = /* @__PURE__ */ new Map();
12705
- _asyncEffectPhaseById = /* @__PURE__ */ new Map();
12706
- constructor({
12707
- platform,
12708
- projectUrl
12709
- } = {}) {
12710
- this.children = [];
12711
- this.db = su5([]);
12712
- this.platform = platform;
12713
- this.projectUrl = projectUrl;
12714
- this.pcbDisabled = platform?.pcbDisabled ?? false;
12715
- this.root = this;
12716
- }
12717
- add(componentOrElm) {
12718
- let component;
12719
- if (isValidElement2(componentOrElm)) {
12720
- component = createInstanceFromReactElement(componentOrElm);
12721
- } else {
12722
- component = componentOrElm;
12605
+ const groupComponents = db.schematic_component.list({
12606
+ schematic_group_id: schGroup?.schematic_group_id
12607
+ });
12608
+ let minX = Infinity;
12609
+ let maxX = -Infinity;
12610
+ let minY = Infinity;
12611
+ let maxY = -Infinity;
12612
+ for (const comp of groupComponents) {
12613
+ if (comp.center && comp.size) {
12614
+ const halfWidth = comp.size.width / 2;
12615
+ const halfHeight = comp.size.height / 2;
12616
+ minX = Math.min(minX, comp.center.x - halfWidth);
12617
+ maxX = Math.max(maxX, comp.center.x + halfWidth);
12618
+ minY = Math.min(minY, comp.center.y - halfHeight);
12619
+ maxY = Math.max(maxY, comp.center.y + halfHeight);
12620
+ }
12723
12621
  }
12724
- this.children.push(component);
12725
- }
12726
- setPlatform(platform) {
12727
- this.platform = {
12728
- ...this.platform,
12729
- ...platform
12730
- };
12731
- }
12732
- /**
12733
- * Get the main board for this Circuit.
12734
- */
12735
- _getBoard() {
12736
- const directBoard = this.children.find((c) => c.componentName === "Board");
12737
- if (directBoard) {
12738
- return directBoard;
12739
- }
12740
- return void 0;
12741
- }
12742
- _guessRootComponent() {
12743
- if (this.firstChild) return;
12744
- if (this.children.length === 0) {
12745
- throw new Error(
12746
- "Not able to guess root component: IsolatedCircuit has no children (use circuit.add(...))"
12747
- );
12748
- }
12749
- const panels = this.children.filter(
12750
- (child) => child.lowercaseComponentName === "panel"
12751
- );
12752
- if (panels.length > 1) {
12753
- throw new Error("Only one <panel> is allowed per circuit");
12754
- }
12755
- if (panels.length === 1) {
12756
- if (this.children.length !== 1) {
12757
- throw new Error("<panel> must be the root element of the circuit");
12758
- }
12759
- this.firstChild = panels[0];
12760
- return;
12761
- }
12762
- if (this.children.length === 1 && this.children[0].isGroup) {
12763
- this.firstChild = this.children[0];
12764
- return;
12765
- }
12766
- const group = new Group({ subcircuit: true });
12767
- group.parent = this;
12768
- group.addAll(this.children);
12769
- this.children = [group];
12770
- this.firstChild = group;
12771
- }
12772
- render() {
12773
- if (!this.firstChild) {
12774
- this._guessRootComponent();
12775
- }
12776
- const { firstChild, db } = this;
12777
- if (!firstChild) throw new Error("IsolatedCircuit has no root component");
12778
- firstChild.parent = this;
12779
- firstChild.runRenderCycle();
12780
- this._hasRenderedAtleastOnce = true;
12781
- }
12782
- async renderUntilSettled() {
12783
- const existing = this.db.source_project_metadata.list()?.[0];
12784
- if (!existing) {
12785
- this.db.source_project_metadata.insert({
12786
- software_used_string: `@tscircuit/core@${this.getCoreVersion()}`,
12787
- ...this.projectUrl ? { project_url: this.projectUrl } : {}
12788
- });
12789
- }
12790
- this.render();
12791
- while (this._hasIncompleteAsyncEffects()) {
12792
- await new Promise((resolve) => setTimeout(resolve, 100));
12793
- this.render();
12794
- }
12795
- this.emit("renderComplete");
12796
- }
12797
- _hasIncompleteAsyncEffects() {
12798
- if (this._asyncEffectPhaseById.size > 0) return true;
12799
- return this.children.some((child) => child._hasIncompleteAsyncEffects());
12800
- }
12801
- _hasIncompleteAsyncEffectsForPhase(phase) {
12802
- return (this._asyncEffectIdsByPhase.get(phase)?.size ?? 0) > 0;
12803
- }
12804
- getCircuitJson() {
12805
- if (!this._hasRenderedAtleastOnce) this.render();
12806
- return this.db.toArray();
12807
- }
12808
- toJson() {
12809
- return this.getCircuitJson();
12810
- }
12811
- async getSvg(options) {
12812
- const circuitToSvg = await import("circuit-to-svg").catch((e) => {
12813
- throw new Error(
12814
- `To use circuit.getSvg, you must install the "circuit-to-svg" package.
12815
-
12816
- "${e.message}"`
12817
- );
12818
- });
12819
- if (options.view === "pcb") {
12820
- return circuitToSvg.convertCircuitJsonToPcbSvg(this.getCircuitJson());
12821
- }
12822
- if (options.view === "schematic") {
12823
- return circuitToSvg.convertCircuitJsonToSchematicSvg(
12824
- this.getCircuitJson()
12825
- );
12826
- }
12827
- throw new Error(`Invalid view: ${options.view}`);
12828
- }
12829
- getCoreVersion() {
12830
- const [major, minor, patch] = package_default.version.split(".").map(Number);
12831
- return `${major}.${minor}.${patch + 1}`;
12832
- }
12833
- async preview(previewNameOrOpts) {
12834
- const previewOpts = typeof previewNameOrOpts === "object" ? previewNameOrOpts : { previewName: previewNameOrOpts };
12835
- throw new Error("project.preview is not yet implemented");
12836
- }
12837
- computeSchematicGlobalTransform() {
12838
- return identity4();
12839
- }
12840
- _computePcbGlobalTransformBeforeLayout() {
12841
- return identity4();
12842
- }
12843
- selectAll(selector) {
12844
- this._guessRootComponent();
12845
- return this.firstChild?.selectAll(selector) ?? [];
12846
- }
12847
- selectOne(selector, opts) {
12848
- this._guessRootComponent();
12849
- return this.firstChild?.selectOne(selector, opts) ?? null;
12850
- }
12851
- _eventListeners = {};
12852
- emit(event, ...args) {
12853
- if (event === "asyncEffect:start") {
12854
- this._registerAsyncEffectStart(args[0]);
12855
- } else if (event === "asyncEffect:end") {
12856
- this._registerAsyncEffectEnd(args[0]);
12857
- }
12858
- if (!this._eventListeners[event]) return;
12859
- for (const listener of this._eventListeners[event]) {
12860
- listener(...args);
12861
- }
12862
- }
12863
- on(event, listener) {
12864
- if (!this._eventListeners[event]) {
12865
- this._eventListeners[event] = [];
12866
- }
12867
- this._eventListeners[event].push(listener);
12868
- }
12869
- removeListener(event, listener) {
12870
- if (!this._eventListeners[event]) return;
12871
- this._eventListeners[event] = this._eventListeners[event].filter(
12872
- (l) => l !== listener
12873
- );
12874
- }
12875
- enableDebug(debug11) {
12876
- if (typeof debug11 === "string") {
12877
- Debug7.enable(debug11);
12878
- } else if (debug11 === null || debug11 === false) {
12879
- Debug7.disable();
12880
- }
12881
- }
12882
- getClientOrigin() {
12883
- if (typeof window !== "undefined" && window.location) {
12884
- return window.location.origin;
12885
- }
12886
- if (typeof self !== "undefined" && self.location) {
12887
- return self.location.origin;
12888
- }
12889
- return "";
12890
- }
12891
- _registerAsyncEffectStart(payload) {
12892
- if (!payload?.asyncEffectId || !payload.phase) return;
12893
- const { asyncEffectId, phase } = payload;
12894
- const existingPhase = this._asyncEffectPhaseById.get(asyncEffectId);
12895
- if (existingPhase && existingPhase !== phase) {
12896
- this._asyncEffectIdsByPhase.get(existingPhase)?.delete(asyncEffectId);
12897
- }
12898
- if (!this._asyncEffectIdsByPhase.has(phase)) {
12899
- this._asyncEffectIdsByPhase.set(phase, /* @__PURE__ */ new Set());
12900
- }
12901
- this._asyncEffectIdsByPhase.get(phase).add(asyncEffectId);
12902
- this._asyncEffectPhaseById.set(asyncEffectId, phase);
12903
- }
12904
- _registerAsyncEffectEnd(payload) {
12905
- if (!payload?.asyncEffectId) return;
12906
- const { asyncEffectId } = payload;
12907
- const phase = this._asyncEffectPhaseById.get(asyncEffectId) ?? payload.phase;
12908
- if (phase) {
12909
- const phaseSet = this._asyncEffectIdsByPhase.get(phase);
12910
- phaseSet?.delete(asyncEffectId);
12911
- if (phaseSet && phaseSet.size === 0) {
12912
- this._asyncEffectIdsByPhase.delete(phase);
12913
- }
12914
- }
12915
- this._asyncEffectPhaseById.delete(asyncEffectId);
12916
- }
12917
- };
12918
-
12919
- // lib/components/primitive-components/Group/Group_doInitialRenderIsolatedSubcircuits.ts
12920
- function Group_doInitialRenderIsolatedSubcircuits(group) {
12921
- if (!group._isolatedCircuit) {
12922
- const parentRoot = group.root;
12923
- group._isolatedCircuit = new IsolatedCircuit({
12924
- platform: {
12925
- ...parentRoot.platform,
12926
- pcbDisabled: parentRoot.pcbDisabled,
12927
- schematicDisabled: parentRoot.schematicDisabled
12928
- }
12929
- });
12930
- for (const child of group.children) {
12931
- group._isolatedCircuit.add(child);
12932
- }
12933
- }
12934
- group._isolatedCircuit.render();
12935
- if (group._isolatedCircuit._hasIncompleteAsyncEffects()) {
12936
- return false;
12937
- }
12938
- group._isolatedCircuitJson = group._isolatedCircuit.getCircuitJson();
12939
- group.children = [];
12940
- group._normalComponentNameMap = null;
12941
- group._isolatedCircuit = null;
12942
- return true;
12943
- }
12944
-
12945
- // lib/components/primitive-components/Group/Group_doInitialSchematicLayoutFlex.ts
12946
- import {
12947
- getCircuitJsonTree,
12948
- getMinimumFlexContainer as getMinimumFlexContainer2,
12949
- repositionSchematicComponentTo,
12950
- repositionSchematicGroupTo
12951
- } from "@tscircuit/circuit-json-util";
12952
- import { RootFlexBox as RootFlexBox2 } from "@tscircuit/miniflex";
12953
- import { length as length4 } from "circuit-json";
12954
- var getSizeOfTreeNodeChild = (db, child) => {
12955
- const { sourceComponent, sourceGroup } = child;
12956
- if (child.nodeType === "component") {
12957
- const schComponent = db.schematic_component.getWhere({
12958
- source_component_id: sourceComponent?.source_component_id
12959
- });
12960
- if (!schComponent?.size) return null;
12961
- return {
12962
- width: schComponent.size.width,
12963
- height: schComponent.size.height
12964
- };
12965
- }
12966
- if (child.nodeType === "group") {
12967
- const schGroup = db.schematic_group.getWhere({
12968
- source_group_id: sourceGroup?.source_group_id
12969
- });
12970
- if (schGroup?.width && schGroup?.height) {
12971
- return {
12972
- width: schGroup.width,
12973
- height: schGroup.height
12974
- };
12975
- }
12976
- const groupComponents = db.schematic_component.list({
12977
- schematic_group_id: schGroup?.schematic_group_id
12978
- });
12979
- let minX = Infinity;
12980
- let maxX = -Infinity;
12981
- let minY = Infinity;
12982
- let maxY = -Infinity;
12983
- for (const comp of groupComponents) {
12984
- if (comp.center && comp.size) {
12985
- const halfWidth = comp.size.width / 2;
12986
- const halfHeight = comp.size.height / 2;
12987
- minX = Math.min(minX, comp.center.x - halfWidth);
12988
- maxX = Math.max(maxX, comp.center.x + halfWidth);
12989
- minY = Math.min(minY, comp.center.y - halfHeight);
12990
- maxY = Math.max(maxY, comp.center.y + halfHeight);
12991
- }
12992
- }
12993
- const groupWidth = maxX - minX;
12994
- const groupHeight = maxY - minY;
12995
- return {
12996
- width: groupWidth,
12997
- height: groupHeight
12622
+ const groupWidth = maxX - minX;
12623
+ const groupHeight = maxY - minY;
12624
+ return {
12625
+ width: groupWidth,
12626
+ height: groupHeight
12998
12627
  };
12999
12628
  }
13000
12629
  return null;
@@ -13322,9 +12951,9 @@ function Group_doInitialSchematicLayoutGrid(group) {
13322
12951
  // lib/components/primitive-components/Group/Group_doInitialSchematicLayoutMatchAdapt.ts
13323
12952
  import { convertCircuitJsonToBpc } from "circuit-json-to-bpc";
13324
12953
  import { getGraphicsForBpcGraph, layoutSchematicGraphVariants } from "bpc-graph";
13325
- import Debug8 from "debug";
12954
+ import Debug7 from "debug";
13326
12955
  import { buildSubtree } from "@tscircuit/circuit-json-util";
13327
- var debug5 = Debug8("Group_doInitialSchematicLayoutMatchAdapt");
12956
+ var debug5 = Debug7("Group_doInitialSchematicLayoutMatchAdapt");
13328
12957
  function Group_doInitialSchematicLayoutMatchAdapt(group) {
13329
12958
  const { db } = group.root;
13330
12959
  const subtreeCircuitJson = buildSubtree(db.toArray(), {
@@ -13450,8 +13079,8 @@ import {
13450
13079
  getCircuitJsonTree as getCircuitJsonTree2
13451
13080
  } from "@tscircuit/circuit-json-util";
13452
13081
  import { LayoutPipelineSolver } from "@tscircuit/matchpack";
13453
- import Debug9 from "debug";
13454
- var debug6 = Debug9("Group_doInitialSchematicLayoutMatchpack");
13082
+ import Debug8 from "debug";
13083
+ var debug6 = Debug8("Group_doInitialSchematicLayoutMatchpack");
13455
13084
  function facingDirectionToSide(facingDirection) {
13456
13085
  switch (facingDirection) {
13457
13086
  case "up":
@@ -14069,7 +13698,7 @@ function Group_doInitialSchematicLayoutMatchPack(group) {
14069
13698
 
14070
13699
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/Group_doInitialSchematicTraceRender.ts
14071
13700
  import { SchematicTracePipelineSolver as SchematicTracePipelineSolver4 } from "@tscircuit/schematic-trace-solver";
14072
- import Debug12 from "debug";
13701
+ import Debug11 from "debug";
14073
13702
 
14074
13703
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/createSchematicTraceSolverInputProblem.ts
14075
13704
  import "@tscircuit/schematic-trace-solver";
@@ -14588,8 +14217,8 @@ function computeJunctions(traces, opts = {}) {
14588
14217
  }
14589
14218
 
14590
14219
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/applyTracesFromSolverOutput.ts
14591
- import Debug10 from "debug";
14592
- var debug7 = Debug10("Group_doInitialSchematicTraceRender");
14220
+ import Debug9 from "debug";
14221
+ var debug7 = Debug9("Group_doInitialSchematicTraceRender");
14593
14222
  function applyTracesFromSolverOutput(args) {
14594
14223
  const { group, solver, pinIdToSchematicPortId, userNetIdToSck } = args;
14595
14224
  const { db } = group.root;
@@ -14701,8 +14330,8 @@ var getNetNameFromPorts = (ports) => {
14701
14330
  };
14702
14331
 
14703
14332
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/applyNetLabelPlacements.ts
14704
- import Debug11 from "debug";
14705
- var debug8 = Debug11("Group_doInitialSchematicTraceRender");
14333
+ import Debug10 from "debug";
14334
+ var debug8 = Debug10("Group_doInitialSchematicTraceRender");
14706
14335
  function applyNetLabelPlacements(args) {
14707
14336
  const {
14708
14337
  group,
@@ -14867,7 +14496,7 @@ var getSchematicPortIdsWithRoutedTraces = ({
14867
14496
  };
14868
14497
 
14869
14498
  // lib/components/primitive-components/Group/Group_doInitialSchematicTraceRender/Group_doInitialSchematicTraceRender.ts
14870
- var debug9 = Debug12("Group_doInitialSchematicTraceRender");
14499
+ var debug9 = Debug11("Group_doInitialSchematicTraceRender");
14871
14500
  var Group_doInitialSchematicTraceRender = (group) => {
14872
14501
  if (!group.root?._featureMspSchematicTraceRouting) return;
14873
14502
  if (!group.isSubcircuit) return;
@@ -14927,7 +14556,7 @@ var Group_doInitialSchematicTraceRender = (group) => {
14927
14556
 
14928
14557
  // lib/components/primitive-components/Group/Group_doInitialSimulationSpiceEngineRender.ts
14929
14558
  import { circuitJsonToSpice } from "circuit-json-to-spice";
14930
- import Debug13 from "debug";
14559
+ import Debug12 from "debug";
14931
14560
 
14932
14561
  // lib/spice/get-spicey-engine.ts
14933
14562
  import { simulate, spiceyTranToVGraphs } from "spicey";
@@ -14985,7 +14614,7 @@ function resetSimulationColorState() {
14985
14614
  }
14986
14615
 
14987
14616
  // lib/components/primitive-components/Group/Group_doInitialSimulationSpiceEngineRender.ts
14988
- var debug10 = Debug13("tscircuit:core:Group_doInitialSimulationSpiceEngineRender");
14617
+ var debug10 = Debug12("tscircuit:core:Group_doInitialSimulationSpiceEngineRender");
14989
14618
  function Group_doInitialSimulationSpiceEngineRender(group) {
14990
14619
  if (!group.isSubcircuit) return;
14991
14620
  const { root } = group;
@@ -15471,14 +15100,13 @@ function computeCenterFromAnchorPosition(anchorPosition, ctx) {
15471
15100
  }
15472
15101
 
15473
15102
  // lib/components/primitive-components/Group/Group.ts
15474
- var Group = class extends NormalComponent3 {
15103
+ var Group6 = class extends NormalComponent3 {
15475
15104
  pcb_group_id = null;
15476
15105
  schematic_group_id = null;
15477
15106
  subcircuit_id = null;
15478
15107
  _hasStartedAsyncAutorouting = false;
15479
15108
  _isInflatedFromCircuitJson = false;
15480
15109
  _isolatedCircuitJson = null;
15481
- _isolatedCircuit = null;
15482
15110
  get _isIsolatedSubcircuit() {
15483
15111
  return Boolean(this._parsedProps._subcircuitCachingEnabled);
15484
15112
  }
@@ -15518,14 +15146,6 @@ var Group = class extends NormalComponent3 {
15518
15146
  componentName: "Group"
15519
15147
  };
15520
15148
  }
15521
- runRenderCycle() {
15522
- if (!this._isIsolatedSubcircuit || !this.root) {
15523
- super.runRenderCycle();
15524
- return;
15525
- }
15526
- if (!Group_doInitialRenderIsolatedSubcircuits(this)) return;
15527
- super.runRenderCycle();
15528
- }
15529
15149
  doInitialSourceGroupRender() {
15530
15150
  const { db } = this.root;
15531
15151
  const hasExplicitName = typeof this._parsedProps.name === "string" && this._parsedProps.name.length > 0;
@@ -15714,14 +15334,14 @@ var Group = class extends NormalComponent3 {
15714
15334
  return false;
15715
15335
  }
15716
15336
  _hasTracesToRoute() {
15717
- const debug11 = Debug14("tscircuit:core:_hasTracesToRoute");
15337
+ const debug11 = Debug13("tscircuit:core:_hasTracesToRoute");
15718
15338
  const traces = this.selectAll("trace");
15719
15339
  debug11(`[${this.getString()}] has ${traces.length} traces to route`);
15720
15340
  return traces.length > 0;
15721
15341
  }
15722
15342
  async _runEffectMakeHttpAutoroutingRequest() {
15723
15343
  const { db } = this.root;
15724
- const debug11 = Debug14("tscircuit:core:_runEffectMakeHttpAutoroutingRequest");
15344
+ const debug11 = Debug13("tscircuit:core:_runEffectMakeHttpAutoroutingRequest");
15725
15345
  const props = this._parsedProps;
15726
15346
  const autorouterConfig = this._getAutorouterConfig();
15727
15347
  const serverUrl = autorouterConfig.serverUrl;
@@ -15844,7 +15464,7 @@ var Group = class extends NormalComponent3 {
15844
15464
  async _runLocalAutorouting() {
15845
15465
  const { db } = this.root;
15846
15466
  const props = this._parsedProps;
15847
- const debug11 = Debug14("tscircuit:core:_runLocalAutorouting");
15467
+ const debug11 = Debug13("tscircuit:core:_runLocalAutorouting");
15848
15468
  debug11(`[${this.getString()}] starting local autorouting`);
15849
15469
  const autorouterConfig = this._getAutorouterConfig();
15850
15470
  const isLaserPrefabPreset = this._isLaserPrefabAutorouter(autorouterConfig);
@@ -15983,7 +15603,7 @@ var Group = class extends NormalComponent3 {
15983
15603
  }
15984
15604
  }
15985
15605
  doInitialPcbTraceRender() {
15986
- const debug11 = Debug14("tscircuit:core:doInitialPcbTraceRender");
15606
+ const debug11 = Debug13("tscircuit:core:doInitialPcbTraceRender");
15987
15607
  if (!this.isSubcircuit) return;
15988
15608
  if (this.root?.pcbDisabled) return;
15989
15609
  if (this.getInheritedProperty("routingDisabled")) return;
@@ -16005,7 +15625,7 @@ var Group = class extends NormalComponent3 {
16005
15625
  Group_doInitialSchematicTraceRender(this);
16006
15626
  }
16007
15627
  updatePcbTraceRender() {
16008
- const debug11 = Debug14("tscircuit:core:updatePcbTraceRender");
15628
+ const debug11 = Debug13("tscircuit:core:updatePcbTraceRender");
16009
15629
  debug11(`[${this.getString()}] updating...`);
16010
15630
  if (!this.isSubcircuit) return;
16011
15631
  if (this._isInflatedFromCircuitJson) return;
@@ -16473,19 +16093,6 @@ function inflatePcbBoard(pcbBoard, inflatorContext) {
16473
16093
 
16474
16094
  // lib/components/normal-components/Capacitor.ts
16475
16095
  import { capacitorProps } from "@tscircuit/props";
16476
-
16477
- // lib/utils/constants.ts
16478
- var stringProxy = new Proxy(
16479
- {},
16480
- {
16481
- get: (target, prop) => prop
16482
- }
16483
- );
16484
- var FTYPE = stringProxy;
16485
- var SCHEMATIC_COMPONENT_OUTLINE_COLOR = "rgba(132, 0, 0)";
16486
- var SCHEMATIC_COMPONENT_OUTLINE_STROKE_WIDTH = 0.12;
16487
-
16488
- // lib/components/normal-components/Capacitor.ts
16489
16096
  import { formatSiUnit } from "format-si-unit";
16490
16097
  var Capacitor = class extends NormalComponent3 {
16491
16098
  _adjustSilkscreenTextAutomatically = true;
@@ -16975,7 +16582,7 @@ function inflateSourceDiode(sourceElm, inflatorContext) {
16975
16582
  // lib/components/primitive-components/Group/Subcircuit/inflators/inflateSourceGroup.ts
16976
16583
  function inflateSourceGroup(sourceGroup, inflatorContext) {
16977
16584
  const { subcircuit, groupsMap } = inflatorContext;
16978
- const group = new Group({
16585
+ const group = new Group6({
16979
16586
  name: sourceGroup.name ?? `inflated_group_${sourceGroup.source_group_id}`
16980
16587
  });
16981
16588
  group.source_group_id = sourceGroup.source_group_id;
@@ -17216,7 +16823,13 @@ function pcbTraceRouteToPcbPath(route) {
17216
16823
  if (route.length <= 2) {
17217
16824
  return [];
17218
16825
  }
17219
- return route.slice(1, -1).map((point6) => {
16826
+ const firstPoint = route[0];
16827
+ const lastPoint = route[route.length - 1];
16828
+ return route.slice(1, -1).filter((point6) => {
16829
+ const isSameAsFirst = point6.x === firstPoint.x && point6.y === firstPoint.y;
16830
+ const isSameAsLast = point6.x === lastPoint.x && point6.y === lastPoint.y;
16831
+ return !isSameAsFirst && !isSameAsLast;
16832
+ }).map((point6) => {
17220
16833
  if (point6.route_type === "via") {
17221
16834
  return {
17222
16835
  x: point6.x,
@@ -17297,6 +16910,8 @@ function inflateSourceTrace(sourceTrace, inflatorContext) {
17297
16910
  };
17298
16911
  if (pcbPath && pcbPath.length > 0) {
17299
16912
  traceProps2.pcbPath = pcbPath;
16913
+ } else if (pcbTrace) {
16914
+ traceProps2.pcbStraightLine = true;
17300
16915
  }
17301
16916
  const trace = new Trace3(traceProps2);
17302
16917
  trace.source_trace_id = sourceTrace.source_trace_id;
@@ -17508,7 +17123,7 @@ var getRoundedRectOutline = (width, height, radius) => {
17508
17123
  }
17509
17124
  return outline;
17510
17125
  };
17511
- var Board = class extends Group {
17126
+ var Board = class extends Group6 {
17512
17127
  pcb_board_id = null;
17513
17128
  source_board_id = null;
17514
17129
  _drcChecksComplete = false;
@@ -17759,152 +17374,631 @@ var Board = class extends Group {
17759
17374
  computedWidth = maxX - minX;
17760
17375
  computedHeight = maxY - minY;
17761
17376
  }
17762
- let outline = props.outline;
17763
- if (!outline && props.borderRadius != null && computedWidth > 0 && computedHeight > 0) {
17764
- outline = getRoundedRectOutline(
17765
- computedWidth,
17766
- computedHeight,
17767
- props.borderRadius
17377
+ let outline = props.outline;
17378
+ if (!outline && props.borderRadius != null && computedWidth > 0 && computedHeight > 0) {
17379
+ outline = getRoundedRectOutline(
17380
+ computedWidth,
17381
+ computedHeight,
17382
+ props.borderRadius
17383
+ );
17384
+ }
17385
+ let outlineTranslation = { x: 0, y: 0 };
17386
+ if (outline && outline.length > 0 && (this.parent?.lowercaseComponentName === "panel" || this.parent?.lowercaseComponentName === "subpanel")) {
17387
+ const outlineBounds = getBoundsFromPoints4(outline);
17388
+ if (outlineBounds) {
17389
+ const outlineCenterX = (outlineBounds.minX + outlineBounds.maxX) / 2;
17390
+ const outlineCenterY = (outlineBounds.minY + outlineBounds.maxY) / 2;
17391
+ outlineTranslation = {
17392
+ x: center.x - outlineCenterX,
17393
+ y: center.y - outlineCenterY
17394
+ };
17395
+ }
17396
+ }
17397
+ const pcb_board = db.pcb_board.insert({
17398
+ source_board_id: this.source_board_id,
17399
+ center,
17400
+ thickness: this.boardThickness,
17401
+ num_layers: this.allLayers.length,
17402
+ width: computedWidth,
17403
+ height: computedHeight,
17404
+ outline: outline?.map((point6) => ({
17405
+ x: point6.x + (props.outlineOffsetX ?? 0) + outlineTranslation.x,
17406
+ y: point6.y + (props.outlineOffsetY ?? 0) + outlineTranslation.y
17407
+ })),
17408
+ material: props.material
17409
+ });
17410
+ this.pcb_board_id = pcb_board.pcb_board_id;
17411
+ this._addBoardInformationToSilkscreen();
17412
+ }
17413
+ removePcbComponentRender() {
17414
+ const { db } = this.root;
17415
+ if (!this.pcb_board_id) return;
17416
+ db.pcb_board.delete(this.pcb_board_id);
17417
+ this.pcb_board_id = null;
17418
+ }
17419
+ doInitialPcbDesignRuleChecks() {
17420
+ if (this.root?.pcbDisabled) return;
17421
+ if (this.getInheritedProperty("routingDisabled")) return;
17422
+ super.doInitialPcbDesignRuleChecks();
17423
+ }
17424
+ updatePcbDesignRuleChecks() {
17425
+ if (this.root?.pcbDisabled) return;
17426
+ if (this.getInheritedProperty("routingDisabled")) return;
17427
+ const { db } = this.root;
17428
+ if (!this._areChildSubcircuitsRouted()) return;
17429
+ if (this._drcChecksComplete) return;
17430
+ const runDrcChecks = (circuitJson) => {
17431
+ const pcbTraceOverlappingErrors = checkEachPcbTraceNonOverlapping(circuitJson);
17432
+ for (const error of pcbTraceOverlappingErrors) {
17433
+ db.pcb_trace_error.insert(error);
17434
+ }
17435
+ const pcbPortNotConnectedErrors = checkEachPcbPortConnectedToPcbTraces(circuitJson);
17436
+ for (const error of pcbPortNotConnectedErrors) {
17437
+ db.pcb_port_not_connected_error.insert(error);
17438
+ }
17439
+ const pcbComponentOutsideErrors = checkPcbComponentsOutOfBoard(circuitJson);
17440
+ for (const error of pcbComponentOutsideErrors) {
17441
+ db.pcb_component_outside_board_error.insert(error);
17442
+ }
17443
+ const pcbTracesOutOfBoardErrors = checkPcbTracesOutOfBoard(circuitJson);
17444
+ for (const error of pcbTracesOutOfBoardErrors) {
17445
+ db.pcb_trace_error.insert(error);
17446
+ }
17447
+ const differentNetViaErrors = checkDifferentNetViaSpacing(circuitJson);
17448
+ for (const error of differentNetViaErrors) {
17449
+ db.pcb_via_clearance_error.insert(error);
17450
+ }
17451
+ const sameNetViaErrors = checkSameNetViaSpacing(circuitJson);
17452
+ for (const error of sameNetViaErrors) {
17453
+ db.pcb_via_clearance_error.insert(error);
17454
+ }
17455
+ const pcbComponentOverlapErrors = checkPcbComponentOverlap(circuitJson);
17456
+ for (const error of pcbComponentOverlapErrors) {
17457
+ db.pcb_footprint_overlap_error.insert(error);
17458
+ }
17459
+ const sourcePinMustBeConnectedErrors = checkPinMustBeConnected(circuitJson);
17460
+ for (const error of sourcePinMustBeConnectedErrors) {
17461
+ db.source_pin_must_be_connected_error.insert(error);
17462
+ }
17463
+ };
17464
+ const subcircuit = db.subtree({ subcircuit_id: this.subcircuit_id });
17465
+ const subcircuitCircuitJson = subcircuit.toArray();
17466
+ runDrcChecks(subcircuitCircuitJson);
17467
+ this._drcChecksComplete = true;
17468
+ }
17469
+ _emitRenderLifecycleEvent(phase, startOrEnd) {
17470
+ super._emitRenderLifecycleEvent(phase, startOrEnd);
17471
+ if (startOrEnd === "start") {
17472
+ this.root?.emit("board:renderPhaseStarted", {
17473
+ renderId: this._renderId,
17474
+ phase
17475
+ });
17476
+ }
17477
+ }
17478
+ _repositionOnPcb(position) {
17479
+ const { db } = this.root;
17480
+ const pcbBoard = this.pcb_board_id ? db.pcb_board.get(this.pcb_board_id) : null;
17481
+ const oldPos = pcbBoard?.center;
17482
+ if (!oldPos) {
17483
+ if (this.pcb_board_id) {
17484
+ db.pcb_board.update(this.pcb_board_id, { center: position });
17485
+ }
17486
+ return;
17487
+ }
17488
+ const deltaX = position.x - oldPos.x;
17489
+ const deltaY = position.y - oldPos.y;
17490
+ if (Math.abs(deltaX) < 1e-6 && Math.abs(deltaY) < 1e-6) {
17491
+ return;
17492
+ }
17493
+ if (this.pcb_board_id) {
17494
+ db.pcb_board.update(this.pcb_board_id, { center: position });
17495
+ if (pcbBoard?.outline) {
17496
+ const outlineBounds = getBoundsFromPoints4(pcbBoard.outline);
17497
+ if (outlineBounds) {
17498
+ const oldOutlineCenter = {
17499
+ x: (outlineBounds.minX + outlineBounds.maxX) / 2,
17500
+ y: (outlineBounds.minY + outlineBounds.maxY) / 2
17501
+ };
17502
+ const outlineDeltaX = position.x - oldOutlineCenter.x;
17503
+ const outlineDeltaY = position.y - oldOutlineCenter.y;
17504
+ const newOutline = pcbBoard.outline.map((p) => ({
17505
+ x: p.x + outlineDeltaX,
17506
+ y: p.y + outlineDeltaY
17507
+ }));
17508
+ db.pcb_board.update(this.pcb_board_id, {
17509
+ outline: newOutline
17510
+ });
17511
+ }
17512
+ }
17513
+ }
17514
+ }
17515
+ };
17516
+
17517
+ // lib/components/normal-components/MountedBoard.ts
17518
+ import { mountedboardProps } from "@tscircuit/props";
17519
+
17520
+ // lib/components/primitive-components/Group/Subcircuit/Subcircuit.ts
17521
+ import "@tscircuit/props";
17522
+
17523
+ // lib/IsolatedCircuit.ts
17524
+ import { su as su5 } from "@tscircuit/circuit-json-util";
17525
+ import Debug14 from "debug";
17526
+ import { isValidElement as isValidElement2 } from "react";
17527
+ import { identity as identity4 } from "transformation-matrix";
17528
+
17529
+ // package.json
17530
+ var package_default = {
17531
+ name: "@tscircuit/core",
17532
+ type: "module",
17533
+ version: "0.0.1038",
17534
+ types: "dist/index.d.ts",
17535
+ main: "dist/index.js",
17536
+ module: "dist/index.js",
17537
+ exports: {
17538
+ ".": {
17539
+ import: "./dist/index.js",
17540
+ types: "./dist/index.d.ts"
17541
+ }
17542
+ },
17543
+ files: [
17544
+ "dist"
17545
+ ],
17546
+ repository: {
17547
+ type: "git",
17548
+ url: "https://github.com/tscircuit/core"
17549
+ },
17550
+ scripts: {
17551
+ build: "tsup-node index.ts --format esm --dts",
17552
+ format: "biome format . --write",
17553
+ "measure-bundle": "howfat -r table .",
17554
+ "pkg-pr-new-release": "bunx pkg-pr-new publish --comment=off --peerDeps",
17555
+ "smoke-test:dist": "bun run scripts/smoke-tests/test-dist-simple-circuit.tsx",
17556
+ "build:benchmarking": "bun build --experimental-html ./benchmarking/website/index.html --outdir ./benchmarking-dist",
17557
+ "build:benchmarking:watch": `chokidar "./{benchmarking,lib}/**/*.{ts,tsx}" -c 'bun build --experimental-html ./benchmarking/website/index.html --outdir ./benchmarking-dist'`,
17558
+ "start:benchmarking": 'concurrently "bun run build:benchmarking:watch" "live-server ./benchmarking-dist"',
17559
+ "generate-test-plan": "bun run scripts/generate-test-plan.ts"
17560
+ },
17561
+ devDependencies: {
17562
+ "@biomejs/biome": "^1.8.3",
17563
+ "@resvg/resvg-js": "^2.6.2",
17564
+ "@tscircuit/alphabet": "0.0.18",
17565
+ "@tscircuit/capacity-autorouter": "^0.0.269",
17566
+ "@tscircuit/checks": "^0.0.90",
17567
+ "@tscircuit/circuit-json-util": "^0.0.77",
17568
+ "@tscircuit/common": "^0.0.20",
17569
+ "@tscircuit/copper-pour-solver": "^0.0.20",
17570
+ "@tscircuit/footprinter": "^0.0.288",
17571
+ "@tscircuit/infgrid-ijump-astar": "^0.0.35",
17572
+ "@tscircuit/log-soup": "^1.0.2",
17573
+ "@tscircuit/matchpack": "^0.0.16",
17574
+ "@tscircuit/math-utils": "^0.0.29",
17575
+ "@tscircuit/miniflex": "^0.0.4",
17576
+ "@tscircuit/ngspice-spice-engine": "^0.0.8",
17577
+ "@tscircuit/props": "^0.0.474",
17578
+ "@tscircuit/schematic-match-adapt": "^0.0.16",
17579
+ "@tscircuit/schematic-trace-solver": "^v0.0.45",
17580
+ "@tscircuit/solver-utils": "^0.0.3",
17581
+ "@tscircuit/soup-util": "^0.0.41",
17582
+ "@types/bun": "^1.2.16",
17583
+ "@types/debug": "^4.1.12",
17584
+ "@types/react": "^19.1.8",
17585
+ "@types/react-dom": "^19.1.6",
17586
+ "@types/react-reconciler": "^0.28.9",
17587
+ "bpc-graph": "^0.0.57",
17588
+ "bun-match-svg": "0.0.12",
17589
+ "calculate-elbow": "^0.0.12",
17590
+ "chokidar-cli": "^3.0.0",
17591
+ "circuit-json": "^0.0.379",
17592
+ "circuit-json-to-bpc": "^0.0.13",
17593
+ "circuit-json-to-connectivity-map": "^0.0.23",
17594
+ "circuit-json-to-gltf": "^0.0.65",
17595
+ "circuit-json-to-simple-3d": "^0.0.9",
17596
+ "circuit-json-to-spice": "^0.0.34",
17597
+ "circuit-to-svg": "^0.0.328",
17598
+ concurrently: "^9.1.2",
17599
+ "connectivity-map": "^1.0.0",
17600
+ debug: "^4.3.6",
17601
+ "eecircuit-engine": "^1.5.6",
17602
+ flatbush: "^4.5.0",
17603
+ "graphics-debug": "^0.0.60",
17604
+ howfat: "^0.3.8",
17605
+ "live-server": "^1.2.2",
17606
+ "looks-same": "^9.0.1",
17607
+ minicssgrid: "^0.0.9",
17608
+ "pkg-pr-new": "^0.0.37",
17609
+ poppygl: "^0.0.16",
17610
+ react: "^19.1.0",
17611
+ "react-dom": "^19.1.0",
17612
+ "schematic-symbols": "^0.0.208",
17613
+ spicey: "^0.0.14",
17614
+ "ts-expect": "^1.3.0",
17615
+ tsup: "^8.2.4"
17616
+ },
17617
+ peerDependencies: {
17618
+ "@tscircuit/capacity-autorouter": "*",
17619
+ "@tscircuit/checks": "*",
17620
+ "@tscircuit/circuit-json-util": "*",
17621
+ "@tscircuit/footprinter": "*",
17622
+ "@tscircuit/infgrid-ijump-astar": "*",
17623
+ "@tscircuit/math-utils": "*",
17624
+ "@tscircuit/props": "*",
17625
+ "@tscircuit/schematic-match-adapt": "*",
17626
+ "circuit-json-to-bpc": "*",
17627
+ "bpc-graph": "*",
17628
+ "@tscircuit/matchpack": "*",
17629
+ "circuit-json": "*",
17630
+ "circuit-json-to-connectivity-map": "*",
17631
+ "schematic-symbols": "*",
17632
+ typescript: "^5.0.0"
17633
+ },
17634
+ dependencies: {
17635
+ "@flatten-js/core": "^1.6.2",
17636
+ "@lume/kiwi": "^0.4.3",
17637
+ "calculate-packing": "0.0.68",
17638
+ "css-select": "5.1.0",
17639
+ "format-si-unit": "^0.0.3",
17640
+ nanoid: "^5.0.7",
17641
+ "performance-now": "^2.1.0",
17642
+ "react-reconciler": "^0.32.0",
17643
+ "svg-path-commander": "^2.1.11",
17644
+ "transformation-matrix": "^2.16.1",
17645
+ zod: "^3.25.67"
17646
+ }
17647
+ };
17648
+
17649
+ // lib/IsolatedCircuit.ts
17650
+ var IsolatedCircuit = class {
17651
+ firstChild = null;
17652
+ children;
17653
+ db;
17654
+ root = null;
17655
+ isRootCircuit = false;
17656
+ /**
17657
+ * Optional cache for isolated subcircuit circuit JSON, keyed by prop hash.
17658
+ * This is passed down from the RootCircuit when creating isolated circuits
17659
+ * for subcircuit rendering.
17660
+ */
17661
+ cachedSubcircuits;
17662
+ _schematicDisabledOverride;
17663
+ get schematicDisabled() {
17664
+ if (this._schematicDisabledOverride !== void 0) {
17665
+ return this._schematicDisabledOverride;
17666
+ }
17667
+ if (this.platform?.schematicDisabled !== void 0) {
17668
+ return this.platform.schematicDisabled;
17669
+ }
17670
+ const board = this._getBoard();
17671
+ return board?._parsedProps?.schematicDisabled ?? false;
17672
+ }
17673
+ set schematicDisabled(value) {
17674
+ this._schematicDisabledOverride = value;
17675
+ }
17676
+ pcbDisabled = false;
17677
+ pcbRoutingDisabled = false;
17678
+ _featureMspSchematicTraceRouting = true;
17679
+ /**
17680
+ * The IsolatedCircuit name is usually set by the platform, it's not required but
17681
+ * if supplied can identify the circuit in certain effects, e.g. it is passed
17682
+ * as the display_name parameter for autorouting effects.
17683
+ */
17684
+ name;
17685
+ platform;
17686
+ /**
17687
+ * Optional URL pointing to where this project is hosted or documented.
17688
+ * When provided it is stored in the source_project_metadata.project_url field
17689
+ * of the generated Circuit JSON.
17690
+ */
17691
+ projectUrl;
17692
+ _hasRenderedAtleastOnce = false;
17693
+ _asyncEffectIdsByPhase = /* @__PURE__ */ new Map();
17694
+ _asyncEffectPhaseById = /* @__PURE__ */ new Map();
17695
+ constructor({
17696
+ platform,
17697
+ projectUrl,
17698
+ cachedSubcircuits
17699
+ } = {}) {
17700
+ this.children = [];
17701
+ this.db = su5([]);
17702
+ this.platform = platform;
17703
+ this.projectUrl = projectUrl;
17704
+ this.pcbDisabled = platform?.pcbDisabled ?? false;
17705
+ this.cachedSubcircuits = cachedSubcircuits;
17706
+ this.root = this;
17707
+ }
17708
+ add(componentOrElm) {
17709
+ let component;
17710
+ if (isValidElement2(componentOrElm)) {
17711
+ component = createInstanceFromReactElement(componentOrElm);
17712
+ } else {
17713
+ component = componentOrElm;
17714
+ }
17715
+ this.children.push(component);
17716
+ }
17717
+ setPlatform(platform) {
17718
+ this.platform = {
17719
+ ...this.platform,
17720
+ ...platform
17721
+ };
17722
+ }
17723
+ /**
17724
+ * Get the main board for this Circuit.
17725
+ */
17726
+ _getBoard() {
17727
+ const directBoard = this.children.find((c) => c.componentName === "Board");
17728
+ if (directBoard) {
17729
+ return directBoard;
17730
+ }
17731
+ return void 0;
17732
+ }
17733
+ _guessRootComponent() {
17734
+ if (this.firstChild) return;
17735
+ if (this.children.length === 0) {
17736
+ throw new Error(
17737
+ "Not able to guess root component: IsolatedCircuit has no children (use circuit.add(...))"
17738
+ );
17739
+ }
17740
+ const panels = this.children.filter(
17741
+ (child) => child.lowercaseComponentName === "panel"
17742
+ );
17743
+ if (panels.length > 1) {
17744
+ throw new Error("Only one <panel> is allowed per circuit");
17745
+ }
17746
+ if (panels.length === 1) {
17747
+ if (this.children.length !== 1) {
17748
+ throw new Error("<panel> must be the root element of the circuit");
17749
+ }
17750
+ this.firstChild = panels[0];
17751
+ return;
17752
+ }
17753
+ if (this.children.length === 1 && this.children[0].isGroup) {
17754
+ this.firstChild = this.children[0];
17755
+ return;
17756
+ }
17757
+ const group = new Group6({ subcircuit: true });
17758
+ group.parent = this;
17759
+ group.addAll(this.children);
17760
+ this.children = [group];
17761
+ this.firstChild = group;
17762
+ }
17763
+ render() {
17764
+ if (!this.firstChild) {
17765
+ this._guessRootComponent();
17766
+ }
17767
+ const { firstChild, db } = this;
17768
+ if (!firstChild) throw new Error("IsolatedCircuit has no root component");
17769
+ firstChild.parent = this;
17770
+ firstChild.runRenderCycle();
17771
+ this._hasRenderedAtleastOnce = true;
17772
+ }
17773
+ async renderUntilSettled() {
17774
+ const existing = this.db.source_project_metadata.list()?.[0];
17775
+ if (!existing) {
17776
+ this.db.source_project_metadata.insert({
17777
+ software_used_string: `@tscircuit/core@${this.getCoreVersion()}`,
17778
+ ...this.projectUrl ? { project_url: this.projectUrl } : {}
17779
+ });
17780
+ }
17781
+ this.render();
17782
+ while (this._hasIncompleteAsyncEffects()) {
17783
+ await new Promise((resolve) => setTimeout(resolve, 100));
17784
+ this.render();
17785
+ }
17786
+ this.emit("renderComplete");
17787
+ }
17788
+ _hasIncompleteAsyncEffects() {
17789
+ if (this._asyncEffectPhaseById.size > 0) return true;
17790
+ return this.children.some((child) => child._hasIncompleteAsyncEffects());
17791
+ }
17792
+ _hasIncompleteAsyncEffectsForPhase(phase) {
17793
+ return (this._asyncEffectIdsByPhase.get(phase)?.size ?? 0) > 0;
17794
+ }
17795
+ getCircuitJson() {
17796
+ if (!this._hasRenderedAtleastOnce) this.render();
17797
+ return this.db.toArray();
17798
+ }
17799
+ toJson() {
17800
+ return this.getCircuitJson();
17801
+ }
17802
+ async getSvg(options) {
17803
+ const circuitToSvg = await import("circuit-to-svg").catch((e) => {
17804
+ throw new Error(
17805
+ `To use circuit.getSvg, you must install the "circuit-to-svg" package.
17806
+
17807
+ "${e.message}"`
17808
+ );
17809
+ });
17810
+ if (options.view === "pcb") {
17811
+ return circuitToSvg.convertCircuitJsonToPcbSvg(this.getCircuitJson());
17812
+ }
17813
+ if (options.view === "schematic") {
17814
+ return circuitToSvg.convertCircuitJsonToSchematicSvg(
17815
+ this.getCircuitJson()
17768
17816
  );
17769
17817
  }
17770
- let outlineTranslation = { x: 0, y: 0 };
17771
- if (outline && outline.length > 0 && (this.parent?.lowercaseComponentName === "panel" || this.parent?.lowercaseComponentName === "subpanel")) {
17772
- const outlineBounds = getBoundsFromPoints4(outline);
17773
- if (outlineBounds) {
17774
- const outlineCenterX = (outlineBounds.minX + outlineBounds.maxX) / 2;
17775
- const outlineCenterY = (outlineBounds.minY + outlineBounds.maxY) / 2;
17776
- outlineTranslation = {
17777
- x: center.x - outlineCenterX,
17778
- y: center.y - outlineCenterY
17779
- };
17780
- }
17818
+ throw new Error(`Invalid view: ${options.view}`);
17819
+ }
17820
+ getCoreVersion() {
17821
+ const [major, minor, patch] = package_default.version.split(".").map(Number);
17822
+ return `${major}.${minor}.${patch + 1}`;
17823
+ }
17824
+ async preview(previewNameOrOpts) {
17825
+ const previewOpts = typeof previewNameOrOpts === "object" ? previewNameOrOpts : { previewName: previewNameOrOpts };
17826
+ throw new Error("project.preview is not yet implemented");
17827
+ }
17828
+ computeSchematicGlobalTransform() {
17829
+ return identity4();
17830
+ }
17831
+ _computePcbGlobalTransformBeforeLayout() {
17832
+ return identity4();
17833
+ }
17834
+ selectAll(selector) {
17835
+ this._guessRootComponent();
17836
+ return this.firstChild?.selectAll(selector) ?? [];
17837
+ }
17838
+ selectOne(selector, opts) {
17839
+ this._guessRootComponent();
17840
+ return this.firstChild?.selectOne(selector, opts) ?? null;
17841
+ }
17842
+ _eventListeners = {};
17843
+ emit(event, ...args) {
17844
+ if (event === "asyncEffect:start") {
17845
+ this._registerAsyncEffectStart(args[0]);
17846
+ } else if (event === "asyncEffect:end") {
17847
+ this._registerAsyncEffectEnd(args[0]);
17848
+ }
17849
+ if (!this._eventListeners[event]) return;
17850
+ for (const listener of this._eventListeners[event]) {
17851
+ listener(...args);
17781
17852
  }
17782
- const pcb_board = db.pcb_board.insert({
17783
- source_board_id: this.source_board_id,
17784
- center,
17785
- thickness: this.boardThickness,
17786
- num_layers: this.allLayers.length,
17787
- width: computedWidth,
17788
- height: computedHeight,
17789
- outline: outline?.map((point6) => ({
17790
- x: point6.x + (props.outlineOffsetX ?? 0) + outlineTranslation.x,
17791
- y: point6.y + (props.outlineOffsetY ?? 0) + outlineTranslation.y
17792
- })),
17793
- material: props.material
17794
- });
17795
- this.pcb_board_id = pcb_board.pcb_board_id;
17796
- this._addBoardInformationToSilkscreen();
17797
17853
  }
17798
- removePcbComponentRender() {
17799
- const { db } = this.root;
17800
- if (!this.pcb_board_id) return;
17801
- db.pcb_board.delete(this.pcb_board_id);
17802
- this.pcb_board_id = null;
17854
+ on(event, listener) {
17855
+ if (!this._eventListeners[event]) {
17856
+ this._eventListeners[event] = [];
17857
+ }
17858
+ this._eventListeners[event].push(listener);
17803
17859
  }
17804
- doInitialPcbDesignRuleChecks() {
17805
- if (this.root?.pcbDisabled) return;
17806
- if (this.getInheritedProperty("routingDisabled")) return;
17807
- super.doInitialPcbDesignRuleChecks();
17860
+ removeListener(event, listener) {
17861
+ if (!this._eventListeners[event]) return;
17862
+ this._eventListeners[event] = this._eventListeners[event].filter(
17863
+ (l) => l !== listener
17864
+ );
17808
17865
  }
17809
- updatePcbDesignRuleChecks() {
17810
- if (this.root?.pcbDisabled) return;
17811
- if (this.getInheritedProperty("routingDisabled")) return;
17812
- const { db } = this.root;
17813
- if (!this._areChildSubcircuitsRouted()) return;
17814
- if (this._drcChecksComplete) return;
17815
- const runDrcChecks = (circuitJson) => {
17816
- const pcbTraceOverlappingErrors = checkEachPcbTraceNonOverlapping(circuitJson);
17817
- for (const error of pcbTraceOverlappingErrors) {
17818
- db.pcb_trace_error.insert(error);
17819
- }
17820
- const pcbPortNotConnectedErrors = checkEachPcbPortConnectedToPcbTraces(circuitJson);
17821
- for (const error of pcbPortNotConnectedErrors) {
17822
- db.pcb_port_not_connected_error.insert(error);
17823
- }
17824
- const pcbComponentOutsideErrors = checkPcbComponentsOutOfBoard(circuitJson);
17825
- for (const error of pcbComponentOutsideErrors) {
17826
- db.pcb_component_outside_board_error.insert(error);
17827
- }
17828
- const pcbTracesOutOfBoardErrors = checkPcbTracesOutOfBoard(circuitJson);
17829
- for (const error of pcbTracesOutOfBoardErrors) {
17830
- db.pcb_trace_error.insert(error);
17831
- }
17832
- const differentNetViaErrors = checkDifferentNetViaSpacing(circuitJson);
17833
- for (const error of differentNetViaErrors) {
17834
- db.pcb_via_clearance_error.insert(error);
17835
- }
17836
- const sameNetViaErrors = checkSameNetViaSpacing(circuitJson);
17837
- for (const error of sameNetViaErrors) {
17838
- db.pcb_via_clearance_error.insert(error);
17839
- }
17840
- const pcbComponentOverlapErrors = checkPcbComponentOverlap(circuitJson);
17841
- for (const error of pcbComponentOverlapErrors) {
17842
- db.pcb_footprint_overlap_error.insert(error);
17843
- }
17844
- const sourcePinMustBeConnectedErrors = checkPinMustBeConnected(circuitJson);
17845
- for (const error of sourcePinMustBeConnectedErrors) {
17846
- db.source_pin_must_be_connected_error.insert(error);
17847
- }
17848
- };
17849
- const subcircuit = db.subtree({ subcircuit_id: this.subcircuit_id });
17850
- const subcircuitCircuitJson = subcircuit.toArray();
17851
- runDrcChecks(subcircuitCircuitJson);
17852
- this._drcChecksComplete = true;
17866
+ enableDebug(debug11) {
17867
+ if (typeof debug11 === "string") {
17868
+ Debug14.enable(debug11);
17869
+ } else if (debug11 === null || debug11 === false) {
17870
+ Debug14.disable();
17871
+ }
17853
17872
  }
17854
- _emitRenderLifecycleEvent(phase, startOrEnd) {
17855
- super._emitRenderLifecycleEvent(phase, startOrEnd);
17856
- if (startOrEnd === "start") {
17857
- this.root?.emit("board:renderPhaseStarted", {
17858
- renderId: this._renderId,
17859
- phase
17860
- });
17873
+ getClientOrigin() {
17874
+ if (typeof window !== "undefined" && window.location) {
17875
+ return window.location.origin;
17876
+ }
17877
+ if (typeof self !== "undefined" && self.location) {
17878
+ return self.location.origin;
17861
17879
  }
17880
+ return "";
17862
17881
  }
17863
- _repositionOnPcb(position) {
17864
- const { db } = this.root;
17865
- const pcbBoard = this.pcb_board_id ? db.pcb_board.get(this.pcb_board_id) : null;
17866
- const oldPos = pcbBoard?.center;
17867
- if (!oldPos) {
17868
- if (this.pcb_board_id) {
17869
- db.pcb_board.update(this.pcb_board_id, { center: position });
17870
- }
17871
- return;
17882
+ _registerAsyncEffectStart(payload) {
17883
+ if (!payload?.asyncEffectId || !payload.phase) return;
17884
+ const { asyncEffectId, phase } = payload;
17885
+ const existingPhase = this._asyncEffectPhaseById.get(asyncEffectId);
17886
+ if (existingPhase && existingPhase !== phase) {
17887
+ this._asyncEffectIdsByPhase.get(existingPhase)?.delete(asyncEffectId);
17872
17888
  }
17873
- const deltaX = position.x - oldPos.x;
17874
- const deltaY = position.y - oldPos.y;
17875
- if (Math.abs(deltaX) < 1e-6 && Math.abs(deltaY) < 1e-6) {
17876
- return;
17889
+ if (!this._asyncEffectIdsByPhase.has(phase)) {
17890
+ this._asyncEffectIdsByPhase.set(phase, /* @__PURE__ */ new Set());
17877
17891
  }
17878
- if (this.pcb_board_id) {
17879
- db.pcb_board.update(this.pcb_board_id, { center: position });
17880
- if (pcbBoard?.outline) {
17881
- const outlineBounds = getBoundsFromPoints4(pcbBoard.outline);
17882
- if (outlineBounds) {
17883
- const oldOutlineCenter = {
17884
- x: (outlineBounds.minX + outlineBounds.maxX) / 2,
17885
- y: (outlineBounds.minY + outlineBounds.maxY) / 2
17886
- };
17887
- const outlineDeltaX = position.x - oldOutlineCenter.x;
17888
- const outlineDeltaY = position.y - oldOutlineCenter.y;
17889
- const newOutline = pcbBoard.outline.map((p) => ({
17890
- x: p.x + outlineDeltaX,
17891
- y: p.y + outlineDeltaY
17892
- }));
17893
- db.pcb_board.update(this.pcb_board_id, {
17894
- outline: newOutline
17895
- });
17896
- }
17892
+ this._asyncEffectIdsByPhase.get(phase).add(asyncEffectId);
17893
+ this._asyncEffectPhaseById.set(asyncEffectId, phase);
17894
+ }
17895
+ _registerAsyncEffectEnd(payload) {
17896
+ if (!payload?.asyncEffectId) return;
17897
+ const { asyncEffectId } = payload;
17898
+ const phase = this._asyncEffectPhaseById.get(asyncEffectId) ?? payload.phase;
17899
+ if (phase) {
17900
+ const phaseSet = this._asyncEffectIdsByPhase.get(phase);
17901
+ phaseSet?.delete(asyncEffectId);
17902
+ if (phaseSet && phaseSet.size === 0) {
17903
+ this._asyncEffectIdsByPhase.delete(phase);
17897
17904
  }
17898
17905
  }
17906
+ this._asyncEffectPhaseById.delete(asyncEffectId);
17899
17907
  }
17900
17908
  };
17901
17909
 
17902
- // lib/components/normal-components/MountedBoard.ts
17903
- import { mountedboardProps } from "@tscircuit/props";
17910
+ // lib/components/primitive-components/Group/Subcircuit/Subcircuit_doInitialRenderIsolatedSubcircuits.ts
17911
+ function Subcircuit_doInitialRenderIsolatedSubcircuits(subcircuit) {
17912
+ if (!subcircuit._isIsolatedSubcircuit) return;
17913
+ if (subcircuit._isolatedCircuitJson) return;
17914
+ const propHash = subcircuit.getSubcircuitPropHash();
17915
+ const cachedSubcircuits = subcircuit.root?.cachedSubcircuits;
17916
+ const cached = cachedSubcircuits?.get(propHash);
17917
+ if (cached) {
17918
+ subcircuit._isolatedCircuitJson = cached;
17919
+ subcircuit.children = [];
17920
+ subcircuit._normalComponentNameMap = null;
17921
+ return;
17922
+ }
17923
+ const parentRoot = subcircuit.root;
17924
+ const childrenToRender = [...subcircuit.children];
17925
+ subcircuit.children = [];
17926
+ subcircuit._normalComponentNameMap = null;
17927
+ subcircuit._queueAsyncEffect("render-isolated-subcircuit", async () => {
17928
+ const isolatedCircuit = new IsolatedCircuit({
17929
+ platform: {
17930
+ ...parentRoot.platform,
17931
+ pcbDisabled: parentRoot.pcbDisabled,
17932
+ schematicDisabled: parentRoot.schematicDisabled
17933
+ },
17934
+ cachedSubcircuits
17935
+ });
17936
+ for (const child of childrenToRender) {
17937
+ isolatedCircuit.add(child);
17938
+ }
17939
+ await isolatedCircuit.renderUntilSettled();
17940
+ const circuitJson = isolatedCircuit.getCircuitJson();
17941
+ cachedSubcircuits?.set(propHash, circuitJson);
17942
+ subcircuit._isolatedCircuitJson = circuitJson;
17943
+ });
17944
+ }
17945
+
17946
+ // lib/components/primitive-components/Group/Subcircuit_getSubcircuitPropHash.ts
17947
+ var EXCLUDED_PROPS = /* @__PURE__ */ new Set([
17948
+ "name",
17949
+ "key",
17950
+ "pcbX",
17951
+ "pcbY",
17952
+ "schX",
17953
+ "schY",
17954
+ "pcbLeftEdgeX",
17955
+ "pcbRightEdgeX",
17956
+ "pcbTopEdgeY",
17957
+ "pcbBottomEdgeY",
17958
+ "pcbRotation",
17959
+ "schRotation"
17960
+ ]);
17961
+ function getHashableProps(props) {
17962
+ const result = {};
17963
+ const keys = Object.keys(props).sort();
17964
+ for (const key of keys) {
17965
+ if (!EXCLUDED_PROPS.has(key) && props[key] !== void 0) {
17966
+ result[key] = props[key];
17967
+ }
17968
+ }
17969
+ return result;
17970
+ }
17971
+ function getChildrenHashData(children) {
17972
+ return children.map((child) => ({
17973
+ componentName: child.componentName,
17974
+ props: getHashableProps(child.props ?? {}),
17975
+ children: getChildrenHashData(child.children)
17976
+ }));
17977
+ }
17978
+ function fnv1aHash(str) {
17979
+ let hash = 2166136261;
17980
+ for (let i = 0; i < str.length; i++) {
17981
+ hash ^= str.charCodeAt(i);
17982
+ hash = Math.imul(hash, 16777619);
17983
+ }
17984
+ return hash >>> 0;
17985
+ }
17986
+ function computeHash(data) {
17987
+ const jsonString = JSON.stringify(data);
17988
+ const hash1 = fnv1aHash(jsonString);
17989
+ const hash2 = fnv1aHash(jsonString + hash1.toString());
17990
+ return hash1.toString(16).padStart(8, "0") + hash2.toString(16).padStart(8, "0");
17991
+ }
17992
+ function Subcircuit_getSubcircuitPropHash(subcircuit) {
17993
+ const hashableData = {
17994
+ props: getHashableProps(subcircuit.props ?? {}),
17995
+ children: getChildrenHashData(subcircuit.children)
17996
+ };
17997
+ return computeHash(hashableData);
17998
+ }
17904
17999
 
17905
18000
  // lib/components/primitive-components/Group/Subcircuit/Subcircuit.ts
17906
- import "@tscircuit/props";
17907
- var Subcircuit = class extends Group {
18001
+ var Subcircuit = class extends Group6 {
17908
18002
  constructor(props) {
17909
18003
  super({
17910
18004
  ...props,
@@ -17912,6 +18006,26 @@ var Subcircuit = class extends Group {
17912
18006
  subcircuit: true
17913
18007
  });
17914
18008
  }
18009
+ /**
18010
+ * Computes a hash of this subcircuit's props and children for caching.
18011
+ * Position/identity props are excluded so identical subcircuits at
18012
+ * different locations share the same hash.
18013
+ */
18014
+ getSubcircuitPropHash() {
18015
+ return Subcircuit_getSubcircuitPropHash(this);
18016
+ }
18017
+ /**
18018
+ * Render this subcircuit in isolation if _subcircuitCachingEnabled is set.
18019
+ * This phase runs before InflateSubcircuitCircuitJson to prepare the
18020
+ * isolated circuit JSON that will be inflated.
18021
+ *
18022
+ * The rendering is synchronous - it loops until all async effects in the
18023
+ * isolated circuit are complete, ensuring the cache is populated before
18024
+ * processing the next subcircuit with potentially the same props.
18025
+ */
18026
+ doInitialRenderIsolatedSubcircuits() {
18027
+ Subcircuit_doInitialRenderIsolatedSubcircuits(this);
18028
+ }
17915
18029
  /**
17916
18030
  * During this phase, we inflate the subcircuit circuit json into class
17917
18031
  * instances
@@ -18395,7 +18509,7 @@ var packBoardsIntoGrid = ({
18395
18509
  };
18396
18510
 
18397
18511
  // lib/components/normal-components/Subpanel.ts
18398
- var Subpanel = class _Subpanel extends Group {
18512
+ var Subpanel = class _Subpanel extends Group6 {
18399
18513
  pcb_panel_id = null;
18400
18514
  _tabsAndMouseBitesGenerated = false;
18401
18515
  get config() {
@@ -20196,7 +20310,7 @@ var PcbNoteDimension = class extends PrimitiveComponent2 {
20196
20310
 
20197
20311
  // lib/components/primitive-components/Breakout/Breakout.ts
20198
20312
  import "@tscircuit/props";
20199
- var Breakout = class extends Group {
20313
+ var Breakout = class extends Group6 {
20200
20314
  constructor(props) {
20201
20315
  super({
20202
20316
  ...props,
@@ -23192,7 +23306,11 @@ var RootCircuit = class extends IsolatedCircuit {
23192
23306
  platform,
23193
23307
  projectUrl
23194
23308
  } = {}) {
23195
- super({ platform, projectUrl });
23309
+ super({
23310
+ platform,
23311
+ projectUrl,
23312
+ cachedSubcircuits: /* @__PURE__ */ new Map()
23313
+ });
23196
23314
  this.root = this;
23197
23315
  }
23198
23316
  };
@@ -23433,7 +23551,7 @@ export {
23433
23551
  Fiducial,
23434
23552
  Footprint,
23435
23553
  Fuse,
23436
- Group,
23554
+ Group6 as Group,
23437
23555
  Hole,
23438
23556
  Inductor,
23439
23557
  Interconnect,