@principal-ai/file-city-react 0.5.37 → 0.5.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/components/FileCity3D/FileCity3D.d.ts +77 -1
- package/dist/components/FileCity3D/FileCity3D.d.ts.map +1 -1
- package/dist/components/FileCity3D/FileCity3D.js +149 -14
- package/dist/components/FileCity3D/index.d.ts +2 -2
- package/dist/components/FileCity3D/index.d.ts.map +1 -1
- package/dist/components/FileCity3D/index.js +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/package.json +2 -1
- package/src/components/FileCity3D/FileCity3D.tsx +308 -8
- package/src/components/FileCity3D/index.ts +7 -0
- package/src/index.ts +1 -0
- package/src/stories/FileCity3D.stories.tsx +669 -0
- package/src/stories/ScopeOverlay.stories.tsx +1687 -0
|
@@ -35,6 +35,42 @@ export interface AnimationConfig {
|
|
|
35
35
|
}
|
|
36
36
|
/** Height scaling mode for buildings */
|
|
37
37
|
export type HeightScaling = 'logarithmic' | 'linear';
|
|
38
|
+
/**
|
|
39
|
+
* An opaque slab rendered above the flat city to visualize scope coverage.
|
|
40
|
+
* Only renders when the city is in 2D (flat) mode — in 3D the buildings show
|
|
41
|
+
* through normally. When opaque, the slab's depth value occludes buildings and
|
|
42
|
+
* icons beneath its `bounds`, so the scope reads as a single colored tile.
|
|
43
|
+
*/
|
|
44
|
+
export interface ElevatedScopePanel {
|
|
45
|
+
/** Unique identifier (used as React key) */
|
|
46
|
+
id: string;
|
|
47
|
+
/** Hex color */
|
|
48
|
+
color: string;
|
|
49
|
+
/** 0–1 opacity. Default 1 (fully opaque). */
|
|
50
|
+
opacity?: number;
|
|
51
|
+
/** Y position (world units) above the ground when flat. Default 4. */
|
|
52
|
+
height?: number;
|
|
53
|
+
/** Slab thickness in world units (default 2) */
|
|
54
|
+
thickness?: number;
|
|
55
|
+
/** World-space bounds the slab covers */
|
|
56
|
+
bounds: {
|
|
57
|
+
minX: number;
|
|
58
|
+
maxX: number;
|
|
59
|
+
minZ: number;
|
|
60
|
+
maxZ: number;
|
|
61
|
+
};
|
|
62
|
+
/** Optional label rendered flat on top of the slab. */
|
|
63
|
+
label?: string;
|
|
64
|
+
/** Hex color for the label (default white). */
|
|
65
|
+
labelColor?: string;
|
|
66
|
+
/**
|
|
67
|
+
* Absolute label font size in world units. When omitted, falls back to a
|
|
68
|
+
* size derived from the panel's footprint. Always clamped to fit the tile.
|
|
69
|
+
*/
|
|
70
|
+
labelSize?: number;
|
|
71
|
+
/** Click handler. When set, the slab becomes interactive and shows a pointer cursor. */
|
|
72
|
+
onClick?: () => void;
|
|
73
|
+
}
|
|
38
74
|
/** Pattern for files that should render flat (e.g., lock files, generated files) */
|
|
39
75
|
export interface FlatPattern {
|
|
40
76
|
/** Glob-like pattern or regex to match file paths */
|
|
@@ -48,6 +84,32 @@ export interface RotateOptions {
|
|
|
48
84
|
/** Animation duration in milliseconds. Default uses spring physics (~800ms feel). */
|
|
49
85
|
duration?: number;
|
|
50
86
|
}
|
|
87
|
+
export type MouseDragAction = 'pan' | 'rotate' | 'zoom' | 'none';
|
|
88
|
+
export type TouchOneAction = 'pan' | 'rotate' | 'none';
|
|
89
|
+
export type TouchTwoAction = 'pan' | 'rotate' | 'dolly-pan' | 'dolly-rotate' | 'none';
|
|
90
|
+
export type WheelAction = 'zoom' | 'pan';
|
|
91
|
+
export interface CameraControlsConfig {
|
|
92
|
+
/** Left mouse button drag. Default: 'pan' */
|
|
93
|
+
leftDrag?: MouseDragAction;
|
|
94
|
+
/** Right mouse button drag. Default: 'rotate' */
|
|
95
|
+
rightDrag?: MouseDragAction;
|
|
96
|
+
/** Middle mouse button drag. Default: 'zoom' */
|
|
97
|
+
middleDrag?: MouseDragAction;
|
|
98
|
+
/** Mouse wheel / two-finger trackpad scroll. Default: 'zoom'.
|
|
99
|
+
* When 'pan', ctrl/⌘+wheel still zooms (matches trackpad pinch). */
|
|
100
|
+
wheel?: WheelAction;
|
|
101
|
+
/** One-finger touch. Default: 'pan' */
|
|
102
|
+
oneFingerTouch?: TouchOneAction;
|
|
103
|
+
/** Two-finger touch. Default: 'dolly-pan' */
|
|
104
|
+
twoFingerTouch?: TouchTwoAction;
|
|
105
|
+
/** Pan speed multiplier. Default: 1 */
|
|
106
|
+
panSpeed?: number;
|
|
107
|
+
/** Rotate speed multiplier. Default: 1 */
|
|
108
|
+
rotateSpeed?: number;
|
|
109
|
+
/** Zoom speed multiplier. Default: 1 */
|
|
110
|
+
zoomSpeed?: number;
|
|
111
|
+
}
|
|
112
|
+
export declare const DEFAULT_CAMERA_CONTROLS: Required<Omit<CameraControlsConfig, 'panSpeed' | 'rotateSpeed' | 'zoomSpeed'>> & Pick<CameraControlsConfig, 'panSpeed' | 'rotateSpeed' | 'zoomSpeed'>;
|
|
51
113
|
export declare function resetCamera(): void;
|
|
52
114
|
export declare function moveCameraTo(x: number, z: number, size?: number): void;
|
|
53
115
|
/**
|
|
@@ -164,6 +226,20 @@ export interface FileCity3DProps {
|
|
|
164
226
|
adaptCameraToBuildings?: boolean;
|
|
165
227
|
/** Base file type color layers (resolved with highlightLayers) */
|
|
166
228
|
fileColorLayers?: HighlightLayer[];
|
|
229
|
+
/**
|
|
230
|
+
* Translucent slabs rendered above the city showing scope coverage as
|
|
231
|
+
* elevated planes over the directories they own.
|
|
232
|
+
*/
|
|
233
|
+
elevatedScopePanels?: ElevatedScopePanel[];
|
|
234
|
+
/**
|
|
235
|
+
* Configure how mouse / trackpad / touch input drives the camera.
|
|
236
|
+
* Defaults match Google Maps style: left-drag pans, right-drag rotates,
|
|
237
|
+
* wheel zooms. Set `wheel: 'pan'` to make trackpad two-finger scroll pan
|
|
238
|
+
* (ctrl/⌘+wheel still zooms so pinch-zoom keeps working).
|
|
239
|
+
*
|
|
240
|
+
* Memoize this object to avoid unnecessary camera re-mounts.
|
|
241
|
+
*/
|
|
242
|
+
cameraControls?: CameraControlsConfig;
|
|
167
243
|
}
|
|
168
244
|
/**
|
|
169
245
|
* FileCity3D - 3D visualization of codebase structure
|
|
@@ -171,6 +247,6 @@ export interface FileCity3DProps {
|
|
|
171
247
|
* Renders CityData as an interactive 3D city where buildings represent files
|
|
172
248
|
* and their height corresponds to line count or file size.
|
|
173
249
|
*/
|
|
174
|
-
export declare function FileCity3D({ cityData, width, height, onBuildingClick, className, style, animation, isGrown: externalIsGrown, onGrowChange, showControls, highlightLayers: externalHighlightLayers, isolationMode: externalIsolationMode, dimOpacity: _dimOpacity, isLoading, loadingMessage, emptyMessage, heightScaling, linearScale, flatPatterns, focusDirectory: externalFocusDirectory, focusColor: externalFocusColor, onDirectorySelect: _onDirectorySelect, backgroundColor, textColor, selectedBuilding, adaptCameraToBuildings, fileColorLayers, }: FileCity3DProps): import("react/jsx-runtime").JSX.Element;
|
|
250
|
+
export declare function FileCity3D({ cityData, width, height, onBuildingClick, className, style, animation, isGrown: externalIsGrown, onGrowChange, showControls, elevatedScopePanels, highlightLayers: externalHighlightLayers, isolationMode: externalIsolationMode, dimOpacity: _dimOpacity, isLoading, loadingMessage, emptyMessage, heightScaling, linearScale, flatPatterns, focusDirectory: externalFocusDirectory, focusColor: externalFocusColor, onDirectorySelect: _onDirectorySelect, backgroundColor, textColor, selectedBuilding, adaptCameraToBuildings, fileColorLayers, cameraControls, }: FileCity3DProps): import("react/jsx-runtime").JSX.Element;
|
|
175
251
|
export default FileCity3D;
|
|
176
252
|
//# sourceMappingURL=FileCity3D.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileCity3D.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/FileCity3D.tsx"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAA4D,MAAM,OAAO,CAAC;AAMjF,OAAO,KAAK,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EAEZ,cAAc,IAAI,qBAAqB,EACvC,SAAS,EACT,mBAAmB,EACpB,MAAM,iCAAiC,CAAC;AAEzC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAIxD,OAAO,QAAQ,OAAO,CAAC;IAErB,UAAU,GAAG,CAAC;QAEZ,UAAU,iBAAkB,SAAQ,aAAa;SAAG;KACrD;CACF;AAGD,YAAY,EAAE,QAAQ,EAAE,YAAY,EAAE,YAAY,EAAE,SAAS,EAAE,mBAAmB,EAAE,CAAC;AACrF,MAAM,MAAM,cAAc,GAAG,qBAAqB,CAAC;AAEnD,gDAAgD;AAChD,MAAM,MAAM,aAAa,GACrB,MAAM,GACN,aAAa,GACb,UAAU,GACV,MAAM,CAAC;AAGX,MAAM,WAAW,eAAe;IAC9B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,mFAAmF;IACnF,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,2CAA2C;IAC3C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,4CAA4C;IAC5C,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gDAAgD;IAChD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,6CAA6C;IAC7C,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,wCAAwC;AACxC,MAAM,MAAM,aAAa,GAAG,aAAa,GAAG,QAAQ,CAAC;AAErD,oFAAoF;AACpF,MAAM,WAAW,WAAW;IAC1B,qDAAqD;IACrD,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;IACzB,qDAAqD;IACrD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,yDAAyD;AACzD,eAAO,MAAM,qBAAqB,EAAE,WAAW,EAS9C,CAAC;
|
|
1
|
+
{"version":3,"file":"FileCity3D.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/FileCity3D.tsx"],"names":[],"mappings":"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"}
|
|
@@ -10,7 +10,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
10
10
|
import React, { useMemo, useRef, useState, useEffect, useCallback } from 'react';
|
|
11
11
|
import { Canvas, useFrame, useThree } from '@react-three/fiber';
|
|
12
12
|
import { useSpring } from '@react-spring/three';
|
|
13
|
-
import {
|
|
13
|
+
import { MapControls, PerspectiveCamera, Text } from '@react-three/drei';
|
|
14
14
|
import { getFileConfig } from '@principal-ai/file-city-builder';
|
|
15
15
|
import * as THREE from 'three';
|
|
16
16
|
import { resolveVisualizationIntent } from '../../utils/visualizationResolution';
|
|
@@ -777,6 +777,38 @@ function DistrictFloor({ district, centerOffset, highlightColor, growProgress })
|
|
|
777
777
|
const textZ = flatZ + (grownZ - flatZ) * growProgress;
|
|
778
778
|
return (_jsxs("group", { position: [centerX, 0, centerZ], children: [_jsxs("lineSegments", { rotation: [-Math.PI / 2, 0, 0], position: [0, floorY, 0], renderOrder: -1, children: [_jsx("edgesGeometry", { args: [new THREE.PlaneGeometry(width, depth)], attach: "geometry" }), _jsx("lineBasicMaterial", { color: borderColor, linewidth: lineWidth, depthWrite: false })] }), highlightColor && (_jsxs("mesh", { rotation: [-Math.PI / 2, 0, 0], position: [0, floorY - 0.1, 0], renderOrder: -2, children: [_jsx("planeGeometry", { args: [width, depth] }), _jsx("meshBasicMaterial", { color: highlightColor, transparent: true, opacity: 0.15, depthWrite: false })] })), _jsx(Text, { position: [0, textY, textZ], rotation: [textRotationX, 0, 0], fontSize: Math.max(6, Math.min(12, width / 3)), color: labelColor, anchorX: "center", anchorY: "middle", outlineWidth: 0.15, outlineColor: "#0f172a", children: dirName })] }));
|
|
779
779
|
}
|
|
780
|
+
export const DEFAULT_CAMERA_CONTROLS = {
|
|
781
|
+
leftDrag: 'pan',
|
|
782
|
+
rightDrag: 'rotate',
|
|
783
|
+
middleDrag: 'zoom',
|
|
784
|
+
wheel: 'pan',
|
|
785
|
+
oneFingerTouch: 'pan',
|
|
786
|
+
twoFingerTouch: 'dolly-pan',
|
|
787
|
+
};
|
|
788
|
+
function mouseAction(action) {
|
|
789
|
+
switch (action) {
|
|
790
|
+
case 'pan': return THREE.MOUSE.PAN;
|
|
791
|
+
case 'rotate': return THREE.MOUSE.ROTATE;
|
|
792
|
+
case 'zoom': return THREE.MOUSE.DOLLY;
|
|
793
|
+
case 'none': return undefined;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
function touchOneAction(action) {
|
|
797
|
+
switch (action) {
|
|
798
|
+
case 'pan': return THREE.TOUCH.PAN;
|
|
799
|
+
case 'rotate': return THREE.TOUCH.ROTATE;
|
|
800
|
+
case 'none': return undefined;
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
function touchTwoAction(action) {
|
|
804
|
+
switch (action) {
|
|
805
|
+
case 'pan': return THREE.TOUCH.PAN;
|
|
806
|
+
case 'rotate': return THREE.TOUCH.ROTATE;
|
|
807
|
+
case 'dolly-pan': return THREE.TOUCH.DOLLY_PAN;
|
|
808
|
+
case 'dolly-rotate': return THREE.TOUCH.DOLLY_ROTATE;
|
|
809
|
+
case 'none': return undefined;
|
|
810
|
+
}
|
|
811
|
+
}
|
|
780
812
|
let cameraApi = null;
|
|
781
813
|
export function resetCamera() {
|
|
782
814
|
cameraApi?.reset();
|
|
@@ -853,10 +885,12 @@ export function getCameraAngle() {
|
|
|
853
885
|
export function getCameraTilt() {
|
|
854
886
|
return cameraApi?.getCurrentTilt() ?? null;
|
|
855
887
|
}
|
|
856
|
-
const AnimatedCamera = React.memo(function AnimatedCamera({ citySize, isFlat, focusTarget, maxBuildingHeight = 0, onCameraReady, }) {
|
|
888
|
+
const AnimatedCamera = React.memo(function AnimatedCamera({ citySize, isFlat, focusTarget, maxBuildingHeight = 0, cameraControls, onCameraReady, }) {
|
|
857
889
|
// Use selector to only subscribe to camera, not the entire R3F state
|
|
858
890
|
// This prevents re-renders on pointer movement
|
|
859
891
|
const camera = useThree((state) => state.camera);
|
|
892
|
+
const gl = useThree((state) => state.gl);
|
|
893
|
+
const controlsConfig = useMemo(() => ({ ...DEFAULT_CAMERA_CONTROLS, ...cameraControls }), [cameraControls]);
|
|
860
894
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
861
895
|
const controlsRef = useRef(null);
|
|
862
896
|
const isAnimatingRef = useRef(false);
|
|
@@ -1069,7 +1103,7 @@ const AnimatedCamera = React.memo(function AnimatedCamera({ citySize, isFlat, fo
|
|
|
1069
1103
|
const currentTilt = tiltAngle.get();
|
|
1070
1104
|
// Convert tilt angle to polar angle (0° tilt = looking down, 90° tilt = level)
|
|
1071
1105
|
// Clamp to avoid extreme angles
|
|
1072
|
-
const clampedTilt = Math.max(
|
|
1106
|
+
const clampedTilt = Math.max(0, Math.min(85, currentTilt));
|
|
1073
1107
|
const polarRadians = (clampedTilt * Math.PI) / 180;
|
|
1074
1108
|
const azimuthRadians = (azimuthAngle * Math.PI) / 180;
|
|
1075
1109
|
// Spherical to Cartesian conversion
|
|
@@ -1331,13 +1365,73 @@ const AnimatedCamera = React.memo(function AnimatedCamera({ citySize, isFlat, fo
|
|
|
1331
1365
|
cameraApi = null;
|
|
1332
1366
|
};
|
|
1333
1367
|
}, [resetToInitial, moveTo, setTarget, rotateTo, rotateBy, tiltTo, tiltBy, getCurrentPosition, getCurrentTarget, getCurrentAngle, getCurrentTilt]);
|
|
1334
|
-
|
|
1368
|
+
// Custom wheel handler for wheel === 'pan'. We disable MapControls' built-in
|
|
1369
|
+
// zoom (otherwise it competes with our handler) and handle both axes here:
|
|
1370
|
+
// ctrl/⌘+wheel = zoom (matches trackpad pinch), plain wheel = pan along the
|
|
1371
|
+
// camera-relative ground plane.
|
|
1372
|
+
useEffect(() => {
|
|
1373
|
+
if (controlsConfig.wheel !== 'pan')
|
|
1374
|
+
return;
|
|
1375
|
+
const canvas = gl.domElement;
|
|
1376
|
+
const right = new THREE.Vector3();
|
|
1377
|
+
const forward = new THREE.Vector3();
|
|
1378
|
+
const offset = new THREE.Vector3();
|
|
1379
|
+
const direction = new THREE.Vector3();
|
|
1380
|
+
const panSpeed = controlsConfig.panSpeed ?? 1;
|
|
1381
|
+
const zoomSpeed = controlsConfig.zoomSpeed ?? 1;
|
|
1382
|
+
const onWheel = (e) => {
|
|
1383
|
+
const controls = controlsRef.current;
|
|
1384
|
+
if (!controls)
|
|
1385
|
+
return;
|
|
1386
|
+
e.preventDefault();
|
|
1387
|
+
const target = controls.target;
|
|
1388
|
+
if (e.ctrlKey || e.metaKey) {
|
|
1389
|
+
direction.subVectors(camera.position, target);
|
|
1390
|
+
const distance = direction.length();
|
|
1391
|
+
const scale = Math.exp(e.deltaY * 0.01 * zoomSpeed);
|
|
1392
|
+
const minD = controls.minDistance ?? 0;
|
|
1393
|
+
const maxD = controls.maxDistance ?? Infinity;
|
|
1394
|
+
const newDistance = Math.min(Math.max(distance * scale, minD), maxD);
|
|
1395
|
+
direction.normalize().multiplyScalar(newDistance);
|
|
1396
|
+
camera.position.copy(target).add(direction);
|
|
1397
|
+
controls.update();
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const distance = camera.position.distanceTo(target);
|
|
1401
|
+
const factor = distance * 0.0015 * panSpeed;
|
|
1402
|
+
camera.getWorldDirection(forward);
|
|
1403
|
+
forward.y = 0;
|
|
1404
|
+
if (forward.lengthSq() < 1e-6)
|
|
1405
|
+
forward.set(0, 0, -1);
|
|
1406
|
+
forward.normalize();
|
|
1407
|
+
right.crossVectors(forward, camera.up).normalize();
|
|
1408
|
+
offset.set(0, 0, 0);
|
|
1409
|
+
offset.addScaledVector(right, e.deltaX * factor);
|
|
1410
|
+
offset.addScaledVector(forward, -e.deltaY * factor);
|
|
1411
|
+
camera.position.add(offset);
|
|
1412
|
+
target.add(offset);
|
|
1413
|
+
controls.update();
|
|
1414
|
+
};
|
|
1415
|
+
canvas.addEventListener('wheel', onWheel, { passive: false });
|
|
1416
|
+
return () => canvas.removeEventListener('wheel', onWheel);
|
|
1417
|
+
}, [camera, gl, controlsConfig.wheel, controlsConfig.panSpeed, controlsConfig.zoomSpeed]);
|
|
1418
|
+
const mouseButtons = useMemo(() => ({
|
|
1419
|
+
LEFT: mouseAction(controlsConfig.leftDrag),
|
|
1420
|
+
MIDDLE: mouseAction(controlsConfig.middleDrag),
|
|
1421
|
+
RIGHT: mouseAction(controlsConfig.rightDrag),
|
|
1422
|
+
}), [controlsConfig.leftDrag, controlsConfig.middleDrag, controlsConfig.rightDrag]);
|
|
1423
|
+
const touches = useMemo(() => ({
|
|
1424
|
+
ONE: touchOneAction(controlsConfig.oneFingerTouch),
|
|
1425
|
+
TWO: touchTwoAction(controlsConfig.twoFingerTouch),
|
|
1426
|
+
}), [controlsConfig.oneFingerTouch, controlsConfig.twoFingerTouch]);
|
|
1427
|
+
return (_jsxs(_Fragment, { children: [_jsx(PerspectiveCamera, { makeDefault: true, fov: 50, near: 1, far: citySize * 10 }), _jsx(MapControls, { ref: controlsRef, enableDamping: true, dampingFactor: 0.05, minDistance: 10, maxDistance: citySize * 3, maxPolarAngle: Math.PI / 2.1, mouseButtons: mouseButtons, touches: touches, enableZoom: controlsConfig.wheel !== 'pan', panSpeed: controlsConfig.panSpeed ?? 1, rotateSpeed: controlsConfig.rotateSpeed ?? 1, zoomSpeed: controlsConfig.zoomSpeed ?? 1 })] }));
|
|
1335
1428
|
}, (prevProps, nextProps) => {
|
|
1336
|
-
// Custom comparison: only re-render if isFlat, citySize, or
|
|
1429
|
+
// Custom comparison: only re-render if isFlat, citySize, maxBuildingHeight, or cameraControls changes
|
|
1337
1430
|
// Skip re-render when only focusTarget changes (handled internally by useEffect on isFlat)
|
|
1338
1431
|
return (prevProps.isFlat === nextProps.isFlat &&
|
|
1339
1432
|
prevProps.citySize === nextProps.citySize &&
|
|
1340
|
-
prevProps.maxBuildingHeight === nextProps.maxBuildingHeight
|
|
1433
|
+
prevProps.maxBuildingHeight === nextProps.maxBuildingHeight &&
|
|
1434
|
+
prevProps.cameraControls === nextProps.cameraControls);
|
|
1341
1435
|
});
|
|
1342
1436
|
function InfoPanel({ building }) {
|
|
1343
1437
|
if (!building)
|
|
@@ -1347,7 +1441,7 @@ function InfoPanel({ building }) {
|
|
|
1347
1441
|
return (_jsxs("div", { style: {
|
|
1348
1442
|
position: 'absolute',
|
|
1349
1443
|
bottom: 16,
|
|
1350
|
-
left:
|
|
1444
|
+
left: 60,
|
|
1351
1445
|
background: 'rgba(15, 23, 42, 0.9)',
|
|
1352
1446
|
border: '1px solid #334155',
|
|
1353
1447
|
borderRadius: 8,
|
|
@@ -1365,7 +1459,7 @@ function InfoPanel({ building }) {
|
|
|
1365
1459
|
gap: 12,
|
|
1366
1460
|
}, children: [building.lineCount !== undefined && (_jsxs("span", { children: [building.lineCount.toLocaleString(), " lines"] })), building.size !== undefined && _jsxs("span", { children: [(building.size / 1024).toFixed(1), " KB"] })] })] }));
|
|
1367
1461
|
}
|
|
1368
|
-
function ControlsOverlay({ isFlat, onToggle, onResetCamera }) {
|
|
1462
|
+
function ControlsOverlay({ isFlat, onToggle, onResetCamera, onLookDown }) {
|
|
1369
1463
|
const buttonStyle = {
|
|
1370
1464
|
background: 'rgba(15, 23, 42, 0.9)',
|
|
1371
1465
|
border: '1px solid #334155',
|
|
@@ -1391,9 +1485,14 @@ function ControlsOverlay({ isFlat, onToggle, onResetCamera }) {
|
|
|
1391
1485
|
position: 'absolute',
|
|
1392
1486
|
top: 8,
|
|
1393
1487
|
right: 8,
|
|
1394
|
-
}, title: "Reset View", children: "\u21BB" })
|
|
1488
|
+
}, title: "Reset View", children: "\u21BB" }), _jsx("button", { onClick: onLookDown, style: {
|
|
1489
|
+
...buttonStyle,
|
|
1490
|
+
position: 'absolute',
|
|
1491
|
+
bottom: 8,
|
|
1492
|
+
left: 8,
|
|
1493
|
+
}, title: "Look down", children: "\u2B07" })] }));
|
|
1395
1494
|
}
|
|
1396
|
-
function CityScene({ cityData, onBuildingHover, onBuildingClick, hoveredBuilding, selectedBuilding, growProgress, animationConfig, highlightLayers, isolationMode, heightScaling, linearScale, flatPatterns, focusDirectory, focusColor, adaptCameraToBuildings = false, onCameraReady, }) {
|
|
1495
|
+
function CityScene({ cityData, onBuildingHover, onBuildingClick, hoveredBuilding, selectedBuilding, growProgress, animationConfig, highlightLayers, isolationMode, heightScaling, linearScale, flatPatterns, focusDirectory, focusColor, adaptCameraToBuildings = false, elevatedScopePanels, cameraControls, onCameraReady, }) {
|
|
1397
1496
|
const centerOffset = useMemo(() => ({
|
|
1398
1497
|
x: (cityData.bounds.minX + cityData.bounds.maxX) / 2,
|
|
1399
1498
|
z: (cityData.bounds.minZ + cityData.bounds.maxZ) / 2,
|
|
@@ -1557,7 +1656,7 @@ function CityScene({ cityData, onBuildingHover, onBuildingClick, hoveredBuilding
|
|
|
1557
1656
|
return null;
|
|
1558
1657
|
return cityData.buildings.findIndex(b => b.path === selectedBuilding.path);
|
|
1559
1658
|
}, [selectedBuilding, cityData.buildings]);
|
|
1560
|
-
return (_jsxs(_Fragment, { children: [_jsx(AnimatedCamera, { citySize: citySize, isFlat: growProgress === 0, focusTarget: focusTarget, maxBuildingHeight: maxBuildingHeight, onCameraReady: onCameraReady }), _jsx("ambientLight", { intensity: 1.2 }), _jsx("hemisphereLight", { args: ['#ddeeff', '#667788', 0.8], position: [0, citySize, 0] }), _jsx("directionalLight", { position: [citySize, citySize * 1.5, citySize * 0.5], intensity: 2, castShadow: true, "shadow-mapSize": [2048, 2048] }), _jsx("directionalLight", { position: [-citySize * 0.5, citySize * 0.8, -citySize * 0.5], intensity: 1 }), _jsx("directionalLight", { position: [citySize * 0.3, citySize, citySize], intensity: 0.6 }), cityData.districts.map(district => {
|
|
1659
|
+
return (_jsxs(_Fragment, { children: [_jsx(AnimatedCamera, { citySize: citySize, isFlat: growProgress === 0, focusTarget: focusTarget, maxBuildingHeight: maxBuildingHeight, cameraControls: cameraControls, onCameraReady: onCameraReady }), _jsx("ambientLight", { intensity: 1.2 }), _jsx("hemisphereLight", { args: ['#ddeeff', '#667788', 0.8], position: [0, citySize, 0] }), _jsx("directionalLight", { position: [citySize, citySize * 1.5, citySize * 0.5], intensity: 2, castShadow: true, "shadow-mapSize": [2048, 2048] }), _jsx("directionalLight", { position: [-citySize * 0.5, citySize * 0.8, -citySize * 0.5], intensity: 1 }), _jsx("directionalLight", { position: [citySize * 0.3, citySize, citySize], intensity: 0.6 }), cityData.districts.map(district => {
|
|
1561
1660
|
// Check if district matches focusDirectory
|
|
1562
1661
|
const isFocused = buildingFocusDirectory
|
|
1563
1662
|
? district.path === buildingFocusDirectory
|
|
@@ -1580,7 +1679,43 @@ function CityScene({ cityData, onBuildingHover, onBuildingClick, hoveredBuilding
|
|
|
1580
1679
|
// Focus color takes priority, then highlight layer color
|
|
1581
1680
|
const districtColor = (isFocused && buildingFocusColor) ? buildingFocusColor : highlightLayerColor;
|
|
1582
1681
|
return (_jsx(DistrictFloor, { district: district, centerOffset: centerOffset, opacity: 1, highlightColor: districtColor, growProgress: growProgress }, district.path));
|
|
1583
|
-
}), _jsx(InstancedBuildings, { buildings: cityData.buildings, centerOffset: centerOffset, onHover: onBuildingHover, onClick: onBuildingClick, hoveredIndex: hoveredIndex, selectedIndex: selectedIndex, growProgress: growProgress, animationConfig: animationConfig, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, staggerIndices: staggerIndices, focusDirectory: buildingFocusDirectory, highlightLayers: highlightLayers, isolationMode: isolationMode }), _jsx(BuildingIcons, { buildings: cityData.buildings, centerOffset: centerOffset, growProgress: growProgress, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, highlightLayers: highlightLayers, isolationMode: isolationMode, hasActiveHighlights: activeHighlights })
|
|
1682
|
+
}), _jsx(InstancedBuildings, { buildings: cityData.buildings, centerOffset: centerOffset, onHover: onBuildingHover, onClick: onBuildingClick, hoveredIndex: hoveredIndex, selectedIndex: selectedIndex, growProgress: growProgress, animationConfig: animationConfig, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, staggerIndices: staggerIndices, focusDirectory: buildingFocusDirectory, highlightLayers: highlightLayers, isolationMode: isolationMode }), _jsx(BuildingIcons, { buildings: cityData.buildings, centerOffset: centerOffset, growProgress: growProgress, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, highlightLayers: highlightLayers, isolationMode: isolationMode, hasActiveHighlights: activeHighlights }), growProgress === 0 &&
|
|
1683
|
+
elevatedScopePanels?.map(panel => {
|
|
1684
|
+
const cx = (panel.bounds.minX + panel.bounds.maxX) / 2 - centerOffset.x;
|
|
1685
|
+
const cz = (panel.bounds.minZ + panel.bounds.maxZ) / 2 - centerOffset.z;
|
|
1686
|
+
const w = Math.max(1, panel.bounds.maxX - panel.bounds.minX);
|
|
1687
|
+
const d = Math.max(1, panel.bounds.maxZ - panel.bounds.minZ);
|
|
1688
|
+
const t = panel.thickness ?? 2;
|
|
1689
|
+
const y = (panel.height ?? 4) + t / 2;
|
|
1690
|
+
const opacity = panel.opacity ?? 1;
|
|
1691
|
+
const isOpaque = opacity >= 1;
|
|
1692
|
+
const topY = y + t / 2;
|
|
1693
|
+
// Size text to the panel: roughly fit longest reasonable label,
|
|
1694
|
+
// clamped so tiny tiles still render legibly and huge ones don't
|
|
1695
|
+
// get absurd. Callers may override via panel.labelSize, but we
|
|
1696
|
+
// still cap to the tile footprint so the label fits.
|
|
1697
|
+
const tileMax = Math.min(w, d) / 2;
|
|
1698
|
+
const requested = panel.labelSize ?? Math.min(w, d) / 6;
|
|
1699
|
+
const labelSize = Math.max(4, Math.min(tileMax, requested));
|
|
1700
|
+
const handleClick = panel.onClick
|
|
1701
|
+
? (e) => {
|
|
1702
|
+
e.stopPropagation();
|
|
1703
|
+
panel.onClick();
|
|
1704
|
+
}
|
|
1705
|
+
: undefined;
|
|
1706
|
+
const handlePointerOver = panel.onClick
|
|
1707
|
+
? (e) => {
|
|
1708
|
+
e.stopPropagation();
|
|
1709
|
+
document.body.style.cursor = 'pointer';
|
|
1710
|
+
}
|
|
1711
|
+
: undefined;
|
|
1712
|
+
const handlePointerOut = panel.onClick
|
|
1713
|
+
? () => {
|
|
1714
|
+
document.body.style.cursor = '';
|
|
1715
|
+
}
|
|
1716
|
+
: undefined;
|
|
1717
|
+
return (_jsxs("group", { children: [_jsxs("mesh", { position: [cx, y, cz], renderOrder: 10, onClick: handleClick, onPointerOver: handlePointerOver, onPointerOut: handlePointerOut, children: [_jsx("boxGeometry", { args: [w, t, d] }), _jsx("meshBasicMaterial", { color: panel.color, transparent: !isOpaque, opacity: opacity, depthWrite: isOpaque })] }), panel.label && (_jsxs(Text, { position: [cx, topY + 0.05, cz], rotation: [-Math.PI / 2, 0, 0], fontSize: labelSize, color: panel.labelColor ?? '#ffffff', anchorX: "center", anchorY: "middle", maxWidth: w * 0.9, textAlign: "center", renderOrder: 11, frustumCulled: false, children: [panel.label, _jsx("meshBasicMaterial", { attach: "material", color: panel.labelColor ?? '#ffffff', depthWrite: false, depthTest: false })] }))] }, panel.id));
|
|
1718
|
+
})] }));
|
|
1584
1719
|
}
|
|
1585
1720
|
/**
|
|
1586
1721
|
* FileCity3D - 3D visualization of codebase structure
|
|
@@ -1588,7 +1723,7 @@ function CityScene({ cityData, onBuildingHover, onBuildingClick, hoveredBuilding
|
|
|
1588
1723
|
* Renders CityData as an interactive 3D city where buildings represent files
|
|
1589
1724
|
* and their height corresponds to line count or file size.
|
|
1590
1725
|
*/
|
|
1591
|
-
export function FileCity3D({ cityData, width = '100%', height = 600, onBuildingClick, className, style, animation, isGrown: externalIsGrown, onGrowChange, showControls = false, highlightLayers: externalHighlightLayers, isolationMode: externalIsolationMode, dimOpacity: _dimOpacity = 0.15, isLoading = false, loadingMessage = 'Loading file city...', emptyMessage = 'No file tree data available', heightScaling = 'linear', linearScale = 1, flatPatterns = DEFAULT_FLAT_PATTERNS, focusDirectory: externalFocusDirectory, focusColor: externalFocusColor, onDirectorySelect: _onDirectorySelect, backgroundColor = '#0f172a', textColor = '#94a3b8', selectedBuilding = null, adaptCameraToBuildings = false, fileColorLayers, }) {
|
|
1726
|
+
export function FileCity3D({ cityData, width = '100%', height = 600, onBuildingClick, className, style, animation, isGrown: externalIsGrown, onGrowChange, showControls = false, elevatedScopePanels, highlightLayers: externalHighlightLayers, isolationMode: externalIsolationMode, dimOpacity: _dimOpacity = 0.15, isLoading = false, loadingMessage = 'Loading file city...', emptyMessage = 'No file tree data available', heightScaling = 'linear', linearScale = 1, flatPatterns = DEFAULT_FLAT_PATTERNS, focusDirectory: externalFocusDirectory, focusColor: externalFocusColor, onDirectorySelect: _onDirectorySelect, backgroundColor = '#0f172a', textColor = '#94a3b8', selectedBuilding = null, adaptCameraToBuildings = false, fileColorLayers, cameraControls, }) {
|
|
1592
1727
|
const [hoveredBuilding, setHoveredBuilding] = useState(null);
|
|
1593
1728
|
const [internalIsGrown, setInternalIsGrown] = useState(false);
|
|
1594
1729
|
const [cameraReady, setCameraReady] = useState(false);
|
|
@@ -1695,6 +1830,6 @@ export function FileCity3D({ cityData, width = '100%', height = 600, onBuildingC
|
|
|
1695
1830
|
height: '100%',
|
|
1696
1831
|
opacity: cameraReady ? 1 : 0,
|
|
1697
1832
|
transition: 'opacity 0.1s ease-in',
|
|
1698
|
-
}, children: _jsx(CityScene, { cityData: cityData, onBuildingHover: setHoveredBuilding, onBuildingClick: onBuildingClick, hoveredBuilding: hoveredBuilding, selectedBuilding: selectedBuilding, growProgress: growProgress, animationConfig: animationConfig, highlightLayers: highlightLayers, isolationMode: isolationMode, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, focusDirectory: focusDirectory, focusColor: focusColor, adaptCameraToBuildings: adaptCameraToBuildings, onCameraReady: () => setCameraReady(true) }) }), _jsx(InfoPanel, { building: selectedBuilding }), showControls && (_jsx(ControlsOverlay, { isFlat: !isGrown, onToggle: handleToggle, onResetCamera: resetCamera }))] }));
|
|
1833
|
+
}, children: _jsx(CityScene, { cityData: cityData, onBuildingHover: setHoveredBuilding, onBuildingClick: onBuildingClick, hoveredBuilding: hoveredBuilding, selectedBuilding: selectedBuilding, growProgress: growProgress, animationConfig: animationConfig, highlightLayers: highlightLayers, isolationMode: isolationMode, heightScaling: heightScaling, linearScale: linearScale, flatPatterns: flatPatterns, focusDirectory: focusDirectory, focusColor: focusColor, adaptCameraToBuildings: adaptCameraToBuildings, elevatedScopePanels: elevatedScopePanels, cameraControls: cameraControls, onCameraReady: () => setCameraReady(true) }) }), _jsx(InfoPanel, { building: selectedBuilding }), showControls && (_jsx(ControlsOverlay, { isFlat: !isGrown, onToggle: handleToggle, onResetCamera: resetCamera, onLookDown: () => tiltCameraTo(0) }))] }));
|
|
1699
1834
|
}
|
|
1700
1835
|
export default FileCity3D;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FileCity3D - 3D visualization component
|
|
3
3
|
*/
|
|
4
|
-
export { FileCity3D, resetCamera, getCameraAngle, getCameraTarget, getCameraTilt, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, moveCameraTo, setCameraTarget, DEFAULT_FLAT_PATTERNS, } from './FileCity3D';
|
|
5
|
-
export type { FileCity3DProps, AnimationConfig, HighlightLayer, LayerItem, LayerRenderStrategy, IsolationMode, HeightScaling, FlatPattern, CityData, CityBuilding, CityDistrict, } from './FileCity3D';
|
|
4
|
+
export { FileCity3D, resetCamera, getCameraAngle, getCameraTarget, getCameraTilt, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, moveCameraTo, setCameraTarget, DEFAULT_FLAT_PATTERNS, DEFAULT_CAMERA_CONTROLS, } from './FileCity3D';
|
|
5
|
+
export type { FileCity3DProps, AnimationConfig, HighlightLayer, LayerItem, LayerRenderStrategy, IsolationMode, HeightScaling, FlatPattern, ElevatedScopePanel, CityData, CityBuilding, CityDistrict, CameraControlsConfig, MouseDragAction, TouchOneAction, TouchTwoAction, WheelAction, } from './FileCity3D';
|
|
6
6
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,UAAU,EACV,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,qBAAqB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/components/FileCity3D/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EACL,UAAU,EACV,WAAW,EACX,cAAc,EACd,eAAe,EACf,aAAa,EACb,cAAc,EACd,cAAc,EACd,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,eAAe,EACf,qBAAqB,EACrB,uBAAuB,GACxB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,eAAe,EACf,eAAe,EACf,cAAc,EACd,SAAS,EACT,mBAAmB,EACnB,aAAa,EACb,aAAa,EACb,WAAW,EACX,kBAAkB,EAClB,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,oBAAoB,EACpB,eAAe,EACf,cAAc,EACd,cAAc,EACd,WAAW,GACZ,MAAM,cAAc,CAAC"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* FileCity3D - 3D visualization component
|
|
3
3
|
*/
|
|
4
|
-
export { FileCity3D, resetCamera, getCameraAngle, getCameraTarget, getCameraTilt, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, moveCameraTo, setCameraTarget, DEFAULT_FLAT_PATTERNS, } from './FileCity3D';
|
|
4
|
+
export { FileCity3D, resetCamera, getCameraAngle, getCameraTarget, getCameraTilt, rotateCameraTo, rotateCameraBy, tiltCameraTo, tiltCameraBy, moveCameraTo, setCameraTarget, DEFAULT_FLAT_PATTERNS, DEFAULT_CAMERA_CONTROLS, } from './FileCity3D';
|
package/dist/index.d.ts
CHANGED
|
@@ -14,7 +14,7 @@ export type { FileTree } from '@principal-ai/file-city-builder';
|
|
|
14
14
|
export { CityViewWithReactFlow, type CityViewWithReactFlowProps, } from './components/CityViewWithReactFlow';
|
|
15
15
|
export { ThemeProvider, useTheme } from '@principal-ade/industry-theme';
|
|
16
16
|
export { FileCity3D, resetCamera, DEFAULT_FLAT_PATTERNS } from './components/FileCity3D';
|
|
17
|
-
export type { FileCity3DProps, AnimationConfig, HighlightLayer as FileCity3DHighlightLayer, IsolationMode, HeightScaling, FlatPattern, } from './components/FileCity3D';
|
|
17
|
+
export type { FileCity3DProps, AnimationConfig, HighlightLayer as FileCity3DHighlightLayer, IsolationMode, HeightScaling, FlatPattern, ElevatedScopePanel, } from './components/FileCity3D';
|
|
18
18
|
export type { HighlightLayer as FileCity3DHL } from './components/FileCity3D';
|
|
19
19
|
export { resolveVisualizationIntent } from './utils/visualizationResolution';
|
|
20
20
|
export type { VisualizationIntent, ResolvedVisualizationState, } from './utils/visualizationResolution';
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,8BAA8B,EAC9B,KAAK,mCAAmC,GACzC,MAAM,6CAA6C,CAAC;AAGrD,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,UAAU,GACX,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGvF,OAAO,EACL,gCAAgC,EAChC,6BAA6B,EAC7B,oCAAoC,GACrC,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,8BAA8B,EAC9B,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAGzF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG7F,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,QAAQ,EACR,UAAU,GACX,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAG1E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAG7F,YAAY,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAGhE,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAGxE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACzF,YAAY,EACV,eAAe,EACf,eAAe,EACf,cAAc,IAAI,wBAAwB,EAC1C,aAAa,EACb,aAAa,EACb,WAAW,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EACL,8BAA8B,EAC9B,KAAK,mCAAmC,GACzC,MAAM,6CAA6C,CAAC;AAGrD,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,SAAS,EACd,KAAK,cAAc,EACnB,UAAU,GACX,MAAM,sCAAsC,CAAC;AAG9C,OAAO,EAAE,KAAK,mBAAmB,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGvF,OAAO,EACL,gCAAgC,EAChC,6BAA6B,EAC7B,oCAAoC,GACrC,MAAM,yBAAyB,CAAC;AAGjC,OAAO,EACL,8BAA8B,EAC9B,yBAAyB,EACzB,mBAAmB,GACpB,MAAM,kCAAkC,CAAC;AAE1C,YAAY,EACV,gBAAgB,EAChB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,GACnB,MAAM,kCAAkC,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,oBAAoB,EAAE,MAAM,4BAA4B,CAAC;AAGzF,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAG7F,YAAY,EACV,QAAQ,EACR,YAAY,EACZ,YAAY,EACZ,sBAAsB,EACtB,QAAQ,EACR,UAAU,GACX,MAAM,iCAAiC,CAAC;AAGzC,OAAO,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAC;AAG1E,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,YAAY,EAAE,sBAAsB,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAG7F,YAAY,EAAE,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AAGhE,OAAO,EACL,qBAAqB,EACrB,KAAK,0BAA0B,GAChC,MAAM,oCAAoC,CAAC;AAG5C,OAAO,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAGxE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AACzF,YAAY,EACV,eAAe,EACf,eAAe,EACf,cAAc,IAAI,wBAAwB,EAC1C,aAAa,EACb,aAAa,EACb,WAAW,EACX,kBAAkB,GACnB,MAAM,yBAAyB,CAAC;AAIjC,YAAY,EAAE,cAAc,IAAI,YAAY,EAAE,MAAM,yBAAyB,CAAC;AAI9E,OAAO,EAAE,0BAA0B,EAAE,MAAM,iCAAiC,CAAC;AAC7E,YAAY,EACV,mBAAmB,EACnB,0BAA0B,GAC3B,MAAM,iCAAiC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@principal-ai/file-city-react",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.39",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "React components for File City visualization",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -26,6 +26,7 @@
|
|
|
26
26
|
"three": ">=0.170.0"
|
|
27
27
|
},
|
|
28
28
|
"devDependencies": {
|
|
29
|
+
"@pierre/trees": "^1.0.0-beta.3",
|
|
29
30
|
"@principal-ade/industry-theme": "^0.1.19",
|
|
30
31
|
"@principal-ai/file-city-builder": "^0.4.5",
|
|
31
32
|
"@react-spring/three": "^10.0.3",
|