@imfusion/sdk-react 0.7.0-dev.31.g0ba92924

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 (42) hide show
  1. package/README.md +51 -0
  2. package/dist/ImFusionCanvas.d.ts +26 -0
  3. package/dist/ImFusionCanvas.js +51 -0
  4. package/dist/ImFusionError.d.ts +37 -0
  5. package/dist/ImFusionError.js +41 -0
  6. package/dist/ImFusionLoading.d.ts +25 -0
  7. package/dist/ImFusionLoading.js +30 -0
  8. package/dist/ImFusionProvider.d.ts +56 -0
  9. package/dist/ImFusionProvider.js +88 -0
  10. package/dist/ImFusionReady.d.ts +25 -0
  11. package/dist/ImFusionReady.js +30 -0
  12. package/dist/context.d.ts +14 -0
  13. package/dist/context.js +3 -0
  14. package/dist/index.d.ts +17 -0
  15. package/dist/index.js +17 -0
  16. package/dist/useAnnotations.d.ts +33 -0
  17. package/dist/useAnnotations.js +67 -0
  18. package/dist/useContextMenu.d.ts +21 -0
  19. package/dist/useContextMenu.js +30 -0
  20. package/dist/useData.d.ts +26 -0
  21. package/dist/useData.js +40 -0
  22. package/dist/useDataLoader.d.ts +50 -0
  23. package/dist/useDataLoader.js +70 -0
  24. package/dist/useDisplayOptions.d.ts +59 -0
  25. package/dist/useDisplayOptions.js +87 -0
  26. package/dist/useFrameSelection.d.ts +32 -0
  27. package/dist/useFrameSelection.js +43 -0
  28. package/dist/useImFusion.d.ts +22 -0
  29. package/dist/useImFusion.js +32 -0
  30. package/dist/useImFusionError.d.ts +21 -0
  31. package/dist/useImFusionError.js +32 -0
  32. package/dist/useImFusionState.d.ts +31 -0
  33. package/dist/useImFusionState.js +32 -0
  34. package/dist/useLayoutMode.d.ts +29 -0
  35. package/dist/useLayoutMode.js +38 -0
  36. package/dist/useStableHandle.d.ts +15 -0
  37. package/dist/useStableHandle.js +12 -0
  38. package/dist/useViewVisibility.d.ts +30 -0
  39. package/dist/useViewVisibility.js +45 -0
  40. package/dist/useVisibleData.d.ts +21 -0
  41. package/dist/useVisibleData.js +32 -0
  42. package/package.json +51 -0
@@ -0,0 +1,30 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { useImFusion } from './useImFusion.js';
3
+ /**
4
+ * Registers a context menu handler that fires when the SDK produces a
5
+ * context menu from an input event.
6
+ *
7
+ * @param callback - Receives the {@link @imfusion/sdk!Menu | Menu} and the DOM {@link Event} that triggered it
8
+ * @throws If called outside of an {@link ImFusionProvider}
9
+ * @throws If called before the SDK has finished initializing
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * function ContextMenuHandler() {
14
+ * useContextMenu((menu, event) => {
15
+ * event.preventDefault();
16
+ * // Build a custom menu UI from menu.items()
17
+ * });
18
+ * return null;
19
+ * }
20
+ * ```
21
+ */
22
+ export function useContextMenu(callback) {
23
+ const imf = useImFusion();
24
+ const callbackRef = useRef(callback);
25
+ callbackRef.current = callback;
26
+ useEffect(() => {
27
+ const off = imf.onContextMenu((menu, event) => callbackRef.current(menu, event));
28
+ return off;
29
+ }, [imf]);
30
+ }
@@ -0,0 +1,26 @@
1
+ import type { Data, HandleArray } from '@imfusion/sdk';
2
+ /**
3
+ * Returns a reactive list of all data in the data model.
4
+ *
5
+ * Subscribes to {@link @imfusion/sdk!DataModel.onDataAdded | DataModel.onDataAdded} and
6
+ * {@link @imfusion/sdk!DataModel.onDataAboutToBeRemoved | DataModel.onDataAboutToBeRemoved}.
7
+ *
8
+ * @returns A {@link @imfusion/sdk!HandleArray | HandleArray} of all data
9
+ * @throws If called outside of an {@link ImFusionProvider}
10
+ * @throws If called before the SDK has finished initializing
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function DataList() {
15
+ * const data = useData();
16
+ * return (
17
+ * <ul>
18
+ * {data.map((d, i) => <li key={i}>{d.name}</li>)}
19
+ * </ul>
20
+ * );
21
+ * }
22
+ * ```
23
+ *
24
+ * @see {@link useVisibleData}
25
+ */
26
+ export declare function useData(): HandleArray<Data>;
@@ -0,0 +1,40 @@
1
+ import { useState, useEffect } from 'react';
2
+ import { useImFusion } from './useImFusion.js';
3
+ /**
4
+ * Returns a reactive list of all data in the data model.
5
+ *
6
+ * Subscribes to {@link @imfusion/sdk!DataModel.onDataAdded | DataModel.onDataAdded} and
7
+ * {@link @imfusion/sdk!DataModel.onDataAboutToBeRemoved | DataModel.onDataAboutToBeRemoved}.
8
+ *
9
+ * @returns A {@link @imfusion/sdk!HandleArray | HandleArray} of all data
10
+ * @throws If called outside of an {@link ImFusionProvider}
11
+ * @throws If called before the SDK has finished initializing
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * function DataList() {
16
+ * const data = useData();
17
+ * return (
18
+ * <ul>
19
+ * {data.map((d, i) => <li key={i}>{d.name}</li>)}
20
+ * </ul>
21
+ * );
22
+ * }
23
+ * ```
24
+ *
25
+ * @see {@link useVisibleData}
26
+ */
27
+ export function useData() {
28
+ const imf = useImFusion();
29
+ const [data, setData] = useState(() => imf.dataModel.data());
30
+ useEffect(() => {
31
+ const refresh = () => setData(imf.dataModel.data());
32
+ const offAdded = imf.dataModel.onDataAdded(refresh);
33
+ const offRemoved = imf.dataModel.onDataAboutToBeRemoved(() => queueMicrotask(refresh));
34
+ return () => {
35
+ offAdded();
36
+ offRemoved();
37
+ };
38
+ }, [imf]);
39
+ return data;
40
+ }
@@ -0,0 +1,50 @@
1
+ import type { Data, HandleArray } from '@imfusion/sdk';
2
+ export interface DataLoaderProgress {
3
+ received: number;
4
+ total: number | null;
5
+ }
6
+ /**
7
+ * Provides data loading methods with reactive loading, progress, and error state.
8
+ *
9
+ * Wraps {@link @imfusion/sdk!ImFusion.loadUrl | ImFusion.loadUrl}, {@link @imfusion/sdk!ImFusion.loadFile | ImFusion.loadFile},
10
+ * {@link @imfusion/sdk!ImFusion.loadBuffer | ImFusion.loadBuffer}, and {@link @imfusion/sdk!ImFusion.loadFolder | ImFusion.loadFolder} with
11
+ * React-friendly state management.
12
+ *
13
+ * State (`isLoading`, `progress`, `error`) tracks a single load operation at a time.
14
+ * Concurrent loads from the same hook instance are not supported, use separate instances if needed.
15
+ *
16
+ * @returns A memoized object with load methods and state
17
+ * @throws If called outside of an {@link ImFusionProvider}
18
+ * @throws If called before the SDK has finished initializing
19
+ *
20
+ * @example
21
+ * ```tsx
22
+ * function LoadButton() {
23
+ * const { loadUrl, isLoading, progress, error } = useDataLoader();
24
+ * return (
25
+ * <>
26
+ * <button onClick={() => loadUrl('/data/ct.nii.gz')} disabled={isLoading}>
27
+ * Load CT
28
+ * </button>
29
+ * {isLoading && progress && (
30
+ * <p>{Math.round((progress.received / (progress.total ?? 1)) * 100)}%</p>
31
+ * )}
32
+ * {error && <p>Error: {error.message}</p>}
33
+ * </>
34
+ * );
35
+ * }
36
+ * ```
37
+ *
38
+ * @see {@link useData}
39
+ * @see {@link useVisibleData}
40
+ */
41
+ export declare function useDataLoader(): {
42
+ loadUrl: (url: string) => Promise<HandleArray<Data>>;
43
+ loadFile: (file: File) => Promise<HandleArray<Data>>;
44
+ loadBuffer: (buffer: ArrayBufferLike, filename: string) => Promise<HandleArray<Data>>;
45
+ loadFolder: (files: File[]) => Promise<HandleArray<Data>>;
46
+ isLoading: boolean;
47
+ progress: DataLoaderProgress | null;
48
+ error: Error | null;
49
+ reset: () => void;
50
+ };
@@ -0,0 +1,70 @@
1
+ import { useState, useCallback, useMemo } from 'react';
2
+ import { useImFusion } from './useImFusion.js';
3
+ /**
4
+ * Provides data loading methods with reactive loading, progress, and error state.
5
+ *
6
+ * Wraps {@link @imfusion/sdk!ImFusion.loadUrl | ImFusion.loadUrl}, {@link @imfusion/sdk!ImFusion.loadFile | ImFusion.loadFile},
7
+ * {@link @imfusion/sdk!ImFusion.loadBuffer | ImFusion.loadBuffer}, and {@link @imfusion/sdk!ImFusion.loadFolder | ImFusion.loadFolder} with
8
+ * React-friendly state management.
9
+ *
10
+ * State (`isLoading`, `progress`, `error`) tracks a single load operation at a time.
11
+ * Concurrent loads from the same hook instance are not supported, use separate instances if needed.
12
+ *
13
+ * @returns A memoized object with load methods and state
14
+ * @throws If called outside of an {@link ImFusionProvider}
15
+ * @throws If called before the SDK has finished initializing
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * function LoadButton() {
20
+ * const { loadUrl, isLoading, progress, error } = useDataLoader();
21
+ * return (
22
+ * <>
23
+ * <button onClick={() => loadUrl('/data/ct.nii.gz')} disabled={isLoading}>
24
+ * Load CT
25
+ * </button>
26
+ * {isLoading && progress && (
27
+ * <p>{Math.round((progress.received / (progress.total ?? 1)) * 100)}%</p>
28
+ * )}
29
+ * {error && <p>Error: {error.message}</p>}
30
+ * </>
31
+ * );
32
+ * }
33
+ * ```
34
+ *
35
+ * @see {@link useData}
36
+ * @see {@link useVisibleData}
37
+ */
38
+ export function useDataLoader() {
39
+ const imf = useImFusion();
40
+ const [isLoading, setIsLoading] = useState(false);
41
+ const [progress, setProgress] = useState(null);
42
+ const [error, setError] = useState(null);
43
+ const run = useCallback(async (fn) => {
44
+ setIsLoading(true);
45
+ setError(null);
46
+ setProgress(null);
47
+ try {
48
+ return await fn();
49
+ }
50
+ catch (err) {
51
+ const e = err instanceof Error ? err : new Error(String(err));
52
+ setError(e);
53
+ throw e;
54
+ }
55
+ finally {
56
+ setIsLoading(false);
57
+ }
58
+ }, []);
59
+ const loadUrl = useCallback((url) => run(() => imf.loadUrl(url, {
60
+ onProgress: (received, total) => setProgress({ received, total }),
61
+ })), [imf, run]);
62
+ const loadFile = useCallback((file) => run(() => imf.loadFile(file)), [imf, run]);
63
+ const loadBuffer = useCallback((buffer, filename) => run(() => imf.loadBuffer(buffer, filename)), [imf, run]);
64
+ const loadFolder = useCallback((files) => run(() => imf.loadFolder(files)), [imf, run]);
65
+ const reset = useCallback(() => {
66
+ setError(null);
67
+ setProgress(null);
68
+ }, []);
69
+ return useMemo(() => ({ loadUrl, loadFile, loadBuffer, loadFolder, isLoading, progress, error, reset }), [loadUrl, loadFile, loadBuffer, loadFolder, isLoading, progress, error, reset]);
70
+ }
@@ -0,0 +1,59 @@
1
+ import type { SharedImageSet, DisplayOptions2d, DisplayOptions3d } from '@imfusion/sdk';
2
+ /**
3
+ * Returns the reactive 2D display options for a dataset.
4
+ *
5
+ * Subscribes to {@link @imfusion/sdk!DisplayOptions2d.onChanged | DisplayOptions2d.onChanged}. The hook triggers a
6
+ * re-render whenever the options change.
7
+ *
8
+ * @param sis - The dataset whose 2D display options to observe
9
+ * @returns The {@link @imfusion/sdk!DisplayOptions2d | DisplayOptions2d} handle
10
+ * @throws If called outside of an {@link ImFusionProvider}
11
+ * @throws If called before the SDK has finished initializing
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * function DisplayControls2D({ sis }: { sis: SharedImageSet }) {
16
+ * const opts = useDisplayOptions2d(sis);
17
+ * return (
18
+ * <div>
19
+ * <p>Window: {opts.window} / Level: {opts.level}</p>
20
+ * <button onClick={() => { opts.window = 400; opts.level = 40; }}>
21
+ * Lung preset
22
+ * </button>
23
+ * </div>
24
+ * );
25
+ * }
26
+ * ```
27
+ *
28
+ * @see {@link useDisplayOptions3d}
29
+ */
30
+ export declare function useDisplayOptions2d(sis: SharedImageSet): DisplayOptions2d;
31
+ /**
32
+ * Returns the reactive 3D display options for a dataset.
33
+ *
34
+ * Subscribes to {@link @imfusion/sdk!DisplayOptions3d.onChanged | DisplayOptions3d.onChanged}. The hook triggers a
35
+ * re-render whenever the options change.
36
+ *
37
+ * @param sis - The dataset whose 3D display options to observe
38
+ * @returns The {@link @imfusion/sdk!DisplayOptions3d | DisplayOptions3d} handle
39
+ * @throws If called outside of an {@link ImFusionProvider}
40
+ * @throws If called before the SDK has finished initializing
41
+ *
42
+ * @example
43
+ * ```tsx
44
+ * function DisplayControls3D({ sis }: { sis: SharedImageSet }) {
45
+ * const opts = useDisplayOptions3d(sis);
46
+ * return (
47
+ * <div>
48
+ * <p>Window: {opts.window} / Level: {opts.level}</p>
49
+ * <button onClick={() => { opts.window = 400; opts.level = 40; }}>
50
+ * Lung preset
51
+ * </button>
52
+ * </div>
53
+ * );
54
+ * }
55
+ * ```
56
+ *
57
+ * @see {@link useDisplayOptions2d}
58
+ */
59
+ export declare function useDisplayOptions3d(sis: SharedImageSet): DisplayOptions3d;
@@ -0,0 +1,87 @@
1
+ import { useState, useEffect, useReducer } from 'react';
2
+ import { useImFusion } from './useImFusion.js';
3
+ import { useStableHandle } from './useStableHandle.js';
4
+ /**
5
+ * Returns the reactive 2D display options for a dataset.
6
+ *
7
+ * Subscribes to {@link @imfusion/sdk!DisplayOptions2d.onChanged | DisplayOptions2d.onChanged}. The hook triggers a
8
+ * re-render whenever the options change.
9
+ *
10
+ * @param sis - The dataset whose 2D display options to observe
11
+ * @returns The {@link @imfusion/sdk!DisplayOptions2d | DisplayOptions2d} handle
12
+ * @throws If called outside of an {@link ImFusionProvider}
13
+ * @throws If called before the SDK has finished initializing
14
+ *
15
+ * @example
16
+ * ```tsx
17
+ * function DisplayControls2D({ sis }: { sis: SharedImageSet }) {
18
+ * const opts = useDisplayOptions2d(sis);
19
+ * return (
20
+ * <div>
21
+ * <p>Window: {opts.window} / Level: {opts.level}</p>
22
+ * <button onClick={() => { opts.window = 400; opts.level = 40; }}>
23
+ * Lung preset
24
+ * </button>
25
+ * </div>
26
+ * );
27
+ * }
28
+ * ```
29
+ *
30
+ * @see {@link useDisplayOptions3d}
31
+ */
32
+ export function useDisplayOptions2d(sis) {
33
+ useImFusion();
34
+ // Triggers a re-render without mirroring all C++ properties as React state.
35
+ const [, forceUpdate] = useReducer((x) => !x, false);
36
+ const stableSis = useStableHandle(sis);
37
+ const [options, setOptions] = useState(() => stableSis.displayOptions2d());
38
+ useEffect(() => {
39
+ const opts = stableSis.displayOptions2d();
40
+ setOptions(opts);
41
+ const off = opts.onChanged(() => forceUpdate());
42
+ return off;
43
+ }, [stableSis]);
44
+ return options;
45
+ }
46
+ /**
47
+ * Returns the reactive 3D display options for a dataset.
48
+ *
49
+ * Subscribes to {@link @imfusion/sdk!DisplayOptions3d.onChanged | DisplayOptions3d.onChanged}. The hook triggers a
50
+ * re-render whenever the options change.
51
+ *
52
+ * @param sis - The dataset whose 3D display options to observe
53
+ * @returns The {@link @imfusion/sdk!DisplayOptions3d | DisplayOptions3d} handle
54
+ * @throws If called outside of an {@link ImFusionProvider}
55
+ * @throws If called before the SDK has finished initializing
56
+ *
57
+ * @example
58
+ * ```tsx
59
+ * function DisplayControls3D({ sis }: { sis: SharedImageSet }) {
60
+ * const opts = useDisplayOptions3d(sis);
61
+ * return (
62
+ * <div>
63
+ * <p>Window: {opts.window} / Level: {opts.level}</p>
64
+ * <button onClick={() => { opts.window = 400; opts.level = 40; }}>
65
+ * Lung preset
66
+ * </button>
67
+ * </div>
68
+ * );
69
+ * }
70
+ * ```
71
+ *
72
+ * @see {@link useDisplayOptions2d}
73
+ */
74
+ export function useDisplayOptions3d(sis) {
75
+ useImFusion();
76
+ // Triggers a re-render without mirroring all C++ properties as React state.
77
+ const [, forceUpdate] = useReducer((x) => !x, false);
78
+ const stableSis = useStableHandle(sis);
79
+ const [options, setOptions] = useState(() => stableSis.displayOptions3d());
80
+ useEffect(() => {
81
+ const opts = stableSis.displayOptions3d();
82
+ setOptions(opts);
83
+ const off = opts.onChanged(() => forceUpdate());
84
+ return off;
85
+ }, [stableSis]);
86
+ return options;
87
+ }
@@ -0,0 +1,32 @@
1
+ import type { SharedImageSet } from '@imfusion/sdk';
2
+ /**
3
+ * Returns the reactive selection for a dataset.
4
+ *
5
+ * Subscribes to {@link @imfusion/sdk!SharedImageSet.onSelectionChanged | SharedImageSet.onSelectionChanged}.
6
+ *
7
+ * @param sis - The dataset to observe
8
+ * @returns The current focus index, a setter, and the total frame count
9
+ * @throws If called outside of an {@link ImFusionProvider}
10
+ * @throws If called before the SDK has finished initializing
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function FrameSlider({ sis }: { sis: SharedImageSet }) {
15
+ * const { focus, setFocus, count } = useFrameSelection(sis);
16
+ * return (
17
+ * <input
18
+ * type="range"
19
+ * min={0}
20
+ * max={count - 1}
21
+ * value={focus}
22
+ * onChange={e => setFocus(Number(e.target.value))}
23
+ * />
24
+ * );
25
+ * }
26
+ * ```
27
+ */
28
+ export declare function useFrameSelection(sis: SharedImageSet): {
29
+ focus: number;
30
+ setFocus: (index: number) => void;
31
+ count: number;
32
+ };
@@ -0,0 +1,43 @@
1
+ import { useState, useEffect, useCallback } from 'react';
2
+ import { useImFusion } from './useImFusion.js';
3
+ import { useStableHandle } from './useStableHandle.js';
4
+ /**
5
+ * Returns the reactive selection for a dataset.
6
+ *
7
+ * Subscribes to {@link @imfusion/sdk!SharedImageSet.onSelectionChanged | SharedImageSet.onSelectionChanged}.
8
+ *
9
+ * @param sis - The dataset to observe
10
+ * @returns The current focus index, a setter, and the total frame count
11
+ * @throws If called outside of an {@link ImFusionProvider}
12
+ * @throws If called before the SDK has finished initializing
13
+ *
14
+ * @example
15
+ * ```tsx
16
+ * function FrameSlider({ sis }: { sis: SharedImageSet }) {
17
+ * const { focus, setFocus, count } = useFrameSelection(sis);
18
+ * return (
19
+ * <input
20
+ * type="range"
21
+ * min={0}
22
+ * max={count - 1}
23
+ * value={focus}
24
+ * onChange={e => setFocus(Number(e.target.value))}
25
+ * />
26
+ * );
27
+ * }
28
+ * ```
29
+ */
30
+ export function useFrameSelection(sis) {
31
+ useImFusion();
32
+ const stableSis = useStableHandle(sis);
33
+ const [focus, setFocusState] = useState(() => stableSis.focus());
34
+ useEffect(() => {
35
+ setFocusState(stableSis.focus());
36
+ const off = stableSis.onSelectionChanged(() => {
37
+ setFocusState(stableSis.focus());
38
+ });
39
+ return off;
40
+ }, [stableSis]);
41
+ const setFocus = useCallback((index) => stableSis.setFocus(index), [stableSis]);
42
+ return { focus, setFocus, count: stableSis.size() };
43
+ }
@@ -0,0 +1,22 @@
1
+ import type { ImFusion } from '@imfusion/sdk';
2
+ /**
3
+ * Returns the initialized ImFusion SDK instance.
4
+ *
5
+ * Throws if the SDK is not yet ready. Safe to call inside {@link ImFusionReady}.
6
+ *
7
+ * @returns The initialized {@link @imfusion/sdk!ImFusion | ImFusion} instance
8
+ * @throws If called outside of an {@link ImFusionProvider}
9
+ * @throws If called before the SDK has finished initializing
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * function MyComponent() {
14
+ * const imf = useImFusion();
15
+ * return <button onClick={() => imf.render()}>Render</button>;
16
+ * }
17
+ * ```
18
+ *
19
+ * @see {@link ImFusionReady}
20
+ * @see {@link useImFusionState}
21
+ */
22
+ export declare function useImFusion(): ImFusion;
@@ -0,0 +1,32 @@
1
+ import { useContext } from 'react';
2
+ import { ImFusionContext } from './context.js';
3
+ /**
4
+ * Returns the initialized ImFusion SDK instance.
5
+ *
6
+ * Throws if the SDK is not yet ready. Safe to call inside {@link ImFusionReady}.
7
+ *
8
+ * @returns The initialized {@link @imfusion/sdk!ImFusion | ImFusion} instance
9
+ * @throws If called outside of an {@link ImFusionProvider}
10
+ * @throws If called before the SDK has finished initializing
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function MyComponent() {
15
+ * const imf = useImFusion();
16
+ * return <button onClick={() => imf.render()}>Render</button>;
17
+ * }
18
+ * ```
19
+ *
20
+ * @see {@link ImFusionReady}
21
+ * @see {@link useImFusionState}
22
+ */
23
+ export function useImFusion() {
24
+ const context = useContext(ImFusionContext);
25
+ if (!context) {
26
+ throw new Error('useImFusion must be used within an ImFusionProvider');
27
+ }
28
+ if (!context.imf) {
29
+ throw new Error('ImFusion SDK is not yet initialized');
30
+ }
31
+ return context.imf;
32
+ }
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns the SDK initialization error.
3
+ *
4
+ * Throws if no error has occurred. Safe to call inside {@link ImFusionError}.
5
+ *
6
+ * @returns The initialization {@link Error}
7
+ * @throws If called outside of an {@link ImFusionProvider}
8
+ * @throws If called when there is no error
9
+ *
10
+ * @example
11
+ * ```tsx
12
+ * function ErrorDisplay() {
13
+ * const error = useImFusionError();
14
+ * return <p>Failed to initialize: {error.message}</p>;
15
+ * }
16
+ * ```
17
+ *
18
+ * @see {@link ImFusionError}
19
+ * @see {@link useImFusionState}
20
+ */
21
+ export declare function useImFusionError(): Error;
@@ -0,0 +1,32 @@
1
+ import { useContext } from 'react';
2
+ import { ImFusionContext } from './context.js';
3
+ /**
4
+ * Returns the SDK initialization error.
5
+ *
6
+ * Throws if no error has occurred. Safe to call inside {@link ImFusionError}.
7
+ *
8
+ * @returns The initialization {@link Error}
9
+ * @throws If called outside of an {@link ImFusionProvider}
10
+ * @throws If called when there is no error
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function ErrorDisplay() {
15
+ * const error = useImFusionError();
16
+ * return <p>Failed to initialize: {error.message}</p>;
17
+ * }
18
+ * ```
19
+ *
20
+ * @see {@link ImFusionError}
21
+ * @see {@link useImFusionState}
22
+ */
23
+ export function useImFusionError() {
24
+ const context = useContext(ImFusionContext);
25
+ if (!context) {
26
+ throw new Error('useImFusionError must be used within an ImFusionProvider');
27
+ }
28
+ if (!context.error) {
29
+ throw new Error('No initialization error has occurred');
30
+ }
31
+ return context.error;
32
+ }
@@ -0,0 +1,31 @@
1
+ import type { ImFusion } from '@imfusion/sdk';
2
+ export interface ImFusionState {
3
+ /** The initialized SDK instance, or null if not yet ready. */
4
+ imf: ImFusion | null;
5
+ /** The initialization error, or null if no error occurred. */
6
+ error: Error | null;
7
+ }
8
+ /**
9
+ * Returns the SDK initialization state.
10
+ *
11
+ * Both `imf` and `error` are nullable. Use this when you need to handle
12
+ * loading, ready, and error states in a single component.
13
+ *
14
+ * @returns The current {@link ImFusionState}
15
+ * @throws If called outside of an {@link ImFusionProvider}
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * function StatusBar() {
20
+ * const { imf, error } = useImFusionState();
21
+ *
22
+ * if (error) return <p>Error: {error.message}</p>;
23
+ * if (!imf) return <p>Loading...</p>;
24
+ * return <p>Ready</p>;
25
+ * }
26
+ * ```
27
+ *
28
+ * @see {@link useImFusion}
29
+ * @see {@link useImFusionError}
30
+ */
31
+ export declare function useImFusionState(): ImFusionState;
@@ -0,0 +1,32 @@
1
+ import { useContext } from 'react';
2
+ import { ImFusionContext } from './context.js';
3
+ /**
4
+ * Returns the SDK initialization state.
5
+ *
6
+ * Both `imf` and `error` are nullable. Use this when you need to handle
7
+ * loading, ready, and error states in a single component.
8
+ *
9
+ * @returns The current {@link ImFusionState}
10
+ * @throws If called outside of an {@link ImFusionProvider}
11
+ *
12
+ * @example
13
+ * ```tsx
14
+ * function StatusBar() {
15
+ * const { imf, error } = useImFusionState();
16
+ *
17
+ * if (error) return <p>Error: {error.message}</p>;
18
+ * if (!imf) return <p>Loading...</p>;
19
+ * return <p>Ready</p>;
20
+ * }
21
+ * ```
22
+ *
23
+ * @see {@link useImFusion}
24
+ * @see {@link useImFusionError}
25
+ */
26
+ export function useImFusionState() {
27
+ const context = useContext(ImFusionContext);
28
+ if (!context) {
29
+ throw new Error('useImFusionState must be used within an ImFusionProvider');
30
+ }
31
+ return { imf: context.imf, error: context.error };
32
+ }
@@ -0,0 +1,29 @@
1
+ import type { DisplayLayoutMode } from '@imfusion/sdk';
2
+ /**
3
+ * Returns the reactive display layout mode.
4
+ *
5
+ * Subscribes to {@link @imfusion/sdk!DisplayAutoLayouter.onModeChanged | DisplayAutoLayouter.onModeChanged}.
6
+ *
7
+ * @returns The current mode and a function to change it
8
+ * @throws If called outside of an {@link ImFusionProvider}
9
+ * @throws If called before the SDK has finished initializing
10
+ *
11
+ * @example
12
+ * ```tsx
13
+ * function LayoutPicker() {
14
+ * const { mode, setMode } = useLayoutMode();
15
+ * return (
16
+ * <select value={mode} onChange={e => setMode(e.target.value as DisplayLayoutMode)}>
17
+ * <option value="Auto">Auto</option>
18
+ * <option value="Rows">Rows</option>
19
+ * <option value="FocusPlusStack">Focus + Stack</option>
20
+ * <option value="FocusPlusRows">Focus + Rows</option>
21
+ * </select>
22
+ * );
23
+ * }
24
+ * ```
25
+ */
26
+ export declare function useLayoutMode(): {
27
+ mode: DisplayLayoutMode;
28
+ setMode: (mode: DisplayLayoutMode) => void;
29
+ };