@tscircuit/pcb-viewer 1.11.352 → 1.11.354

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -22,6 +22,7 @@ interface State {
22
22
  is_showing_pcb_groups: boolean;
23
23
  is_showing_group_anchor_offsets: boolean;
24
24
  is_showing_solder_mask: boolean;
25
+ is_showing_silkscreen: boolean;
25
26
  is_showing_fabrication_notes: boolean;
26
27
  pcb_group_view_mode: "all" | "named_only";
27
28
  hovered_error_id: string | null;
@@ -39,6 +40,7 @@ interface State {
39
40
  setIsShowingPcbGroups: (is_showing: boolean) => void;
40
41
  setIsShowingGroupAnchorOffsets: (is_showing: boolean) => void;
41
42
  setIsShowingSolderMask: (is_showing: boolean) => void;
43
+ setIsShowingSilkscreen: (is_showing: boolean) => void;
42
44
  setIsShowingFabricationNotes: (is_showing: boolean) => void;
43
45
  setPcbGroupViewMode: (mode: "all" | "named_only") => void;
44
46
  setHoveredErrorId: (errorId: string | null) => void;
package/dist/index.js CHANGED
@@ -5572,6 +5572,34 @@ var cju = (circuitJsonInput, options = {}) => {
5572
5572
  if (prop === "subtree") {
5573
5573
  return (opts) => cju(buildSubtree(circuitJson, opts), options);
5574
5574
  }
5575
+ if (prop === "insert") {
5576
+ return (elm) => {
5577
+ const component_type2 = elm.type;
5578
+ if (!component_type2) {
5579
+ throw new Error("insert requires an element with a type");
5580
+ }
5581
+ internalStore.counts[component_type2] ??= -1;
5582
+ internalStore.counts[component_type2]++;
5583
+ const index = internalStore.counts[component_type2];
5584
+ const newElm = {
5585
+ ...elm,
5586
+ type: component_type2,
5587
+ [`${component_type2}_id`]: `${component_type2}_${index}`
5588
+ };
5589
+ if (options.validateInserts) {
5590
+ const parser = Soup[component_type2] ?? Soup.any_soup_element;
5591
+ parser.parse(newElm);
5592
+ }
5593
+ circuitJson.push(newElm);
5594
+ internalStore.editCount++;
5595
+ return newElm;
5596
+ };
5597
+ }
5598
+ if (prop === "insertAll") {
5599
+ return (elms) => {
5600
+ return elms.map((elm) => su2.insert(elm));
5601
+ };
5602
+ }
5575
5603
  const component_type = prop;
5576
5604
  return {
5577
5605
  get: (id) => circuitJson.find(
@@ -6199,6 +6227,43 @@ var getElementId = (elm) => {
6199
6227
  const id = elm[`${type}_id`];
6200
6228
  return id;
6201
6229
  };
6230
+ var mergeBounds = (currentBounds, nextBounds) => ({
6231
+ minX: Math.min(currentBounds.minX, nextBounds.minX),
6232
+ minY: Math.min(currentBounds.minY, nextBounds.minY),
6233
+ maxX: Math.max(currentBounds.maxX, nextBounds.maxX),
6234
+ maxY: Math.max(currentBounds.maxY, nextBounds.maxY)
6235
+ });
6236
+ var getCircleBounds = (x, y, diameter) => {
6237
+ const radius = diameter / 2;
6238
+ return {
6239
+ minX: x - radius,
6240
+ minY: y - radius,
6241
+ maxX: x + radius,
6242
+ maxY: y + radius
6243
+ };
6244
+ };
6245
+ var getRotatedRectBounds = (x, y, width, height, rotationDegrees) => {
6246
+ const halfWidth = width / 2;
6247
+ const halfHeight = height / 2;
6248
+ const theta = rotationDegrees * Math.PI / 180;
6249
+ const cosTheta = Math.cos(theta);
6250
+ const sinTheta = Math.sin(theta);
6251
+ const corners = [
6252
+ { x: -halfWidth, y: -halfHeight },
6253
+ { x: halfWidth, y: -halfHeight },
6254
+ { x: halfWidth, y: halfHeight },
6255
+ { x: -halfWidth, y: halfHeight }
6256
+ ].map((corner) => ({
6257
+ x: x + corner.x * cosTheta - corner.y * sinTheta,
6258
+ y: y + corner.x * sinTheta + corner.y * cosTheta
6259
+ }));
6260
+ return {
6261
+ minX: Math.min(...corners.map((corner) => corner.x)),
6262
+ minY: Math.min(...corners.map((corner) => corner.y)),
6263
+ maxX: Math.max(...corners.map((corner) => corner.x)),
6264
+ maxY: Math.max(...corners.map((corner) => corner.y))
6265
+ };
6266
+ };
6202
6267
  var getBoundsOfPcbElements = (elements) => {
6203
6268
  let minX = Number.POSITIVE_INFINITY;
6204
6269
  let minY = Number.POSITIVE_INFINITY;
@@ -6215,6 +6280,47 @@ var getBoundsOfPcbElements = (elements) => {
6215
6280
  }
6216
6281
  continue;
6217
6282
  }
6283
+ if (elm.type === "pcb_hole" && elm.hole_shape === "circle") {
6284
+ const holeBounds = getCircleBounds(elm.x, elm.y, elm.hole_diameter);
6285
+ minX = Math.min(minX, holeBounds.minX);
6286
+ minY = Math.min(minY, holeBounds.minY);
6287
+ maxX = Math.max(maxX, holeBounds.maxX);
6288
+ maxY = Math.max(maxY, holeBounds.maxY);
6289
+ continue;
6290
+ }
6291
+ if (elm.type === "pcb_plated_hole") {
6292
+ let platedHoleBounds;
6293
+ if ("outer_diameter" in elm && typeof elm.outer_diameter === "number") {
6294
+ platedHoleBounds = getCircleBounds(elm.x, elm.y, elm.outer_diameter);
6295
+ } else if ("hole_diameter" in elm && typeof elm.hole_diameter === "number") {
6296
+ platedHoleBounds = getCircleBounds(elm.x, elm.y, elm.hole_diameter);
6297
+ }
6298
+ if ("rect_pad_width" in elm && typeof elm.rect_pad_width === "number" && "rect_pad_height" in elm && typeof elm.rect_pad_height === "number") {
6299
+ const rectBounds = getRotatedRectBounds(
6300
+ elm.x,
6301
+ elm.y,
6302
+ elm.rect_pad_width,
6303
+ elm.rect_pad_height,
6304
+ "rect_ccw_rotation" in elm ? elm.rect_ccw_rotation ?? 0 : 0
6305
+ );
6306
+ platedHoleBounds = platedHoleBounds ? mergeBounds(platedHoleBounds, rectBounds) : rectBounds;
6307
+ }
6308
+ if ("hole_diameter" in elm && typeof elm.hole_diameter === "number") {
6309
+ const drillBounds = getCircleBounds(
6310
+ elm.x + ("hole_offset_x" in elm ? elm.hole_offset_x ?? 0 : 0),
6311
+ elm.y + ("hole_offset_y" in elm ? elm.hole_offset_y ?? 0 : 0),
6312
+ elm.hole_diameter
6313
+ );
6314
+ platedHoleBounds = platedHoleBounds ? mergeBounds(platedHoleBounds, drillBounds) : drillBounds;
6315
+ }
6316
+ if (platedHoleBounds) {
6317
+ minX = Math.min(minX, platedHoleBounds.minX);
6318
+ minY = Math.min(minY, platedHoleBounds.minY);
6319
+ maxX = Math.max(maxX, platedHoleBounds.maxX);
6320
+ maxY = Math.max(maxY, platedHoleBounds.maxY);
6321
+ continue;
6322
+ }
6323
+ }
6218
6324
  let centerX;
6219
6325
  let centerY;
6220
6326
  let width;
@@ -6261,6 +6367,20 @@ var getBoundsOfPcbElements = (elements) => {
6261
6367
  maxX = Math.max(maxX, point.x);
6262
6368
  maxY = Math.max(maxY, point.y);
6263
6369
  }
6370
+ } else if (elm.type === "pcb_courtyard_outline") {
6371
+ for (const point of elm.outline) {
6372
+ minX = Math.min(minX, point.x);
6373
+ minY = Math.min(minY, point.y);
6374
+ maxX = Math.max(maxX, point.x);
6375
+ maxY = Math.max(maxY, point.y);
6376
+ }
6377
+ } else if (elm.type === "pcb_courtyard_polygon") {
6378
+ for (const point of elm.points) {
6379
+ minX = Math.min(minX, point.x);
6380
+ minY = Math.min(minY, point.y);
6381
+ maxX = Math.max(maxX, point.x);
6382
+ maxY = Math.max(maxY, point.y);
6383
+ }
6264
6384
  }
6265
6385
  }
6266
6386
  return { minX, minY, maxX, maxY };
@@ -6477,7 +6597,8 @@ var STORAGE_KEYS = {
6477
6597
  IS_SHOWING_COURTYARDS: "pcb_viewer_is_showing_courtyards",
6478
6598
  IS_SHOWING_GROUP_ANCHOR_OFFSETS: "pcb_viewer_is_showing_group_anchor_offsets",
6479
6599
  IS_SHOWING_SOLDER_MASK: "pcb_viewer_is_showing_solder_mask",
6480
- IS_SHOWING_FABRICATION_NOTES: "pcb_viewer_is_showing_fabrication_notes"
6600
+ IS_SHOWING_FABRICATION_NOTES: "pcb_viewer_is_showing_fabrication_notes",
6601
+ IS_SHOWING_SILKSCREEN: "pcb_viewer_is_showing_silkscreen"
6481
6602
  };
6482
6603
  var getStoredBoolean = (key, defaultValue) => {
6483
6604
  if (typeof window === "undefined") return defaultValue;
@@ -6545,6 +6666,10 @@ var createStore = (initialState = {}, disablePcbGroups = false) => createZustand
6545
6666
  STORAGE_KEYS.IS_SHOWING_SOLDER_MASK,
6546
6667
  false
6547
6668
  ),
6669
+ is_showing_silkscreen: getStoredBoolean(
6670
+ STORAGE_KEYS.IS_SHOWING_SILKSCREEN,
6671
+ true
6672
+ ),
6548
6673
  is_showing_fabrication_notes: getStoredBoolean(
6549
6674
  STORAGE_KEYS.IS_SHOWING_FABRICATION_NOTES,
6550
6675
  false
@@ -6594,6 +6719,10 @@ var createStore = (initialState = {}, disablePcbGroups = false) => createZustand
6594
6719
  setStoredBoolean(STORAGE_KEYS.IS_SHOWING_SOLDER_MASK, is_showing);
6595
6720
  set({ is_showing_solder_mask: is_showing });
6596
6721
  },
6722
+ setIsShowingSilkscreen: (is_showing) => {
6723
+ setStoredBoolean(STORAGE_KEYS.IS_SHOWING_SILKSCREEN, is_showing);
6724
+ set({ is_showing_silkscreen: is_showing });
6725
+ },
6597
6726
  setIsShowingFabricationNotes: (is_showing) => {
6598
6727
  setStoredBoolean(
6599
6728
  STORAGE_KEYS.IS_SHOWING_FABRICATION_NOTES,
@@ -9906,9 +10035,8 @@ var CanvasPrimitiveRenderer = ({
9906
10035
  const isShowingFabricationNotes = useGlobalStore(
9907
10036
  (s) => s.is_showing_fabrication_notes
9908
10037
  );
9909
- const isShowingCourtyards = useGlobalStore(
9910
- (s) => s.is_showing_courtyards
9911
- );
10038
+ const isShowingCourtyards = useGlobalStore((s) => s.is_showing_courtyards);
10039
+ const isShowingSilkscreen = useGlobalStore((s) => s.is_showing_silkscreen);
9912
10040
  useEffect5(() => {
9913
10041
  if (!canvasRefs.current) return;
9914
10042
  if (Object.keys(canvasRefs.current).length === 0) return;
@@ -9923,7 +10051,7 @@ var CanvasPrimitiveRenderer = ({
9923
10051
  if (transform) drawer.transform = transform;
9924
10052
  drawer.clear();
9925
10053
  drawer.foregroundLayer = selectedLayer;
9926
- const filteredPrimitives = primitives.filter((p) => isShowingSolderMask || !p.layer?.includes("soldermask")).filter(
10054
+ const filteredPrimitives = primitives.filter((p) => isShowingSolderMask || !p.layer?.includes("soldermask")).filter((p) => isShowingSilkscreen || !p.layer?.includes("silkscreen")).filter(
9927
10055
  (p) => isShowingFabricationNotes || !p.layer?.includes("fabrication")
9928
10056
  ).filter((p) => p.layer !== "board").filter((p) => p._element?.type !== "pcb_smtpad").filter((p) => p._element?.type !== "pcb_plated_hole").filter((p) => p._element?.type !== "pcb_via").filter((p) => p._element?.type !== "pcb_trace");
9929
10057
  drawPrimitives(drawer, filteredPrimitives);
@@ -10077,23 +10205,25 @@ var CanvasPrimitiveRenderer = ({
10077
10205
  realToCanvasMat: transform
10078
10206
  });
10079
10207
  }
10080
- const topSilkscreenCanvas = canvasRefs.current.top_silkscreen;
10081
- if (topSilkscreenCanvas) {
10082
- drawSilkscreenElementsForLayer({
10083
- canvas: topSilkscreenCanvas,
10084
- elements,
10085
- layers: ["top_silkscreen"],
10086
- realToCanvasMat: transform
10087
- });
10088
- }
10089
- const bottomSilkscreenCanvas = canvasRefs.current.bottom_silkscreen;
10090
- if (bottomSilkscreenCanvas) {
10091
- drawSilkscreenElementsForLayer({
10092
- canvas: bottomSilkscreenCanvas,
10093
- elements,
10094
- layers: ["bottom_silkscreen"],
10095
- realToCanvasMat: transform
10096
- });
10208
+ if (isShowingSilkscreen) {
10209
+ const topSilkscreenCanvas = canvasRefs.current.top_silkscreen;
10210
+ if (topSilkscreenCanvas) {
10211
+ drawSilkscreenElementsForLayer({
10212
+ canvas: topSilkscreenCanvas,
10213
+ elements,
10214
+ layers: ["top_silkscreen"],
10215
+ realToCanvasMat: transform
10216
+ });
10217
+ }
10218
+ const bottomSilkscreenCanvas = canvasRefs.current.bottom_silkscreen;
10219
+ if (bottomSilkscreenCanvas) {
10220
+ drawSilkscreenElementsForLayer({
10221
+ canvas: bottomSilkscreenCanvas,
10222
+ elements,
10223
+ layers: ["bottom_silkscreen"],
10224
+ realToCanvasMat: transform
10225
+ });
10226
+ }
10097
10227
  }
10098
10228
  if (isShowingFabricationNotes) {
10099
10229
  const topFabCanvas = canvasRefs.current.top_fabrication;
@@ -10201,7 +10331,8 @@ var CanvasPrimitiveRenderer = ({
10201
10331
  selectedLayer,
10202
10332
  isShowingSolderMask,
10203
10333
  isShowingFabricationNotes,
10204
- isShowingCourtyards
10334
+ isShowingCourtyards,
10335
+ isShowingSilkscreen
10205
10336
  ]);
10206
10337
  return /* @__PURE__ */ jsxs(
10207
10338
  "div",
@@ -10227,9 +10358,8 @@ var CanvasPrimitiveRenderer = ({
10227
10358
  }
10228
10359
  ),
10229
10360
  orderedLayers.filter((layer) => {
10230
- if (!isShowingSolderMask) {
10231
- return !layer.includes("soldermask");
10232
- }
10361
+ if (!isShowingSolderMask && layer.includes("soldermask")) return false;
10362
+ if (!isShowingSilkscreen && layer.includes("silkscreen")) return false;
10233
10363
  return true;
10234
10364
  }).map((l) => l.replace(/-/g, "")).map((layer, i) => /* @__PURE__ */ jsx3(
10235
10365
  "canvas",
@@ -14241,7 +14371,7 @@ import { css as css3 } from "@emotion/css";
14241
14371
  // package.json
14242
14372
  var package_default = {
14243
14373
  name: "@tscircuit/pcb-viewer",
14244
- version: "1.11.351",
14374
+ version: "1.11.353",
14245
14375
  main: "dist/index.js",
14246
14376
  type: "module",
14247
14377
  repository: "tscircuit/pcb-viewer",
@@ -14265,7 +14395,7 @@ var package_default = {
14265
14395
  "@semantic-release/npm": "^9.0.1",
14266
14396
  "@semantic-release/release-notes-generator": "^10.0.3",
14267
14397
  "@swc/core": "^1.4.12",
14268
- "@tscircuit/circuit-json-util": "^0.0.78",
14398
+ "@tscircuit/circuit-json-util": "^0.0.90",
14269
14399
  "@tscircuit/eagle-xml-converter": "^1.0.0",
14270
14400
  "@types/bun": "latest",
14271
14401
  "@types/color": "^3.0.6",
@@ -14278,7 +14408,7 @@ var package_default = {
14278
14408
  "react-cosmos-plugin-vite": "7.0.0-beta.0",
14279
14409
  "react-dom": "19.1.0",
14280
14410
  "react-use": "^17.4.0",
14281
- tscircuit: "^0.0.1421",
14411
+ tscircuit: "^0.0.1517",
14282
14412
  tsup: "^8.0.2",
14283
14413
  "type-fest": "^3.0.0",
14284
14414
  typescript: "^5.4.4",
@@ -14294,9 +14424,9 @@ var package_default = {
14294
14424
  "@tscircuit/alphabet": "^0.0.22",
14295
14425
  "@tscircuit/math-utils": "^0.0.29",
14296
14426
  "@vitejs/plugin-react": "^5.0.2",
14297
- "circuit-json": "^0.0.387",
14298
- "circuit-to-canvas": "^0.0.92",
14299
- "circuit-to-svg": "^0.0.323",
14427
+ "circuit-json": "^0.0.403",
14428
+ "circuit-to-canvas": "^0.0.93",
14429
+ "circuit-to-svg": "^0.0.337",
14300
14430
  color: "^4.2.3",
14301
14431
  "react-supergrid": "^1.0.10",
14302
14432
  "react-toastify": "^10.0.5",
@@ -14579,6 +14709,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14579
14709
  setIsShowingPcbGroups,
14580
14710
  setIsShowingGroupAnchorOffsets,
14581
14711
  setIsShowingSolderMask,
14712
+ setIsShowingSilkscreen,
14582
14713
  setIsShowingFabricationNotes,
14583
14714
  setPcbGroupViewMode,
14584
14715
  setHoveredErrorId
@@ -14601,6 +14732,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14601
14732
  is_showing_pcb_groups: s.is_showing_pcb_groups,
14602
14733
  is_showing_group_anchor_offsets: s.is_showing_group_anchor_offsets,
14603
14734
  is_showing_solder_mask: s.is_showing_solder_mask,
14735
+ is_showing_silkscreen: s.is_showing_silkscreen,
14604
14736
  is_showing_fabrication_notes: s.is_showing_fabrication_notes,
14605
14737
  pcb_group_view_mode: s.pcb_group_view_mode
14606
14738
  },
@@ -14614,6 +14746,7 @@ var ToolbarOverlay = ({ children, elements }) => {
14614
14746
  setIsShowingPcbGroups: s.setIsShowingPcbGroups,
14615
14747
  setIsShowingGroupAnchorOffsets: s.setIsShowingGroupAnchorOffsets,
14616
14748
  setIsShowingSolderMask: s.setIsShowingSolderMask,
14749
+ setIsShowingSilkscreen: s.setIsShowingSilkscreen,
14617
14750
  setIsShowingFabricationNotes: s.setIsShowingFabricationNotes,
14618
14751
  setPcbGroupViewMode: s.setPcbGroupViewMode,
14619
14752
  setHoveredErrorId: s.setHoveredErrorId
@@ -15178,6 +15311,16 @@ var ToolbarOverlay = ({ children, elements }) => {
15178
15311
  }
15179
15312
  }
15180
15313
  ),
15314
+ /* @__PURE__ */ jsx20(
15315
+ CheckboxMenuItem,
15316
+ {
15317
+ label: "Show Silkscreen",
15318
+ checked: viewSettings.is_showing_silkscreen,
15319
+ onClick: () => {
15320
+ setIsShowingSilkscreen(!viewSettings.is_showing_silkscreen);
15321
+ }
15322
+ }
15323
+ ),
15181
15324
  /* @__PURE__ */ jsx20(
15182
15325
  CheckboxMenuItem,
15183
15326
  {