@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.
- package/README.md +51 -0
- package/dist/ImFusionCanvas.d.ts +26 -0
- package/dist/ImFusionCanvas.js +51 -0
- package/dist/ImFusionError.d.ts +37 -0
- package/dist/ImFusionError.js +41 -0
- package/dist/ImFusionLoading.d.ts +25 -0
- package/dist/ImFusionLoading.js +30 -0
- package/dist/ImFusionProvider.d.ts +56 -0
- package/dist/ImFusionProvider.js +88 -0
- package/dist/ImFusionReady.d.ts +25 -0
- package/dist/ImFusionReady.js +30 -0
- package/dist/context.d.ts +14 -0
- package/dist/context.js +3 -0
- package/dist/index.d.ts +17 -0
- package/dist/index.js +17 -0
- package/dist/useAnnotations.d.ts +33 -0
- package/dist/useAnnotations.js +67 -0
- package/dist/useContextMenu.d.ts +21 -0
- package/dist/useContextMenu.js +30 -0
- package/dist/useData.d.ts +26 -0
- package/dist/useData.js +40 -0
- package/dist/useDataLoader.d.ts +50 -0
- package/dist/useDataLoader.js +70 -0
- package/dist/useDisplayOptions.d.ts +59 -0
- package/dist/useDisplayOptions.js +87 -0
- package/dist/useFrameSelection.d.ts +32 -0
- package/dist/useFrameSelection.js +43 -0
- package/dist/useImFusion.d.ts +22 -0
- package/dist/useImFusion.js +32 -0
- package/dist/useImFusionError.d.ts +21 -0
- package/dist/useImFusionError.js +32 -0
- package/dist/useImFusionState.d.ts +31 -0
- package/dist/useImFusionState.js +32 -0
- package/dist/useLayoutMode.d.ts +29 -0
- package/dist/useLayoutMode.js +38 -0
- package/dist/useStableHandle.d.ts +15 -0
- package/dist/useStableHandle.js +12 -0
- package/dist/useViewVisibility.d.ts +30 -0
- package/dist/useViewVisibility.js +45 -0
- package/dist/useVisibleData.d.ts +21 -0
- package/dist/useVisibleData.js +32 -0
- 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>;
|
package/dist/useData.js
ADDED
|
@@ -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
|
+
};
|