@ifc-lite/viewer 1.6.1 → 1.7.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.
Files changed (95) hide show
  1. package/CHANGELOG.md +71 -0
  2. package/dist/assets/{Arrow.dom-Be1tgmo6.js → Arrow.dom-BGPQieQQ.js} +1 -1
  3. package/dist/assets/ifc-lite_bg-DyIN_nBM.wasm +0 -0
  4. package/dist/assets/{index-D1Du89Pa.js → index-dgdgiQ9p.js} +40198 -29999
  5. package/dist/assets/index-yTqs8kgX.css +1 -0
  6. package/dist/assets/{native-bridge-A6zNnTfi.js → native-bridge-DD0SNyQ5.js} +1 -1
  7. package/dist/assets/{wasm-bridge-DkRhgSvE.js → wasm-bridge-D54YMO7X.js} +1 -1
  8. package/dist/index.html +2 -2
  9. package/package.json +18 -15
  10. package/src/components/viewer/BCFPanel.tsx +7 -789
  11. package/src/components/viewer/Drawing2DCanvas.tsx +1048 -0
  12. package/src/components/viewer/DrawingSettingsPanel.tsx +3 -3
  13. package/src/components/viewer/HierarchyPanel.tsx +110 -842
  14. package/src/components/viewer/IDSExportDialog.tsx +281 -0
  15. package/src/components/viewer/IDSPanel.tsx +126 -17
  16. package/src/components/viewer/KeyboardShortcutsDialog.tsx +9 -0
  17. package/src/components/viewer/LensPanel.tsx +603 -0
  18. package/src/components/viewer/MainToolbar.tsx +188 -21
  19. package/src/components/viewer/PropertiesPanel.tsx +171 -652
  20. package/src/components/viewer/PropertyEditor.tsx +866 -77
  21. package/src/components/viewer/Section2DPanel.tsx +76 -2648
  22. package/src/components/viewer/ToolOverlays.tsx +3 -1097
  23. package/src/components/viewer/ViewerLayout.tsx +132 -45
  24. package/src/components/viewer/Viewport.tsx +237 -1659
  25. package/src/components/viewer/ViewportContainer.tsx +11 -3
  26. package/src/components/viewer/bcf/BCFCreateTopicForm.tsx +134 -0
  27. package/src/components/viewer/bcf/BCFTopicDetail.tsx +388 -0
  28. package/src/components/viewer/bcf/BCFTopicList.tsx +239 -0
  29. package/src/components/viewer/bcf/bcfHelpers.tsx +109 -0
  30. package/src/components/viewer/hierarchy/HierarchyNode.tsx +328 -0
  31. package/src/components/viewer/hierarchy/treeDataBuilder.ts +464 -0
  32. package/src/components/viewer/hierarchy/types.ts +54 -0
  33. package/src/components/viewer/hierarchy/useHierarchyTree.ts +280 -0
  34. package/src/components/viewer/lists/ListBuilder.tsx +486 -0
  35. package/src/components/viewer/lists/ListPanel.tsx +540 -0
  36. package/src/components/viewer/lists/ListResultsTable.tsx +193 -0
  37. package/src/components/viewer/properties/ClassificationCard.tsx +70 -0
  38. package/src/components/viewer/properties/CoordinateDisplay.tsx +49 -0
  39. package/src/components/viewer/properties/DocumentCard.tsx +89 -0
  40. package/src/components/viewer/properties/MaterialCard.tsx +201 -0
  41. package/src/components/viewer/properties/ModelMetadataPanel.tsx +335 -0
  42. package/src/components/viewer/properties/PropertySetCard.tsx +132 -0
  43. package/src/components/viewer/properties/QuantitySetCard.tsx +79 -0
  44. package/src/components/viewer/properties/RelationshipsCard.tsx +100 -0
  45. package/src/components/viewer/properties/encodingUtils.ts +29 -0
  46. package/src/components/viewer/tools/MeasurePanel.tsx +218 -0
  47. package/src/components/viewer/tools/MeasurementVisuals.tsx +644 -0
  48. package/src/components/viewer/tools/SectionPanel.tsx +183 -0
  49. package/src/components/viewer/tools/SectionVisualization.tsx +78 -0
  50. package/src/components/viewer/tools/formatDistance.ts +18 -0
  51. package/src/components/viewer/tools/sectionConstants.ts +14 -0
  52. package/src/components/viewer/useAnimationLoop.ts +166 -0
  53. package/src/components/viewer/useGeometryStreaming.ts +398 -0
  54. package/src/components/viewer/useKeyboardControls.ts +221 -0
  55. package/src/components/viewer/useMouseControls.ts +1009 -0
  56. package/src/components/viewer/useRenderUpdates.ts +165 -0
  57. package/src/components/viewer/useTouchControls.ts +245 -0
  58. package/src/hooks/ids/idsColorSystem.ts +125 -0
  59. package/src/hooks/ids/idsDataAccessor.ts +237 -0
  60. package/src/hooks/ids/idsExportService.ts +444 -0
  61. package/src/hooks/useBCF.ts +7 -0
  62. package/src/hooks/useDrawingExport.ts +627 -0
  63. package/src/hooks/useDrawingGeneration.ts +627 -0
  64. package/src/hooks/useFloorplanView.ts +108 -0
  65. package/src/hooks/useIDS.ts +270 -463
  66. package/src/hooks/useIfc.ts +26 -1628
  67. package/src/hooks/useIfcFederation.ts +803 -0
  68. package/src/hooks/useIfcLoader.ts +508 -0
  69. package/src/hooks/useIfcServer.ts +465 -0
  70. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  71. package/src/hooks/useLens.ts +129 -0
  72. package/src/hooks/useMeasure2D.ts +365 -0
  73. package/src/hooks/useViewControls.ts +218 -0
  74. package/src/lib/ifc4-pset-definitions.test.ts +161 -0
  75. package/src/lib/ifc4-pset-definitions.ts +621 -0
  76. package/src/lib/ifc4-qto-definitions.ts +315 -0
  77. package/src/lib/lens/adapter.ts +138 -0
  78. package/src/lib/lens/index.ts +5 -0
  79. package/src/lib/lists/adapter.ts +69 -0
  80. package/src/lib/lists/index.ts +28 -0
  81. package/src/lib/lists/persistence.ts +64 -0
  82. package/src/services/fs-cache.ts +1 -1
  83. package/src/services/tauri-modules.d.ts +25 -0
  84. package/src/store/index.ts +38 -2
  85. package/src/store/slices/cameraSlice.ts +14 -1
  86. package/src/store/slices/dataSlice.ts +14 -1
  87. package/src/store/slices/lensSlice.ts +184 -0
  88. package/src/store/slices/listSlice.ts +74 -0
  89. package/src/store/slices/pinboardSlice.ts +114 -0
  90. package/src/store/types.ts +5 -0
  91. package/src/utils/ifcConfig.ts +16 -3
  92. package/src/utils/serverDataModel.ts +64 -101
  93. package/src/vite-env.d.ts +3 -0
  94. package/dist/assets/ifc-lite_bg-C6kblxf9.wasm +0 -0
  95. package/dist/assets/index-v3mcCUPN.css +0 -1
@@ -2,7 +2,7 @@
2
2
  * License, v. 2.0. If a copy of the MPL was not distributed with this
3
3
  * file, You can obtain one at https://mozilla.org/MPL/2.0/. */
4
4
 
5
- import { useEffect } from 'react';
5
+ import { useCallback, useEffect, useRef, useState } from 'react';
6
6
  import { Panel, Group as PanelGroup, Separator as PanelResizeHandle } from 'react-resizable-panels';
7
7
  import { TooltipProvider } from '@/components/ui/tooltip';
8
8
  import { MainToolbar } from './MainToolbar';
@@ -17,6 +17,12 @@ import { EntityContextMenu } from './EntityContextMenu';
17
17
  import { HoverTooltip } from './HoverTooltip';
18
18
  import { BCFPanel } from './BCFPanel';
19
19
  import { IDSPanel } from './IDSPanel';
20
+ import { LensPanel } from './LensPanel';
21
+ import { ListPanel } from './lists/ListPanel';
22
+
23
+ const BOTTOM_PANEL_MIN_HEIGHT = 120;
24
+ const BOTTOM_PANEL_DEFAULT_HEIGHT = 300;
25
+ const BOTTOM_PANEL_MAX_RATIO = 0.7; // max 70% of container
20
26
 
21
27
  export function ViewerLayout() {
22
28
  // Initialize keyboard shortcuts
@@ -35,6 +41,60 @@ export function ViewerLayout() {
35
41
  const setBcfPanelVisible = useViewerStore((s) => s.setBcfPanelVisible);
36
42
  const idsPanelVisible = useViewerStore((s) => s.idsPanelVisible);
37
43
  const setIdsPanelVisible = useViewerStore((s) => s.setIdsPanelVisible);
44
+ const listPanelVisible = useViewerStore((s) => s.listPanelVisible);
45
+ const setListPanelVisible = useViewerStore((s) => s.setListPanelVisible);
46
+ const lensPanelVisible = useViewerStore((s) => s.lensPanelVisible);
47
+ const setLensPanelVisible = useViewerStore((s) => s.setLensPanelVisible);
48
+
49
+ // Bottom panel resize state (pixel height, persisted in ref to avoid re-renders during drag)
50
+ const [bottomHeight, setBottomHeight] = useState(BOTTOM_PANEL_DEFAULT_HEIGHT);
51
+ const containerRef = useRef<HTMLDivElement>(null);
52
+ const isDraggingRef = useRef(false);
53
+ const cleanupRef = useRef<(() => void) | null>(null);
54
+
55
+ // Cleanup drag listeners on unmount
56
+ useEffect(() => {
57
+ return () => { cleanupRef.current?.(); };
58
+ }, []);
59
+
60
+ const handleResizeStart = useCallback((e: React.MouseEvent) => {
61
+ e.preventDefault();
62
+ isDraggingRef.current = true;
63
+
64
+ const startY = e.clientY;
65
+ const startHeight = bottomHeight;
66
+
67
+ const onMouseMove = (moveEvent: MouseEvent) => {
68
+ if (!isDraggingRef.current) return;
69
+ const container = containerRef.current;
70
+ if (!container) return;
71
+
72
+ const maxHeight = container.clientHeight * BOTTOM_PANEL_MAX_RATIO;
73
+ const delta = startY - moveEvent.clientY;
74
+ const newHeight = Math.min(
75
+ maxHeight,
76
+ Math.max(BOTTOM_PANEL_MIN_HEIGHT, startHeight + delta)
77
+ );
78
+ setBottomHeight(newHeight);
79
+ };
80
+
81
+ const cleanup = () => {
82
+ isDraggingRef.current = false;
83
+ document.removeEventListener('mousemove', onMouseMove);
84
+ document.removeEventListener('mouseup', onMouseUp);
85
+ document.body.style.cursor = '';
86
+ document.body.style.userSelect = '';
87
+ cleanupRef.current = null;
88
+ };
89
+
90
+ const onMouseUp = () => { cleanup(); };
91
+
92
+ document.addEventListener('mousemove', onMouseMove);
93
+ document.addEventListener('mouseup', onMouseUp);
94
+ document.body.style.cursor = 'row-resize';
95
+ document.body.style.userSelect = 'none';
96
+ cleanupRef.current = cleanup;
97
+ }, [bottomHeight]);
38
98
 
39
99
  // Detect mobile viewport
40
100
  useEffect(() => {
@@ -79,50 +139,71 @@ export function ViewerLayout() {
79
139
 
80
140
  {/* Main Content Area - Desktop Layout */}
81
141
  {!isMobile && (
82
- <PanelGroup orientation="horizontal" className="flex-1 min-h-0">
83
- {/* Left Panel - Hierarchy */}
84
- <Panel
85
- id="left-panel"
86
- defaultSize={20}
87
- minSize={10}
88
- collapsible
89
- collapsedSize={0}
90
- >
91
- <div className="h-full w-full overflow-hidden">
92
- <HierarchyPanel />
93
- </div>
94
- </Panel>
142
+ <div ref={containerRef} className="flex-1 min-h-0 flex flex-col">
143
+ {/* Top: horizontal split (hierarchy | viewport | properties) */}
144
+ <div className="flex-1 min-h-0">
145
+ <PanelGroup orientation="horizontal" className="h-full">
146
+ {/* Left Panel - Hierarchy */}
147
+ <Panel
148
+ id="left-panel"
149
+ defaultSize={20}
150
+ minSize={10}
151
+ collapsible
152
+ collapsedSize={0}
153
+ >
154
+ <div className="h-full w-full overflow-hidden">
155
+ <HierarchyPanel />
156
+ </div>
157
+ </Panel>
95
158
 
96
- <PanelResizeHandle className="w-1.5 bg-border hover:bg-primary/50 active:bg-primary/70 transition-colors cursor-col-resize" />
159
+ <PanelResizeHandle className="w-1.5 bg-border hover:bg-primary/50 active:bg-primary/70 transition-colors cursor-col-resize" />
97
160
 
98
- {/* Center - Viewport */}
99
- <Panel id="viewport-panel" defaultSize={58} minSize={30}>
100
- <div className="h-full w-full overflow-hidden">
101
- <ViewportContainer />
102
- </div>
103
- </Panel>
104
-
105
- <PanelResizeHandle className="w-1.5 bg-border hover:bg-primary/50 active:bg-primary/70 transition-colors cursor-col-resize" />
106
-
107
- {/* Right Panel - Properties, BCF, or IDS */}
108
- <Panel
109
- id="right-panel"
110
- defaultSize={22}
111
- minSize={15}
112
- collapsible
113
- collapsedSize={0}
114
- >
115
- <div className="h-full w-full overflow-hidden">
116
- {idsPanelVisible ? (
117
- <IDSPanel onClose={() => setIdsPanelVisible(false)} />
118
- ) : bcfPanelVisible ? (
119
- <BCFPanel onClose={() => setBcfPanelVisible(false)} />
120
- ) : (
121
- <PropertiesPanel />
122
- )}
161
+ {/* Center - Viewport */}
162
+ <Panel id="viewport-panel" defaultSize={58} minSize={30}>
163
+ <div className="h-full w-full overflow-hidden">
164
+ <ViewportContainer />
165
+ </div>
166
+ </Panel>
167
+
168
+ <PanelResizeHandle className="w-1.5 bg-border hover:bg-primary/50 active:bg-primary/70 transition-colors cursor-col-resize" />
169
+
170
+ {/* Right Panel - Properties, BCF, or IDS */}
171
+ <Panel
172
+ id="right-panel"
173
+ defaultSize={22}
174
+ minSize={15}
175
+ collapsible
176
+ collapsedSize={0}
177
+ >
178
+ <div className="h-full w-full overflow-hidden">
179
+ {lensPanelVisible ? (
180
+ <LensPanel onClose={() => setLensPanelVisible(false)} />
181
+ ) : idsPanelVisible ? (
182
+ <IDSPanel onClose={() => setIdsPanelVisible(false)} />
183
+ ) : bcfPanelVisible ? (
184
+ <BCFPanel onClose={() => setBcfPanelVisible(false)} />
185
+ ) : (
186
+ <PropertiesPanel />
187
+ )}
188
+ </div>
189
+ </Panel>
190
+ </PanelGroup>
191
+ </div>
192
+
193
+ {/* Bottom Panel - Lists (custom resizable, outside PanelGroup) */}
194
+ {listPanelVisible && (
195
+ <div style={{ height: bottomHeight, flexShrink: 0 }} className="relative">
196
+ {/* Drag handle */}
197
+ <div
198
+ className="absolute inset-x-0 top-0 h-1.5 bg-border hover:bg-primary/50 active:bg-primary/70 transition-colors cursor-row-resize z-10"
199
+ onMouseDown={handleResizeStart}
200
+ />
201
+ <div className="h-full w-full overflow-hidden border-t pt-1.5">
202
+ <ListPanel onClose={() => setListPanelVisible(false)} />
203
+ </div>
123
204
  </div>
124
- </Panel>
125
- </PanelGroup>
205
+ )}
206
+ </div>
126
207
  )}
127
208
 
128
209
  {/* Main Content Area - Mobile Layout */}
@@ -154,18 +235,20 @@ export function ViewerLayout() {
154
235
  </div>
155
236
  )}
156
237
 
157
- {/* Mobile Bottom Sheet - Properties, BCF, or IDS */}
238
+ {/* Mobile Bottom Sheet - Properties, BCF, IDS, or Lists */}
158
239
  {!rightPanelCollapsed && (
159
240
  <div className="absolute inset-x-0 bottom-0 h-[50vh] bg-background border-t rounded-t-xl shadow-xl z-40 animate-in slide-in-from-bottom">
160
241
  <div className="flex items-center justify-between p-2 border-b">
161
242
  <span className="font-medium text-sm">
162
- {idsPanelVisible ? 'IDS Validation' : bcfPanelVisible ? 'BCF Issues' : 'Properties'}
243
+ {listPanelVisible ? 'Lists' : lensPanelVisible ? 'Lens' : idsPanelVisible ? 'IDS Validation' : bcfPanelVisible ? 'BCF Issues' : 'Properties'}
163
244
  </span>
164
245
  <button
165
246
  className="p-1 hover:bg-muted rounded"
166
247
  onClick={() => {
167
248
  setRightPanelCollapsed(true);
249
+ if (listPanelVisible) setListPanelVisible(false);
168
250
  if (bcfPanelVisible) setBcfPanelVisible(false);
251
+ if (lensPanelVisible) setLensPanelVisible(false);
169
252
  if (idsPanelVisible) setIdsPanelVisible(false);
170
253
  }}
171
254
  >
@@ -176,7 +259,11 @@ export function ViewerLayout() {
176
259
  </button>
177
260
  </div>
178
261
  <div className="h-[calc(50vh-48px)] overflow-auto">
179
- {idsPanelVisible ? (
262
+ {listPanelVisible ? (
263
+ <ListPanel onClose={() => setListPanelVisible(false)} />
264
+ ) : lensPanelVisible ? (
265
+ <LensPanel onClose={() => setLensPanelVisible(false)} />
266
+ ) : idsPanelVisible ? (
180
267
  <IDSPanel onClose={() => setIdsPanelVisible(false)} />
181
268
  ) : bcfPanelVisible ? (
182
269
  <BCFPanel onClose={() => setBcfPanelVisible(false)} />