@equinor/fusion-framework-react 9.0.0-next.0 → 9.0.1

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.
package/src/Framework.tsx DELETED
@@ -1,68 +0,0 @@
1
- import type { FrameworkConfigurator } from '@equinor/fusion-framework';
2
- import { createFrameworkProvider } from './create-framework-provider';
3
- import { type PropsWithChildren, type ReactNode, Suspense, useMemo } from 'react';
4
- import { useModules } from '@equinor/fusion-framework-react-module';
5
- import type { ModulesInstance } from '@equinor/fusion-framework-module';
6
-
7
- /**
8
- * Callback invoked during framework initialisation to configure modules.
9
- *
10
- * @param configurator - The framework configurator instance to apply settings to.
11
- */
12
- type ConfigureCallback = (configurator: FrameworkConfigurator) => void;
13
-
14
- /**
15
- * Declarative React component that initialises a Fusion Framework instance
16
- * and provides it to descendant components via context.
17
- *
18
- * @remarks
19
- * Internally calls {@link createFrameworkProvider} and wraps the lazy-loaded
20
- * provider in a `<Suspense>` boundary. This is the recommended high-level
21
- * component for portal / host applications that need to bootstrap the
22
- * framework inside a React tree.
23
- *
24
- * @param props.configure - Callback that receives a {@link FrameworkConfigurator}
25
- * for registering modules and configuration.
26
- * @param props.fallback - React node shown while the framework is initialising.
27
- * @param props.parent - Optional parent module instance to inherit configuration from.
28
- * @param props.children - Application content rendered after initialisation.
29
- *
30
- * @example
31
- * ```tsx
32
- * import { Framework } from '@equinor/fusion-framework-react';
33
- *
34
- * const App = () => (
35
- * <Framework
36
- * configure={(configurator) => {
37
- * configurator.http.configureClient('my-api', { baseUri: 'https://api.example.com' });
38
- * }}
39
- * fallback={<span>Loading…</span>}
40
- * >
41
- * <MyApp />
42
- * </Framework>
43
- * );
44
- * ```
45
- */
46
- export const Framework = (
47
- props: PropsWithChildren<{
48
- readonly configure: ConfigureCallback;
49
- readonly fallback: NonNullable<ReactNode> | null;
50
- // biome-ignore lint/suspicious/noExplicitAny: should allow any
51
- readonly parent?: ModulesInstance<any>;
52
- }>,
53
- ) => {
54
- const { configure, fallback, parent, children } = props;
55
- //import modules from parent context
56
- const ref = useModules<[]>();
57
- const Component = useMemo(
58
- () => createFrameworkProvider(configure, parent ?? ref),
59
- [configure, ref, parent],
60
- );
61
- return (
62
- <Suspense fallback={fallback}>
63
- <Component>{children}</Component>
64
- </Suspense>
65
- );
66
- };
67
-
68
- export default Framework;
package/src/app/index.ts DELETED
@@ -1,17 +0,0 @@
1
- /**
2
- * Application React hooks.
3
- *
4
- * @remarks
5
- * Available via the `@equinor/fusion-framework-react/app` sub-entry-point.
6
- * Provides hooks and types for querying application manifests, observing
7
- * the currently active app, and accessing app-level modules.
8
- *
9
- * @module
10
- */
11
- export type { AppConfig, AppManifest, AppType, IApp } from '@equinor/fusion-framework-module-app';
12
-
13
- export { useCurrentApp } from './useCurrentApp';
14
- export { useCurrentAppModule } from './useCurrentAppModule';
15
- export { useCurrentAppModules } from './useCurrentAppModules';
16
- export { useApps } from './useApps';
17
- export { useAppProvider } from './useAppProvider';
@@ -1,29 +0,0 @@
1
- import type { FusionModulesInstance } from '@equinor/fusion-framework';
2
- import type { AppModule } from '@equinor/fusion-framework-module-app';
3
-
4
- import { useFramework } from '../useFramework';
5
-
6
- /**
7
- * React hook that returns the App module provider from the framework.
8
- *
9
- * @returns The app module instance (`AppModule`) for querying and managing
10
- * application manifests and the currently active app.
11
- * @throws {Error} If the `AppModule` is not configured in the framework.
12
- *
13
- * @example
14
- * ```ts
15
- * const provider = useAppProvider();
16
- * provider.getAppManifests().subscribe(console.log);
17
- * ```
18
- */
19
- export const useAppProvider = (): FusionModulesInstance<[AppModule]>['app'] => {
20
- const provider = useFramework<[AppModule]>().modules.app;
21
- // Fail fast when the AppModule has not been configured on the framework
22
- if (!provider) {
23
- throw Error('Current framework does not have AppModule configured');
24
- }
25
-
26
- return provider;
27
- };
28
-
29
- export default useAppProvider;
@@ -1,55 +0,0 @@
1
- import type { AppManifest } from '@equinor/fusion-framework-module-app';
2
- import { useObservableState } from '@equinor/fusion-observable/react';
3
- import { useMemo } from 'react';
4
-
5
- import { useAppProvider } from './useAppProvider';
6
-
7
- type UseAppsArgs = {
8
- /** @deprecated - no longer available */
9
- includeHidden?: boolean;
10
- // only show apps that the current user has access to
11
- filterByCurrentUser?: boolean;
12
- };
13
-
14
- /**
15
- * React hook that retrieves available application manifests from the framework.
16
- *
17
- * @param args - Optional filtering options.
18
- * @param args.filterByCurrentUser - When `true`, only apps accessible to the
19
- * current user are returned.
20
- * @returns An object containing:
21
- * - `apps` — Array of {@link AppManifest} objects, or `undefined` while loading.
22
- * - `isLoading` — `true` until the observable completes.
23
- * - `error` — Any error emitted by the underlying observable.
24
- *
25
- * @example
26
- * ```tsx
27
- * const { apps, isLoading, error } = useApps({ filterByCurrentUser: true });
28
- * if (isLoading) return <Spinner />;
29
- * return <AppList apps={apps} />;
30
- * ```
31
- *
32
- * @since 7.1.1
33
- */
34
- export const useApps = (
35
- args?: UseAppsArgs,
36
- ): { apps: AppManifest[] | undefined; isLoading: boolean; error: unknown } => {
37
- const provider = useAppProvider();
38
-
39
- const { filterByCurrentUser } = args || {};
40
-
41
- const {
42
- value: apps,
43
- complete,
44
- error,
45
- } = useObservableState(
46
- useMemo(
47
- () => provider.getAppManifests(filterByCurrentUser ? { filterByCurrentUser } : undefined),
48
- [provider, filterByCurrentUser],
49
- ),
50
- );
51
-
52
- return { apps: apps as AppManifest[] | undefined, isLoading: !complete, error };
53
- };
54
-
55
- export default useApps;
@@ -1,67 +0,0 @@
1
- import { useMemo } from 'react';
2
-
3
- import { useObservableState } from '@equinor/fusion-observable/react';
4
-
5
- import type { AnyModule } from '@equinor/fusion-framework-module';
6
- import type {
7
- ConfigEnvironment,
8
- AppModule,
9
- CurrentApp,
10
- } from '@equinor/fusion-framework-module-app';
11
-
12
- import { useFramework } from '../useFramework';
13
-
14
- /**
15
- * React hook that observes and returns the currently active application.
16
- *
17
- * @remarks
18
- * Subscribes to the `current$` stream on the App module and returns the
19
- * latest value together with helpers to change or clear the active app.
20
- *
21
- * **Warning:** The template parameters are compile-time hints only — the
22
- * hook does not validate that the specified modules are actually enabled.
23
- *
24
- * @template TModules - Tuple of module types the current app is expected to
25
- * have configured (type-hint only).
26
- * @template TEnv - Expected environment configuration shape (type-hint only).
27
- *
28
- * @returns An object containing:
29
- * - `currentApp` — The current {@link CurrentApp} instance, `null` when
30
- * explicitly cleared, or `undefined` while loading.
31
- * - `setCurrentApp(appKey)` — Sets the active app by its key.
32
- * - `clearCurrentApp()` — Clears the currently active app.
33
- * - `error` — Any error emitted by the observable.
34
- *
35
- * @throws {Error} If the `AppModule` is not configured in the framework.
36
- *
37
- * @example
38
- * ```tsx
39
- * const { currentApp, setCurrentApp } = useCurrentApp();
40
- * return <button onClick={() => setCurrentApp('my-app')}>{currentApp?.manifest?.name}</button>;
41
- * ```
42
- */
43
- export const useCurrentApp = <
44
- TModules extends Array<AnyModule> = [],
45
- TEnv extends ConfigEnvironment = ConfigEnvironment,
46
- >(): {
47
- currentApp?: CurrentApp<TModules, TEnv> | null;
48
- setCurrentApp: (appKey: string) => void;
49
- clearCurrentApp: () => void;
50
- error?: unknown;
51
- } => {
52
- const provider = useFramework<[AppModule]>().modules.app;
53
- // Fail fast when the AppModule has not been configured on the framework
54
- if (!provider) {
55
- throw Error('Current framework does not have AppModule configured');
56
- }
57
- const currentApp$ = useMemo(() => provider.current$, [provider]);
58
- const { value, error } = useObservableState(currentApp$, { initial: provider.current });
59
- return {
60
- currentApp: value as CurrentApp<TModules, TEnv>,
61
- setCurrentApp: useMemo(() => provider.setCurrentApp.bind(provider), [provider]),
62
- clearCurrentApp: useMemo(() => provider.clearCurrentApp.bind(provider), [provider]),
63
- error,
64
- };
65
- };
66
-
67
- export default useCurrentApp;
@@ -1,57 +0,0 @@
1
- import type { AppModules, AppModulesInstance } from '@equinor/fusion-framework-module-app';
2
- import type {
3
- ModuleKey,
4
- AnyModule,
5
- ModuleTypes,
6
- ModuleType,
7
- } from '@equinor/fusion-framework-module';
8
- import useCurrentAppModules from './useCurrentAppModules';
9
-
10
- /**
11
- * React hook that retrieves a specific module from the current application.
12
- *
13
- * @template TType - The expected module type.
14
- * @template TKey - The module key used for look-up.
15
- * @param moduleKey - The key of the module to retrieve.
16
- * @returns An object containing:
17
- * - `module` — The resolved module instance, `null` when no app is
18
- * selected, or `undefined` if the app does not enable the requested module.
19
- * - `error` — Any error emitted during initialisation.
20
- * - `complete` — `true` when the observable has completed.
21
- *
22
- * @remarks
23
- * - A `null` value means no application is currently selected.
24
- * - An `undefined` value means the application has not enabled the requested module.
25
- */
26
- export const useCurrentAppModule = <
27
- TType extends AnyModule | unknown = unknown,
28
- TKey extends string = ModuleKey<ModuleTypes<AppModules<[TType]>>>,
29
- >(
30
- moduleKey: TKey,
31
- ): {
32
- module?:
33
- | (TType extends AnyModule
34
- ? ModuleType<TType>
35
- : AppModulesInstance[Extract<keyof AppModulesInstance, TKey>])
36
- | null;
37
- error?: unknown;
38
- complete: boolean;
39
- } => {
40
- const { modules, error, complete } = useCurrentAppModules();
41
- const module = (() => {
42
- // Preserve an explicit null (modules not applicable) distinct from undefined (not yet loaded)
43
- if (modules === null) {
44
- return null;
45
- }
46
- // Modules are still loading; propagate undefined rather than throwing
47
- if (modules === undefined) {
48
- return undefined;
49
- }
50
- // Module lookup by dynamic key can't be statically narrowed to the exact module type; cast to any.
51
- // biome-ignore lint/suspicious/noExplicitAny: dynamic key lookup can't be statically narrowed to the exact module type
52
- return modules[moduleKey as keyof typeof modules] as any;
53
- })();
54
- return { module, error, complete };
55
- };
56
-
57
- export default useCurrentAppModule;
@@ -1,52 +0,0 @@
1
- import { useMemo } from 'react';
2
- import useCurrentApp from './useCurrentApp';
3
-
4
- import type { AppModulesInstance } from '@equinor/fusion-framework-module-app';
5
- import { type Observable, of } from 'rxjs';
6
- import type { AnyModule } from '@equinor/fusion-framework-module';
7
- import { useObservableState } from '@equinor/fusion-observable/react';
8
-
9
- /**
10
- * React hook that observes the initialised modules of the current application.
11
- *
12
- * @remarks
13
- * Subscribes to the `instance$` stream of the current app and returns the
14
- * resolved module instances.
15
- *
16
- * **Warning:** The template parameter is a compile-time hint only — the
17
- * hook does not validate that the specified modules are actually enabled.
18
- *
19
- * @template TModules - Tuple of module types expected on the current app
20
- * (type-hint only).
21
- * @returns An object containing:
22
- * - `modules` — The initialised {@link AppModulesInstance}, `null` when no
23
- * app is selected, or `undefined` while loading.
24
- * - `error` — Any error emitted during initialisation.
25
- * - `complete` — `true` when the observable has completed.
26
- */
27
- export const useCurrentAppModules = <TModules extends Array<AnyModule> = []>(): {
28
- modules?: AppModulesInstance<TModules> | null;
29
- error?: unknown;
30
- complete: boolean;
31
- } => {
32
- const { currentApp, error: appError } = useCurrentApp<TModules>();
33
- const modules$ = useMemo(
34
- () =>
35
- currentApp ? (currentApp.instance$ as Observable<AppModulesInstance<TModules>>) : of(null),
36
- [currentApp],
37
- );
38
- const {
39
- value: modules,
40
- error,
41
- complete,
42
- } = useObservableState(modules$, {
43
- initial: currentApp === undefined ? undefined : (currentApp?.instance ?? null),
44
- });
45
- return {
46
- modules,
47
- error: error ?? appError,
48
- complete,
49
- };
50
- };
51
-
52
- export default useCurrentAppModules;
@@ -1,13 +0,0 @@
1
- /**
2
- * Context React hooks.
3
- *
4
- * @remarks
5
- * Available via the `@equinor/fusion-framework-react/context` sub-entry-point.
6
- * Re-exports the context module’s React API and adds a convenience
7
- * `useCurrentContext` hook that resolves the module from the framework.
8
- *
9
- * @module
10
- */
11
- export * from '@equinor/fusion-framework-react-module-context';
12
-
13
- export { useCurrentContext } from './useCurrentContext';
@@ -1,22 +0,0 @@
1
- import { useCurrentContext as _useCurrentContext } from '@equinor/fusion-framework-react-module-context';
2
- import { useFramework } from '../useFramework';
3
-
4
- /**
5
- * React hook that returns the currently selected Fusion context.
6
- *
7
- * @remarks
8
- * This is a convenience wrapper that resolves the context module from the
9
- * framework instance and delegates to the underlying
10
- * `useCurrentContext` hook from `@equinor/fusion-framework-react-module-context`.
11
- *
12
- * @returns The current context state as defined by the context module.
13
- *
14
- * @example
15
- * ```ts
16
- * const { currentContext } = useCurrentContext();
17
- * console.log(currentContext?.id);
18
- * ```
19
- */
20
- export const useCurrentContext = () => _useCurrentContext(useFramework().modules.context);
21
-
22
- export default useCurrentContext;
package/src/context.ts DELETED
@@ -1,14 +0,0 @@
1
- import { createContext } from 'react';
2
- import type { Fusion } from '@equinor/fusion-framework';
3
-
4
- /**
5
- * Internal React context that holds the current {@link Fusion} instance.
6
- *
7
- * @remarks
8
- * Consumers should not use this directly — prefer the {@link useFramework}
9
- * hook or the {@link FrameworkProvider} component.
10
- *
11
- * @internal
12
- */
13
- // biome-ignore lint/suspicious/noExplicitAny: `Fusion<any>` widens the context to accept a Fusion instance with any concrete module set
14
- export const context = createContext<Fusion<any> | null>(null);
@@ -1,69 +0,0 @@
1
- import type React from 'react';
2
- import { lazy } from 'react';
3
- import initFusion from '@equinor/fusion-framework';
4
- import { FrameworkConfigurator } from '@equinor/fusion-framework';
5
-
6
- import { FrameworkProvider } from './framework-provider';
7
- import type { AnyModule, ModulesInstanceType } from '@equinor/fusion-framework-module';
8
- import { ModuleProvider } from '@equinor/fusion-framework-react-module';
9
-
10
- /**
11
- * Creates a lazy-loaded React component that initialises a Fusion Framework
12
- * instance and exposes it via context providers.
13
- *
14
- * @remarks
15
- * This is the low-level factory used by the {@link Framework} component.
16
- * Call it when you need fine-grained control over memoisation or when you
17
- * want to embed the provider in a custom `<Suspense>` boundary.
18
- *
19
- * The returned component is created with `React.lazy`, so it **must** be
20
- * rendered inside a `<Suspense>` boundary.
21
- *
22
- * @template TModules - Tuple of additional module types to register.
23
- * @template TRef - Type of the optional parent module-instance reference.
24
- *
25
- * @param cb - Callback that receives a {@link FrameworkConfigurator} (and an
26
- * optional parent ref) for registering modules and configuration.
27
- * @param ref - Optional parent module instance to inherit configuration from.
28
- * @returns A `React.lazy` component that provides the initialised framework
29
- * to its children.
30
- *
31
- * @example
32
- * ```tsx
33
- * import { createFrameworkProvider } from '@equinor/fusion-framework-react';
34
- *
35
- * const Portal = () => {
36
- * const FrameworkProvider = createFrameworkProvider((config) => {
37
- * config.http.configureClient('my-api', { baseUri: 'https://api.example.com' });
38
- * });
39
- *
40
- * return (
41
- * <Suspense fallback={<span>Loading…</span>}>
42
- * <FrameworkProvider>
43
- * <App />
44
- * </FrameworkProvider>
45
- * </Suspense>
46
- * );
47
- * };
48
- * ```
49
- */
50
- export const createFrameworkProvider = <
51
- TModules extends Array<AnyModule> = [],
52
- // biome-ignore lint/suspicious/noExplicitAny: default must be bivariant `any`, not `unknown` \u2014 `unknown` breaks assignability when a concrete `TRef` is passed where the default-typed generic is expected
53
- TRef extends ModulesInstanceType<[AnyModule]> = any,
54
- >(
55
- cb: (configurator: FrameworkConfigurator<TModules>, ref?: TRef) => void | Promise<void>,
56
- ref?: TRef,
57
- ): React.LazyExoticComponent<React.FunctionComponent<React.PropsWithChildren<unknown>>> =>
58
- lazy(async () => {
59
- const configurator = new FrameworkConfigurator<TModules>();
60
- await cb(configurator, ref);
61
- const framework = await initFusion(configurator, ref);
62
- return {
63
- default: ({ children }: { children?: React.ReactNode }) => (
64
- <FrameworkProvider value={framework}>
65
- <ModuleProvider value={framework.modules}>{children}</ModuleProvider>
66
- </FrameworkProvider>
67
- ),
68
- };
69
- });
@@ -1,44 +0,0 @@
1
- __useCurrentAppFeatures__
2
-
3
- Custom hook for accessing all feature flags for an application
4
-
5
- ```tsx
6
- const Component = () => {
7
- const appFeatures = useCurrentAppFeatures();
8
- if( appFeatures.features === undefined ){
9
- return <p>The current app does not have features enabled</p>
10
- }
11
- return (
12
- <>
13
- {
14
- appFeatures.features.map(feature => (
15
- <button
16
- key={feature.key}
17
- disabled={ appFeatures.readOnly }
18
- onClick={ () => appFeatures.toggleFeature( feature.key ) }
19
- >
20
- { feature.enabled ? 'disable' : 'enable' } feature { feature.title }
21
- </button>
22
- ))
23
-
24
- }
25
- </>
26
- )
27
- }
28
- ```
29
-
30
- __useFrameworkFeature__
31
-
32
- Custom hook for using a framework feature
33
-
34
- __useFrameworkFeatures__
35
-
36
- Custom hook for using all framework features
37
-
38
- __useFeature__
39
-
40
- > internal hook for getting a feature from a feature flag module
41
-
42
- __useFeatures__
43
-
44
- > internal hook for getting features of a feature flag module
@@ -1,17 +0,0 @@
1
- /**
2
- * Feature-flag React hooks.
3
- *
4
- * @remarks
5
- * Available via the `@equinor/fusion-framework-react/feature-flag` sub-entry-point.
6
- * Provides hooks to read, toggle, and observe feature flags at the
7
- * framework or application level.
8
- *
9
- * @module
10
- */
11
- export { useFeature } from './useFeature';
12
- export { useFeatures } from './useFeatures';
13
- export { useCurrentAppFeatures } from './useCurrentAppFeatures';
14
- export { useFrameworkFeature } from './useFrameworkFeature';
15
- export { useFrameworkFeatures } from './useFrameworkFeatures';
16
-
17
- export { IFeatureFlag, IFeatureFlagProvider } from '@equinor/fusion-framework-module-feature-flag';
@@ -1,29 +0,0 @@
1
- import type { FeatureFlagModule } from '@equinor/fusion-framework-module-feature-flag';
2
- import { useCurrentAppModule } from '../app';
3
- import { useFeatures, type UseFeaturesResult } from './useFeatures';
4
-
5
- /**
6
- * React hook that returns feature flags registered on the current application.
7
- *
8
- * @returns A {@link UseFeaturesResult} containing:
9
- * - `features` — Array of feature flags for the current app.
10
- * - `toggleFeature(key, enable?)` — Toggles a feature flag on or off.
11
- * - `error` — Any error from the feature-flag or app-module streams.
12
- *
13
- * @example
14
- * ```ts
15
- * const { features, toggleFeature } = useCurrentAppFeatures();
16
- * toggleFeature('dark-mode', true);
17
- * ```
18
- */
19
- export const useCurrentAppFeatures = (): UseFeaturesResult => {
20
- const { module, error: moduleError } = useCurrentAppModule<FeatureFlagModule>('featureFlag');
21
-
22
- const { features, toggleFeature, error } = useFeatures(module);
23
-
24
- return {
25
- features,
26
- toggleFeature,
27
- error: error ?? moduleError,
28
- };
29
- };
@@ -1,71 +0,0 @@
1
- import { useCallback, useMemo } from 'react';
2
-
3
- import { EMPTY } from 'rxjs';
4
-
5
- import type {
6
- IFeatureFlag,
7
- IFeatureFlagProvider,
8
- } from '@equinor/fusion-framework-module-feature-flag';
9
-
10
- import { useObservableState } from '@equinor/fusion-observable/react';
11
-
12
- import { findFeature } from '@equinor/fusion-framework-module-feature-flag/selectors';
13
-
14
- /**
15
- * Return type of the {@link useFeature} hook.
16
- *
17
- * @template T - Value type carried by the feature flag.
18
- */
19
- export interface UseFeatureResult<T> {
20
- /** The resolved feature flag, or `undefined` while loading. */
21
- feature?: IFeatureFlag<T>;
22
- /** Any error emitted by the feature-flag observable. */
23
- error?: unknown;
24
- /**
25
- * Toggles the feature flag.
26
- *
27
- * @param enable - Explicit enabled state. When omitted the current state
28
- * is inverted.
29
- */
30
- toggleFeature: (enable?: boolean) => void;
31
- }
32
-
33
- /**
34
- * React hook that retrieves and manages a single feature flag.
35
- *
36
- * @template T - Value type carried by the feature flag.
37
- * @param provider - The feature-flag provider instance.
38
- * @param key - Unique key identifying the feature flag.
39
- * @returns A {@link UseFeatureResult} with the flag value, toggle helper,
40
- * and any error.
41
- *
42
- * @example
43
- * ```ts
44
- * const { feature, toggleFeature } = useFeature(provider, 'dark-mode');
45
- * console.log(feature?.enabled);
46
- * ```
47
- */
48
- export const useFeature = <T = unknown>(
49
- provider: IFeatureFlagProvider,
50
- key: string,
51
- ): UseFeatureResult<T> => {
52
- // Narrow the features stream down to just the one matching feature by key.
53
- const feature$ = useMemo(
54
- () =>
55
- provider.features$
56
- // Keep the observable scoped to the requested feature key.
57
- .pipe(findFeature<T>(key)),
58
- [provider, key],
59
- );
60
- const { value: feature, error } = useObservableState(feature$ ?? EMPTY);
61
- const toggleFeature = useCallback(
62
- (enable?: boolean) => {
63
- const enabled = enable === undefined ? !provider.getFeature(key)?.enabled : enable;
64
- provider.toggleFeature({ key, enabled });
65
- },
66
- [provider, key],
67
- );
68
- return { feature, toggleFeature, error };
69
- };
70
-
71
- export default useFeature;