@ifc-lite/viewer 1.7.0 → 1.9.0
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/CHANGELOG.md +88 -0
- package/dist/assets/{Arrow.dom-BGPQieQQ.js → Arrow.dom-CusgkT03.js} +1 -1
- package/dist/assets/browser-BXNIkE8a.js +694 -0
- package/dist/assets/emscripten-module-BTRCZGcB.wasm +0 -0
- package/dist/assets/emscripten-module-CGIn_cMh.wasm +0 -0
- package/dist/assets/emscripten-module-DYvzWiHh.wasm +0 -0
- package/dist/assets/emscripten-module-NWak2PoB.wasm +0 -0
- package/dist/assets/emscripten-module.browser-CY5t0Vfq.js +1 -0
- package/dist/assets/esbuild-COv63sf-.js +1 -0
- package/dist/assets/esbuild-Cpd5nU_H.wasm +0 -0
- package/dist/assets/ffi-DlhRHxHv.js +1 -0
- package/dist/assets/index-6Mr3byM-.js +216 -0
- package/dist/assets/index-CGbokkQ9.css +1 -0
- package/dist/assets/index-huvR-kGC.js +98305 -0
- package/dist/assets/module-6F3E5H7Y-tx0BadV3.js +6 -0
- package/dist/assets/{native-bridge-DD0SNyQ5.js → native-bridge-DsHOKdgD.js} +1 -1
- package/dist/assets/{wasm-bridge-D54YMO7X.js → wasm-bridge-Bd73HXn-.js} +1 -1
- package/dist/index.html +12 -3
- package/index.html +10 -1
- package/package.json +30 -21
- package/src/App.tsx +6 -1
- package/src/components/ui/dialog.tsx +8 -6
- package/src/components/viewer/CodeEditor.tsx +309 -0
- package/src/components/viewer/CommandPalette.tsx +597 -0
- package/src/components/viewer/Drawing2DCanvas.tsx +364 -1
- package/src/components/viewer/EntityContextMenu.tsx +47 -20
- package/src/components/viewer/ExportDialog.tsx +166 -17
- package/src/components/viewer/HierarchyPanel.tsx +3 -1
- package/src/components/viewer/LensPanel.tsx +848 -85
- package/src/components/viewer/MainToolbar.tsx +145 -84
- package/src/components/viewer/ScriptPanel.tsx +416 -0
- package/src/components/viewer/Section2DPanel.tsx +269 -29
- package/src/components/viewer/TextAnnotationEditor.tsx +112 -0
- package/src/components/viewer/ViewerLayout.tsx +63 -11
- package/src/components/viewer/Viewport.tsx +58 -23
- package/src/components/viewer/ViewportContainer.tsx +2 -0
- package/src/components/viewer/hierarchy/HierarchyNode.tsx +1 -1
- package/src/components/viewer/hierarchy/types.ts +1 -1
- package/src/components/viewer/lists/ListResultsTable.tsx +53 -19
- package/src/components/viewer/tools/cloudPathGenerator.test.ts +118 -0
- package/src/components/viewer/tools/cloudPathGenerator.ts +275 -0
- package/src/components/viewer/tools/computePolygonArea.test.ts +165 -0
- package/src/components/viewer/tools/computePolygonArea.ts +72 -0
- package/src/components/viewer/useGeometryStreaming.ts +25 -5
- package/src/hooks/ids/idsExportService.ts +1 -1
- package/src/hooks/useAnnotation2D.ts +551 -0
- package/src/hooks/useDrawingExport.ts +83 -1
- package/src/hooks/useKeyboardShortcuts.ts +114 -14
- package/src/hooks/useLens.ts +40 -55
- package/src/hooks/useLensDiscovery.ts +46 -0
- package/src/hooks/useModelSelection.ts +5 -22
- package/src/hooks/useSandbox.ts +113 -0
- package/src/index.css +7 -1
- package/src/lib/lens/adapter.ts +127 -1
- package/src/lib/lists/columnToAutoColor.ts +33 -0
- package/src/lib/recent-files.ts +122 -0
- package/src/lib/scripts/persistence.ts +132 -0
- package/src/lib/scripts/templates/bim-globals.d.ts +111 -0
- package/src/lib/scripts/templates/data-quality-audit.ts +149 -0
- package/src/lib/scripts/templates/envelope-check.ts +164 -0
- package/src/lib/scripts/templates/federation-compare.ts +189 -0
- package/src/lib/scripts/templates/fire-safety-check.ts +161 -0
- package/src/lib/scripts/templates/mep-equipment-schedule.ts +175 -0
- package/src/lib/scripts/templates/quantity-takeoff.ts +145 -0
- package/src/lib/scripts/templates/reset-view.ts +6 -0
- package/src/lib/scripts/templates/space-validation.ts +189 -0
- package/src/lib/scripts/templates/tsconfig.json +13 -0
- package/src/lib/scripts/templates.ts +86 -0
- package/src/sdk/BimProvider.tsx +50 -0
- package/src/sdk/adapters/export-adapter.ts +283 -0
- package/src/sdk/adapters/lens-adapter.ts +44 -0
- package/src/sdk/adapters/model-adapter.ts +32 -0
- package/src/sdk/adapters/model-compat.ts +80 -0
- package/src/sdk/adapters/mutate-adapter.ts +45 -0
- package/src/sdk/adapters/query-adapter.ts +241 -0
- package/src/sdk/adapters/selection-adapter.ts +29 -0
- package/src/sdk/adapters/spatial-adapter.ts +37 -0
- package/src/sdk/adapters/types.ts +11 -0
- package/src/sdk/adapters/viewer-adapter.ts +103 -0
- package/src/sdk/adapters/visibility-adapter.ts +61 -0
- package/src/sdk/local-backend.ts +144 -0
- package/src/sdk/useBimHost.ts +69 -0
- package/src/store/constants.ts +10 -2
- package/src/store/index.ts +28 -2
- package/src/store/resolveEntityRef.ts +44 -0
- package/src/store/slices/drawing2DSlice.ts +321 -0
- package/src/store/slices/lensSlice.ts +46 -4
- package/src/store/slices/pinboardSlice.ts +171 -42
- package/src/store/slices/scriptSlice.ts +218 -0
- package/src/store/slices/uiSlice.ts +2 -0
- package/src/store.ts +3 -0
- package/tsconfig.json +5 -2
- package/vite.config.ts +8 -0
- package/dist/assets/index-dgdgiQ9p.js +0 -75456
- package/dist/assets/index-yTqs8kgX.css +0 -1
|
@@ -41,11 +41,12 @@ import {
|
|
|
41
41
|
AlertTitle,
|
|
42
42
|
} from '@/components/ui/alert';
|
|
43
43
|
import { useViewerStore } from '@/store';
|
|
44
|
-
import { StepExporter } from '@ifc-lite/export';
|
|
44
|
+
import { StepExporter, MergedExporter, type MergeModelInput } from '@ifc-lite/export';
|
|
45
45
|
import { MutablePropertyView } from '@ifc-lite/mutations';
|
|
46
46
|
import { extractPropertiesOnDemand, type IfcDataStore } from '@ifc-lite/parser';
|
|
47
47
|
|
|
48
48
|
type ExportFormat = 'ifc' | 'ifcx' | 'json';
|
|
49
|
+
type ExportScope = 'single' | 'merged';
|
|
49
50
|
type SchemaVersion = 'IFC2X3' | 'IFC4' | 'IFC4X3';
|
|
50
51
|
|
|
51
52
|
interface ExportDialogProps {
|
|
@@ -58,6 +59,10 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
58
59
|
const getMutationView = useViewerStore((s) => s.getMutationView);
|
|
59
60
|
const registerMutationView = useViewerStore((s) => s.registerMutationView);
|
|
60
61
|
const getModifiedEntityCount = useViewerStore((s) => s.getModifiedEntityCount);
|
|
62
|
+
const hiddenEntities = useViewerStore((s) => s.hiddenEntities);
|
|
63
|
+
const isolatedEntities = useViewerStore((s) => s.isolatedEntities);
|
|
64
|
+
const hiddenEntitiesByModel = useViewerStore((s) => s.hiddenEntitiesByModel);
|
|
65
|
+
const isolatedEntitiesByModel = useViewerStore((s) => s.isolatedEntitiesByModel);
|
|
61
66
|
// Also get legacy single-model state for backward compatibility
|
|
62
67
|
const legacyIfcDataStore = useViewerStore((s) => s.ifcDataStore);
|
|
63
68
|
const legacyGeometryResult = useViewerStore((s) => s.geometryResult);
|
|
@@ -66,9 +71,11 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
66
71
|
const [format, setFormat] = useState<ExportFormat>('ifc');
|
|
67
72
|
const [schema, setSchema] = useState<SchemaVersion>('IFC4');
|
|
68
73
|
const [selectedModelId, setSelectedModelId] = useState<string>('');
|
|
74
|
+
const [exportScope, setExportScope] = useState<ExportScope>('single');
|
|
69
75
|
const [includeGeometry, setIncludeGeometry] = useState(true);
|
|
70
76
|
const [applyMutations, setApplyMutations] = useState(true);
|
|
71
77
|
const [deltaOnly, setDeltaOnly] = useState(false);
|
|
78
|
+
const [visibleOnly, setVisibleOnly] = useState(false);
|
|
72
79
|
const [isExporting, setIsExporting] = useState(false);
|
|
73
80
|
const [exportResult, setExportResult] = useState<{ success: boolean; message: string } | null>(null);
|
|
74
81
|
|
|
@@ -145,22 +152,137 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
145
152
|
return getModifiedEntityCount();
|
|
146
153
|
}, [getModifiedEntityCount]);
|
|
147
154
|
|
|
155
|
+
/**
|
|
156
|
+
* Convert global visibility state IDs to local expressIds for a given model.
|
|
157
|
+
* The store uses global IDs (localId + idOffset), but the exporter needs local IDs.
|
|
158
|
+
*/
|
|
159
|
+
const getLocalHiddenIds = useCallback((modelId: string): Set<number> => {
|
|
160
|
+
// Legacy single-model path: no federation offset, global IDs = local IDs
|
|
161
|
+
if (modelId === '__legacy__') {
|
|
162
|
+
return hiddenEntities;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const model = models.get(modelId);
|
|
166
|
+
if (!model) return new Set();
|
|
167
|
+
const offset = model.idOffset ?? 0;
|
|
168
|
+
|
|
169
|
+
// Prefer per-model visibility state, fall back to legacy global state
|
|
170
|
+
const modelHidden = hiddenEntitiesByModel.get(modelId);
|
|
171
|
+
if (modelHidden && modelHidden.size > 0) {
|
|
172
|
+
return modelHidden; // Already local expressIds
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
// Federated model: convert global IDs to local
|
|
176
|
+
const localIds = new Set<number>();
|
|
177
|
+
for (const globalId of hiddenEntities) {
|
|
178
|
+
const localId = globalId - offset;
|
|
179
|
+
if (localId > 0 && localId <= model.maxExpressId) {
|
|
180
|
+
localIds.add(localId);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return localIds;
|
|
184
|
+
}, [models, hiddenEntities, hiddenEntitiesByModel]);
|
|
185
|
+
|
|
186
|
+
const getLocalIsolatedIds = useCallback((modelId: string): Set<number> | null => {
|
|
187
|
+
// Legacy single-model path: no federation offset, global IDs = local IDs
|
|
188
|
+
if (modelId === '__legacy__') {
|
|
189
|
+
return isolatedEntities;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
const model = models.get(modelId);
|
|
193
|
+
if (!model) return null;
|
|
194
|
+
const offset = model.idOffset ?? 0;
|
|
195
|
+
|
|
196
|
+
// Prefer per-model isolation state
|
|
197
|
+
const modelIsolated = isolatedEntitiesByModel.get(modelId);
|
|
198
|
+
if (modelIsolated && modelIsolated.size > 0) {
|
|
199
|
+
return modelIsolated; // Already local expressIds
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// Federated model: convert global IDs to local
|
|
203
|
+
if (!isolatedEntities) return null;
|
|
204
|
+
const localIds = new Set<number>();
|
|
205
|
+
for (const globalId of isolatedEntities) {
|
|
206
|
+
const localId = globalId - offset;
|
|
207
|
+
if (localId > 0 && localId <= model.maxExpressId) {
|
|
208
|
+
localIds.add(localId);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
return localIds.size > 0 ? localIds : null;
|
|
212
|
+
}, [models, isolatedEntities, isolatedEntitiesByModel]);
|
|
213
|
+
|
|
148
214
|
const handleExport = useCallback(async () => {
|
|
149
|
-
if (!selectedModel) return;
|
|
215
|
+
if (exportScope === 'single' && !selectedModel) return;
|
|
150
216
|
|
|
151
217
|
setIsExporting(true);
|
|
152
218
|
setExportResult(null);
|
|
153
219
|
|
|
154
220
|
try {
|
|
221
|
+
// Handle merged export of all models
|
|
222
|
+
if (format === 'ifc' && exportScope === 'merged') {
|
|
223
|
+
const mergeInputs: MergeModelInput[] = Array.from(models.values()).map((m) => ({
|
|
224
|
+
id: m.id,
|
|
225
|
+
name: m.name,
|
|
226
|
+
dataStore: m.ifcDataStore,
|
|
227
|
+
}));
|
|
228
|
+
|
|
229
|
+
const mergedExporter = new MergedExporter(mergeInputs);
|
|
230
|
+
|
|
231
|
+
// Build per-model visibility maps if visible-only export
|
|
232
|
+
const hiddenByModel = new Map<string, Set<number>>();
|
|
233
|
+
const isolatedByModel = new Map<string, Set<number> | null>();
|
|
234
|
+
if (visibleOnly) {
|
|
235
|
+
for (const m of models.values()) {
|
|
236
|
+
hiddenByModel.set(m.id, getLocalHiddenIds(m.id));
|
|
237
|
+
isolatedByModel.set(m.id, getLocalIsolatedIds(m.id));
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const result = mergedExporter.export({
|
|
242
|
+
schema,
|
|
243
|
+
projectStrategy: 'keep-first',
|
|
244
|
+
visibleOnly,
|
|
245
|
+
hiddenEntityIdsByModel: hiddenByModel,
|
|
246
|
+
isolatedEntityIdsByModel: isolatedByModel,
|
|
247
|
+
description: `Merged export of ${mergeInputs.length} models from ifc-lite`,
|
|
248
|
+
application: 'ifc-lite',
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
const blob = new Blob([result.content], { type: 'text/plain' });
|
|
252
|
+
const url = URL.createObjectURL(blob);
|
|
253
|
+
const a = document.createElement('a');
|
|
254
|
+
a.href = url;
|
|
255
|
+
a.download = 'merged_export.ifc';
|
|
256
|
+
document.body.appendChild(a);
|
|
257
|
+
a.click();
|
|
258
|
+
document.body.removeChild(a);
|
|
259
|
+
URL.revokeObjectURL(url);
|
|
260
|
+
|
|
261
|
+
setExportResult({
|
|
262
|
+
success: true,
|
|
263
|
+
message: `Merged ${result.stats.modelCount} models, ${result.stats.totalEntityCount} entities`,
|
|
264
|
+
});
|
|
265
|
+
return;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (!selectedModel) return;
|
|
155
269
|
const mutationView = getMutationView(selectedModelId);
|
|
156
270
|
|
|
157
271
|
if (format === 'ifc') {
|
|
158
272
|
const exporter = new StepExporter(selectedModel.ifcDataStore, mutationView || undefined);
|
|
273
|
+
|
|
274
|
+
// Build visibility filter for visible-only export
|
|
275
|
+
const localHidden = visibleOnly ? getLocalHiddenIds(selectedModelId) : undefined;
|
|
276
|
+
const localIsolated = visibleOnly ? getLocalIsolatedIds(selectedModelId) : undefined;
|
|
277
|
+
|
|
159
278
|
const result = exporter.export({
|
|
160
279
|
schema,
|
|
161
280
|
includeGeometry,
|
|
162
281
|
applyMutations,
|
|
163
282
|
deltaOnly,
|
|
283
|
+
visibleOnly,
|
|
284
|
+
hiddenEntityIds: localHidden,
|
|
285
|
+
isolatedEntityIds: localIsolated,
|
|
164
286
|
description: `Exported from ifc-lite with ${modifiedCount} modifications`,
|
|
165
287
|
application: 'ifc-lite',
|
|
166
288
|
});
|
|
@@ -170,7 +292,8 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
170
292
|
const url = URL.createObjectURL(blob);
|
|
171
293
|
const a = document.createElement('a');
|
|
172
294
|
a.href = url;
|
|
173
|
-
|
|
295
|
+
const suffix = visibleOnly ? '_visible' : '_modified';
|
|
296
|
+
a.download = `${selectedModel.name.replace(/\.[^.]+$/, '')}${suffix}.ifc`;
|
|
174
297
|
document.body.appendChild(a);
|
|
175
298
|
a.click();
|
|
176
299
|
document.body.removeChild(a);
|
|
@@ -240,7 +363,7 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
240
363
|
} finally {
|
|
241
364
|
setIsExporting(false);
|
|
242
365
|
}
|
|
243
|
-
}, [selectedModel, selectedModelId, format, schema, includeGeometry, applyMutations, deltaOnly, getMutationView, modifiedCount]);
|
|
366
|
+
}, [selectedModel, selectedModelId, format, schema, exportScope, includeGeometry, applyMutations, deltaOnly, visibleOnly, getMutationView, getLocalHiddenIds, getLocalIsolatedIds, modifiedCount, models]);
|
|
244
367
|
|
|
245
368
|
return (
|
|
246
369
|
<Dialog open={open} onOpenChange={setOpen}>
|
|
@@ -252,7 +375,7 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
252
375
|
</Button>
|
|
253
376
|
)}
|
|
254
377
|
</DialogTrigger>
|
|
255
|
-
<DialogContent className="sm:max-w-
|
|
378
|
+
<DialogContent className="sm:max-w-md overflow-hidden">
|
|
256
379
|
<DialogHeader>
|
|
257
380
|
<DialogTitle className="flex items-center gap-2">
|
|
258
381
|
<Download className="h-5 w-5" />
|
|
@@ -264,7 +387,24 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
264
387
|
</DialogHeader>
|
|
265
388
|
|
|
266
389
|
<div className="grid gap-4 py-4">
|
|
267
|
-
{/*
|
|
390
|
+
{/* Export scope selector (only when multiple models loaded) */}
|
|
391
|
+
{format === 'ifc' && modelList.length > 1 && (
|
|
392
|
+
<div className="flex items-center gap-4">
|
|
393
|
+
<Label className="w-32">Scope</Label>
|
|
394
|
+
<Select value={exportScope} onValueChange={(v) => setExportScope(v as ExportScope)}>
|
|
395
|
+
<SelectTrigger>
|
|
396
|
+
<SelectValue />
|
|
397
|
+
</SelectTrigger>
|
|
398
|
+
<SelectContent>
|
|
399
|
+
<SelectItem value="single">Single Model</SelectItem>
|
|
400
|
+
<SelectItem value="merged">Merged (All Models)</SelectItem>
|
|
401
|
+
</SelectContent>
|
|
402
|
+
</Select>
|
|
403
|
+
</div>
|
|
404
|
+
)}
|
|
405
|
+
|
|
406
|
+
{/* Model selector (only for single-model export) */}
|
|
407
|
+
{exportScope === 'single' && (
|
|
268
408
|
<div className="flex items-center gap-4">
|
|
269
409
|
<Label className="w-32">Model</Label>
|
|
270
410
|
<Select value={selectedModelId} onValueChange={setSelectedModelId}>
|
|
@@ -272,21 +412,19 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
272
412
|
<SelectValue placeholder="Select model" />
|
|
273
413
|
</SelectTrigger>
|
|
274
414
|
<SelectContent>
|
|
275
|
-
{modelList.map((m) =>
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
modified
|
|
282
|
-
</Badge>
|
|
283
|
-
)}
|
|
284
|
-
</div>
|
|
415
|
+
{modelList.map((m) => {
|
|
416
|
+
const maxLen = 24;
|
|
417
|
+
const displayName = m.name.length > maxLen ? m.name.slice(0, maxLen) + '\u2026' : m.name;
|
|
418
|
+
return (
|
|
419
|
+
<SelectItem key={m.id} value={m.id} title={m.name}>
|
|
420
|
+
{displayName}{m.isDirty ? ' *' : ''}
|
|
285
421
|
</SelectItem>
|
|
286
|
-
|
|
422
|
+
);
|
|
423
|
+
})}
|
|
287
424
|
</SelectContent>
|
|
288
425
|
</Select>
|
|
289
426
|
</div>
|
|
427
|
+
)}
|
|
290
428
|
|
|
291
429
|
{/* Format selector */}
|
|
292
430
|
<div className="flex items-center gap-4">
|
|
@@ -338,6 +476,15 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
338
476
|
{/* Options */}
|
|
339
477
|
{format === 'ifc' && (
|
|
340
478
|
<>
|
|
479
|
+
<div className="flex items-center justify-between">
|
|
480
|
+
<div>
|
|
481
|
+
<Label>Export Visible Only</Label>
|
|
482
|
+
<p className="text-xs text-muted-foreground">Only include entities currently visible in the 3D view</p>
|
|
483
|
+
</div>
|
|
484
|
+
<Switch checked={visibleOnly} onCheckedChange={setVisibleOnly} />
|
|
485
|
+
</div>
|
|
486
|
+
{exportScope === 'single' && (
|
|
487
|
+
<>
|
|
341
488
|
<div className="flex items-center justify-between">
|
|
342
489
|
<Label>Include Geometry</Label>
|
|
343
490
|
<Switch checked={includeGeometry} onCheckedChange={setIncludeGeometry} />
|
|
@@ -350,6 +497,8 @@ export function ExportDialog({ trigger }: ExportDialogProps) {
|
|
|
350
497
|
<Label>Export Changes Only (Delta)</Label>
|
|
351
498
|
<Switch checked={deltaOnly} onCheckedChange={setDeltaOnly} />
|
|
352
499
|
</div>
|
|
500
|
+
</>
|
|
501
|
+
)}
|
|
353
502
|
</>
|
|
354
503
|
)}
|
|
355
504
|
|
|
@@ -15,7 +15,7 @@ import {
|
|
|
15
15
|
import { Input } from '@/components/ui/input';
|
|
16
16
|
import { Button } from '@/components/ui/button';
|
|
17
17
|
import { cn } from '@/lib/utils';
|
|
18
|
-
import { useViewerStore } from '@/store';
|
|
18
|
+
import { useViewerStore, resolveEntityRef } from '@/store';
|
|
19
19
|
import { useIfc } from '@/hooks/useIfc';
|
|
20
20
|
|
|
21
21
|
import type { TreeNode } from './hierarchy/types';
|
|
@@ -280,6 +280,8 @@ export function HierarchyPanel() {
|
|
|
280
280
|
} else {
|
|
281
281
|
// Legacy single-model: expressId = globalId (offset is 0)
|
|
282
282
|
setSelectedEntityId(elementId);
|
|
283
|
+
// Also set selectedEntity for property panel (was missing, causing blank panel)
|
|
284
|
+
setSelectedEntity(resolveEntityRef(elementId));
|
|
283
285
|
}
|
|
284
286
|
}
|
|
285
287
|
}, [selectedStoreys, setStoreysSelection, clearStoreySelection, setSelectedEntityId, setSelectedEntity, setSelectedEntities, setActiveModel, toggleExpand, unifiedStoreys, models, isolateEntities, getNodeElements]);
|