@ifc-lite/viewer 1.15.0 → 1.17.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 (62) hide show
  1. package/.turbo/turbo-build.log +46 -0
  2. package/.turbo/turbo-typecheck.log +4 -0
  3. package/CHANGELOG.md +35 -0
  4. package/dist/assets/{Arrow.dom-OVBBPqOB.js → Arrow.dom-CcoDLP6E.js} +1 -1
  5. package/dist/assets/{basketViewActivator-Bx6QU4ma.js → basketViewActivator-FtbS__bG.js} +1 -1
  6. package/dist/assets/{browser-BMqEoJw4.js → browser-CXd3z0DO.js} +1 -1
  7. package/dist/assets/ifc-lite-TI3u_Zyw.js +7 -0
  8. package/dist/assets/ifc-lite_bg-DeZrXTKQ.wasm +0 -0
  9. package/dist/assets/index-Ba4eoTe7.css +1 -0
  10. package/dist/assets/{index-DZY6uD8A.js → index-D99fzcwI.js} +32109 -28671
  11. package/dist/assets/{index-DsX-NCtx.js → index-DqNiuQep.js} +4 -4
  12. package/dist/assets/{native-bridge-D6tKFqGO.js → native-bridge-DjDj2M6p.js} +1 -1
  13. package/dist/assets/{wasm-bridge-D4kvZVDw.js → wasm-bridge-CDTF4ZQc.js} +1 -1
  14. package/dist/assets/workerHelpers-G7llXNMi.js +36 -0
  15. package/dist/index.html +7 -2
  16. package/index.html +5 -0
  17. package/package.json +15 -14
  18. package/src/components/viewer/BCFPanel.tsx +12 -0
  19. package/src/components/viewer/BulkPropertyEditor.tsx +315 -154
  20. package/src/components/viewer/CommandPalette.tsx +0 -6
  21. package/src/components/viewer/DataConnector.tsx +489 -284
  22. package/src/components/viewer/ExportDialog.tsx +66 -6
  23. package/src/components/viewer/KeyboardShortcutsDialog.tsx +227 -82
  24. package/src/components/viewer/MainToolbar.tsx +1 -5
  25. package/src/components/viewer/Viewport.tsx +42 -56
  26. package/src/components/viewer/ViewportContainer.tsx +3 -0
  27. package/src/components/viewer/ViewportOverlays.tsx +12 -10
  28. package/src/components/viewer/bcf/BCFOverlay.tsx +254 -0
  29. package/src/components/viewer/hierarchy/HierarchyNode.tsx +26 -20
  30. package/src/components/viewer/hierarchy/ifc-icons.ts +90 -0
  31. package/src/components/viewer/lists/ListPanel.tsx +0 -21
  32. package/src/components/viewer/lists/ListResultsTable.tsx +93 -5
  33. package/src/components/viewer/measureHandlers.ts +558 -0
  34. package/src/components/viewer/mouseHandlerTypes.ts +108 -0
  35. package/src/components/viewer/selectionHandlers.ts +86 -0
  36. package/src/components/viewer/useAnimationLoop.ts +116 -44
  37. package/src/components/viewer/useGeometryStreaming.ts +155 -367
  38. package/src/components/viewer/useKeyboardControls.ts +30 -46
  39. package/src/components/viewer/useMouseControls.ts +169 -695
  40. package/src/components/viewer/useRenderUpdates.ts +9 -59
  41. package/src/components/viewer/useTouchControls.ts +55 -40
  42. package/src/hooks/bcfIdLookup.ts +70 -0
  43. package/src/hooks/useBCF.ts +12 -31
  44. package/src/hooks/useIfcCache.ts +11 -29
  45. package/src/hooks/useIfcFederation.ts +5 -11
  46. package/src/hooks/useIfcLoader.ts +47 -56
  47. package/src/hooks/useIfcServer.ts +9 -1
  48. package/src/hooks/useKeyboardShortcuts.ts +28 -12
  49. package/src/hooks/useLatestRef.ts +24 -0
  50. package/src/sdk/adapters/export-adapter.ts +2 -2
  51. package/src/sdk/adapters/model-adapter.ts +1 -0
  52. package/src/sdk/local-backend.ts +2 -0
  53. package/src/store/basketVisibleSet.ts +12 -0
  54. package/src/store/slices/bcfSlice.ts +9 -0
  55. package/src/store/slices/pinboardSlice.ts +46 -45
  56. package/src/utils/loadingUtils.ts +46 -0
  57. package/src/utils/serverDataModel.ts +4 -3
  58. package/src/utils/spatialHierarchy.ts +1 -1
  59. package/src/vite-env.d.ts +6 -2
  60. package/vite.config.ts +75 -23
  61. package/dist/assets/ifc-lite_bg-CyWQTvp5.wasm +0 -0
  62. package/dist/assets/index-CJr7Itua.css +0 -1
@@ -1,6 +1,6 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/browser-BMqEoJw4.js","assets/index-DZY6uD8A.js","assets/index-CJr7Itua.css"])))=>i.map(i=>d[i]);
2
- import { _ as u, b as _, d as M, __tla as __tla_0 } from "./index-DZY6uD8A.js";
3
- import { N as Z, m as $, __tla as __tla_1 } from "./index-DZY6uD8A.js";
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/browser-CXd3z0DO.js","assets/index-D99fzcwI.js","assets/index-Ba4eoTe7.css"])))=>i.map(i=>d[i]);
2
+ import { _ as u, b as _, d as M, __tla as __tla_0 } from "./index-D99fzcwI.js";
3
+ import { N as Z, m as $, __tla as __tla_1 } from "./index-D99fzcwI.js";
4
4
  let c, y, O, V, I, C, L;
5
5
  let __tla = Promise.all([
6
6
  (()=>{
@@ -91,7 +91,7 @@ let __tla = Promise.all([
91
91
  function D() {
92
92
  return m || (m = (async ()=>{
93
93
  try {
94
- const s = await u(()=>import("./browser-BMqEoJw4.js").then((i)=>i.b), __vite__mapDeps([0,1,2])), t = s.default ?? s;
94
+ const s = await u(()=>import("./browser-CXd3z0DO.js").then((i)=>i.b), __vite__mapDeps([0,1,2])), t = s.default ?? s;
95
95
  let e;
96
96
  try {
97
97
  e = (await u(()=>import("./esbuild-COv63sf-.js"), [])).default;
@@ -1,4 +1,4 @@
1
- import { _ as c, __tla as __tla_0 } from "./index-DZY6uD8A.js";
1
+ import { _ as c, __tla as __tla_0 } from "./index-D99fzcwI.js";
2
2
  let m;
3
3
  let __tla = Promise.all([
4
4
  (()=>{
@@ -1 +1 @@
1
- import{I as f,a as m}from"./index-DZY6uD8A.js";class u{bridge;initialized=!1;constructor(){this.bridge=new f}async init(){this.initialized||(await this.bridge.init(),this.initialized=!0)}isInitialized(){return this.initialized}async processGeometry(s){this.initialized||await this.init(),performance.now();const i=new m(this.bridge.getApi(),s),n=i.collectMeshes(),r=i.getBuildingRotation();performance.now();let e=0,o=0;for(const c of n)e+=c.positions.length/3,o+=c.indices.length/3;return{meshes:n,totalVertices:e,totalTriangles:o,coordinateInfo:{originShift:{x:0,y:0,z:0},originalBounds:{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}},shiftedBounds:{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}},hasLargeCoordinates:!1,buildingRotation:r}}}async processGeometryStreaming(s,i){this.initialized||await this.init();const n=performance.now(),r=new m(this.bridge.getApi(),s);let e=0,o=0,a=0;try{for await(const t of r.collectMeshesStreaming(50)){if(t&&typeof t=="object"&&"type"in t&&t.type==="colorUpdate")continue;const l=t;e+=l.length;for(const d of l)o+=d.positions.length/3,a+=d.indices.length/3;i.onBatch?.({meshes:l,progress:{processed:e,total:e,currentType:"processing"}})}}catch(t){throw i.onError?.(t instanceof Error?t:new Error(String(t))),t}const h=performance.now()-n,g={totalMeshes:e,totalVertices:o,totalTriangles:a,parseTimeMs:h*.3,geometryTimeMs:h*.7};return i.onComplete?.(g),g}getApi(){return this.bridge.getApi()}}export{u as WasmBridge};
1
+ import{I as f,a as m}from"./index-D99fzcwI.js";class u{bridge;initialized=!1;constructor(){this.bridge=new f}async init(){this.initialized||(await this.bridge.init(),this.initialized=!0)}isInitialized(){return this.initialized}async processGeometry(s){this.initialized||await this.init(),performance.now();const i=new m(this.bridge.getApi(),s),n=i.collectMeshes(),r=i.getBuildingRotation();performance.now();let e=0,o=0;for(const c of n)e+=c.positions.length/3,o+=c.indices.length/3;return{meshes:n,totalVertices:e,totalTriangles:o,coordinateInfo:{originShift:{x:0,y:0,z:0},originalBounds:{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}},shiftedBounds:{min:{x:0,y:0,z:0},max:{x:0,y:0,z:0}},hasLargeCoordinates:!1,buildingRotation:r}}}async processGeometryStreaming(s,i){this.initialized||await this.init();const n=performance.now(),r=new m(this.bridge.getApi(),s);let e=0,o=0,a=0;try{for await(const t of r.collectMeshesStreaming(50)){if(t&&typeof t=="object"&&"type"in t&&t.type==="colorUpdate")continue;const l=t;e+=l.length;for(const d of l)o+=d.positions.length/3,a+=d.indices.length/3;i.onBatch?.({meshes:l,progress:{processed:e,total:e,currentType:"processing"}})}}catch(t){throw i.onError?.(t instanceof Error?t:new Error(String(t))),t}const h=performance.now()-n,g={totalMeshes:e,totalVertices:o,totalTriangles:a,parseTimeMs:h*.3,geometryTimeMs:h*.7};return i.onComplete?.(g),g}getApi(){return this.bridge.getApi()}}export{u as WasmBridge};
@@ -0,0 +1,36 @@
1
+ let a;
2
+ let __tla = (async ()=>{
3
+ function o(r, t) {
4
+ return new Promise((e)=>{
5
+ r.addEventListener("message", function s({ data: n }) {
6
+ n?.type === t && (r.removeEventListener("message", s), e(n));
7
+ });
8
+ });
9
+ }
10
+ typeof self < "u" && o(self, "wasm_bindgen_worker_init").then(async ({ init: r, receiver: t })=>{
11
+ const e = await import("./ifc-lite-TI3u_Zyw.js");
12
+ await e.default(r), postMessage({
13
+ type: "wasm_bindgen_worker_ready"
14
+ }), e.wbg_rayon_start_worker(t);
15
+ });
16
+ a = async function(r, t, e) {
17
+ if (e.numThreads() === 0) throw new Error("num_threads must be > 0.");
18
+ const s = {
19
+ type: "wasm_bindgen_worker_init",
20
+ init: {
21
+ module_or_path: r,
22
+ memory: t
23
+ },
24
+ receiver: e.receiver()
25
+ };
26
+ await Promise.all(Array.from({
27
+ length: e.numThreads()
28
+ }, async ()=>{
29
+ const n = new Worker(self.location.href, {
30
+ type: "module"
31
+ });
32
+ return n.postMessage(s), await o(n, "wasm_bindgen_worker_ready"), n;
33
+ })), e.build();
34
+ };
35
+ })();
36
+ export { a as s, __tla };
package/dist/index.html CHANGED
@@ -40,12 +40,17 @@
40
40
  <!-- Web App Manifest (PWA support) -->
41
41
  <link rel="manifest" href="/manifest.json">
42
42
 
43
+ <!-- Material Symbols font for IFC class icons -->
44
+ <link rel="preconnect" href="https://fonts.googleapis.com">
45
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
46
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">
47
+
43
48
  <!-- Theme colors -->
44
49
  <meta name="theme-color" content="#7aa2f7">
45
50
  <meta name="msapplication-TileColor" content="#1a1b26">
46
51
  <meta name="msapplication-TileImage" content="/favicon-192x192-cropped.png">
47
- <script type="module" crossorigin src="/assets/index-DZY6uD8A.js"></script>
48
- <link rel="stylesheet" crossorigin href="/assets/index-CJr7Itua.css">
52
+ <script type="module" crossorigin src="/assets/index-D99fzcwI.js"></script>
53
+ <link rel="stylesheet" crossorigin href="/assets/index-Ba4eoTe7.css">
49
54
  </head>
50
55
  <body>
51
56
  <div id="root"></div>
package/index.html CHANGED
@@ -40,6 +40,11 @@
40
40
  <!-- Web App Manifest (PWA support) -->
41
41
  <link rel="manifest" href="/manifest.json">
42
42
 
43
+ <!-- Material Symbols font for IFC class icons -->
44
+ <link rel="preconnect" href="https://fonts.googleapis.com">
45
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
46
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200&display=swap">
47
+
43
48
  <!-- Theme colors -->
44
49
  <meta name="theme-color" content="#7aa2f7">
45
50
  <meta name="msapplication-TileColor" content="#1a1b26">
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ifc-lite/viewer",
3
- "version": "1.15.0",
3
+ "version": "1.17.0",
4
4
  "description": "IFC-Lite viewer application",
5
5
  "type": "module",
6
6
  "dependencies": {
@@ -42,24 +42,24 @@
42
42
  "tailwind-merge": "^3.4.0",
43
43
  "tailwindcss": "^4.1.18",
44
44
  "zustand": "^4.4.0",
45
- "@ifc-lite/bcf": "^1.14.3",
45
+ "@ifc-lite/bcf": "^1.15.0",
46
46
  "@ifc-lite/cache": "^1.14.3",
47
- "@ifc-lite/data": "^1.14.3",
48
47
  "@ifc-lite/drawing-2d": "^1.14.3",
48
+ "@ifc-lite/data": "^1.14.5",
49
+ "@ifc-lite/export": "^1.16.0",
50
+ "@ifc-lite/geometry": "^1.14.4",
49
51
  "@ifc-lite/encoding": "^1.14.4",
50
- "@ifc-lite/export": "^1.15.0",
51
- "@ifc-lite/geometry": "^1.14.3",
52
- "@ifc-lite/ids": "^1.14.4",
52
+ "@ifc-lite/ids": "^1.14.6",
53
53
  "@ifc-lite/lens": "^1.14.3",
54
- "@ifc-lite/lists": "^1.14.4",
55
- "@ifc-lite/mutations": "^1.14.3",
56
- "@ifc-lite/parser": "^2.1.0",
54
+ "@ifc-lite/lists": "^1.14.6",
55
+ "@ifc-lite/parser": "^2.1.3",
56
+ "@ifc-lite/renderer": "^1.14.6",
57
57
  "@ifc-lite/query": "^1.14.4",
58
- "@ifc-lite/renderer": "^1.14.3",
59
- "@ifc-lite/sandbox": "^1.14.3",
60
58
  "@ifc-lite/server-client": "^1.14.3",
61
- "@ifc-lite/spatial": "^1.14.3",
62
- "@ifc-lite/wasm": "^1.14.3"
59
+ "@ifc-lite/spatial": "^1.14.4",
60
+ "@ifc-lite/sandbox": "^1.14.4",
61
+ "@ifc-lite/wasm": "^1.14.5",
62
+ "@ifc-lite/mutations": "^1.14.3"
63
63
  },
64
64
  "devDependencies": {
65
65
  "@tailwindcss/postcss": "^4.1.18",
@@ -75,7 +75,8 @@
75
75
  },
76
76
  "scripts": {
77
77
  "dev": "vite",
78
- "build": "NODE_OPTIONS='--max-old-space-size=4096' bash -c '(tsc || true) && vite build'",
78
+ "build": "vite build",
79
+ "typecheck": "tsc --noEmit",
79
80
  "preview": "vite preview",
80
81
  "test": "tsx --test --test-concurrency=1 $(find src -type f \\( -name '*.test.ts' -o -name '*.test.tsx' \\) | sort)",
81
82
  "check:templates": "tsc -p src/lib/scripts/templates/tsconfig.json --noEmit"
@@ -20,6 +20,7 @@ import {
20
20
  Upload,
21
21
  Download,
22
22
  User,
23
+ MapPin,
23
24
  } from 'lucide-react';
24
25
  import { Button } from '@/components/ui/button';
25
26
  import { Input } from '@/components/ui/input';
@@ -63,6 +64,8 @@ export function BCFPanel({ onClose }: BCFPanelProps) {
63
64
  const bcfAuthor = useViewerStore((s) => s.bcfAuthor);
64
65
  const setBcfAuthor = useViewerStore((s) => s.setBcfAuthor);
65
66
  const setBcfLoading = useViewerStore((s) => s.setBcfLoading);
67
+ const bcfOverlayVisible = useViewerStore((s) => s.bcfOverlayVisible);
68
+ const toggleBcfOverlay = useViewerStore((s) => s.toggleBcfOverlay);
66
69
 
67
70
  // Viewer state for capture feedback
68
71
  const selectedEntityId = useViewerStore((s) => s.selectedEntityId);
@@ -302,6 +305,15 @@ export function BCFPanel({ onClose }: BCFPanelProps) {
302
305
  >
303
306
  <Download className="h-4 w-4" />
304
307
  </Button>
308
+ <Button
309
+ variant={bcfOverlayVisible ? 'secondary' : 'ghost'}
310
+ size="icon"
311
+ className="h-7 w-7"
312
+ onClick={toggleBcfOverlay}
313
+ title={bcfOverlayVisible ? 'Hide 3D markers' : 'Show 3D markers'}
314
+ >
315
+ <MapPin className="h-4 w-4" />
316
+ </Button>
305
317
  <Button
306
318
  variant="ghost"
307
319
  size="icon"