schematex 0.9.18 → 0.9.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/README.md +13 -0
  2. package/dist/ai/ai-sdk.cjs +9 -9
  3. package/dist/ai/ai-sdk.d.cts +3 -3
  4. package/dist/ai/ai-sdk.d.ts +3 -3
  5. package/dist/ai/ai-sdk.js +4 -4
  6. package/dist/ai/index.cjs +18 -18
  7. package/dist/ai/index.d.cts +4 -4
  8. package/dist/ai/index.d.ts +4 -4
  9. package/dist/ai/index.js +5 -5
  10. package/dist/{api-DAUFeETp.d.cts → api-DH9a1V6Q.d.cts} +1 -1
  11. package/dist/{api-C9ufsgIb.d.ts → api-DsAwn8ne.d.ts} +1 -1
  12. package/dist/browser.cjs +10 -10
  13. package/dist/browser.d.cts +3 -3
  14. package/dist/browser.d.ts +3 -3
  15. package/dist/browser.js +4 -4
  16. package/dist/{chunk-FA6Y4QRS.js → chunk-5IPT6OFE.js} +356 -47
  17. package/dist/chunk-5IPT6OFE.js.map +1 -0
  18. package/dist/{chunk-LZHLFNM3.js → chunk-BP52JB7C.js} +4 -4
  19. package/dist/{chunk-LZHLFNM3.js.map → chunk-BP52JB7C.js.map} +1 -1
  20. package/dist/{chunk-VLK5T7B7.cjs → chunk-GJTD3RQE.cjs} +6 -6
  21. package/dist/{chunk-VLK5T7B7.cjs.map → chunk-GJTD3RQE.cjs.map} +1 -1
  22. package/dist/{chunk-DSKPJYQO.js → chunk-JBNLZQP2.js} +47 -5
  23. package/dist/chunk-JBNLZQP2.js.map +1 -0
  24. package/dist/{chunk-AG4WA4NF.cjs → chunk-JXPBZEFM.cjs} +355 -47
  25. package/dist/chunk-JXPBZEFM.cjs.map +1 -0
  26. package/dist/{chunk-6GVFKOSH.js → chunk-OZD4CYAK.js} +2 -2
  27. package/dist/{chunk-6GVFKOSH.js.map → chunk-OZD4CYAK.js.map} +1 -1
  28. package/dist/{chunk-JWILBXGR.cjs → chunk-PZ5MNDVY.cjs} +49 -7
  29. package/dist/chunk-PZ5MNDVY.cjs.map +1 -0
  30. package/dist/{chunk-AWUUGDN4.cjs → chunk-RVPYIBBH.cjs} +2 -2
  31. package/dist/{chunk-AWUUGDN4.cjs.map → chunk-RVPYIBBH.cjs.map} +1 -1
  32. package/dist/{diagnostics-DSxLohjY.d.cts → diagnostics-CKacYRIE.d.cts} +1 -1
  33. package/dist/{diagnostics-DSxLohjY.d.ts → diagnostics-CKacYRIE.d.ts} +1 -1
  34. package/dist/diagrams/blockdiagram/index.d.cts +1 -1
  35. package/dist/diagrams/blockdiagram/index.d.ts +1 -1
  36. package/dist/diagrams/circuit/index.cjs +8 -8
  37. package/dist/diagrams/circuit/index.d.cts +3 -1
  38. package/dist/diagrams/circuit/index.d.ts +3 -1
  39. package/dist/diagrams/circuit/index.js +1 -1
  40. package/dist/diagrams/ecomap/index.d.cts +1 -1
  41. package/dist/diagrams/ecomap/index.d.ts +1 -1
  42. package/dist/diagrams/entity/index.d.cts +1 -1
  43. package/dist/diagrams/entity/index.d.ts +1 -1
  44. package/dist/diagrams/fishbone/index.d.cts +1 -1
  45. package/dist/diagrams/fishbone/index.d.ts +1 -1
  46. package/dist/diagrams/flowchart/index.d.cts +2 -2
  47. package/dist/diagrams/flowchart/index.d.ts +2 -2
  48. package/dist/diagrams/genogram/index.d.cts +1 -1
  49. package/dist/diagrams/genogram/index.d.ts +1 -1
  50. package/dist/diagrams/ladder/index.d.cts +1 -1
  51. package/dist/diagrams/ladder/index.d.ts +1 -1
  52. package/dist/diagrams/logic/index.d.cts +1 -1
  53. package/dist/diagrams/logic/index.d.ts +1 -1
  54. package/dist/diagrams/orgchart/index.d.cts +1 -1
  55. package/dist/diagrams/orgchart/index.d.ts +1 -1
  56. package/dist/diagrams/pedigree/index.d.cts +1 -1
  57. package/dist/diagrams/pedigree/index.d.ts +1 -1
  58. package/dist/diagrams/phylo/index.d.cts +1 -1
  59. package/dist/diagrams/phylo/index.d.ts +1 -1
  60. package/dist/diagrams/siteplan/index.d.cts +1 -1
  61. package/dist/diagrams/siteplan/index.d.ts +1 -1
  62. package/dist/diagrams/sld/index.cjs +7 -7
  63. package/dist/diagrams/sld/index.d.cts +1 -1
  64. package/dist/diagrams/sld/index.d.ts +1 -1
  65. package/dist/diagrams/sld/index.js +1 -1
  66. package/dist/diagrams/sociogram/index.d.cts +1 -1
  67. package/dist/diagrams/sociogram/index.d.ts +1 -1
  68. package/dist/diagrams/timing/index.d.cts +1 -1
  69. package/dist/diagrams/timing/index.d.ts +1 -1
  70. package/dist/diagrams/venn/index.d.cts +1 -1
  71. package/dist/diagrams/venn/index.d.ts +1 -1
  72. package/dist/{index-CZa2pU0T.d.ts → index-BmJxw0lf.d.ts} +1 -1
  73. package/dist/{index-CDDfbChc.d.cts → index-Dth_Wjwf.d.cts} +1 -1
  74. package/dist/index.cjs +45 -48
  75. package/dist/index.cjs.map +1 -1
  76. package/dist/index.d.cts +4 -4
  77. package/dist/index.d.ts +4 -4
  78. package/dist/index.js +8 -11
  79. package/dist/index.js.map +1 -1
  80. package/dist/react.cjs +4 -4
  81. package/dist/react.d.cts +2 -2
  82. package/dist/react.d.ts +2 -2
  83. package/dist/react.js +3 -3
  84. package/dist/{tools-Bvw6dwIR.d.cts → tools-Bl6w3h3P.d.cts} +2 -2
  85. package/dist/{tools-DtuvE-K4.d.ts → tools-CBYFRF2a.d.ts} +2 -2
  86. package/package.json +1 -1
  87. package/dist/chunk-AG4WA4NF.cjs.map +0 -1
  88. package/dist/chunk-DSKPJYQO.js.map +0 -1
  89. package/dist/chunk-FA6Y4QRS.js.map +0 -1
  90. package/dist/chunk-JWILBXGR.cjs.map +0 -1
@@ -1458,6 +1458,7 @@ var SYMBOLS = {
1458
1458
  voltmeter,
1459
1459
  wattmeter,
1460
1460
  motor,
1461
+ lamp,
1461
1462
  speaker,
1462
1463
  microphone,
1463
1464
  buzzer,
@@ -1519,14 +1520,9 @@ var SYMBOLS = {
1519
1520
  switch_dpdt,
1520
1521
  oscilloscope,
1521
1522
  port
1522
- // Lamp reuses buzzer slot? No, needs its own entry but our CircuitComponentType
1523
- // doesn't have "lamp". We map it via parser alias to "buzzer" or add specifically.
1524
- };
1525
- var EXTRA_SYMBOLS = {
1526
- lamp
1527
1523
  };
1528
1524
  function getSymbol(t) {
1529
- return SYMBOLS[t] ?? EXTRA_SYMBOLS[t];
1525
+ return SYMBOLS[t];
1530
1526
  }
1531
1527
  function getNetlistPinOrder(t) {
1532
1528
  const sym = getSymbol(t);
@@ -1590,7 +1586,10 @@ var TYPE_ALIASES = {
1590
1586
  wireduct: "wire_duct",
1591
1587
  wire_duct: "wire_duct",
1592
1588
  trunking: "wire_duct",
1593
- plc: "plc"
1589
+ plc: "plc",
1590
+ lamp: "lamp",
1591
+ light: "lamp",
1592
+ bulb: "lamp"
1594
1593
  };
1595
1594
  var GROUND_REF = /^(0|gnd|ground|earth|pe|agnd|dgnd|gnda|gndd|vss|com)(_\w+|\d+)?$/i;
1596
1595
  function isGroundRef(s) {
@@ -1885,6 +1884,7 @@ var COMPONENT_TYPES = /* @__PURE__ */ new Set([
1885
1884
  "thermal_overload",
1886
1885
  "disconnect_switch",
1887
1886
  "motor",
1887
+ "lamp",
1888
1888
  "speaker",
1889
1889
  "microphone",
1890
1890
  "buzzer",
@@ -1949,18 +1949,16 @@ var ALIASES = {
1949
1949
  overload: "thermal_overload",
1950
1950
  thermal: "thermal_overload",
1951
1951
  disconnect: "disconnect_switch",
1952
- isolator: "disconnect_switch"
1952
+ isolator: "disconnect_switch",
1953
+ light: "lamp",
1954
+ bulb: "lamp"
1953
1955
  };
1954
- var EXTRA_TYPES = /* @__PURE__ */ new Set(["lamp"]);
1955
1956
  function normalizeType(raw) {
1956
1957
  const lower = raw.toLowerCase();
1957
1958
  if (ALIASES[lower]) return ALIASES[lower];
1958
1959
  if (COMPONENT_TYPES.has(lower)) {
1959
1960
  return lower;
1960
1961
  }
1961
- if (EXTRA_TYPES.has(lower)) {
1962
- return lower;
1963
- }
1964
1962
  return null;
1965
1963
  }
1966
1964
  var DIRECTIONS = /* @__PURE__ */ new Set(["right", "left", "up", "down"]);
@@ -2472,6 +2470,11 @@ var ROW_H = 80;
2472
2470
  var LEFT_MARGIN = 70;
2473
2471
  var TOP_MARGIN = 56;
2474
2472
  var SHUNT_OFFSET = 28;
2473
+ var AC_LEFT_MARGIN = 96;
2474
+ var AC_LIVE_Y = 56;
2475
+ var AC_RETURN_Y = 150;
2476
+ var AC_SERIES_GAP = 58;
2477
+ var AC_TRAVELER_SPAN = 128;
2475
2478
  function isPowerSource(c) {
2476
2479
  return c.componentType === "voltage_source" || c.componentType === "current_source" || c.componentType === "ac_source" || c.componentType === "battery" || c.componentType === "vcc";
2477
2480
  }
@@ -2498,8 +2501,334 @@ function extendBBox(bbox, pt) {
2498
2501
  if (pt.x > bbox.maxX) bbox.maxX = pt.x;
2499
2502
  if (pt.y > bbox.maxY) bbox.maxY = pt.y;
2500
2503
  }
2504
+ function placeComponent(comp, x, y, fallbackDir) {
2505
+ const direction = comp.attrs?.dirExplicit === "true" ? comp.direction : fallbackDir ?? defaultDirection(comp);
2506
+ comp.direction = direction;
2507
+ const rot = rotationOf(direction);
2508
+ const sym = getSymbol(comp.componentType);
2509
+ const worldAnchors = {};
2510
+ if (sym) {
2511
+ for (const [name, pt] of Object.entries(sym.anchors)) {
2512
+ const rp = rotatePt(pt, rot);
2513
+ worldAnchors[name] = { x: x + rp.x, y: y + rp.y };
2514
+ }
2515
+ } else {
2516
+ worldAnchors.start = { x, y };
2517
+ worldAnchors.end = { x: x + 30, y };
2518
+ }
2519
+ return {
2520
+ component: comp,
2521
+ x,
2522
+ y,
2523
+ rotation: rot,
2524
+ length: sym?.length ?? 30,
2525
+ anchors: worldAnchors
2526
+ };
2527
+ }
2528
+ function placeMirroredComponent(comp, x, y) {
2529
+ const sym = getSymbol(comp.componentType);
2530
+ const length = sym?.length ?? 30;
2531
+ const worldAnchors = {};
2532
+ comp.direction = "left";
2533
+ if (sym) {
2534
+ for (const [name, pt] of Object.entries(sym.anchors)) {
2535
+ worldAnchors[name] = { x: x + length - pt.x, y: y + pt.y };
2536
+ }
2537
+ } else {
2538
+ worldAnchors.start = { x: x + length, y };
2539
+ worldAnchors.end = { x, y };
2540
+ }
2541
+ return {
2542
+ component: comp,
2543
+ x,
2544
+ y,
2545
+ rotation: 0,
2546
+ mirrorX: true,
2547
+ length,
2548
+ anchors: worldAnchors
2549
+ };
2550
+ }
2551
+ function pinEntries(pinMap, comp) {
2552
+ return Object.entries(pinMap[comp.id] ?? {});
2553
+ }
2554
+ function anchorForNet(pinMap, laid, netId) {
2555
+ const pin = Object.entries(pinMap[laid.component.id] ?? {}).find(
2556
+ ([, net]) => net === netId
2557
+ )?.[0];
2558
+ return pin ? laid.anchors[pin] : void 0;
2559
+ }
2560
+ function compactPoints(points) {
2561
+ const out = [];
2562
+ for (const p of points) {
2563
+ const prev = out[out.length - 1];
2564
+ if (!prev || Math.abs(prev.x - p.x) > 0.5 || Math.abs(prev.y - p.y) > 0.5) {
2565
+ out.push(p);
2566
+ }
2567
+ }
2568
+ return out;
2569
+ }
2570
+ function routeViaY(netId, a, b, y) {
2571
+ if (Math.abs(a.y - b.y) < 0.5) return { netId, points: [a, b] };
2572
+ return {
2573
+ netId,
2574
+ points: compactPoints([a, { x: a.x, y }, { x: b.x, y }, b])
2575
+ };
2576
+ }
2577
+ function routeViaX(netId, a, b, x) {
2578
+ if (Math.abs(a.x - b.x) < 0.5) return { netId, points: [a, b] };
2579
+ return {
2580
+ netId,
2581
+ points: compactPoints([a, { x, y: a.y }, { x, y: b.y }, b])
2582
+ };
2583
+ }
2584
+ function isAutoGround(c) {
2585
+ return isGround(c) && c.attrs?.auto === "true";
2586
+ }
2587
+ function isTwoTerminal(pinMap, comp) {
2588
+ return pinEntries(pinMap, comp).length === 2;
2589
+ }
2590
+ function isLightingLoad(c) {
2591
+ return c.componentType === "lamp" || c.componentType === "pilot_light" || c.componentType === "motor" || c.componentType === "buzzer" || c.componentType === "speaker";
2592
+ }
2593
+ function traceTwoTerminalChain(pinMap, candidates, startNet, endNet) {
2594
+ const remaining = new Set(candidates.map((c) => c.id));
2595
+ const steps = [];
2596
+ const seenNets = /* @__PURE__ */ new Set([startNet]);
2597
+ let current = startNet;
2598
+ for (let guard = 0; guard <= candidates.length; guard++) {
2599
+ if (current === endNet) return { steps, used: new Set(steps.map((s) => s.comp.id)) };
2600
+ const hits = candidates.filter((c) => {
2601
+ if (!remaining.has(c.id) || !isTwoTerminal(pinMap, c)) return false;
2602
+ return pinEntries(pinMap, c).some(([, net]) => net === current);
2603
+ });
2604
+ if (hits.length !== 1) return null;
2605
+ const comp = hits[0];
2606
+ const nets = pinEntries(pinMap, comp).map(([, net]) => net);
2607
+ const next = nets[0] === current ? nets[1] : nets[0];
2608
+ if (!next || seenNets.has(next) && next !== endNet) return null;
2609
+ steps.push({ comp, inNet: current, outNet: next });
2610
+ remaining.delete(comp.id);
2611
+ seenNets.add(next);
2612
+ current = next;
2613
+ }
2614
+ return null;
2615
+ }
2616
+ function finalizeAutoLayout(items, routes) {
2617
+ const bbox = {
2618
+ minX: Infinity,
2619
+ minY: Infinity,
2620
+ maxX: -Infinity,
2621
+ maxY: -Infinity
2622
+ };
2623
+ for (const it of items) {
2624
+ for (const a of Object.values(it.anchors)) extendBBox(bbox, a);
2625
+ }
2626
+ for (const r of routes) {
2627
+ for (const p of r.points) extendBBox(bbox, p);
2628
+ }
2629
+ if (!isFinite(bbox.minX)) {
2630
+ bbox.minX = 0;
2631
+ bbox.minY = 0;
2632
+ bbox.maxX = 200;
2633
+ bbox.maxY = 200;
2634
+ }
2635
+ const pad = 52;
2636
+ const minX = bbox.minX - pad;
2637
+ const minY = bbox.minY - pad;
2638
+ const maxX = bbox.maxX + pad;
2639
+ const maxY = bbox.maxY + pad;
2640
+ return {
2641
+ width: maxX - minX,
2642
+ height: maxY - minY,
2643
+ offsetX: -minX,
2644
+ offsetY: -minY,
2645
+ items,
2646
+ routes
2647
+ };
2648
+ }
2649
+ function appendReturnRail(routes, pinMap, sourceLaid, loadLaid, returnNet) {
2650
+ const sourceReturn = anchorForNet(pinMap, sourceLaid, returnNet);
2651
+ const loadReturn = anchorForNet(pinMap, loadLaid, returnNet);
2652
+ if (!sourceReturn || !loadReturn) return false;
2653
+ routes.push({
2654
+ netId: returnNet,
2655
+ points: [
2656
+ { x: sourceReturn.x, y: AC_RETURN_Y },
2657
+ { x: loadReturn.x, y: AC_RETURN_Y }
2658
+ ]
2659
+ });
2660
+ routes.push({
2661
+ netId: `${returnNet}.${sourceLaid.component.id}`,
2662
+ points: compactPoints([sourceReturn, { x: sourceReturn.x, y: AC_RETURN_Y }])
2663
+ });
2664
+ routes.push({
2665
+ netId: `${returnNet}.${loadLaid.component.id}`,
2666
+ points: compactPoints([loadReturn, { x: loadReturn.x, y: AC_RETURN_Y }])
2667
+ });
2668
+ return true;
2669
+ }
2670
+ function sourceLiveReturnNets(pinMap, source) {
2671
+ const pins = pinMap[source.id];
2672
+ if (!pins) return null;
2673
+ const liveNet = pins.plus ?? pins.end ?? Object.values(pins)[0];
2674
+ const returnNet = pins.minus ?? pins.start ?? Object.values(pins)[1];
2675
+ if (!liveNet || !returnNet || liveNet === returnNet) return null;
2676
+ return { liveNet, returnNet };
2677
+ }
2678
+ function layoutTwoWireSeriesLoop(ast, source, chain, load, liveNet, returnNet, loadLiveNet) {
2679
+ const pinMap = ast.pinMap ?? {};
2680
+ const items = [];
2681
+ const routes = [];
2682
+ const put = (comp, x, y, fallbackDir) => {
2683
+ const laid = placeComponent(comp, x, y, fallbackDir);
2684
+ items.push(laid);
2685
+ return laid;
2686
+ };
2687
+ const sourceLaid = put(source, AC_LEFT_MARGIN, AC_LIVE_Y + 62, "up");
2688
+ let cursorX = AC_LEFT_MARGIN + 86;
2689
+ let prevPt = anchorForNet(pinMap, sourceLaid, liveNet);
2690
+ if (!prevPt) return null;
2691
+ for (const step of chain) {
2692
+ const laid = put(step.comp, cursorX, AC_LIVE_Y, "right");
2693
+ const inPt = anchorForNet(pinMap, laid, step.inNet);
2694
+ const outPt = anchorForNet(pinMap, laid, step.outNet);
2695
+ if (!inPt || !outPt) return null;
2696
+ routes.push(routeViaY(step.inNet, prevPt, inPt, AC_LIVE_Y));
2697
+ prevPt = outPt;
2698
+ cursorX += laid.length + AC_SERIES_GAP;
2699
+ }
2700
+ const loadLaid = put(load, cursorX, AC_LIVE_Y, "right");
2701
+ const loadLive = anchorForNet(pinMap, loadLaid, loadLiveNet);
2702
+ if (!loadLive) return null;
2703
+ routes.push(routeViaY(loadLiveNet, prevPt, loadLive, AC_LIVE_Y));
2704
+ if (!appendReturnRail(routes, pinMap, sourceLaid, loadLaid, returnNet)) return null;
2705
+ return finalizeAutoLayout(items, routes);
2706
+ }
2707
+ function layoutTwoWayLightingLoop(ast, source, preChain, leftSwitch, rightSwitch, postChain, load, liveNet, returnNet, loadLiveNet) {
2708
+ const pinMap = ast.pinMap ?? {};
2709
+ const leftPins = pinMap[leftSwitch.id] ?? {};
2710
+ const rightPins = pinMap[rightSwitch.id] ?? {};
2711
+ const travelerNets = [leftPins.nc, leftPins.no].filter(Boolean);
2712
+ if (travelerNets.length !== 2 || !travelerNets.every((n) => n === rightPins.nc || n === rightPins.no)) {
2713
+ return null;
2714
+ }
2715
+ const items = [];
2716
+ const routes = [];
2717
+ const put = (comp, x, y, fallbackDir) => {
2718
+ const laid = placeComponent(comp, x, y, fallbackDir);
2719
+ items.push(laid);
2720
+ return laid;
2721
+ };
2722
+ const sourceLaid = put(source, AC_LEFT_MARGIN, AC_LIVE_Y + 62, "up");
2723
+ let cursorX = AC_LEFT_MARGIN + 86;
2724
+ let prevPt = anchorForNet(pinMap, sourceLaid, liveNet);
2725
+ if (!prevPt) return null;
2726
+ for (const step of preChain) {
2727
+ const laid = put(step.comp, cursorX, AC_LIVE_Y, "right");
2728
+ const inPt = anchorForNet(pinMap, laid, step.inNet);
2729
+ const outPt = anchorForNet(pinMap, laid, step.outNet);
2730
+ if (!inPt || !outPt) return null;
2731
+ routes.push(routeViaY(step.inNet, prevPt, inPt, AC_LIVE_Y));
2732
+ prevPt = outPt;
2733
+ cursorX += laid.length + AC_SERIES_GAP;
2734
+ }
2735
+ const leftLaid = put(leftSwitch, cursorX, AC_LIVE_Y, "right");
2736
+ const leftCommon = leftLaid.anchors.common;
2737
+ if (!leftCommon) return null;
2738
+ routes.push(routeViaY(leftPins.common ?? liveNet, prevPt, leftCommon, AC_LIVE_Y));
2739
+ const rightCommonX = leftLaid.x + leftLaid.length + AC_TRAVELER_SPAN + leftLaid.length;
2740
+ const sameTravelerOrder = leftPins.nc === rightPins.nc && leftPins.no === rightPins.no;
2741
+ const rightLength = getSymbol(rightSwitch.componentType)?.length ?? 30;
2742
+ const rightLaid = sameTravelerOrder ? placeMirroredComponent(rightSwitch, rightCommonX - rightLength, AC_LIVE_Y) : placeComponent(rightSwitch, rightCommonX, AC_LIVE_Y, "left");
2743
+ items.push(rightLaid);
2744
+ for (const net of travelerNets) {
2745
+ const a = anchorForNet(pinMap, leftLaid, net);
2746
+ const b = anchorForNet(pinMap, rightLaid, net);
2747
+ if (!a || !b) return null;
2748
+ routes.push(routeViaX(net, a, b, (a.x + b.x) / 2));
2749
+ }
2750
+ prevPt = rightLaid.anchors.common;
2751
+ if (!prevPt) return null;
2752
+ cursorX = rightCommonX + AC_SERIES_GAP;
2753
+ for (const step of postChain) {
2754
+ const laid = put(step.comp, cursorX, AC_LIVE_Y, "right");
2755
+ const inPt = anchorForNet(pinMap, laid, step.inNet);
2756
+ const outPt = anchorForNet(pinMap, laid, step.outNet);
2757
+ if (!inPt || !outPt) return null;
2758
+ routes.push(routeViaY(step.inNet, prevPt, inPt, AC_LIVE_Y));
2759
+ prevPt = outPt;
2760
+ cursorX += laid.length + AC_SERIES_GAP;
2761
+ }
2762
+ const loadLaid = put(load, cursorX, AC_LIVE_Y, "right");
2763
+ const loadLive = anchorForNet(pinMap, loadLaid, loadLiveNet);
2764
+ if (!loadLive) return null;
2765
+ routes.push(routeViaY(loadLiveNet, prevPt, loadLive, AC_LIVE_Y));
2766
+ if (!appendReturnRail(routes, pinMap, sourceLaid, loadLaid, returnNet)) return null;
2767
+ return finalizeAutoLayout(items, routes);
2768
+ }
2769
+ function tryLayoutTwoWireLighting(ast) {
2770
+ const pinMap = ast.pinMap ?? {};
2771
+ const sources = ast.components.filter(isPowerSource);
2772
+ if (sources.length !== 1) return null;
2773
+ const source = sources[0];
2774
+ const nets = sourceLiveReturnNets(pinMap, source);
2775
+ if (!nets || nets.liveNet === "GND" || nets.returnNet === "GND") return null;
2776
+ const { liveNet, returnNet } = nets;
2777
+ const loads = ast.components.filter((c) => {
2778
+ if (!isLightingLoad(c)) return false;
2779
+ const pins = pinEntries(pinMap, c);
2780
+ return pins.length === 2 && pins.some(([, net]) => net === returnNet);
2781
+ });
2782
+ if (loads.length !== 1) return null;
2783
+ const load = loads[0];
2784
+ const loadLiveNet = pinEntries(pinMap, load).find(([, net]) => net !== returnNet)?.[1];
2785
+ if (!loadLiveNet) return null;
2786
+ const excluded = /* @__PURE__ */ new Set([source.id, load.id]);
2787
+ const middle = ast.components.filter((c) => !excluded.has(c.id) && !isAutoGround(c));
2788
+ const spdts = middle.filter((c) => c.componentType === "switch_spdt");
2789
+ if (spdts.length === 0) {
2790
+ if (!middle.every((c) => isTwoTerminal(pinMap, c))) return null;
2791
+ const traced = traceTwoTerminalChain(pinMap, middle, liveNet, loadLiveNet);
2792
+ if (!traced || traced.used.size !== middle.length) return null;
2793
+ return layoutTwoWireSeriesLoop(ast, source, traced.steps, load, liveNet, returnNet, loadLiveNet);
2794
+ }
2795
+ if (spdts.length === 2) {
2796
+ const twoTerminal = middle.filter((c) => c.componentType !== "switch_spdt");
2797
+ if (!twoTerminal.every((c) => isTwoTerminal(pinMap, c))) return null;
2798
+ for (const [leftSwitch, rightSwitch] of [
2799
+ [spdts[0], spdts[1]],
2800
+ [spdts[1], spdts[0]]
2801
+ ]) {
2802
+ const leftCommon = pinMap[leftSwitch.id]?.common;
2803
+ const rightCommon = pinMap[rightSwitch.id]?.common;
2804
+ if (!leftCommon || !rightCommon) continue;
2805
+ const pre = traceTwoTerminalChain(pinMap, twoTerminal, liveNet, leftCommon);
2806
+ if (!pre) continue;
2807
+ const postCandidates = twoTerminal.filter((c) => !pre.used.has(c.id));
2808
+ const post = traceTwoTerminalChain(pinMap, postCandidates, rightCommon, loadLiveNet);
2809
+ if (!post) continue;
2810
+ if (pre.used.size + post.used.size !== twoTerminal.length) continue;
2811
+ const rendered = layoutTwoWayLightingLoop(
2812
+ ast,
2813
+ source,
2814
+ pre.steps,
2815
+ leftSwitch,
2816
+ rightSwitch,
2817
+ post.steps,
2818
+ load,
2819
+ liveNet,
2820
+ returnNet,
2821
+ loadLiveNet
2822
+ );
2823
+ if (rendered) return rendered;
2824
+ }
2825
+ }
2826
+ return null;
2827
+ }
2501
2828
  function layoutCircuitNetlist(ast) {
2502
2829
  const pinMap = ast.pinMap ?? {};
2830
+ const twoWireLighting = tryLayoutTwoWireLighting(ast);
2831
+ if (twoWireLighting) return twoWireLighting;
2503
2832
  const isShunt = (c) => {
2504
2833
  if (isPowerSource(c) || isGround(c)) return false;
2505
2834
  const pins = pinMap[c.id];
@@ -2521,28 +2850,7 @@ function layoutCircuitNetlist(ast) {
2521
2850
  const placed = /* @__PURE__ */ new Map();
2522
2851
  const items = [];
2523
2852
  const place = (comp, x, y, fallbackDir) => {
2524
- const direction = comp.attrs?.dirExplicit === "true" ? comp.direction : fallbackDir ?? defaultDirection(comp);
2525
- comp.direction = direction;
2526
- const rot = rotationOf(direction);
2527
- const sym = getSymbol(comp.componentType);
2528
- const worldAnchors = {};
2529
- if (sym) {
2530
- for (const [name, pt] of Object.entries(sym.anchors)) {
2531
- const rp = rotatePt(pt, rot);
2532
- worldAnchors[name] = { x: x + rp.x, y: y + rp.y };
2533
- }
2534
- } else {
2535
- worldAnchors.start = { x, y };
2536
- worldAnchors.end = { x: x + 30, y };
2537
- }
2538
- const laid = {
2539
- component: comp,
2540
- x,
2541
- y,
2542
- rotation: rot,
2543
- length: sym?.length ?? 30,
2544
- anchors: worldAnchors
2545
- };
2853
+ const laid = placeComponent(comp, x, y, fallbackDir);
2546
2854
  items.push(laid);
2547
2855
  placed.set(comp.id, laid);
2548
2856
  return laid;
@@ -2759,20 +3067,21 @@ function renderItem(it, offX, offY) {
2759
3067
  return `<rect x="${tx - 10}" y="${ty - 10}" width="20" height="20" fill="none" class="schematex-circuit-err" stroke-dasharray="3,2"/><text x="${tx}" y="${ty + 3}" text-anchor="middle" font-size="9" class="schematex-circuit-err">?${escapeXml(comp.componentType)}</text>`;
2760
3068
  }
2761
3069
  const body = sym.svg(comp.label, comp.value, comp.attrs);
2762
- const transform = `translate(${tx}, ${ty}) rotate(${it.rotation})`;
3070
+ const transform = it.mirrorX ? `translate(${tx + it.length}, ${ty}) scale(-1, 1)` : `translate(${tx}, ${ty}) rotate(${it.rotation})`;
2763
3071
  const labels = [];
2764
3072
  if (comp.label || comp.value) {
2765
- const labelX = it.x + offX + it.length * Math.cos(it.rotation * Math.PI / 180) / 2;
2766
- const labelY = it.y + offY + it.length * Math.sin(it.rotation * Math.PI / 180) / 2;
2767
- const perpDX = Math.sin(it.rotation * Math.PI / 180);
2768
- const perpDY = -Math.cos(it.rotation * Math.PI / 180);
2769
- const off = 16;
3073
+ const angle = it.rotation * Math.PI / 180;
3074
+ const midpointX = it.x + offX + it.length * Math.cos(angle) / 2;
3075
+ const midpointY = it.y + offY + it.length * Math.sin(angle) / 2;
3076
+ const vertical = Math.abs(Math.sin(angle)) > 0.5;
3077
+ const labelX = midpointX + (vertical ? 34 : 0);
3078
+ const labelY = midpointY - (vertical ? 2 : 18);
2770
3079
  if (comp.label) {
2771
3080
  labels.push(
2772
3081
  text(
2773
3082
  {
2774
- x: labelX + perpDX * off,
2775
- y: labelY + perpDY * off - 2,
3083
+ x: labelX,
3084
+ y: labelY,
2776
3085
  class: "schematex-circuit-label",
2777
3086
  "text-anchor": "middle"
2778
3087
  },
@@ -2784,8 +3093,8 @@ function renderItem(it, offX, offY) {
2784
3093
  labels.push(
2785
3094
  text(
2786
3095
  {
2787
- x: labelX + perpDX * off,
2788
- y: labelY + perpDY * off + 10,
3096
+ x: labelX,
3097
+ y: labelY + 12,
2789
3098
  class: "schematex-circuit-value",
2790
3099
  "text-anchor": "middle"
2791
3100
  },
@@ -2882,6 +3191,6 @@ var circuit = {
2882
3191
  }
2883
3192
  };
2884
3193
 
2885
- export { EXTRA_SYMBOLS, SYMBOLS, circuit, layoutCircuit, layoutCircuitNetlist, lintCircuit, parseCircuit, parseNetlist, renderCircuit };
2886
- //# sourceMappingURL=chunk-FA6Y4QRS.js.map
2887
- //# sourceMappingURL=chunk-FA6Y4QRS.js.map
3194
+ export { SYMBOLS, circuit, layoutCircuit, layoutCircuitNetlist, lintCircuit, parseCircuit, parseNetlist, renderCircuit };
3195
+ //# sourceMappingURL=chunk-5IPT6OFE.js.map
3196
+ //# sourceMappingURL=chunk-5IPT6OFE.js.map