@equinor/fusion-framework-react-app 6.1.6-next.0 → 6.2.0-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9

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.
@@ -0,0 +1,18 @@
1
+ export type FusionApploaderProps = {
2
+ appKey: string;
3
+ };
4
+ /**
5
+ * FusionApploader component
6
+ *
7
+ * Embeds a Fusion child application inside a parent Fusion application.
8
+ * Handles loading and error states, and mounts the child app's DOM element into a container div.
9
+ *
10
+ * @param { FusionApploaderProps } props - The props for the component.
11
+ * @param { string } props.appKey - The key of the Fusion app to load and mount.
12
+ * @returns { JSX.Element } The rendered component, which displays loading, error, or the embedded app.
13
+ *
14
+ * @example
15
+ * <FusionApploader appKey="my-app" />
16
+ */
17
+ export declare const FusionApploader: ({ appKey }: FusionApploaderProps) => JSX.Element;
18
+ export default FusionApploader;
@@ -0,0 +1,2 @@
1
+ export { FusionApploader, type FusionApploaderProps } from './FusionApploader';
2
+ export { useFusionApploader } from './useFusionApploader';
@@ -0,0 +1,33 @@
1
+ import type { FusionApploaderProps as ApploaderProps } from './FusionApploader';
2
+ /**
3
+ * React hook for dynamically loading and mounting a Fusion child app inside a parent Fusion app.
4
+ * Handles loading state, error reporting, and provides a reference to the mounted app’s DOM element.
5
+ *
6
+ * @param { Object } params
7
+ * @param { string } params.appKey - The key of the Fusion app to load and mount.
8
+ * @returns {{
9
+ * loading: boolean,
10
+ * error: Error | undefined,
11
+ * appRef: React.RefObject<HTMLDivElement | null>
12
+ * }} An object containing loading state, error, and a ref to the mounted app element.
13
+ *
14
+ * @example
15
+ * ```typescript
16
+ * const { loading, error, appRef } = useFusionApploader({ appKey: 'my-app' });
17
+ *
18
+ * useEffect(() => {
19
+ * if (containerRef.current && appRef.current) {
20
+ * containerRef.current.appendChild(appRef.current);
21
+ * }
22
+ * }, [appRef.current]);
23
+ *
24
+ * if (loading) return <div>Loading...</div>;
25
+ * if (error) return <div>Error: {error.message}</div>;
26
+ * return <div ref={containerRef} />;
27
+ * ```
28
+ */
29
+ export declare const useFusionApploader: ({ appKey, }: ApploaderProps) => {
30
+ loading: boolean;
31
+ error: Error | undefined;
32
+ appRef: React.RefObject<HTMLDivElement | null>;
33
+ };
@@ -1 +1 @@
1
- export declare const version = "6.1.6-next.0";
1
+ export declare const version = "6.1.5";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/fusion-framework-react-app",
3
- "version": "6.1.6-next.0",
3
+ "version": "6.2.0-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
4
4
  "description": "",
5
5
  "main": "./dist/esm/index.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -25,6 +25,10 @@
25
25
  "types": "./dist/types/framework/index.d.ts",
26
26
  "import": "./dist/esm/framework/index.js"
27
27
  },
28
+ "./fusion-apploader": {
29
+ "types": "./dist/types/fusion-apploader/index.d.ts",
30
+ "import": "./dist/esm/fusion-apploader/index.js"
31
+ },
28
32
  "./help-center": {
29
33
  "types": "./dist/types/help-center/index.d.ts",
30
34
  "import": "./dist/esm/help-center/index.js"
@@ -64,6 +68,9 @@
64
68
  "framework": [
65
69
  "dist/types/framework/index.d.ts"
66
70
  ],
71
+ "fusion-apploader": [
72
+ "dist/types/fusion-apploader/index.d.ts"
73
+ ],
67
74
  "help-center": [
68
75
  "dist/types/help-center/index.d.ts"
69
76
  ],
@@ -96,13 +103,13 @@
96
103
  "directory": "packages/react"
97
104
  },
98
105
  "dependencies": {
99
- "@equinor/fusion-framework-app": "^9.3.15-next.0",
100
- "@equinor/fusion-framework-module": "^4.4.2",
101
- "@equinor/fusion-framework-module-app": "^6.1.13",
102
- "@equinor/fusion-framework-module-navigation": "^5.0.2",
103
- "@equinor/fusion-framework-react-module": "^3.1.12",
104
- "@equinor/fusion-framework-react-module-http": "^9.0.3-next.0",
105
- "@equinor/fusion-framework-react": "^7.4.13-next.0"
106
+ "@equinor/fusion-framework-app": "^9.3.15-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
107
+ "@equinor/fusion-framework-module": "^4.4.3-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
108
+ "@equinor/fusion-framework-module-app": "^6.1.14-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
109
+ "@equinor/fusion-framework-module-navigation": "^5.0.3-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
110
+ "@equinor/fusion-framework-react": "^7.4.13-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
111
+ "@equinor/fusion-framework-react-module": "^3.1.13-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
112
+ "@equinor/fusion-framework-react-module-http": "^9.0.3-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9"
106
113
  },
107
114
  "devDependencies": {
108
115
  "@types/react": "^18.2.50",
@@ -111,20 +118,20 @@
111
118
  "react-dom": "^18.2.0",
112
119
  "rxjs": "^7.8.1",
113
120
  "typescript": "^5.8.2",
114
- "@equinor/fusion-framework-module-ag-grid": "^34.0.2",
115
- "@equinor/fusion-framework-module-event": "^4.3.6",
116
- "@equinor/fusion-framework-module-feature-flag": "^1.1.18",
117
- "@equinor/fusion-framework-react-module-bookmark": "^4.0.4-next.0",
118
- "@equinor/fusion-framework-module-msal": "^4.0.6",
119
- "@equinor/fusion-framework-react-module-context": "^6.2.28",
120
- "@equinor/fusion-observable": "^8.4.9"
121
+ "@equinor/fusion-framework-module-ag-grid": "^34.0.3-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
122
+ "@equinor/fusion-framework-module-event": "^4.3.7-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
123
+ "@equinor/fusion-framework-module-msal": "^4.0.7-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
124
+ "@equinor/fusion-framework-module-feature-flag": "^1.1.19-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
125
+ "@equinor/fusion-framework-react-module-context": "^6.2.29-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
126
+ "@equinor/fusion-observable": "^8.4.10-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9",
127
+ "@equinor/fusion-framework-react-module-bookmark": "^4.0.4-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9"
121
128
  },
122
129
  "peerDependencies": {
123
130
  "@types/react": "^17.0.0 || ^18.0.0",
124
131
  "react": "^17.0.0 || ^18.0.0",
125
132
  "react-dom": "^17.0.0 || ^18.0.0",
126
133
  "rxjs": "^7.8.1",
127
- "@equinor/fusion-framework-module-msal": "^4.0.6"
134
+ "@equinor/fusion-framework-module-msal": "^4.0.7-apploader-be21a6b60eb13eee8bf869e75002d8634e9c50a9"
128
135
  },
129
136
  "peerDependenciesMeta": {
130
137
  "@equinor/fusion-framework-react-module-ag-grid": {
@@ -0,0 +1,47 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { useFusionApploader } from './useFusionApploader';
3
+
4
+ export type FusionApploaderProps = {
5
+ appKey: string;
6
+ };
7
+
8
+ /**
9
+ * FusionApploader component
10
+ *
11
+ * Embeds a Fusion child application inside a parent Fusion application.
12
+ * Handles loading and error states, and mounts the child app's DOM element into a container div.
13
+ *
14
+ * @param { FusionApploaderProps } props - The props for the component.
15
+ * @param { string } props.appKey - The key of the Fusion app to load and mount.
16
+ * @returns { JSX.Element } The rendered component, which displays loading, error, or the embedded app.
17
+ *
18
+ * @example
19
+ * <FusionApploader appKey="my-app" />
20
+ */
21
+ export const FusionApploader = ({ appKey }: FusionApploaderProps): JSX.Element => {
22
+ const refWrapp = useRef<HTMLDivElement | null>(null);
23
+ const { loading, error, appRef } = useFusionApploader({ appKey });
24
+
25
+ useEffect(() => {
26
+ if (!refWrapp.current || !appRef.current) {
27
+ return;
28
+ }
29
+
30
+ refWrapp.current.appendChild(appRef.current);
31
+ }, [appRef.current]);
32
+
33
+ if (loading) {
34
+ return <div>Loading {appKey}</div>;
35
+ }
36
+ if (error) {
37
+ return (
38
+ <div>
39
+ Error loading {appKey}. Error: {error.message}
40
+ </div>
41
+ );
42
+ }
43
+
44
+ return <div ref={refWrapp} />;
45
+ };
46
+
47
+ export default FusionApploader;
@@ -0,0 +1,78 @@
1
+ # `@equinor/fusion-framework-react-app/fusion-apploader`
2
+
3
+ [FusionApploader](#fusionapploader) component and [useFusionApploader](#usefusionapploader) is intended to be used to embed Fusion applications inside other Fusion application.
4
+
5
+ > [!WARNING]
6
+ > `FusionApploader` is an experimental poc.
7
+ >
8
+ > The embedded application will likely have issues with routing, context and other framework functionality, so use with care.
9
+ >
10
+ > Should only be used to embed 'simple' applications like **PowerBI** and **PowerApps**.
11
+
12
+ ## FusionApploader
13
+
14
+ React component for embeding a Fusion child application inside a parent Fusion application.
15
+
16
+ Handles loading and error states, and mounts the child app's DOM element into a container div.
17
+
18
+ If you need to customise the error and loading messages, then use the hook ``useFusionApploader`` and create your own component.
19
+
20
+ ### Example usage
21
+
22
+ ```typescript
23
+ <FusionApploader appKey="my-app" />
24
+ ```
25
+
26
+ ## useFusionApploader
27
+
28
+ A React hook for dynamically loading and mounting a Fusion child app inside a parent Fusion app. Handles loading state, error reporting, and provides a reference to the mounted app’s DOM element.
29
+
30
+ ### Signature
31
+
32
+ ```typescript
33
+ useFusionApploader({ appKey }: { appKey: string }): {
34
+ loading: boolean;
35
+ error: Error | undefined;
36
+ appRef: React.RefObject<HTMLDivElement | null>;
37
+ }
38
+ ```
39
+
40
+ ### Parameters
41
+
42
+ `appKey (string)`: The key of the Fusion app to load and mount.
43
+
44
+ ### Returns
45
+
46
+ - **loading** ``(boolean)``: true while the app is loading.
47
+ - **error** ``(Error | undefined)``: Error object if loading fails, otherwise undefined.
48
+ - **appRef** ``(React.RefObject<HTMLDivElement | null>)``: Ref to the DOM element where the child app is mounted.
49
+
50
+ ### Usage Example
51
+
52
+ ```typescript
53
+ import React, { useEffect, useRef } from 'react';
54
+ import { useFusionApploader } from './useFusionAppLoader';
55
+
56
+ const MyAppLoader = ({ appKey }: { appKey: string }) => {
57
+ const wrapperRef = useRef<HTMLDivElement | null>(null);
58
+ const { loading, error, appRef } = useFusionApploader({ appKey });
59
+
60
+ useEffect(() => {
61
+ if (wrapperRef.current && appRef.current) {
62
+ wrapperRef.current.appendChild(appRef.current);
63
+ }
64
+ }, [appRef.current]);
65
+
66
+ if (loading) return <div>Loading {appKey}...</div>;
67
+ if (error) return <div>Error loading {appKey}: {error.message}</div>;
68
+
69
+ return <div ref={wrapperRef} />;
70
+ };
71
+ ```
72
+
73
+ ### Notes
74
+
75
+ - The hook is designed to be used in a parent Fusion app context.
76
+ - The returned appRef should be appended to a container element in your component.
77
+ - Handles subscription and cleanup automatically.
78
+ - Useful for micro-frontend scenarios where apps are loaded dynamically.
@@ -0,0 +1,2 @@
1
+ export { FusionApploader, type FusionApploaderProps } from './FusionApploader';
2
+ export { useFusionApploader } from './useFusionApploader';
@@ -0,0 +1,104 @@
1
+ import { useEffect, useMemo, useRef, useState } from 'react';
2
+
3
+ import { useFramework } from '@equinor/fusion-framework-react';
4
+ import type { AppModule } from '@equinor/fusion-framework-module-app';
5
+
6
+ import type { FusionApploaderProps as ApploaderProps } from './FusionApploader';
7
+
8
+ /**
9
+ * React hook for dynamically loading and mounting a Fusion child app inside a parent Fusion app.
10
+ * Handles loading state, error reporting, and provides a reference to the mounted app’s DOM element.
11
+ *
12
+ * @param { Object } params
13
+ * @param { string } params.appKey - The key of the Fusion app to load and mount.
14
+ * @returns {{
15
+ * loading: boolean,
16
+ * error: Error | undefined,
17
+ * appRef: React.RefObject<HTMLDivElement | null>
18
+ * }} An object containing loading state, error, and a ref to the mounted app element.
19
+ *
20
+ * @example
21
+ * ```typescript
22
+ * const { loading, error, appRef } = useFusionApploader({ appKey: 'my-app' });
23
+ *
24
+ * useEffect(() => {
25
+ * if (containerRef.current && appRef.current) {
26
+ * containerRef.current.appendChild(appRef.current);
27
+ * }
28
+ * }, [appRef.current]);
29
+ *
30
+ * if (loading) return <div>Loading...</div>;
31
+ * if (error) return <div>Error: {error.message}</div>;
32
+ * return <div ref={containerRef} />;
33
+ * ```
34
+ */
35
+ export const useFusionApploader = ({
36
+ appKey,
37
+ }: ApploaderProps): {
38
+ loading: boolean;
39
+ error: Error | undefined;
40
+ appRef: React.RefObject<HTMLDivElement | null>;
41
+ } => {
42
+ const [loading, setLoading] = useState(true);
43
+ const [error, setError] = useState<Error | undefined>();
44
+ const appRef = useRef<HTMLDivElement | null>(null);
45
+ const fusion = useFramework<[AppModule]>();
46
+
47
+ /**
48
+ * The current fusion app.
49
+ * aka the parent app that is loading the child app.
50
+ */
51
+ const fusionApp = useMemo(() => fusion.modules.app.current, [fusion]);
52
+
53
+ /**
54
+ * The app to be mounted
55
+ * aka the child app that is being loaded.
56
+ */
57
+ const loadedApp = useMemo(() => fusion.modules.app.createApp({ appKey }), [fusion, appKey]);
58
+
59
+ useEffect(() => {
60
+ setLoading(true);
61
+ setError(undefined);
62
+ const subscription$ = loadedApp?.initialize().subscribe({
63
+ next: ({ manifest, script, config }) => {
64
+ /* Application Element for mounting */
65
+ appRef.current = document.createElement('div');
66
+ appRef.current.id = manifest.appKey;
67
+ appRef.current.style.display = 'contents';
68
+
69
+ /* Use basename of current fusionApp */
70
+ const basename = `/apps/${fusionApp?.appKey}`;
71
+
72
+ try {
73
+ const render = script.renderApp ?? script.default;
74
+ if (render) {
75
+ return render(appRef.current, {
76
+ fusion,
77
+ env: { basename, config, manifest, props: {} },
78
+ });
79
+ }
80
+ throw Error('Application is not supported, no render function provided');
81
+ } catch (error) {
82
+ console.error('App loading Error: ', error);
83
+ setError(error as Error);
84
+ }
85
+ },
86
+ complete: () => {
87
+ setLoading(false);
88
+ },
89
+ error: (error: Error) => {
90
+ setError(error);
91
+ setLoading(false);
92
+ },
93
+ });
94
+ return () => {
95
+ subscription$.unsubscribe();
96
+ };
97
+ }, [fusionApp, loadedApp, fusion]);
98
+
99
+ return {
100
+ loading,
101
+ error,
102
+ appRef,
103
+ };
104
+ };
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '6.1.6-next.0';
2
+ export const version = '6.1.5';