@tscircuit/schematic-viewer 2.0.37 → 2.0.39

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
@@ -220,206 +220,218 @@ var GROUP_COLORS = [
220
220
  var useSchematicGroupsOverlay = (options) => {
221
221
  const { svgDivRef, circuitJson, circuitJsonKey, showGroups } = options;
222
222
  useEffect3(() => {
223
- if (!svgDivRef.current || !showGroups || !circuitJson || circuitJson.length === 0) {
224
- if (svgDivRef.current) {
225
- const existingOverlays2 = svgDivRef.current.querySelectorAll(
226
- ".schematic-group-overlay"
227
- );
228
- existingOverlays2.forEach((overlay) => overlay.remove());
229
- }
230
- return;
223
+ if (svgDivRef.current) {
224
+ const existingOverlays = svgDivRef.current.querySelectorAll(
225
+ ".schematic-group-overlay"
226
+ );
227
+ existingOverlays.forEach((overlay) => overlay.remove());
231
228
  }
232
- const svg = svgDivRef.current.querySelector("svg");
233
- if (!svg) {
229
+ if (!svgDivRef.current || !showGroups || !circuitJson || circuitJson.length === 0) {
234
230
  return;
235
231
  }
236
- const existingOverlays = svg.querySelectorAll(".schematic-group-overlay");
237
- existingOverlays.forEach((overlay) => overlay.remove());
238
- try {
239
- const sourceGroups = su3(circuitJson).source_group?.list().filter((x) => !!!x.is_subcircuit) || [];
240
- const schematicComponents = su3(circuitJson).schematic_component?.list() || [];
241
- const sourceGroupHierarchy = /* @__PURE__ */ new Map();
242
- sourceGroups.forEach((group) => {
243
- const groupWithParent = group;
244
- if (groupWithParent.parent_source_group_id) {
245
- const children = sourceGroupHierarchy.get(groupWithParent.parent_source_group_id) || [];
246
- children.push(group.source_group_id);
247
- sourceGroupHierarchy.set(
248
- groupWithParent.parent_source_group_id,
249
- children
250
- );
251
- }
252
- });
253
- const getAllDescendantSourceGroups = (sourceGroupId) => {
254
- const descendants = [];
255
- const children = sourceGroupHierarchy.get(sourceGroupId) || [];
256
- for (const child of children) {
257
- descendants.push(child);
258
- descendants.push(...getAllDescendantSourceGroups(child));
259
- }
260
- return descendants;
261
- };
262
- const getGroupDepthLevel = (sourceGroupId) => {
263
- const groupWithParent = sourceGroups.find(
264
- (g) => g.source_group_id === sourceGroupId
265
- );
266
- if (!groupWithParent?.parent_source_group_id) {
267
- return 0;
268
- }
269
- return 1 + getGroupDepthLevel(groupWithParent.parent_source_group_id);
270
- };
271
- const hasMeaningfulGroups = sourceGroups.length > 0 && sourceGroups.some((group) => group.name && group.name.trim() !== "");
272
- let groupsToRender = [];
273
- if (hasMeaningfulGroups) {
274
- const groupMap = /* @__PURE__ */ new Map();
275
- for (const comp of schematicComponents) {
276
- const sourceComp = su3(circuitJson).source_component.get(
277
- comp.source_component_id
232
+ const timeoutId = setTimeout(() => {
233
+ if (!svgDivRef.current) return;
234
+ const svg = svgDivRef.current.querySelector("svg");
235
+ if (!svg) {
236
+ return;
237
+ }
238
+ const existingOverlays = svg.querySelectorAll(".schematic-group-overlay");
239
+ existingOverlays.forEach((overlay) => overlay.remove());
240
+ try {
241
+ const sourceGroups = su3(circuitJson).source_group?.list().filter((x) => !!!x.is_subcircuit) || [];
242
+ const schematicComponents = su3(circuitJson).schematic_component?.list() || [];
243
+ const sourceGroupHierarchy = /* @__PURE__ */ new Map();
244
+ sourceGroups.forEach((group) => {
245
+ const groupWithParent = group;
246
+ if (groupWithParent.parent_source_group_id) {
247
+ const children = sourceGroupHierarchy.get(
248
+ groupWithParent.parent_source_group_id
249
+ ) || [];
250
+ children.push(group.source_group_id);
251
+ sourceGroupHierarchy.set(
252
+ groupWithParent.parent_source_group_id,
253
+ children
254
+ );
255
+ }
256
+ });
257
+ const getAllDescendantSourceGroups = (sourceGroupId) => {
258
+ const descendants = [];
259
+ const children = sourceGroupHierarchy.get(sourceGroupId) || [];
260
+ for (const child of children) {
261
+ descendants.push(child);
262
+ descendants.push(...getAllDescendantSourceGroups(child));
263
+ }
264
+ return descendants;
265
+ };
266
+ const getGroupDepthLevel = (sourceGroupId) => {
267
+ const groupWithParent = sourceGroups.find(
268
+ (g) => g.source_group_id === sourceGroupId
278
269
  );
279
- if (sourceComp?.source_group_id) {
280
- if (!groupMap.has(sourceComp.source_group_id)) {
281
- groupMap.set(sourceComp.source_group_id, []);
270
+ if (!groupWithParent?.parent_source_group_id) {
271
+ return 0;
272
+ }
273
+ return 1 + getGroupDepthLevel(groupWithParent.parent_source_group_id);
274
+ };
275
+ const hasMeaningfulGroups = sourceGroups.length > 0 && sourceGroups.some((group) => group.name && group.name.trim() !== "");
276
+ let groupsToRender = [];
277
+ if (hasMeaningfulGroups) {
278
+ const groupMap = /* @__PURE__ */ new Map();
279
+ for (const comp of schematicComponents) {
280
+ const sourceComp = su3(circuitJson).source_component.get(
281
+ comp.source_component_id
282
+ );
283
+ if (sourceComp?.source_group_id) {
284
+ if (!groupMap.has(sourceComp.source_group_id)) {
285
+ groupMap.set(sourceComp.source_group_id, []);
286
+ }
287
+ groupMap.get(sourceComp.source_group_id).push(comp);
282
288
  }
283
- groupMap.get(sourceComp.source_group_id).push(comp);
284
289
  }
290
+ sourceGroups.forEach((group, index) => {
291
+ let groupComponents = groupMap.get(group.source_group_id) || [];
292
+ const descendantGroups = getAllDescendantSourceGroups(
293
+ group.source_group_id
294
+ );
295
+ for (const descendantGroupId of descendantGroups) {
296
+ const descendantComponents = groupMap.get(descendantGroupId) || [];
297
+ groupComponents = [...groupComponents, ...descendantComponents];
298
+ }
299
+ if (groupComponents.length > 0) {
300
+ const depthLevel = getGroupDepthLevel(group.source_group_id);
301
+ const hasChildren = getAllDescendantSourceGroups(group.source_group_id).length > 0;
302
+ if (group.name?.startsWith("unnamed_board")) return;
303
+ groupsToRender.push({
304
+ id: group.source_group_id,
305
+ name: group.name || `Group ${index + 1}`,
306
+ components: groupComponents,
307
+ color: GROUP_COLORS[index % GROUP_COLORS.length],
308
+ depthLevel,
309
+ hasChildren,
310
+ sourceGroupId: group.source_group_id
311
+ });
312
+ }
313
+ });
285
314
  }
286
- sourceGroups.forEach((group, index) => {
287
- let groupComponents = groupMap.get(group.source_group_id) || [];
288
- const descendantGroups = getAllDescendantSourceGroups(
289
- group.source_group_id
315
+ const viewBox = svg.viewBox.baseVal;
316
+ const svgRect = svg.getBoundingClientRect();
317
+ const scale = Math.min(
318
+ svgRect.width / viewBox.width,
319
+ svgRect.height / viewBox.height
320
+ ) || 1;
321
+ groupsToRender.sort((a, b) => a.depthLevel - b.depthLevel);
322
+ groupsToRender.forEach((group) => {
323
+ if (group.components.length === 0) return;
324
+ const groupBounds = calculateGroupBounds(group.components, svg);
325
+ if (!groupBounds) return;
326
+ const basePadding = Math.max(
327
+ 8,
328
+ Math.min(25, 15 / Math.max(scale, 0.3))
290
329
  );
291
- for (const descendantGroupId of descendantGroups) {
292
- const descendantComponents = groupMap.get(descendantGroupId) || [];
293
- groupComponents = [...groupComponents, ...descendantComponents];
294
- }
295
- if (groupComponents.length > 0) {
296
- const depthLevel = getGroupDepthLevel(group.source_group_id);
297
- const hasChildren = getAllDescendantSourceGroups(group.source_group_id).length > 0;
298
- if (group.name?.startsWith("unnamed_board")) return;
299
- groupsToRender.push({
300
- id: group.source_group_id,
301
- name: group.name || `Group ${index + 1}`,
302
- components: groupComponents,
303
- color: GROUP_COLORS[index % GROUP_COLORS.length],
304
- depthLevel,
305
- hasChildren,
306
- sourceGroupId: group.source_group_id
307
- });
308
- }
330
+ const hierarchyPadding = group.hasChildren ? basePadding * 0.6 : 0;
331
+ const totalPadding = basePadding + hierarchyPadding;
332
+ const baseStrokeWidth = Math.max(1, 2 / Math.max(scale, 0.5));
333
+ const strokeWidth = group.depthLevel === 0 ? baseStrokeWidth : baseStrokeWidth * 0.7;
334
+ const baseDashSize = Math.max(4, 8 / Math.max(scale, 0.5));
335
+ const dashMultiplier = group.hasChildren ? 1.3 : 1;
336
+ const dashSize = baseDashSize * dashMultiplier;
337
+ const gapSize = dashSize * 0.5;
338
+ const groupOverlay = document.createElementNS(
339
+ "http://www.w3.org/2000/svg",
340
+ "rect"
341
+ );
342
+ groupOverlay.setAttribute("class", "schematic-group-overlay");
343
+ groupOverlay.setAttribute(
344
+ "x",
345
+ (groupBounds.minX - totalPadding).toString()
346
+ );
347
+ groupOverlay.setAttribute(
348
+ "y",
349
+ (groupBounds.minY - totalPadding).toString()
350
+ );
351
+ groupOverlay.setAttribute(
352
+ "width",
353
+ (groupBounds.maxX - groupBounds.minX + totalPadding * 2).toString()
354
+ );
355
+ groupOverlay.setAttribute(
356
+ "height",
357
+ (groupBounds.maxY - groupBounds.minY + totalPadding * 2).toString()
358
+ );
359
+ groupOverlay.setAttribute("fill", "none");
360
+ groupOverlay.setAttribute("stroke", group.color);
361
+ groupOverlay.setAttribute("stroke-width", strokeWidth.toString());
362
+ groupOverlay.setAttribute(
363
+ "stroke-dasharray",
364
+ `${dashSize},${gapSize}`
365
+ );
366
+ groupOverlay.setAttribute("opacity", "0.8");
367
+ groupOverlay.setAttribute("rx", "4");
368
+ groupOverlay.setAttribute("ry", "4");
369
+ const baseFontSize = Math.max(
370
+ 6,
371
+ Math.min(20, 14 / Math.max(scale, 0.2))
372
+ );
373
+ const fontSizeReduction = group.depthLevel === 0 || group.depthLevel === 1 ? 0 : group.depthLevel * 0.2;
374
+ const fontSize = baseFontSize * (1 - fontSizeReduction);
375
+ const labelPadding = Math.max(1, fontSize * 0.2);
376
+ const labelText = group.name;
377
+ const tempText = document.createElementNS(
378
+ "http://www.w3.org/2000/svg",
379
+ "text"
380
+ );
381
+ tempText.setAttribute("font-size", fontSize.toString());
382
+ tempText.setAttribute("font-family", "Arial, sans-serif");
383
+ tempText.textContent = labelText;
384
+ svg.appendChild(tempText);
385
+ const textBBox = tempText.getBBox();
386
+ svg.removeChild(tempText);
387
+ const labelWidth = textBBox.width + labelPadding * 2;
388
+ const labelHeight = fontSize + labelPadding * 2;
389
+ const labelX = groupBounds.minX - totalPadding;
390
+ const labelY = groupBounds.minY - totalPadding - labelHeight;
391
+ const labelBg = document.createElementNS(
392
+ "http://www.w3.org/2000/svg",
393
+ "rect"
394
+ );
395
+ labelBg.setAttribute("class", "schematic-group-overlay");
396
+ labelBg.setAttribute("x", labelX.toString());
397
+ labelBg.setAttribute("y", (labelY - labelHeight).toString());
398
+ labelBg.setAttribute("width", labelWidth.toString());
399
+ labelBg.setAttribute("height", labelHeight.toString());
400
+ labelBg.setAttribute("fill", "transparent");
401
+ labelBg.setAttribute("rx", "3");
402
+ labelBg.setAttribute("ry", "3");
403
+ const groupLabel = document.createElementNS(
404
+ "http://www.w3.org/2000/svg",
405
+ "text"
406
+ );
407
+ groupLabel.setAttribute("class", "schematic-group-overlay");
408
+ groupLabel.setAttribute("x", (labelX + labelPadding).toString());
409
+ groupLabel.setAttribute(
410
+ "y",
411
+ (labelY + labelHeight - labelPadding).toString()
412
+ );
413
+ groupLabel.setAttribute("fill", group.color);
414
+ groupLabel.setAttribute("font-size", fontSize.toString());
415
+ groupLabel.setAttribute("font-family", "Arial, sans-serif");
416
+ groupLabel.setAttribute(
417
+ "font-weight",
418
+ group.depthLevel === 0 ? "600" : "500"
419
+ );
420
+ groupLabel.setAttribute("stroke", group.color);
421
+ groupLabel.setAttribute(
422
+ "stroke-width",
423
+ Math.max(0.2, fontSize * 0.02).toString()
424
+ );
425
+ groupLabel.textContent = labelText;
426
+ svg.appendChild(groupOverlay);
427
+ svg.appendChild(labelBg);
428
+ svg.appendChild(groupLabel);
309
429
  });
430
+ } catch (error) {
431
+ console.error("Error creating group overlays:", error);
310
432
  }
311
- const viewBox = svg.viewBox.baseVal;
312
- const svgRect = svg.getBoundingClientRect();
313
- const scale = Math.min(
314
- svgRect.width / viewBox.width,
315
- svgRect.height / viewBox.height
316
- ) || 1;
317
- groupsToRender.sort((a, b) => a.depthLevel - b.depthLevel);
318
- groupsToRender.forEach((group) => {
319
- if (group.components.length === 0) return;
320
- const groupBounds = calculateGroupBounds(group.components, svg);
321
- if (!groupBounds) return;
322
- const basePadding = Math.max(8, Math.min(25, 15 / Math.max(scale, 0.3)));
323
- const hierarchyPadding = group.hasChildren ? basePadding * 0.6 : 0;
324
- const totalPadding = basePadding + hierarchyPadding;
325
- const baseStrokeWidth = Math.max(1, 2 / Math.max(scale, 0.5));
326
- const strokeWidth = group.depthLevel === 0 ? baseStrokeWidth : baseStrokeWidth * 0.7;
327
- const baseDashSize = Math.max(4, 8 / Math.max(scale, 0.5));
328
- const dashMultiplier = group.hasChildren ? 1.3 : 1;
329
- const dashSize = baseDashSize * dashMultiplier;
330
- const gapSize = dashSize * 0.5;
331
- const groupOverlay = document.createElementNS(
332
- "http://www.w3.org/2000/svg",
333
- "rect"
334
- );
335
- groupOverlay.setAttribute("class", "schematic-group-overlay");
336
- groupOverlay.setAttribute(
337
- "x",
338
- (groupBounds.minX - totalPadding).toString()
339
- );
340
- groupOverlay.setAttribute(
341
- "y",
342
- (groupBounds.minY - totalPadding).toString()
343
- );
344
- groupOverlay.setAttribute(
345
- "width",
346
- (groupBounds.maxX - groupBounds.minX + totalPadding * 2).toString()
347
- );
348
- groupOverlay.setAttribute(
349
- "height",
350
- (groupBounds.maxY - groupBounds.minY + totalPadding * 2).toString()
351
- );
352
- groupOverlay.setAttribute("fill", "none");
353
- groupOverlay.setAttribute("stroke", group.color);
354
- groupOverlay.setAttribute("stroke-width", strokeWidth.toString());
355
- groupOverlay.setAttribute("stroke-dasharray", `${dashSize},${gapSize}`);
356
- groupOverlay.setAttribute("opacity", "0.8");
357
- groupOverlay.setAttribute("rx", "4");
358
- groupOverlay.setAttribute("ry", "4");
359
- const baseFontSize = Math.max(
360
- 6,
361
- Math.min(20, 14 / Math.max(scale, 0.2))
362
- );
363
- const fontSizeReduction = group.depthLevel === 0 || group.depthLevel === 1 ? 0 : group.depthLevel * 0.2;
364
- const fontSize = baseFontSize * (1 - fontSizeReduction);
365
- const labelPadding = Math.max(1, fontSize * 0.2);
366
- const labelText = group.name;
367
- const tempText = document.createElementNS(
368
- "http://www.w3.org/2000/svg",
369
- "text"
370
- );
371
- tempText.setAttribute("font-size", fontSize.toString());
372
- tempText.setAttribute("font-family", "Arial, sans-serif");
373
- tempText.textContent = labelText;
374
- svg.appendChild(tempText);
375
- const textBBox = tempText.getBBox();
376
- svg.removeChild(tempText);
377
- const labelWidth = textBBox.width + labelPadding * 2;
378
- const labelHeight = fontSize + labelPadding * 2;
379
- const labelX = groupBounds.minX - totalPadding;
380
- const labelY = groupBounds.minY - totalPadding - labelHeight;
381
- const labelBg = document.createElementNS(
382
- "http://www.w3.org/2000/svg",
383
- "rect"
384
- );
385
- labelBg.setAttribute("class", "schematic-group-overlay");
386
- labelBg.setAttribute("x", labelX.toString());
387
- labelBg.setAttribute("y", (labelY - labelHeight).toString());
388
- labelBg.setAttribute("width", labelWidth.toString());
389
- labelBg.setAttribute("height", labelHeight.toString());
390
- labelBg.setAttribute("fill", "transparent");
391
- labelBg.setAttribute("rx", "3");
392
- labelBg.setAttribute("ry", "3");
393
- const groupLabel = document.createElementNS(
394
- "http://www.w3.org/2000/svg",
395
- "text"
396
- );
397
- groupLabel.setAttribute("class", "schematic-group-overlay");
398
- groupLabel.setAttribute("x", (labelX + labelPadding).toString());
399
- groupLabel.setAttribute(
400
- "y",
401
- (labelY + labelHeight - labelPadding).toString()
402
- );
403
- groupLabel.setAttribute("fill", group.color);
404
- groupLabel.setAttribute("font-size", fontSize.toString());
405
- groupLabel.setAttribute("font-family", "Arial, sans-serif");
406
- groupLabel.setAttribute(
407
- "font-weight",
408
- group.depthLevel === 0 ? "600" : "500"
409
- );
410
- groupLabel.setAttribute("stroke", group.color);
411
- groupLabel.setAttribute(
412
- "stroke-width",
413
- Math.max(0.2, fontSize * 0.02).toString()
414
- );
415
- groupLabel.textContent = labelText;
416
- svg.appendChild(groupOverlay);
417
- svg.appendChild(labelBg);
418
- svg.appendChild(groupLabel);
419
- });
420
- } catch (error) {
421
- console.error("Error creating group overlays:", error);
422
- }
433
+ }, 10);
434
+ return () => clearTimeout(timeoutId);
423
435
  }, [svgDivRef, circuitJsonKey, showGroups]);
424
436
  };
425
437
  function calculateGroupBounds(components, svg) {
@@ -677,7 +689,7 @@ var zIndexMap = {
677
689
  schematicGridIcon: 49,
678
690
  spiceSimulationIcon: 50,
679
691
  viewMenuIcon: 48,
680
- viewMenu: 50,
692
+ viewMenu: 55,
681
693
  viewMenuBackdrop: 54,
682
694
  clickToInteractOverlay: 100
683
695
  };
@@ -834,7 +846,7 @@ import { su as su5 } from "@tscircuit/soup-util";
834
846
  // package.json
835
847
  var package_default = {
836
848
  name: "@tscircuit/schematic-viewer",
837
- version: "2.0.36",
849
+ version: "2.0.38",
838
850
  main: "dist/index.js",
839
851
  type: "module",
840
852
  scripts: {