@thatopen/services 0.2.0 → 0.3.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 (115) hide show
  1. package/README.md +59 -59
  2. package/dist/built-in/index.d.ts +486 -563
  3. package/dist/cli.js +10 -0
  4. package/dist/index.cjs.js +2 -2
  5. package/dist/index.es.js +3 -5
  6. package/dist/vite-env.d.ts +1 -1
  7. package/docs/builtin/paths.json +74 -70
  8. package/docs/cli/create.md +28 -28
  9. package/docs/cli/local-server.md +38 -38
  10. package/docs/cli/login.md +32 -32
  11. package/docs/cli/publish.md +31 -31
  12. package/docs/cli/run.md +26 -26
  13. package/docs/cli/serve.md +43 -43
  14. package/docs/cli/swap.md +30 -30
  15. package/package.json +100 -100
  16. package/resources/AGENTS.md +40 -40
  17. package/src/built-in/CDEManager/example.ts +214 -214
  18. package/src/built-in/CDEManager/examples/FileEditing/example.ts +226 -226
  19. package/src/built-in/CDEManager/examples/FileMoves/example.ts +186 -186
  20. package/src/built-in/CDEManager/examples/FileOperations/example.ts +295 -295
  21. package/src/built-in/CDEManager/examples/FileTransfers/example.ts +210 -210
  22. package/src/built-in/CDEManager/examples/FolderManagement/example.ts +230 -230
  23. package/src/built-in/CDEManager/examples/MetadataSchema/example.ts +230 -230
  24. package/src/built-in/CDEManager/examples/MetadataViews/example.ts +166 -166
  25. package/src/built-in/CDEManager/examples/ProjectConfig/example.ts +177 -177
  26. package/src/built-in/UIManager/src/app/example.ts +99 -99
  27. package/src/built-in/UIManager/src/app/examples/AppState/example.ts +142 -142
  28. package/src/built-in/UIManager/src/app/examples/Banner/example.ts +161 -0
  29. package/src/built-in/UIManager/src/app/examples/Contexts/example.ts +125 -125
  30. package/src/built-in/UIManager/src/app/examples/FileDrop/example.ts +126 -0
  31. package/src/built-in/UIManager/src/app/examples/FloatingLayout/example.ts +92 -92
  32. package/src/built-in/UIManager/src/app/examples/Modal/example.ts +165 -0
  33. package/src/built-in/UIManager/src/app/examples/Notifications/example.ts +135 -161
  34. package/src/built-in/UIManager/src/app/examples/Sidebar/example.ts +104 -104
  35. package/src/built-in/index.ts +649 -755
  36. package/src/cli/templates/app/README.md +241 -241
  37. package/src/cli/templates/app/index.html +35 -27
  38. package/src/cli/templates/app/package.json +31 -27
  39. package/src/cli/templates/app/src/app.ts +37 -0
  40. package/src/cli/templates/app/src/assets/tool-placeholder.ts +50 -0
  41. package/src/cli/templates/app/src/bim-components/CloudRunner/index.ts +95 -87
  42. package/src/cli/templates/app/src/bim-components/CloudRunner/src/index.ts +1 -1
  43. package/src/cli/templates/app/src/bim-components/CloudRunner/src/types.ts +5 -5
  44. package/src/cli/templates/app/src/bim-components/index.ts +1 -1
  45. package/src/cli/templates/app/src/globals.ts +1 -0
  46. package/src/cli/templates/app/src/main.ts +340 -56
  47. package/src/cli/templates/app/src/setups/active-tool-hud.ts +69 -0
  48. package/src/cli/templates/app/src/setups/camera-tools.ts +63 -0
  49. package/src/cli/templates/app/src/setups/camera-views.ts +201 -0
  50. package/src/cli/templates/app/src/setups/card-header.ts +35 -0
  51. package/src/cli/templates/app/src/setups/clipper-panel.ts +167 -0
  52. package/src/cli/templates/app/src/setups/clipper-tool.ts +754 -0
  53. package/src/cli/templates/app/src/setups/clipper.ts +75 -0
  54. package/src/cli/templates/app/src/setups/cloud-runner.ts +13 -9
  55. package/src/cli/templates/app/src/setups/commands-panel.ts +239 -0
  56. package/src/cli/templates/app/src/setups/data-table-panel.ts +2224 -0
  57. package/src/cli/templates/app/src/setups/exploded-view.ts +246 -0
  58. package/src/cli/templates/app/src/setups/file-format-icons.ts +95 -0
  59. package/src/cli/templates/app/src/setups/files-panel.ts +1503 -0
  60. package/src/cli/templates/app/src/setups/fps-indicator.ts +63 -0
  61. package/src/cli/templates/app/src/setups/graphics-panel.ts +490 -0
  62. package/src/cli/templates/app/src/setups/helper-panel.ts +88 -0
  63. package/src/cli/templates/app/src/setups/hider.ts +98 -0
  64. package/src/cli/templates/app/src/setups/index.ts +33 -3
  65. package/src/cli/templates/app/src/setups/inspection.ts +136 -0
  66. package/src/cli/templates/app/src/setups/measurement-panel.ts +188 -0
  67. package/src/cli/templates/app/src/setups/measurement-settings-panel.ts +161 -0
  68. package/src/cli/templates/app/src/setups/measurement-tool.ts +570 -0
  69. package/src/cli/templates/app/src/setups/measurements.ts +133 -0
  70. package/src/cli/templates/app/src/setups/model-tree.ts +797 -0
  71. package/src/cli/templates/app/src/setups/navigation-gizmo.ts +316 -0
  72. package/src/cli/templates/app/src/setups/objects-panel.ts +127 -0
  73. package/src/cli/templates/app/src/setups/plans-panel.ts +619 -0
  74. package/src/cli/templates/app/src/setups/properties-panel.ts +1048 -0
  75. package/src/cli/templates/app/src/setups/reality-capture/lib/hidden-tiles-plugin.ts +88 -0
  76. package/src/cli/templates/app/src/setups/reality-capture/lib/point-tile-plugin.ts +166 -0
  77. package/src/cli/templates/app/src/setups/reality-capture/lib/render-frame.ts +31 -0
  78. package/src/cli/templates/app/src/setups/reality-capture/lib/splat-tile-plugin.ts +51 -0
  79. package/src/cli/templates/app/src/setups/reality-capture-viewer.ts +1383 -0
  80. package/src/cli/templates/app/src/setups/right-sidebar.ts +178 -0
  81. package/src/cli/templates/app/src/setups/settings-panel.ts +94 -0
  82. package/src/cli/templates/app/src/setups/styles-panel.ts +110 -0
  83. package/src/cli/templates/app/src/setups/styles.ts +375 -0
  84. package/src/cli/templates/app/src/setups/tool-mode-manager.ts +150 -0
  85. package/src/cli/templates/app/src/setups/tool-mode.ts +23 -0
  86. package/src/cli/templates/app/src/setups/toolbar.ts +229 -0
  87. package/src/cli/templates/app/src/setups/ui-manager.ts +27 -0
  88. package/src/cli/templates/app/src/setups/visibility-toolbar.ts +498 -0
  89. package/src/cli/templates/app/src/setups/walkthrough.ts +528 -0
  90. package/src/cli/templates/app/src/ui-components/app-info-section/index.ts +26 -0
  91. package/src/cli/templates/app/src/ui-components/app-info-section/src/index.ts +1 -0
  92. package/src/cli/templates/app/src/ui-components/app-info-section/src/types.ts +15 -0
  93. package/src/cli/templates/app/src/ui-components/cloud-runner-section/index.ts +37 -0
  94. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/index.ts +1 -0
  95. package/src/cli/templates/app/src/ui-components/cloud-runner-section/src/types.ts +14 -0
  96. package/src/cli/templates/app/src/ui-components/index.ts +2 -1
  97. package/src/cli/templates/app/tsconfig.json +16 -17
  98. package/src/cli/templates/app/vite.config.js +45 -42
  99. package/src/cli/templates/cloud-component/README.md +205 -205
  100. package/src/cli/templates/cloud-component/_thatopen +5 -5
  101. package/src/cli/templates/cloud-component/declarations.json +4 -4
  102. package/src/cli/templates/cloud-component/package.json +21 -21
  103. package/src/cli/templates/cloud-component/src/main.ts +70 -70
  104. package/src/cli/templates/cloud-component/tsconfig.json +16 -16
  105. package/src/cli/templates/cloud-component/vite.config.js +46 -46
  106. package/src/cli/templates/shared/AGENTS.md +8 -8
  107. package/src/cli/templates/shared/CLAUDE.md +1 -1
  108. package/src/cli/templates/shared/_gitignore +5 -5
  109. package/src/built-in/AppManager/example.ts +0 -86
  110. package/src/built-in/FileList/example.ts +0 -107
  111. package/src/built-in/TabbedNavigation/example.ts +0 -115
  112. package/src/built-in/ViewportsManager/example.ts +0 -106
  113. package/src/cli/templates/app/src/setups/fragments.ts +0 -18
  114. package/src/cli/templates/app/src/setups/ifc-loader.ts +0 -12
  115. package/src/cli/templates/app/src/ui-components/AppPanel/index.ts +0 -160
@@ -0,0 +1,165 @@
1
+ /* MD
2
+ ## Confirmation modals with top:modal
3
+ ---
4
+ Destructive or irreversible actions — deleting records, overwriting files,
5
+ leaving unsaved changes — should ask the user to confirm before proceeding.
6
+ Opening a custom dialog element from a deeply nested component means threading
7
+ a reference to a controller up through every layer of the tree.
8
+
9
+ top-app provides a modal slot that any descendant can trigger by dispatching
10
+ a single DOM event. The modal blocks the UI, shows a configurable message and
11
+ action labels, and calls back into the originating component when the user
12
+ confirms or cancels — no reference to the root element required.
13
+
14
+ This tutorial covers showing a modal from a child component by dispatching
15
+ top:modal; setting the label, icon, and button labels; running an async
16
+ confirm handler while the modal shows a loading spinner; and handling the
17
+ cancel path without side effects.
18
+
19
+ By the end, you'll have an app where a panel can trigger confirmation dialogs
20
+ for actions of varying severity, each with its own copy and async behaviour.
21
+ */
22
+
23
+ import { html, LitElement } from "lit";
24
+ import { customElement, state } from "lit/decorators.js";
25
+ import * as THREE from "three";
26
+ import * as OBC from "@thatopen/components";
27
+ import * as OBF from "@thatopen/components-front";
28
+ import * as FRAGS from "@thatopen/fragments";
29
+ import * as BUI from "@thatopen/ui";
30
+ import { PlatformClient } from "thatopen-services";
31
+ import uiManagerDef from "../../../../index";
32
+ import type { App } from "../../index";
33
+
34
+ // A child component that triggers modals without holding a reference to top-app.
35
+ // It dispatches top:modal and receives the result via onConfirm / onCancel callbacks.
36
+ @customElement("modal-actions")
37
+ class ModalActions extends LitElement {
38
+ @state() private _lastAction = "—";
39
+
40
+ private _confirmDelete() {
41
+ // top:modal opens a blocking dialog on the nearest top-app ancestor.
42
+ // The modal stays open (with a loading spinner) while onConfirm is awaited.
43
+ this.dispatchEvent(
44
+ new CustomEvent("top:modal", {
45
+ bubbles: true,
46
+ composed: true,
47
+ detail: {
48
+ label: "Delete model",
49
+ icon: "tabler:trash",
50
+ confirmLabel: "Delete",
51
+ cancelLabel: "Keep",
52
+ content: html`
53
+ <bim-label style="white-space:normal;">
54
+ This will permanently remove the model and all its versions.
55
+ This action cannot be undone.
56
+ </bim-label>
57
+ `,
58
+ onConfirm: async () => {
59
+ // Simulate an async delete operation.
60
+ // The modal shows a loading spinner until this promise resolves.
61
+ await new Promise<void>((resolve) => setTimeout(resolve, 1500));
62
+ this._lastAction = "Model deleted";
63
+ },
64
+ onCancel: () => {
65
+ this._lastAction = "Delete cancelled";
66
+ },
67
+ },
68
+ }),
69
+ );
70
+ }
71
+
72
+ private _confirmOverwrite() {
73
+ this.dispatchEvent(
74
+ new CustomEvent("top:modal", {
75
+ bubbles: true,
76
+ composed: true,
77
+ detail: {
78
+ label: "File already exists",
79
+ icon: "tabler:alert-triangle",
80
+ confirmLabel: "Overwrite",
81
+ cancelLabel: "Cancel",
82
+ content: html`
83
+ <bim-label style="white-space:normal;">
84
+ A file named <strong>structure.ifc</strong> already exists in this
85
+ folder. Uploading will create a new version alongside it.
86
+ </bim-label>
87
+ `,
88
+ // onConfirm can be synchronous too — the modal closes immediately.
89
+ onConfirm: () => {
90
+ this._lastAction = "Overwrite confirmed";
91
+ },
92
+ onCancel: () => {
93
+ this._lastAction = "Overwrite cancelled";
94
+ },
95
+ },
96
+ }),
97
+ );
98
+ }
99
+
100
+ render() {
101
+ return html`
102
+ <bim-panel label="Modal Actions">
103
+ <bim-panel-section label="Actions" icon="tabler:click">
104
+ <bim-button
105
+ label="Delete model (async confirm)"
106
+ icon="tabler:trash"
107
+ @click=${this._confirmDelete}
108
+ ></bim-button>
109
+ <bim-button
110
+ label="Overwrite file (sync confirm)"
111
+ icon="tabler:file-upload"
112
+ @click=${this._confirmOverwrite}
113
+ ></bim-button>
114
+ <bim-label>Last action: ${this._lastAction}</bim-label>
115
+ </bim-panel-section>
116
+ </bim-panel>
117
+ `;
118
+ }
119
+ }
120
+
121
+ // ---- app wiring ----
122
+
123
+ const UIManager = uiManagerDef.componentDefinition;
124
+ const client = PlatformClient.fromPlatformContext();
125
+ const { components } = (await client.setup(
126
+ { OBC, OBF, BUI, THREE, FRAGS },
127
+ { uuid: UIManager.uuid },
128
+ )) as { components: OBC.Components };
129
+ components.get(UIManager).init();
130
+
131
+ const app = document.createElement("top-app") as unknown as App;
132
+
133
+ app.setup = (waitUntil) => {
134
+ waitUntil(
135
+ (async () => {
136
+ const fragments = components.get(OBC.FragmentsManager);
137
+ const workerUrl = await FRAGS.FragmentsModels.getWorker();
138
+ fragments.init(await FRAGS.toClassicWorker(workerUrl), {
139
+ classicWorker: true,
140
+ });
141
+ })(),
142
+ "Fragments Core",
143
+ );
144
+ return { components, client };
145
+ };
146
+
147
+ app.elements = {
148
+ viewer: () =>
149
+ html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
150
+ panel: () => html`<modal-actions></modal-actions>`,
151
+ };
152
+
153
+ app.base = "viewer";
154
+ app.layouts = {
155
+ main: {
156
+ label: "Main",
157
+ icon: "solar:home-bold",
158
+ template: `"panel" 1fr / 22rem`,
159
+ },
160
+ };
161
+ app.layout = "main";
162
+
163
+ const container = document.getElementById("that-open-app") ?? document.body;
164
+ container.appendChild(app);
165
+ document.body.style.margin = "0";
@@ -1,161 +1,135 @@
1
- /* MD
2
- ## Toasts, file drop, and cross-component notifications
3
- ---
4
- Developers building BIM processing UIs need to surface status updates, errors,
5
- and file-drop feedback to users from different points in the component tree —
6
- but reaching back to the app root to trigger a notification from a deeply nested
7
- component requires threading a reference through every layer in between.
8
-
9
- top-app provides a built-in toast system that any descendant can trigger by
10
- dispatching a standard DOM event, a drag-and-drop overlay that activates
11
- automatically when files enter the window, and a drop-zone message that can be
12
- computed from live state at render time rather than set once at initialization.
13
-
14
- This tutorial covers showing a success toast when the app finishes booting;
15
- building a component that dispatches notification events to report async progress
16
- and completion without a reference to the root; handling dropped files, filtering
17
- them by extension, and showing a warning when none are supported; and setting the
18
- drop-zone message as a function that reads a live model counter.
19
-
20
- By the end, you'll have an app with a full notification layer — a boot
21
- confirmation toast, async status reporting from a child component, and a
22
- drag-and-drop zone whose message updates as models are loaded.
23
- */
24
-
25
- import { html, LitElement } from "lit";
26
- import { customElement, state } from "lit/decorators.js";
27
- import * as THREE from "three";
28
- import * as OBC from "@thatopen/components";
29
- import * as OBF from "@thatopen/components-front";
30
- import * as FRAGS from "@thatopen/fragments";
31
- import * as BUI from "@thatopen/ui";
32
- import { PlatformClient } from "thatopen-services";
33
- import uiManagerDef from "../../../../index";
34
- import type { App, AppReadyEvent } from "../../index";
35
-
36
- // A child component that dispatches top:notification to surface messages
37
- // to the nearest top-app ancestor — no reference to the app element needed.
38
- @customElement("status-reporter")
39
- class StatusReporter extends LitElement {
40
- @state() private _busy = false;
41
-
42
- private _simulateWork() {
43
- this._busy = true;
44
-
45
- // Dispatching top:notification from any descendant of top-app shows a toast.
46
- // bubbles:true + composed:true lets it cross shadow-DOM boundaries.
47
- this.dispatchEvent(
48
- new CustomEvent("top:notification", {
49
- bubbles: true,
50
- composed: true,
51
- detail: { message: "Analysis started", type: "info" },
52
- }),
53
- );
54
-
55
- setTimeout(() => {
56
- this._busy = false;
57
- this.dispatchEvent(
58
- new CustomEvent("top:notification", {
59
- bubbles: true,
60
- composed: true,
61
- detail: {
62
- message: "Analysis complete",
63
- type: "success",
64
- description: "Found 342 elements across 5 categories.",
65
- },
66
- }),
67
- );
68
- }, 2000);
69
- }
70
-
71
- render() {
72
- return html`
73
- <bim-panel label="Reporter">
74
- <bim-panel-section label="Actions" icon="solar:play-bold">
75
- <bim-button
76
- label="Run Analysis"
77
- icon="solar:play-bold"
78
- .loading=${this._busy}
79
- @click=${this._simulateWork}
80
- ></bim-button>
81
- </bim-panel-section>
82
- </bim-panel>
83
- `;
84
- }
85
- }
86
-
87
- // ---- app wiring ----
88
-
89
- const UIManager = uiManagerDef.componentDefinition;
90
- const client = PlatformClient.fromPlatformContext();
91
- const { components } = (await client.setup(
92
- { OBC, OBF, BUI, THREE, FRAGS },
93
- { uuid: UIManager.uuid },
94
- )) as { components: OBC.Components };
95
- components.get(UIManager).init();
96
-
97
- const app = document.createElement("top-app") as unknown as App;
98
-
99
- app.setup = (waitUntil) => {
100
- waitUntil(
101
- (async () => {
102
- const fragments = components.get(OBC.FragmentsManager);
103
- const workerUrl = await FRAGS.FragmentsModels.getWorker();
104
- fragments.init(await FRAGS.toClassicWorker(workerUrl), {
105
- classicWorker: true,
106
- });
107
- })(),
108
- "Fragments Core",
109
- );
110
- return { components, client };
111
- };
112
-
113
- app.elements = {
114
- viewer: () =>
115
- html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
116
- panel: () => html`<status-reporter></status-reporter>`,
117
- };
118
-
119
- app.base = "viewer";
120
- app.layouts = {
121
- main: {
122
- label: "Main",
123
- icon: "solar:home-bold",
124
- template: `"panel" 1fr / 22rem`,
125
- },
126
- };
127
- app.layout = "main";
128
-
129
- // dropMessage as a function is called at render time so it can read live state.
130
- // Here it reads how many models are already loaded and adjusts the hint text.
131
- let loadedCount = 0;
132
- app.dropMessage = () =>
133
- loadedCount === 0
134
- ? "Drop an IFC or FRAG file to load your first model"
135
- : `Drop a file to add to the ${loadedCount} loaded model${loadedCount === 1 ? "" : "s"}`;
136
-
137
- // top:files-dropped fires when the user drops files onto the window.
138
- // e.detail.files is a File[]. Handle upload, load, or validation here.
139
- app.addEventListener("top:files-dropped", (e) => {
140
- const { files } = (e as CustomEvent<{ files: File[] }>).detail;
141
- const supported = files.filter((f) =>
142
- f.name.endsWith(".ifc") || f.name.endsWith(".frag"),
143
- );
144
- if (!supported.length) {
145
- app.showToast("No supported files dropped", "warning");
146
- return;
147
- }
148
- app.showToast(`Loading ${supported.length} file${supported.length === 1 ? "" : "s"}…`, "info");
149
- loadedCount += supported.length;
150
- });
151
-
152
- // thatopen:app-ready fires after all waitUntil promises resolve.
153
- // e.detail.app is a reference to the top-app element itself.
154
- app.addEventListener("thatopen:app-ready", (e) => {
155
- const { app: readyApp } = (e as AppReadyEvent).detail;
156
- readyApp.showToast("App ready", "success");
157
- });
158
-
159
- const container = document.getElementById("that-open-app") ?? document.body;
160
- container.appendChild(app);
161
- document.body.style.margin = "0";
1
+ /* MD
2
+ ## Toasts and cross-component notifications
3
+ ---
4
+ Developers building BIM processing UIs need to surface status updates, errors,
5
+ and async feedback to users from different points in the component tree —
6
+ but reaching back to the app root to trigger a notification from a deeply
7
+ nested component requires threading a reference through every layer in between.
8
+
9
+ top-app provides a built-in toast system that any descendant can trigger by
10
+ dispatching a standard DOM event. Toasts are auto-dismissed after a type-based
11
+ duration and stack at the bottom-left of the screen.
12
+
13
+ This tutorial covers showing a toast on app boot via showToast; building a
14
+ component that dispatches top:notification to report async progress and
15
+ completion without a reference to the root; and using the four toast types
16
+ (success, error, warning, info) with their respective durations.
17
+
18
+ By the end, you'll have an app with a boot confirmation toast and a panel that
19
+ reports async work status without holding any reference to top-app.
20
+ */
21
+
22
+ import { html, LitElement } from "lit";
23
+ import { customElement, state } from "lit/decorators.js";
24
+ import * as THREE from "three";
25
+ import * as OBC from "@thatopen/components";
26
+ import * as OBF from "@thatopen/components-front";
27
+ import * as FRAGS from "@thatopen/fragments";
28
+ import * as BUI from "@thatopen/ui";
29
+ import { PlatformClient } from "thatopen-services";
30
+ import uiManagerDef from "../../../../index";
31
+ import type { App, AppReadyEvent } from "../../index";
32
+
33
+ // A child component that dispatches top:notification to surface messages
34
+ // to the nearest top-app ancestor — no reference to the app element needed.
35
+ @customElement("status-reporter")
36
+ class StatusReporter extends LitElement {
37
+ @state() private _busy = false;
38
+
39
+ private _simulateWork() {
40
+ this._busy = true;
41
+
42
+ // Dispatching top:notification from any descendant of top-app shows a toast.
43
+ // bubbles:true + composed:true lets it cross shadow-DOM boundaries.
44
+ this.dispatchEvent(
45
+ new CustomEvent("top:notification", {
46
+ bubbles: true,
47
+ composed: true,
48
+ detail: { message: "Analysis started", type: "info" },
49
+ }),
50
+ );
51
+
52
+ setTimeout(() => {
53
+ this._busy = false;
54
+ this.dispatchEvent(
55
+ new CustomEvent("top:notification", {
56
+ bubbles: true,
57
+ composed: true,
58
+ detail: {
59
+ message: "Analysis complete",
60
+ type: "success",
61
+ description: "Found 342 elements across 5 categories.",
62
+ },
63
+ }),
64
+ );
65
+ }, 2000);
66
+ }
67
+
68
+ render() {
69
+ return html`
70
+ <bim-panel label="Reporter">
71
+ <bim-panel-section label="Actions" icon="solar:play-bold">
72
+ <bim-button
73
+ label="Run Analysis"
74
+ icon="solar:play-bold"
75
+ .loading=${this._busy}
76
+ @click=${this._simulateWork}
77
+ ></bim-button>
78
+ </bim-panel-section>
79
+ </bim-panel>
80
+ `;
81
+ }
82
+ }
83
+
84
+ // ---- app wiring ----
85
+
86
+ const UIManager = uiManagerDef.componentDefinition;
87
+ const client = PlatformClient.fromPlatformContext();
88
+ const { components } = (await client.setup(
89
+ { OBC, OBF, BUI, THREE, FRAGS },
90
+ { uuid: UIManager.uuid },
91
+ )) as { components: OBC.Components };
92
+ components.get(UIManager).init();
93
+
94
+ const app = document.createElement("top-app") as unknown as App;
95
+
96
+ app.setup = (waitUntil) => {
97
+ waitUntil(
98
+ (async () => {
99
+ const fragments = components.get(OBC.FragmentsManager);
100
+ const workerUrl = await FRAGS.FragmentsModels.getWorker();
101
+ fragments.init(await FRAGS.toClassicWorker(workerUrl), {
102
+ classicWorker: true,
103
+ });
104
+ })(),
105
+ "Fragments Core",
106
+ );
107
+ return { components, client };
108
+ };
109
+
110
+ app.elements = {
111
+ viewer: () =>
112
+ html`<top-viewer><top-viewer-tools></top-viewer-tools></top-viewer>`,
113
+ panel: () => html`<status-reporter></status-reporter>`,
114
+ };
115
+
116
+ app.base = "viewer";
117
+ app.layouts = {
118
+ main: {
119
+ label: "Main",
120
+ icon: "solar:home-bold",
121
+ template: `"panel" 1fr / 22rem`,
122
+ },
123
+ };
124
+ app.layout = "main";
125
+
126
+ // top:app-ready fires after all waitUntil promises resolve.
127
+ // e.detail.app is a reference to the top-app element itself.
128
+ app.addEventListener("top:app-ready", (e) => {
129
+ const { app: readyApp } = (e as AppReadyEvent).detail;
130
+ readyApp.showToast("App ready", "success");
131
+ });
132
+
133
+ const container = document.getElementById("that-open-app") ?? document.body;
134
+ container.appendChild(app);
135
+ document.body.style.margin = "0";