@equinor/fusion-framework-react-app 9.0.7 → 9.0.9-next.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.
@@ -1,3 +1,4 @@
1
+ import { type ReactElement } from 'react';
1
2
  export type ApploaderProps = {
2
3
  appKey: string;
3
4
  };
@@ -9,10 +10,10 @@ export type ApploaderProps = {
9
10
  *
10
11
  * @param { ApploaderProps } props - The props for the component.
11
12
  * @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
+ * @returns { ReactElement } The rendered component, which displays loading, error, or the embedded app.
13
14
  *
14
15
  * @example
15
16
  * <Apploader appKey="my-app" />
16
17
  */
17
- export declare const Apploader: ({ appKey }: ApploaderProps) => JSX.Element;
18
+ export declare const Apploader: ({ appKey }: ApploaderProps) => ReactElement;
18
19
  export default Apploader;
@@ -0,0 +1 @@
1
+ export * from '@equinor/fusion-framework-module-http/selectors';
@@ -1,12 +1,14 @@
1
1
  export type { AppConfig, AppEnv, AppModuleInitiator, AppModules, AppModulesInstance, AppRenderFn, IAppConfigurator, } from '@equinor/fusion-framework-app';
2
+ export type { Fusion } from '@equinor/fusion-framework-react';
2
3
  export { AppManifest } from '@equinor/fusion-framework-module-app';
3
4
  export { useAppModule } from './useAppModule';
4
5
  export { useAppModules } from './useAppModules';
5
6
  export { useAppEnvironmentVariables } from './useAppEnvironmentVariables';
6
7
  export { makeComponent, ComponentRenderArgs } from './make-component';
7
8
  export { createLegacyApp } from './create-legacy-app';
8
- export { renderApp } from './render-app';
9
9
  export { createComponent } from './create-component';
10
+ export { renderApp } from './render-app';
10
11
  export { renderComponent } from './render-component';
11
12
  export type { ComponentRenderer } from './create-component';
13
+ export type { RenderTeardown } from './render-component';
12
14
  export { default } from './render-app';
@@ -1,6 +1,12 @@
1
1
  import { createComponent } from './create-component';
2
2
  import { type RenderTeardown } from './render-component';
3
3
  import type { ComponentRenderArgs } from './create-component';
4
- /** @deprecated */
4
+ /**
5
+ * Creates a render function for an app component.
6
+ * Uses React 18's createRoot API via renderComponent.
7
+ *
8
+ * @param componentArgs - Arguments to pass to createComponent
9
+ * @returns A function that renders the app into a DOM element
10
+ */
5
11
  export declare const renderApp: (...componentArgs: Parameters<typeof createComponent>) => (el: HTMLElement, args: ComponentRenderArgs) => RenderTeardown;
6
12
  export default renderApp;
@@ -1,5 +1,11 @@
1
1
  import type { ComponentRenderArgs, ComponentRenderer } from './create-component';
2
2
  export type RenderTeardown = VoidFunction;
3
- /** @deprecated */
3
+ /**
4
+ * Creates a render function for a component renderer.
5
+ * Uses React 18's createRoot API instead of the deprecated ReactDOM.render.
6
+ *
7
+ * @param renderer - A function that creates a component from fusion and env
8
+ * @returns A function that renders the component into a DOM element
9
+ */
4
10
  export declare const renderComponent: (renderer: ComponentRenderer) => (el: HTMLElement, args: ComponentRenderArgs) => RenderTeardown;
5
11
  export default renderComponent;
@@ -1 +1 @@
1
- export declare const version = "9.0.7";
1
+ export declare const version = "9.0.9-next.0";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@equinor/fusion-framework-react-app",
3
- "version": "9.0.7",
3
+ "version": "9.0.9-next.0",
4
4
  "description": "",
5
5
  "main": "./dist/esm/index.js",
6
6
  "types": "./dist/types/index.d.ts",
@@ -41,6 +41,10 @@
41
41
  "types": "./dist/types/http/index.d.ts",
42
42
  "import": "./dist/esm/http/index.js"
43
43
  },
44
+ "./http/selectors": {
45
+ "types": "./dist/types/http/selectors.d.ts",
46
+ "import": "./dist/esm/http/selectors.js"
47
+ },
44
48
  "./msal": {
45
49
  "types": "./dist/types/msal/index.d.ts",
46
50
  "import": "./dist/esm/msal/index.js"
@@ -113,36 +117,40 @@
113
117
  "directory": "packages/react"
114
118
  },
115
119
  "dependencies": {
116
- "@equinor/fusion-framework-app": "10.4.8",
117
- "@equinor/fusion-framework-module-app": "7.4.0",
118
- "@equinor/fusion-framework-module": "5.0.5",
119
- "@equinor/fusion-framework-react": "7.4.19",
120
- "@equinor/fusion-framework-react-module": "3.1.13",
121
- "@equinor/fusion-framework-module-navigation": "6.0.0",
122
- "@equinor/fusion-framework-react-module-http": "10.0.0"
120
+ "@equinor/fusion-framework-app": "10.4.10-next.0",
121
+ "@equinor/fusion-framework-module-app": "7.4.2-next.0",
122
+ "@equinor/fusion-framework-module": "5.0.7-next.0",
123
+ "@equinor/fusion-framework-module-http": "7.0.9-next.0",
124
+ "@equinor/fusion-framework-react": "7.4.21-next.0",
125
+ "@equinor/fusion-framework-react-module": "3.1.15-next.0",
126
+ "@equinor/fusion-framework-module-navigation": "7.0.0-next.2",
127
+ "@equinor/fusion-framework-react-module-http": "10.0.2-next.0"
123
128
  },
124
129
  "devDependencies": {
125
- "@types/react": "^18.2.50",
126
- "@types/react-dom": "^18.2.7",
127
- "react": "^18.2.0",
128
- "react-dom": "^18.2.0",
130
+ "@types/react": "^19.2.7",
131
+ "@types/react-dom": "^19.2.3",
132
+ "happy-dom": "^20.0.0",
133
+ "react": "^19.2.1",
134
+ "react-dom": "^19.2.1",
129
135
  "rxjs": "^7.8.1",
130
136
  "typescript": "^5.8.2",
131
- "@equinor/fusion-framework-module-event": "5.0.0",
132
- "@equinor/fusion-framework-module-ag-grid": "35.0.1",
133
- "@equinor/fusion-framework-module-feature-flag": "1.1.27",
134
- "@equinor/fusion-framework-module-analytics": "1.0.0",
135
- "@equinor/fusion-framework-module-msal": "7.3.0",
136
- "@equinor/fusion-framework-react-module-bookmark": "5.0.1",
137
- "@equinor/fusion-framework-react-module-context": "6.2.33",
138
- "@equinor/fusion-observable": "8.5.7"
137
+ "vite-tsconfig-paths": "^5.1.4",
138
+ "vitest": "^3.2.4",
139
+ "@equinor/fusion-framework-module-analytics": "1.0.3-next.0",
140
+ "@equinor/fusion-framework-module-event": "5.0.2-next.0",
141
+ "@equinor/fusion-framework-module-ag-grid": "35.1.0-next.0",
142
+ "@equinor/fusion-framework-module-feature-flag": "1.1.29-next.0",
143
+ "@equinor/fusion-framework-module-msal": "7.3.2-next.0",
144
+ "@equinor/fusion-framework-react-module-context": "6.2.35-next.0",
145
+ "@equinor/fusion-framework-react-module-bookmark": "5.0.3-next.0",
146
+ "@equinor/fusion-observable": "8.5.9-next.0"
139
147
  },
140
148
  "peerDependencies": {
141
- "@types/react": "^17.0.0 || ^18.0.0",
142
- "react": "^17.0.0 || ^18.0.0",
143
- "react-dom": "^17.0.0 || ^18.0.0",
149
+ "@types/react": "^18.0.0 || ^19.0.0",
150
+ "react": "^18.0.0 || ^19.0.0",
151
+ "react-dom": "^18.0.0 || ^19.0.0",
144
152
  "rxjs": "^7.8.1",
145
- "@equinor/fusion-framework-module-msal": "^7.3.0"
153
+ "@equinor/fusion-framework-module-msal": "^7.3.2-next.0"
146
154
  },
147
155
  "peerDependenciesMeta": {
148
156
  "@equinor/fusion-framework-react-module-ag-grid": {
@@ -174,6 +182,7 @@
174
182
  }
175
183
  },
176
184
  "scripts": {
177
- "build": "tsc -b"
185
+ "build": "tsc -b",
186
+ "test": "vitest --run"
178
187
  }
179
188
  }
@@ -0,0 +1,113 @@
1
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
2
+ import type { ComponentRenderArgs } from '../create-component';
3
+ import type { Fusion } from '@equinor/fusion-framework-react';
4
+ import type { AppEnv } from '@equinor/fusion-framework-app';
5
+
6
+ // Mock dependencies before importing
7
+ vi.mock('../create-component', () => ({
8
+ createComponent: vi.fn(),
9
+ }));
10
+
11
+ vi.mock('../render-component', () => ({
12
+ renderComponent: vi.fn(),
13
+ }));
14
+
15
+ import { renderApp } from '../render-app';
16
+ import { createComponent } from '../create-component';
17
+ import { renderComponent } from '../render-component';
18
+
19
+ describe('renderApp', () => {
20
+ let mockFusion: Fusion;
21
+ let mockEnv: AppEnv;
22
+ let mockElement: HTMLElement;
23
+ let mockTeardown: () => void;
24
+ let mockComponentRenderer: ReturnType<typeof createComponent>;
25
+ let mockRenderFunction: ReturnType<typeof renderComponent>;
26
+
27
+ beforeEach(() => {
28
+ // Setup mock data
29
+ mockFusion = {} as Fusion;
30
+ mockEnv = {} as AppEnv;
31
+ mockElement = document.createElement('div');
32
+ mockTeardown = vi.fn();
33
+
34
+ // Create a mock component renderer
35
+ // createComponent returns a ComponentRenderer function: (fusion, env) => React.LazyExoticComponent
36
+ mockComponentRenderer = vi.fn() as unknown as ReturnType<typeof createComponent>;
37
+
38
+ // Create a mock render function
39
+ mockRenderFunction = vi.fn(() => mockTeardown) as unknown as ReturnType<typeof renderComponent>;
40
+
41
+ // Mock renderComponent to return our mock render function
42
+ vi.mocked(renderComponent).mockReturnValue(mockRenderFunction);
43
+
44
+ // Mock createComponent to return our mock component renderer
45
+ vi.mocked(createComponent).mockReturnValue(mockComponentRenderer);
46
+ });
47
+
48
+ it('should create a render function that calls createComponent with provided arguments', () => {
49
+ const TestComponent = () => <div>Test</div>;
50
+ const mockConfigure = vi.fn();
51
+
52
+ renderApp(TestComponent, mockConfigure);
53
+
54
+ expect(createComponent).toHaveBeenCalledWith(TestComponent, mockConfigure);
55
+ });
56
+
57
+ it('should create a render function that uses renderComponent with the component renderer', () => {
58
+ const TestComponent = () => <div>Test</div>;
59
+ const appRender = renderApp(TestComponent);
60
+
61
+ // Call the render function
62
+ const teardown = appRender(mockElement, { fusion: mockFusion, env: mockEnv });
63
+
64
+ expect(renderComponent).toHaveBeenCalledWith(mockComponentRenderer);
65
+ expect(mockRenderFunction).toHaveBeenCalledWith(mockElement, {
66
+ fusion: mockFusion,
67
+ env: mockEnv,
68
+ });
69
+ expect(teardown).toBe(mockTeardown);
70
+ });
71
+
72
+ it('should return a teardown function that unmounts the component', () => {
73
+ const TestComponent = () => <div>Test</div>;
74
+ const appRender = renderApp(TestComponent);
75
+
76
+ const teardown = appRender(mockElement, { fusion: mockFusion, env: mockEnv });
77
+
78
+ expect(typeof teardown).toBe('function');
79
+ teardown();
80
+ expect(mockTeardown).toHaveBeenCalled();
81
+ });
82
+
83
+ it('should work without a configure callback', () => {
84
+ vi.clearAllMocks();
85
+ const TestComponent = () => <div>Test</div>;
86
+ const appRender = renderApp(TestComponent);
87
+
88
+ // When no configure callback is provided, it may be called with just the component
89
+ // or with undefined as the second parameter
90
+ expect(createComponent).toHaveBeenCalled();
91
+ const calls = vi.mocked(createComponent).mock.calls;
92
+ expect(calls[calls.length - 1][0]).toBe(TestComponent);
93
+ expect(calls[calls.length - 1][1]).toBeUndefined();
94
+
95
+ const teardown = appRender(mockElement, { fusion: mockFusion, env: mockEnv });
96
+
97
+ expect(teardown).toBe(mockTeardown);
98
+ });
99
+
100
+ it('should pass component renderer args correctly to renderComponent', () => {
101
+ const TestComponent = () => <div>Test</div>;
102
+ const appRender = renderApp(TestComponent);
103
+
104
+ const args: ComponentRenderArgs = {
105
+ fusion: mockFusion,
106
+ env: mockEnv,
107
+ };
108
+
109
+ appRender(mockElement, args);
110
+
111
+ expect(mockRenderFunction).toHaveBeenCalledWith(mockElement, args);
112
+ });
113
+ });
@@ -1,4 +1,4 @@
1
- import { useEffect, useRef } from 'react';
1
+ import { useEffect, useRef, type ReactElement } from 'react';
2
2
  import { useApploader } from './useApploader';
3
3
 
4
4
  export type ApploaderProps = {
@@ -13,12 +13,12 @@ export type ApploaderProps = {
13
13
  *
14
14
  * @param { ApploaderProps } props - The props for the component.
15
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.
16
+ * @returns { ReactElement } The rendered component, which displays loading, error, or the embedded app.
17
17
  *
18
18
  * @example
19
19
  * <Apploader appKey="my-app" />
20
20
  */
21
- export const Apploader = ({ appKey }: ApploaderProps): JSX.Element => {
21
+ export const Apploader = ({ appKey }: ApploaderProps): ReactElement => {
22
22
  const refWrapp = useRef<HTMLDivElement | null>(null);
23
23
  const { loading, error, appRef } = useApploader({ appKey });
24
24
 
@@ -0,0 +1 @@
1
+ export * from '@equinor/fusion-framework-module-http/selectors';
package/src/index.ts CHANGED
@@ -8,6 +8,8 @@ export type {
8
8
  IAppConfigurator,
9
9
  } from '@equinor/fusion-framework-app';
10
10
 
11
+ export type { Fusion } from '@equinor/fusion-framework-react';
12
+
11
13
  export { AppManifest } from '@equinor/fusion-framework-module-app';
12
14
 
13
15
  export { useAppModule } from './useAppModule';
@@ -18,11 +20,11 @@ export { makeComponent, ComponentRenderArgs } from './make-component';
18
20
 
19
21
  export { createLegacyApp } from './create-legacy-app';
20
22
 
21
- // TODO deprecate
22
- export { renderApp } from './render-app';
23
23
  export { createComponent } from './create-component';
24
+ export { renderApp } from './render-app';
24
25
  export { renderComponent } from './render-component';
25
26
 
26
27
  export type { ComponentRenderer } from './create-component';
28
+ export type { RenderTeardown } from './render-component';
27
29
 
28
30
  export { default } from './render-app';
@@ -55,7 +55,7 @@ export const makeComponent = <
55
55
  ): React.LazyExoticComponent<React.ComponentType> =>
56
56
  lazy(async () => {
57
57
  const init = configureModules<TModules, TRef, TEnv>(configure);
58
- const modules = (await init(args)) as unknown as AppModulesInstance;
58
+ const modules = await init(args);
59
59
 
60
60
  const { fusion } = args;
61
61
 
package/src/render-app.ts CHANGED
@@ -3,7 +3,13 @@ import { renderComponent, type RenderTeardown } from './render-component';
3
3
 
4
4
  import type { ComponentRenderArgs } from './create-component';
5
5
 
6
- /** @deprecated */
6
+ /**
7
+ * Creates a render function for an app component.
8
+ * Uses React 18's createRoot API via renderComponent.
9
+ *
10
+ * @param componentArgs - Arguments to pass to createComponent
11
+ * @returns A function that renders the app into a DOM element
12
+ */
7
13
  export const renderApp = (...componentArgs: Parameters<typeof createComponent>) => {
8
14
  const renderer = renderComponent(createComponent(...componentArgs));
9
15
  return (el: HTMLElement, args: ComponentRenderArgs): RenderTeardown => {
@@ -1,46 +1,43 @@
1
1
  import { Suspense, StrictMode } from 'react';
2
2
  import type { FunctionComponent } from 'react';
3
+ import { createRoot, type Root } from 'react-dom/client';
3
4
  import type { ComponentRenderArgs, ComponentRenderer } from './create-component';
4
- import ReactDOM from 'react-dom';
5
5
 
6
6
  export type RenderTeardown = VoidFunction;
7
7
 
8
- /** @deprecated */
9
- export const renderComponent = (renderer: ComponentRenderer) => {
10
- return (el: HTMLElement, args: ComponentRenderArgs): RenderTeardown => {
11
- const Component = renderer(args.fusion, args.env);
12
- return render(el, Component);
13
- };
14
- };
15
-
8
+ /**
9
+ * Renders a React component into a DOM element using React 18's createRoot API.
10
+ *
11
+ * @param el - The DOM element to render into
12
+ * @param Component - The React component to render
13
+ * @returns A teardown function that unmounts the component
14
+ */
16
15
  const render = (el: Element, Component: FunctionComponent): RenderTeardown => {
17
- // eslint-disable-next-line react/no-deprecated
18
- ReactDOM.render(
16
+ const root: Root = createRoot(el);
17
+ root.render(
19
18
  <StrictMode>
20
19
  <Suspense fallback={<p>loading app</p>}>
21
20
  <Component />
22
21
  </Suspense>
23
22
  </StrictMode>,
24
- el,
25
23
  );
26
24
  return () => {
27
- // eslint-disable-next-line react/no-deprecated
28
- ReactDOM.unmountComponentAtNode(el);
25
+ root.unmount();
29
26
  };
30
27
  };
31
28
 
32
- // const render = (el: Element, Component: FunctionComponent): RenderTeardown => {
33
- // const root = createRoot(el);
34
- // root.render(
35
- // <StrictMode>
36
- // <Suspense fallback={<p>loading app</p>}>
37
- // <Component />
38
- // </Suspense>
39
- // </StrictMode>
40
- // );
41
- // return () => {
42
- // root.unmount();
43
- // };
44
- // };
29
+ /**
30
+ * Creates a render function for a component renderer.
31
+ * Uses React 18's createRoot API instead of the deprecated ReactDOM.render.
32
+ *
33
+ * @param renderer - A function that creates a component from fusion and env
34
+ * @returns A function that renders the component into a DOM element
35
+ */
36
+ export const renderComponent = (renderer: ComponentRenderer) => {
37
+ return (el: HTMLElement, args: ComponentRenderArgs): RenderTeardown => {
38
+ const Component = renderer(args.fusion, args.env);
39
+ return render(el, Component);
40
+ };
41
+ };
45
42
 
46
43
  export default renderComponent;
@@ -1,4 +1,4 @@
1
- import type { AppModulesInstance } from '@equinor/fusion-framework-app';
1
+ import type { AppModules, AppModulesInstance } from '@equinor/fusion-framework-app';
2
2
  import type { AnyModule } from '@equinor/fusion-framework-module';
3
3
  import { useModules } from '@equinor/fusion-framework-react-module';
4
4
 
@@ -10,6 +10,6 @@ import { useModules } from '@equinor/fusion-framework-react-module';
10
10
  */
11
11
  export const useAppModules = <
12
12
  T extends Array<AnyModule> | unknown = unknown,
13
- >(): AppModulesInstance<T> => useModules<AppModulesInstance<T>>();
13
+ >(): AppModulesInstance<T> => useModules<AppModules<T>>() as AppModulesInstance<T>;
14
14
 
15
15
  export default useAppModules;
package/src/version.ts CHANGED
@@ -1,2 +1,2 @@
1
1
  // Generated by genversion.
2
- export const version = '9.0.7';
2
+ export const version = '9.0.9-next.0';
package/tsconfig.json CHANGED
@@ -38,5 +38,5 @@
38
38
  }
39
39
  ],
40
40
  "include": ["src/**/*"],
41
- "exclude": ["node_modules", "lib"]
41
+ "exclude": ["node_modules", "lib", "src/__tests__/**/*"]
42
42
  }
@@ -0,0 +1,20 @@
1
+ import { defineProject } from 'vitest/config';
2
+ import tsconfigPaths from 'vite-tsconfig-paths';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { resolve } from 'node:path';
5
+
6
+ import { name, version } from './package.json';
7
+
8
+ export default defineProject({
9
+ plugins: [
10
+ tsconfigPaths({
11
+ root: resolve(fileURLToPath(new URL('../../..', import.meta.url))),
12
+ projects: [resolve(fileURLToPath(new URL('.', import.meta.url)), 'tsconfig.json')],
13
+ }),
14
+ ],
15
+ test: {
16
+ include: ['src/__tests__/**'],
17
+ name: `${name}@${version}`,
18
+ environment: 'happy-dom',
19
+ },
20
+ });