@industry-theme/file-city-panel 0.2.29 → 0.2.30

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.
@@ -1 +1 @@
1
- {"version":3,"file":"CodeCityPanel.d.ts","sourceRoot":"","sources":["../../src/panels/CodeCityPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAuBjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAQpD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA2wCD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAEvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EA8BxC,CAAC"}
1
+ {"version":3,"file":"CodeCityPanel.d.ts","sourceRoot":"","sources":["../../src/panels/CodeCityPanel.tsx"],"names":[],"mappings":"AAAA,OAAO,KAA4D,MAAM,OAAO,CAAC;AAuBjF,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAQpD;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,QAAQ,EAAE,MAAM,EAAE,CAAC;IACnB,SAAS,EAAE,MAAM,EAAE,CAAC;IACpB,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB;AA4wCD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CAEvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,oBAAoB,EAAE,KAAK,CAAC,EA8BxC,CAAC"}
@@ -4283,6 +4283,58 @@ function requireArchitectureMapHighlightLayers() {
4283
4283
  this.grid.clear();
4284
4284
  }
4285
4285
  }
4286
+ class PathHierarchyLookup {
4287
+ constructor(paths) {
4288
+ this.abstractedPaths = paths instanceof Set ? paths : new Set(paths);
4289
+ }
4290
+ /**
4291
+ * Check if the given path is inside any abstracted directory.
4292
+ * Walks up the path hierarchy checking each ancestor.
4293
+ * Complexity: O(depth) where depth is the path depth, instead of O(A) for each abstracted path.
4294
+ */
4295
+ isPathAbstracted(path) {
4296
+ if (this.abstractedPaths.has("")) {
4297
+ return true;
4298
+ }
4299
+ let currentPath = path;
4300
+ while (currentPath.includes("/")) {
4301
+ currentPath = currentPath.substring(0, currentPath.lastIndexOf("/"));
4302
+ if (this.abstractedPaths.has(currentPath)) {
4303
+ return true;
4304
+ }
4305
+ }
4306
+ return false;
4307
+ }
4308
+ /**
4309
+ * Check if the path is a direct child of an abstracted directory
4310
+ * (the path itself is abstracted, not just its ancestors).
4311
+ */
4312
+ isDirectlyAbstracted(path) {
4313
+ return this.abstractedPaths.has(path);
4314
+ }
4315
+ /**
4316
+ * Check if the path is a child (not itself) of any abstracted directory.
4317
+ */
4318
+ isChildOfAbstracted(path) {
4319
+ if (!path)
4320
+ return false;
4321
+ if (this.abstractedPaths.has("")) {
4322
+ return true;
4323
+ }
4324
+ for (const abstractedPath of this.abstractedPaths) {
4325
+ if (abstractedPath && path.startsWith(abstractedPath + "/")) {
4326
+ return true;
4327
+ }
4328
+ }
4329
+ return false;
4330
+ }
4331
+ get size() {
4332
+ return this.abstractedPaths.size;
4333
+ }
4334
+ has(path) {
4335
+ return this.abstractedPaths.has(path);
4336
+ }
4337
+ }
4286
4338
  function ArchitectureMapHighlightLayersInner({
4287
4339
  cityData,
4288
4340
  highlightLayers = [],
@@ -4295,6 +4347,7 @@ function requireArchitectureMapHighlightLayers() {
4295
4347
  zoomToPath = null,
4296
4348
  onZoomComplete,
4297
4349
  zoomAnimationSpeed = 0.12,
4350
+ allowZoomToPath = true,
4298
4351
  fullSize = false,
4299
4352
  showGrid = false,
4300
4353
  showFileNames = false,
@@ -4336,20 +4389,28 @@ function requireArchitectureMapHighlightLayers() {
4336
4389
  hasMouseMoved: false
4337
4390
  });
4338
4391
  const [targetZoom, setTargetZoom] = (0, react_1.useState)(null);
4392
+ const [stableZoomScale, setStableZoomScale] = (0, react_1.useState)(1);
4393
+ const stableZoomTimeoutRef = (0, react_1.useRef)(null);
4394
+ const isAnimating = targetZoom !== null;
4339
4395
  const lastZoomToPathRef = (0, react_1.useRef)(null);
4340
4396
  (0, react_1.useEffect)(() => {
4341
4397
  if (!enableZoom) {
4342
4398
  setZoomState((prev) => ({
4343
4399
  ...prev,
4344
- scale: 1,
4345
- offsetX: 0,
4346
- offsetY: 0,
4347
4400
  isDragging: false,
4348
4401
  hasMouseMoved: false
4349
4402
  }));
4403
+ }
4404
+ if (!enableZoom && !allowZoomToPath) {
4405
+ setZoomState((prev) => ({
4406
+ ...prev,
4407
+ scale: 1,
4408
+ offsetX: 0,
4409
+ offsetY: 0
4410
+ }));
4350
4411
  setTargetZoom(null);
4351
4412
  }
4352
- }, [enableZoom]);
4413
+ }, [enableZoom, allowZoomToPath]);
4353
4414
  (0, react_1.useEffect)(() => {
4354
4415
  if (!targetZoom)
4355
4416
  return;
@@ -4384,6 +4445,27 @@ function requireArchitectureMapHighlightLayers() {
4384
4445
  const frameId = requestAnimationFrame(animate);
4385
4446
  return () => cancelAnimationFrame(frameId);
4386
4447
  }, [targetZoom, zoomState, zoomAnimationSpeed, onZoomComplete]);
4448
+ (0, react_1.useEffect)(() => {
4449
+ if (stableZoomTimeoutRef.current) {
4450
+ clearTimeout(stableZoomTimeoutRef.current);
4451
+ }
4452
+ if (isAnimating) {
4453
+ return;
4454
+ }
4455
+ stableZoomTimeoutRef.current = setTimeout(() => {
4456
+ setStableZoomScale(zoomState.scale);
4457
+ }, 100);
4458
+ return () => {
4459
+ if (stableZoomTimeoutRef.current) {
4460
+ clearTimeout(stableZoomTimeoutRef.current);
4461
+ }
4462
+ };
4463
+ }, [zoomState.scale, isAnimating]);
4464
+ (0, react_1.useEffect)(() => {
4465
+ if (!isAnimating && targetZoom === null) {
4466
+ setStableZoomScale(zoomState.scale);
4467
+ }
4468
+ }, [isAnimating, targetZoom, zoomState.scale]);
4387
4469
  const [hitTestCache, setHitTestCache] = (0, react_1.useState)(null);
4388
4470
  const calculateCanvasResolution = (fileCount, _cityBounds) => {
4389
4471
  const minSize = 400;
@@ -4421,7 +4503,7 @@ function requireArchitectureMapHighlightLayers() {
4421
4503
  return filteredCityData;
4422
4504
  }, [subdirectoryMode == null ? void 0 : subdirectoryMode.enabled, subdirectoryMode == null ? void 0 : subdirectoryMode.autoCenter, cityData, filteredCityData]);
4423
4505
  (0, react_1.useEffect)(() => {
4424
- if (!enableZoom || zoomToPath === lastZoomToPathRef.current) {
4506
+ if (!allowZoomToPath || zoomToPath === lastZoomToPathRef.current) {
4425
4507
  return;
4426
4508
  }
4427
4509
  lastZoomToPathRef.current = zoomToPath;
@@ -4483,7 +4565,7 @@ function requireArchitectureMapHighlightLayers() {
4483
4565
  });
4484
4566
  }, [
4485
4567
  zoomToPath,
4486
- enableZoom,
4568
+ allowZoomToPath,
4487
4569
  filteredCityData,
4488
4570
  canvasSizingData,
4489
4571
  canvasSize,
@@ -4491,17 +4573,9 @@ function requireArchitectureMapHighlightLayers() {
4491
4573
  ]);
4492
4574
  const buildHitTestCache = (0, react_1.useCallback)((cityData2, scale, offsetX, offsetZ, zoomState2, abstractedPaths) => {
4493
4575
  const spatialGrid = new SpatialGrid(cityData2.bounds);
4576
+ const pathLookup = new PathHierarchyLookup(abstractedPaths);
4494
4577
  cityData2.buildings.forEach((building) => {
4495
- let currentPath = building.path;
4496
- let isAbstracted = false;
4497
- while (currentPath.includes("/")) {
4498
- currentPath = currentPath.substring(0, currentPath.lastIndexOf("/"));
4499
- if (abstractedPaths.has(currentPath)) {
4500
- isAbstracted = true;
4501
- break;
4502
- }
4503
- }
4504
- if (!isAbstracted) {
4578
+ if (!pathLookup.isPathAbstracted(building.path)) {
4505
4579
  spatialGrid.addBuilding(building);
4506
4580
  }
4507
4581
  });
@@ -4510,14 +4584,7 @@ function requireArchitectureMapHighlightLayers() {
4510
4584
  spatialGrid.addDistrict(district);
4511
4585
  return;
4512
4586
  }
4513
- let isChildOfAbstracted = false;
4514
- for (const abstractedPath of abstractedPaths) {
4515
- if (abstractedPath && district.path.startsWith(abstractedPath + "/")) {
4516
- isChildOfAbstracted = true;
4517
- break;
4518
- }
4519
- }
4520
- if (!isChildOfAbstracted) {
4587
+ if (!pathLookup.isChildOfAbstracted(district.path)) {
4521
4588
  spatialGrid.addDistrict(district);
4522
4589
  }
4523
4590
  });
@@ -4532,6 +4599,7 @@ function requireArchitectureMapHighlightLayers() {
4532
4599
  zoomOffsetY: zoomState2.offsetY
4533
4600
  },
4534
4601
  abstractedPaths,
4602
+ pathLookup,
4535
4603
  timestamp: Date.now()
4536
4604
  };
4537
4605
  }, []);
@@ -4551,7 +4619,7 @@ function requireArchitectureMapHighlightLayers() {
4551
4619
  }
4552
4620
  const config = abstractionLayerDef.abstractionConfig;
4553
4621
  const maxZoomForAbstraction = (config == null ? void 0 : config.maxZoomLevel) ?? 5;
4554
- if (zoomState.scale > maxZoomForAbstraction) {
4622
+ if (stableZoomScale > maxZoomForAbstraction) {
4555
4623
  return null;
4556
4624
  }
4557
4625
  const abstractedItems = [];
@@ -4560,7 +4628,7 @@ function requireArchitectureMapHighlightLayers() {
4560
4628
  const displayHeight = canvasRef.current.clientHeight || canvasSize.height;
4561
4629
  const coordinateSystemData = (subdirectoryMode == null ? void 0 : subdirectoryMode.enabled) && subdirectoryMode.autoCenter !== true && cityData ? cityData : filteredCityData;
4562
4630
  const { scale } = calculateScaleAndOffset(coordinateSystemData, displayWidth, displayHeight, displayOptions.padding);
4563
- const totalScale = scale * zoomState.scale;
4631
+ const totalScale = scale * stableZoomScale;
4564
4632
  const highlightedPaths = /* @__PURE__ */ new Set();
4565
4633
  allLayersWithoutAbstraction.forEach((layer) => {
4566
4634
  if (layer.enabled && layer.id !== "directory-abstraction") {
@@ -4715,7 +4783,8 @@ ${projectInfo.currentBranch}`;
4715
4783
  filteredCityData,
4716
4784
  canvasSize,
4717
4785
  displayOptions.padding,
4718
- zoomState.scale,
4786
+ stableZoomScale,
4787
+ // Use stable zoom scale instead of live zoomState.scale
4719
4788
  subdirectoryMode,
4720
4789
  cityData,
4721
4790
  allLayersWithoutAbstraction
@@ -4745,13 +4814,22 @@ ${projectInfo.currentBranch}`;
4745
4814
  }
4746
4815
  });
4747
4816
  }
4748
- const newCache = buildHitTestCache(filteredCityData, scale, offsetX, offsetZ, zoomState, abstractedPaths);
4817
+ const stableZoomState = {
4818
+ scale: stableZoomScale,
4819
+ offsetX: 0,
4820
+ offsetY: 0,
4821
+ isDragging: false,
4822
+ lastMousePos: { x: 0, y: 0 },
4823
+ hasMouseMoved: false
4824
+ };
4825
+ const newCache = buildHitTestCache(filteredCityData, scale, offsetX, offsetZ, stableZoomState, abstractedPaths);
4749
4826
  setHitTestCache(newCache);
4750
4827
  }, [
4751
4828
  filteredCityData,
4752
4829
  canvasSize,
4753
4830
  displayOptions.padding,
4754
- zoomState,
4831
+ stableZoomScale,
4832
+ // Only rebuild when zoom stabilizes
4755
4833
  buildHitTestCache,
4756
4834
  abstractionLayer
4757
4835
  ]);
@@ -4788,21 +4866,17 @@ ${projectInfo.currentBranch}`;
4788
4866
  }
4789
4867
  });
4790
4868
  }
4791
- let visibleDistricts = abstractedPathsForDistricts.size > 0 ? filteredCityData.districts.filter((district) => {
4792
- if (abstractedPathsForDistricts.has("")) {
4869
+ const pathLookup = new PathHierarchyLookup(abstractedPathsForDistricts);
4870
+ let visibleDistricts = pathLookup.size > 0 ? filteredCityData.districts.filter((district) => {
4871
+ if (pathLookup.has("")) {
4793
4872
  return !district.path || district.path === "";
4794
4873
  }
4795
4874
  if (!district.path)
4796
4875
  return true;
4797
- if (abstractedPathsForDistricts.has(district.path)) {
4876
+ if (pathLookup.has(district.path)) {
4798
4877
  return true;
4799
4878
  }
4800
- for (const abstractedPath of abstractedPathsForDistricts) {
4801
- if (district.path.startsWith(abstractedPath + "/")) {
4802
- return false;
4803
- }
4804
- }
4805
- return true;
4879
+ return !pathLookup.isChildOfAbstracted(district.path);
4806
4880
  }) : filteredCityData.districts;
4807
4881
  if (abstractedPathsForDistricts.has("")) {
4808
4882
  const hasRootDistrict = visibleDistricts.some((d) => !d.path || d.path === "");
@@ -4834,47 +4908,9 @@ ${projectInfo.currentBranch}`;
4834
4908
  showDirectoryLabels,
4835
4909
  districtBorderRadius
4836
4910
  );
4837
- const abstractedPaths = /* @__PURE__ */ new Set();
4838
- const activeAbstractionLayer = allLayers.find((l) => l.id === "directory-abstraction");
4839
- if (activeAbstractionLayer && activeAbstractionLayer.enabled) {
4840
- activeAbstractionLayer.items.forEach((item) => {
4841
- if (item.type === "directory") {
4842
- abstractedPaths.add(item.path);
4843
- }
4844
- });
4845
- }
4846
- const visibleBuildings = abstractedPaths.size > 0 ? filteredCityData.buildings.filter((building) => {
4847
- if (abstractedPaths.has("")) {
4848
- return false;
4849
- }
4850
- const buildingDir = building.path.substring(0, building.path.lastIndexOf("/")) || "";
4851
- for (const abstractedPath of abstractedPaths) {
4852
- if (buildingDir === abstractedPath) {
4853
- return false;
4854
- }
4855
- if (buildingDir.startsWith(abstractedPath + "/")) {
4856
- return false;
4857
- }
4858
- }
4859
- return true;
4911
+ const visibleBuildings = pathLookup.size > 0 ? filteredCityData.buildings.filter((building) => {
4912
+ return !pathLookup.isPathAbstracted(building.path);
4860
4913
  }) : filteredCityData.buildings;
4861
- if (abstractedPaths.size > 0) {
4862
- const suspiciousBuildings = visibleBuildings.filter((building) => {
4863
- const buildingDir = building.path.substring(0, building.path.lastIndexOf("/")) || "";
4864
- for (const abstractedPath of abstractedPaths) {
4865
- if (buildingDir === abstractedPath || buildingDir.startsWith(abstractedPath + "/")) {
4866
- return true;
4867
- }
4868
- }
4869
- return false;
4870
- });
4871
- if (suspiciousBuildings.length > 0) {
4872
- console.error(`[Building Filter] WARNING: ${suspiciousBuildings.length} buildings are being rendered in abstracted directories!`);
4873
- suspiciousBuildings.slice(0, 3).forEach((building) => {
4874
- console.error(` - ${building.path}`);
4875
- });
4876
- }
4877
- }
4878
4914
  (0, drawLayeredBuildings_1.drawLayeredBuildings)(ctx, visibleBuildings, worldToCanvas, scale * zoomState.scale, allLayers, interactionState.hoveredBuilding, resolvedDefaultBuildingColor, showFileNames, resolvedHoverBorderColor, disableOpacityDimming, showFileTypeIcons, buildingBorderRadius);
4879
4915
  }, [
4880
4916
  filteredCityData,
@@ -17339,7 +17375,8 @@ const CodeCityPanelContent = ({
17339
17375
  className: "w-full h-full",
17340
17376
  showDirectoryLabels: true,
17341
17377
  onHover: handleHover,
17342
- enableZoom: true,
17378
+ enableZoom: false,
17379
+ allowZoomToPath: true,
17343
17380
  zoomToPath,
17344
17381
  onZoomComplete: handleZoomComplete,
17345
17382
  zoomAnimationSpeed: 0.12