cloudmr-ux 4.7.7 → 4.7.9
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/dist/CmrComponents/niivue-contrast-adjustments/NiivueContrastAdjustments.d.ts +1 -1
- package/dist/CmrComponents/niivue-contrast-adjustments/NiivueContrastAdjustments.js +4 -1
- package/dist/CmrComponents/niivue-roi-table/NiivueRoiTable.js +3 -1
- package/dist/CmrComponents/niivue-slice-position/NiivueSlicePosition.d.ts +1 -1
- package/dist/CmrComponents/niivue-slice-position/NiivueSlicePosition.js +9 -6
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivuePanel.js +3 -1
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivueViewer.d.ts +5 -0
- package/dist/CmrComponents/niivue-viewer/CloudMrNiivueViewer.js +17 -15
- package/dist/CmrComponents/niivue-viewer/Layer.js +3 -1
- package/dist/CmrComponents/niivue-viewer/NiivueViewerThemeContext.d.ts +14 -0
- package/dist/CmrComponents/niivue-viewer/NiivueViewerThemeContext.js +31 -0
- package/dist/CmrComponents/niivue-viewer/PenDraftOverlay.js +5 -4
- package/dist/CmrComponents/niivue-viewer/ShapeDraftOverlay.js +5 -4
- package/dist/CmrComponents/niivue-viewer/Switch.js +3 -1
- package/dist/CmrComponents/niivue-viewer/Toolbar.js +6 -4
- package/dist/CmrComponents/niivue-viewer/mro-draw-toolkit/MroDrawToolkit.js +5 -7
- package/dist/CmrComponents/niivue-viewer/niivueViewerTheme.d.ts +37 -0
- package/dist/CmrComponents/niivue-viewer/niivueViewerTheme.js +106 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/package.json +1 -1
|
@@ -88,5 +88,5 @@ export interface NiivueContrastAdjustmentsProps {
|
|
|
88
88
|
* Pass `title=""` to suppress the heading strip, or `title="Window / Level"` to
|
|
89
89
|
* rename it for a different application.
|
|
90
90
|
*/
|
|
91
|
-
export declare function NiivueContrastAdjustments({ nv, min, max, setMin, setMax, transformFactors, gamma, gammaKey, setGamma, layerList, title, accentColor, style, className, }: NiivueContrastAdjustmentsProps): import("react/jsx-runtime").JSX.Element;
|
|
91
|
+
export declare function NiivueContrastAdjustments({ nv, min, max, setMin, setMax, transformFactors, gamma, gammaKey, setGamma, layerList, title, accentColor: accentColorProp, style, className, }: NiivueContrastAdjustmentsProps): import("react/jsx-runtime").JSX.Element;
|
|
92
92
|
export default NiivueContrastAdjustments;
|
|
@@ -13,6 +13,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
import { Card, CardContent, Box } from "@mui/material";
|
|
14
14
|
import TKDualRange from "../tk-dualrange/TKDualRange";
|
|
15
15
|
import CmrLabel from "../label/Label";
|
|
16
|
+
import { resolveNiivueAccentColor, useNiivueViewerTheme, } from "../niivue-viewer/NiivueViewerThemeContext";
|
|
16
17
|
// ─── Component ────────────────────────────────────────────────────────────────
|
|
17
18
|
/**
|
|
18
19
|
* **NiivueContrastAdjustments**
|
|
@@ -47,7 +48,9 @@ import CmrLabel from "../label/Label";
|
|
|
47
48
|
*/
|
|
48
49
|
export function NiivueContrastAdjustments(_a) {
|
|
49
50
|
var _b, _c, _d, _e;
|
|
50
|
-
var nv = _a.nv, min = _a.min, max = _a.max, setMin = _a.setMin, setMax = _a.setMax, transformFactors = _a.transformFactors, gamma = _a.gamma, gammaKey = _a.gammaKey, setGamma = _a.setGamma, _f = _a.layerList, layerList = _f === void 0 ? [] : _f, _g = _a.title, title = _g === void 0 ? "Contrast Adjustments" : _g,
|
|
51
|
+
var nv = _a.nv, min = _a.min, max = _a.max, setMin = _a.setMin, setMax = _a.setMax, transformFactors = _a.transformFactors, gamma = _a.gamma, gammaKey = _a.gammaKey, setGamma = _a.setGamma, _f = _a.layerList, layerList = _f === void 0 ? [] : _f, _g = _a.title, title = _g === void 0 ? "Contrast Adjustments" : _g, accentColorProp = _a.accentColor, style = _a.style, className = _a.className;
|
|
52
|
+
var theme = useNiivueViewerTheme();
|
|
53
|
+
var accentColor = resolveNiivueAccentColor(accentColorProp, theme);
|
|
51
54
|
var a = transformFactors.a, b = transformFactors.b;
|
|
52
55
|
return (_jsxs("div", __assign({ style: style, className: className }, { children: [title !== "" && (_jsx("div", __assign({ className: "title", style: { width: "100%" } }, { children: title }))), _jsx(Card, __assign({ variant: "outlined", sx: { mb: 2, borderTopLeftRadius: 0, borderTopRightRadius: 0 } }, { children: _jsx(CardContent, __assign({ sx: { "&:last-child": { paddingBottom: 2 } } }, { children: _jsxs(Box, __assign({ style: { display: "flex", flex: 1, minWidth: "245px", flexDirection: "column" } }, { children: [_jsx(TKDualRange, { name: "Values:", minDomain: (_c = (_b = nv.volumes[0]) === null || _b === void 0 ? void 0 : _b.robust_min) !== null && _c !== void 0 ? _c : 0, maxDomain: (_e = (_d = nv.volumes[0]) === null || _d === void 0 ? void 0 : _d.robust_max) !== null && _e !== void 0 ? _e : 1, valueLow: min, valueHigh: max, onChangeLow: function (newMin) {
|
|
53
56
|
var v = nv.volumes[0];
|
|
@@ -58,6 +58,7 @@ import CmrTable from "../../CmrTable/CmrTable";
|
|
|
58
58
|
import CMRUpload from "../upload/Upload";
|
|
59
59
|
import { getEndpoints } from "../../core/config/AppConfig";
|
|
60
60
|
import { AuthenticatedHttpClient } from "../../core/common/utilities/AuthenticatedRequests";
|
|
61
|
+
import { useNiivueViewerTheme } from "../niivue-viewer/NiivueViewerThemeContext";
|
|
61
62
|
/** Default merged ROI label in Niivue patcher `groupLabelsInto` / `groupLabelsFromSelection`. */
|
|
62
63
|
export var DEFAULT_ROI_GROUP_TARGET_LABEL = 7;
|
|
63
64
|
var ROI_TOOLBAR_ICON_SIZE_PX = 24;
|
|
@@ -79,6 +80,7 @@ export function NiivueRoiTable(props) {
|
|
|
79
80
|
var _this = this;
|
|
80
81
|
var _a = props.groupTargetLabel, groupTargetLabel = _a === void 0 ? DEFAULT_ROI_GROUP_TARGET_LABEL : _a, onAfterRoiUpload = props.onAfterRoiUpload;
|
|
81
82
|
var _b = useState(1), uploadKey = _b[0], setUploadKey = _b[1];
|
|
83
|
+
var theme = useNiivueViewerTheme();
|
|
82
84
|
var endpoints = getEndpoints();
|
|
83
85
|
var _c = useState([]), selectedData = _c[0], setSelectedData = _c[1];
|
|
84
86
|
var roiColumns = [
|
|
@@ -151,7 +153,7 @@ export function NiivueRoiTable(props) {
|
|
|
151
153
|
: uniqueSelected.size < 2 || selectedNums.length < 2
|
|
152
154
|
? "Select at least two different ROIs to group"
|
|
153
155
|
: "Group selected ROIs";
|
|
154
|
-
return (_jsxs(Box, __assign({ style: props.style }, { children: [_jsx(CmrTable, { hideFooter: true, getRowId: function (row) { return row.label; }, style: { height: "70%" }, dataSource: props.rois, columns: roiColumns, columnHeaderHeight: 40, rowSelectionModel: selectedData, onRowSelectionModelChange: function (rowSelectionModel) {
|
|
156
|
+
return (_jsxs(Box, __assign({ style: props.style }, { children: [_jsx(CmrTable, { hideFooter: true, getRowId: function (row) { return row.label; }, style: { height: "70%" }, dataSource: props.rois, columns: roiColumns, columnHeaderHeight: 40, headerBgColor: theme.headerBgColor, headerIconColor: theme.headerIconColor, checkboxCheckedColor: theme.checkboxCheckedColor, checkboxUncheckedColor: theme.checkboxUncheckedColor, rowSelectionModel: selectedData, onRowSelectionModelChange: function (rowSelectionModel) {
|
|
155
157
|
setSelectedData(rowSelectionModel);
|
|
156
158
|
} }), _jsxs(Box, __assign({ sx: {
|
|
157
159
|
display: "flex",
|
|
@@ -68,5 +68,5 @@ export interface NiivueSlicePositionProps {
|
|
|
68
68
|
* <NiivueSlicePosition nv={nv} mins={mins} maxs={maxs} mms={mms} />
|
|
69
69
|
* ```
|
|
70
70
|
*/
|
|
71
|
-
export declare function NiivueSlicePosition({ nv, mins, maxs, mms, title, accentColor, style, className, }: NiivueSlicePositionProps): import("react/jsx-runtime").JSX.Element;
|
|
71
|
+
export declare function NiivueSlicePosition({ nv, mins, maxs, mms, title, accentColor: accentColorProp, style, className, }: NiivueSlicePositionProps): import("react/jsx-runtime").JSX.Element;
|
|
72
72
|
export default NiivueSlicePosition;
|
|
@@ -13,6 +13,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
13
13
|
import React from "react";
|
|
14
14
|
import { Card, CardContent } from "@mui/material";
|
|
15
15
|
import CmrLabel from "../label/Label";
|
|
16
|
+
import { resolveNiivueAccentColor, useNiivueViewerTheme, } from "../niivue-viewer/NiivueViewerThemeContext";
|
|
16
17
|
// ─── Helpers (pure, no React) ─────────────────────────────────────────────────
|
|
17
18
|
var safeSpan = function (min, max) { return Math.max(1e-9, max - min); };
|
|
18
19
|
var clamp = function (v, lo, hi) { return Math.max(lo, Math.min(hi, v)); };
|
|
@@ -47,7 +48,9 @@ var round3 = function (v) { return Math.round(v * 1000) / 1000; };
|
|
|
47
48
|
*/
|
|
48
49
|
export function NiivueSlicePosition(_a) {
|
|
49
50
|
var _b, _c, _d, _e, _f;
|
|
50
|
-
var nv = _a.nv, mins = _a.mins, maxs = _a.maxs, mms = _a.mms, _g = _a.title, title = _g === void 0 ? "Slice Position" : _g,
|
|
51
|
+
var nv = _a.nv, mins = _a.mins, maxs = _a.maxs, mms = _a.mms, _g = _a.title, title = _g === void 0 ? "Slice Position" : _g, accentColorProp = _a.accentColor, style = _a.style, className = _a.className;
|
|
52
|
+
var theme = useNiivueViewerTheme();
|
|
53
|
+
var accentColor = resolveNiivueAccentColor(accentColorProp, theme);
|
|
51
54
|
// ── Derive voxel grid from the loaded volume ─────────────────────────────
|
|
52
55
|
var vol = (_b = nv === null || nv === void 0 ? void 0 : nv.volumes) === null || _b === void 0 ? void 0 : _b[0];
|
|
53
56
|
var meta = (_c = vol === null || vol === void 0 ? void 0 : vol.getImageMetadata) === null || _c === void 0 ? void 0 : _c.call(vol);
|
|
@@ -77,7 +80,7 @@ export function NiivueSlicePosition(_a) {
|
|
|
77
80
|
zAtStart = nv.frac2mm([cx, cy, 0.5 / nz])[2];
|
|
78
81
|
zAtEnd = nv.frac2mm([cx, cy, (nz - 0.5) / nz])[2];
|
|
79
82
|
}
|
|
80
|
-
catch (
|
|
83
|
+
catch (_h) {
|
|
81
84
|
var s = safeSpan(mins[2], maxs[2]) / nz;
|
|
82
85
|
zAtStart = mins[2] + 0.5 * s;
|
|
83
86
|
zAtEnd = maxs[2] - 0.5 * s;
|
|
@@ -128,9 +131,9 @@ export function NiivueSlicePosition(_a) {
|
|
|
128
131
|
}
|
|
129
132
|
};
|
|
130
133
|
// ── Local slider state (mirrors mms; synced by useEffect) ────────────────
|
|
131
|
-
var
|
|
132
|
-
var
|
|
133
|
-
var
|
|
134
|
+
var _j = React.useState(round3(mms[0])), xVal = _j[0], setXVal = _j[1];
|
|
135
|
+
var _k = React.useState(round3(mms[1])), yVal = _k[0], setYVal = _k[1];
|
|
136
|
+
var _l = React.useState(round3(mms[2])), zVal = _l[0], setZVal = _l[1];
|
|
134
137
|
// Keep a ref so snapToVoxel can read the *latest* values without stale closure
|
|
135
138
|
var mmsRef = React.useRef([xVal, yVal, zVal]);
|
|
136
139
|
React.useEffect(function () {
|
|
@@ -208,7 +211,7 @@ export function NiivueSlicePosition(_a) {
|
|
|
208
211
|
try {
|
|
209
212
|
fracZ = nv.mm2frac([xVal, yVal, zVal])[2];
|
|
210
213
|
}
|
|
211
|
-
catch (
|
|
214
|
+
catch (_m) {
|
|
212
215
|
fracZ = ratioAxis(zVal, 2);
|
|
213
216
|
}
|
|
214
217
|
zSliceIndex = clamp(Math.round(fracZ * nz - 0.5), 0, nz - 1);
|
|
@@ -57,8 +57,10 @@ import { NiivueRoiTable } from "../niivue-roi-table/NiivueRoiTable";
|
|
|
57
57
|
import { MroDrawToolkit } from "./mro-draw-toolkit/MroDrawToolkit";
|
|
58
58
|
import { ShapeDraftOverlay } from "./ShapeDraftOverlay";
|
|
59
59
|
import { PenDraftOverlay } from "./PenDraftOverlay";
|
|
60
|
+
import { useNiivueViewerTheme } from "./NiivueViewerThemeContext";
|
|
60
61
|
export function CloudMrNiivuePanel(props) {
|
|
61
62
|
var _this = this;
|
|
63
|
+
var theme = useNiivueViewerTheme();
|
|
62
64
|
var canvas = React.useRef(null);
|
|
63
65
|
var histogram = React.useRef(null);
|
|
64
66
|
var mins = props.mins, maxs = props.maxs, mms = props.mms;
|
|
@@ -150,7 +152,7 @@ export function CloudMrNiivuePanel(props) {
|
|
|
150
152
|
md: "row"
|
|
151
153
|
},
|
|
152
154
|
flexWrap: "nowrap"
|
|
153
|
-
} }, { children: [_jsxs(Box, __assign({ sx: {
|
|
155
|
+
}, style: theme.cssVars }, { children: [_jsxs(Box, __assign({ sx: {
|
|
154
156
|
width: {
|
|
155
157
|
xs: "100%",
|
|
156
158
|
md: "63%"
|
|
@@ -13,6 +13,7 @@ export default function CloudMrNiivueViewer(props: any): import("react/jsx-runti
|
|
|
13
13
|
* @property {string} roiDeleteUrl — full URL for `ROI_DELETE` (app resolves from env)
|
|
14
14
|
* @property {() => Promise<void>} refreshPipelineRois — e.g. dispatch getPipelineROI
|
|
15
15
|
* @property {() => any[]} getPipelineRois — returns current ROI list for pipeline (e.g. from Redux)
|
|
16
|
+
* @property {string} [accentColor] — override viewer accent; else host MUI primary if set, else `#580f8b`
|
|
16
17
|
*/
|
|
17
18
|
export const nv: Niivue;
|
|
18
19
|
export type CloudMrNiivueViewerProps = {
|
|
@@ -37,5 +38,9 @@ export type CloudMrNiivueViewerProps = {
|
|
|
37
38
|
* — returns current ROI list for pipeline (e.g. from Redux)
|
|
38
39
|
*/
|
|
39
40
|
getPipelineRois: () => any[];
|
|
41
|
+
/**
|
|
42
|
+
* — override viewer accent; else host MUI primary if set, else `#580f8b`
|
|
43
|
+
*/
|
|
44
|
+
accentColor?: string | undefined;
|
|
40
45
|
};
|
|
41
46
|
import { Niivue } from "./NiivuePatcher";
|
|
@@ -77,6 +77,7 @@ import axios from "axios";
|
|
|
77
77
|
import JSZip from "jszip";
|
|
78
78
|
import { getMax, getMin } from "../../core/common/utilities";
|
|
79
79
|
import { AuthenticatedHttpClient, getEndpoints } from "../../core";
|
|
80
|
+
import { NiivueViewerThemeProvider } from './NiivueViewerThemeContext';
|
|
80
81
|
/**
|
|
81
82
|
* @typedef {Object} CloudMrNiivueViewerProps
|
|
82
83
|
* @property {any[]} niis
|
|
@@ -91,6 +92,7 @@ import { AuthenticatedHttpClient, getEndpoints } from "../../core";
|
|
|
91
92
|
* @property {string} roiDeleteUrl — full URL for `ROI_DELETE` (app resolves from env)
|
|
92
93
|
* @property {() => Promise<void>} refreshPipelineRois — e.g. dispatch getPipelineROI
|
|
93
94
|
* @property {() => any[]} getPipelineRois — returns current ROI list for pipeline (e.g. from Redux)
|
|
95
|
+
* @property {string} [accentColor] — override viewer accent; else host MUI primary if set, else `#580f8b`
|
|
94
96
|
*/
|
|
95
97
|
export var nv = new Niivue({
|
|
96
98
|
loadingText: '',
|
|
@@ -1765,21 +1767,21 @@ export default function CloudMrNiivueViewer(props) {
|
|
|
1765
1767
|
onDeactivateDrawTools: deactivateDrawTools,
|
|
1766
1768
|
onClearDrawing: clearDrawingHandler
|
|
1767
1769
|
};
|
|
1768
|
-
return (_jsxs(Box, __assign({ sx: {
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1770
|
+
return (_jsx(NiivueViewerThemeProvider, __assign({ accentColor: props.accentColor }, { children: _jsxs(Box, __assign({ sx: {
|
|
1771
|
+
display: 'flex',
|
|
1772
|
+
flexDirection: 'column',
|
|
1773
|
+
height: '100%',
|
|
1774
|
+
width: '100%',
|
|
1775
|
+
alignItems: 'center',
|
|
1776
|
+
justifyContent: 'center'
|
|
1777
|
+
} }, { children: [_jsxs(SettingsPanel, __assign({ open: openSettings, width: 300, toggleMenu: toggleSettings }, { children: [_jsx(ColorPicker, { colorRGB01: backColor, onSetColor: nvUpdateBackColor, title: 'Background color' }), _jsx(ColorPicker, { colorRGB01: clipPlaneColor, onSetColor: nvUpdateClipPlaneColor, title: 'Clip plane color' }), _jsx(NumberPicker, { value: clipPlaneOpacity, onChange: nvUpdateClipPlaneOpacity, title: 'Clip plane opacity', min: 0, max: 1, step: 0.1 }), _jsx(ColorPicker, { colorRGB01: crosshairColor, onSetColor: nvUpdateCrosshairColor, title: 'Crosshair color' }), _jsx(NumberPicker, { value: crosshairOpacity, onChange: nvUpdateCrosshairOpacity, title: 'Crosshair opacity', min: 0, max: 1, step: 0.1 }), _jsx(ColorPicker, { colorRGB01: selectionBoxColor, onSetColor: nvUpdateSelectionBoxColor, title: 'Selection box color' }), _jsx(NumberPicker, { value: nv.opts.crosshairWidth, onChange: nvUpdateCrosshairSize, title: 'Crosshair size', min: 0, max: 10, step: 1 }), _jsx(NumberPicker, { value: textSize, onChange: nvUpdateTextSize, title: 'Text size', min: 0, max: 0.2, step: 0.01 }), _jsx(ColorPicker, { colorRGB01: rulerColor, onSetColor: nvUpdateRulerColor, title: 'Ruler color' }), _jsx(NumberPicker, { value: rulerWidth, onChange: nvUpdateRulerWidth, title: 'Ruler thickness', min: 0, max: 10, step: 1 }), _jsx(NumberPicker, { value: rulerOpacity, onChange: nvUpdateRulerOpacity, title: 'Ruler opacity', min: 0, max: 1, step: 0.1 }), _jsx(NumberPicker, { value: opacity, onChange: nvUpdateOpacity, title: 'Opacity', min: 0, max: 1, step: 0.01 }), _jsx(NumberPicker, { value: drawOpacity, onChange: nvUpdateDrawOpacity, title: 'Draw Opacity', min: 0, max: 1, step: 0.01 }), _jsx("label", __assign({ htmlFor: "drawPen" }, { children: "Draw color:" })), _jsxs("select", __assign({ name: "drawPen", id: "drawPen", onChange: nvUpdateDrawPen, value: drawPen }, { children: [_jsx("option", __assign({ value: "0" }, { children: "Erase" })), _jsx("option", __assign({ value: "1" }, { children: "Red" })), _jsx("option", __assign({ value: "2" }, { children: "Green" })), _jsx("option", __assign({ value: "3" }, { children: "Blue" })), _jsx("option", __assign({ value: "8" }, { children: "Filled Erase" })), _jsx("option", __assign({ value: "9" }, { children: "Filled Red" })), _jsx("option", __assign({ value: "10" }, { children: "Filled Green" })), _jsx("option", __assign({ value: "11" }, { children: "Filled Blue" })), _jsx("option", __assign({ value: "12" }, { children: "Erase Selected Cluster" }))] })), _jsx(Button, __assign({ title: 'Save image', onClick: nvSaveImage }, { children: "Save image" })), _jsx(NVSwitch, { checked: locationTableVisible, title: 'Location table', onChange: toggleLocationTable }), _jsx(NVSwitch, { checked: drawingEnabled, title: 'Enable drawing', onChange: nvUpdateDrawingEnabled }), _jsx(NVSwitch, { checked: orientCube, title: 'Orientation cube', onChange: nvUpdateOrientCube }), _jsx(NVSwitch, { checked: ruler, title: 'Ruler', onChange: nvUpdateRuler }), _jsx(NVSwitch, { checked: clipPlane, title: 'Clip plane', onChange: nvUpdateClipPlane }), _jsx(NVSwitch, { checked: cornerText, title: 'Corner text', onChange: nvUpdateCornerText }), _jsx(NVSwitch, { checked: radiological, title: 'radiological', onChange: nvUpdateRadiological }), _jsx(NVSwitch, { checked: crosshair3D, title: '3D crosshair', onChange: nvUpdateCrosshair3D }), _jsx(NVSwitch, { checked: colorBar, title: 'Show color bar', onChange: nvUpdateColorBar }), _jsx(NVSwitch, { checked: worldSpace, title: 'World space', onChange: nvUpdateWorldSpace }), _jsx(NVSwitch, { checked: sagittalNoseLeft, title: 'Nose left', onChange: nvUpdateSagittalNoseLeft }), _jsx(NVSwitch, { checked: dragToMeasure, title: 'Drag to measure', onChange: nvUpdateDragToMeasure }), _jsx(NVSwitch, { checked: highDPI, title: 'High DPI', onChange: nvUpdateHighDPI }), _jsx(NumberPicker, { value: decimalPrecision, onChange: updateDecimalPrecision, title: 'Decimal precision', min: 0, max: 8, step: 1 }), _jsx(NumberPicker, { value: multiplanarPadPixels, onChange: nvUpdateMultiplanarPadPixels, title: 'Multiplanar padding', min: 0, max: 20, step: 2 }), _jsx(NumberPicker, { value: maxDrawUndoBitmaps, onChange: nvUpdateMaxDrawUndoBitmaps, title: 'Max Draw Undos', min: 8, max: 28, step: 1 }), _jsx(NumberPicker, { value: longTouchTimeout, onChange: nvUpdateLongTouchTimeout, title: 'Long touch timeout msec', min: 1000, max: 5000, step: 100 }), _jsx(NumberPicker, { value: doubleTouchTimeout, onChange: nvUpdateDoubleTouchTimeout, title: 'Double touch timeout msec', min: 500, max: 999, step: 25 })] })), _jsx(LayersPanel, __assign({ open: openLayers, width: 320, onToggleMenu: toggleLayers, onAddLayer: addLayer }, { children: layerList })), _jsx(Toolbar, { nv: nv, nvUpdateSliceType: nvUpdateSliceType, sliceType: sliceType, toggleSettings: toggleSettings, toggleLayers: toggleLayers, volumes: props.niis.map(niiToVolume), selectedVolume: selectedVolume, setSelectedVolume: selectVolume, showColorBar: colorBar, toggleColorBar: nvUpdateColorBar, rois: props.rois, selectedROI: selectedROI, refreshROI: refreshROI, setSelectedROI: selectDrawingLayer, toggleShowCrosshair: nvUpdateCrosshair, showCrosshair: showCrosshair, dragMode: dragMode, setDragMode: nvSetDragMode, toggleRadiological: nvUpdateRadiological, radiological: radiological, saveROI: saveDrawingLayer, complexMode: complexMode, setComplexMode: nvSetDisplayedVoxels, complexOptions: complexOptions, labelsVisible: textsVisible, toggleLabelsVisible: nvToggleLabelVisible, saving: saving, setSaving: setSaving, drawingChanged: drawingChanged, resampleImage: resampleImage, accessToken: props.accessToken, pipelineId: props.pipelineID, roiDeleteUrl: props.roiDeleteUrl, refreshPipelineRois: props.refreshPipelineRois }), _jsx(CmrConfirmation, { name: 'New Changes Made', message: "Consider saving your drawing before switching.", open: confirmationOpen, setOpen: setConfirmationOpen, cancellable: true, confirmCallback: warningConfirmationCallback, cancelCallback: warningCancelCallback, cancelText: "Don't save" }), _jsx(CmrEditConfirmation, { name: 'Save drawings', message: 'Please enter the name of the saved drawing', open: saveDialogOpen, setOpen: setSaveDialogOpen, confirmCallback: saveConfirmCallback, cancellable: true, cancelCallback: function () {
|
|
1778
|
+
},
|
|
1779
|
+
// suffix={'.zip'}
|
|
1780
|
+
defaultText: (props.rois[selectedROI] !== undefined ?
|
|
1781
|
+
props.rois[selectedROI].filename : undefined) }), props.niis[selectedVolume] != undefined && _jsx(CloudMrNiivuePanel, { nv: nv, transformFactors: transformFactors, decimalPrecision: decimalPrecision, locationData: locationData, locationTableVisible: locationTableVisible, pipelineID: props.pipelineID, resampleImage: resampleImage, rois: rois, drawToolkitProps: drawToolkitProps, drawShapeTool: drawShapeTool, setDrawShapeTool: setDrawShapeTool, mins: boundMins, maxs: boundMaxs, mms: mms, min: min, max: max, setMin: setMin, setMax: setMax, unzipAndRenderROI: unpackROI, zipAndSendROI: zipAndSendDrawingLayer, setLabelAlias: setLabelAlias, onAfterRoiUpload: function () {
|
|
1782
|
+
var _a;
|
|
1783
|
+
void ((_a = props.refreshPipelineRois) === null || _a === void 0 ? void 0 : _a.call(props));
|
|
1784
|
+
}, gamma: gamma, gammaKey: gammaKey, setGamma: setGamma, shapeDraft: shapeDraft, onShapeDraftChange: onShapeDraftChange, onApplyShapeDraft: function () { return applyShapeDraft(); }, onApplyShapeDraftKeepTool: function () { return applyShapeDraft({ keepTool: true }); }, onCancelShapeDraft: cancelShapeDraft, penDraft: penDraft, onPenDraftChange: onPenDraftChange, onApplyPenDraft: function () { return applyPenDraftHandler(); }, onApplyPenDraftKeepTool: function () { return applyPenDraftHandler({ keepTool: true }); }, onCancelPenDraft: cancelPenDraftHandler }, "".concat(selectedVolume))] })) })));
|
|
1783
1785
|
}
|
|
1784
1786
|
function niiToVolume(nii) {
|
|
1785
1787
|
return {
|
|
@@ -26,6 +26,7 @@ import KeyboardDoubleArrowUpIcon from '@mui/icons-material/KeyboardDoubleArrowUp
|
|
|
26
26
|
import { NumberPicker } from './NumberPicker';
|
|
27
27
|
import React from 'react';
|
|
28
28
|
import { display } from "@mui/system";
|
|
29
|
+
import { useNiivueViewerTheme } from "./NiivueViewerThemeContext";
|
|
29
30
|
function makeColorGradients(colorMapValues) {
|
|
30
31
|
var gradients = '';
|
|
31
32
|
var c = colorMapValues;
|
|
@@ -41,6 +42,7 @@ function makeColorGradients(colorMapValues) {
|
|
|
41
42
|
}
|
|
42
43
|
export default function Layer(props) {
|
|
43
44
|
var _a;
|
|
45
|
+
var theme = useNiivueViewerTheme();
|
|
44
46
|
var allowedColorMaps = [
|
|
45
47
|
"bone",
|
|
46
48
|
"gray",
|
|
@@ -112,7 +114,7 @@ export default function Layer(props) {
|
|
|
112
114
|
width: '100%',
|
|
113
115
|
alignSelf: 'center',
|
|
114
116
|
margin: '8px 0 16px 0',
|
|
115
|
-
accentColor:
|
|
117
|
+
accentColor: theme.accentColor
|
|
116
118
|
} })] })), _jsx(Box, __assign({ sx: {
|
|
117
119
|
display: 'flex',
|
|
118
120
|
flexDirection: 'row',
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import React from "react";
|
|
2
|
+
import { type NiivueViewerThemeTokens } from "./niivueViewerTheme";
|
|
3
|
+
export interface NiivueViewerThemeProviderProps {
|
|
4
|
+
/**
|
|
5
|
+
* Optional override for viewer accent (sliders, ROI table tints, draw-toolkit, etc.).
|
|
6
|
+
* When omitted: uses host MUI `palette.primary.main` if customized, else package purple.
|
|
7
|
+
*/
|
|
8
|
+
accentColor?: string;
|
|
9
|
+
children: React.ReactNode;
|
|
10
|
+
}
|
|
11
|
+
export declare function NiivueViewerThemeProvider({ accentColor, children, }: NiivueViewerThemeProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
12
|
+
/** Returns the viewer theme from context, or package defaults when outside a provider. */
|
|
13
|
+
export declare function useNiivueViewerTheme(): NiivueViewerThemeTokens;
|
|
14
|
+
export declare function resolveNiivueAccentColor(propAccent: string | undefined, theme: NiivueViewerThemeTokens): string;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
var __assign = (this && this.__assign) || function () {
|
|
2
|
+
__assign = Object.assign || function(t) {
|
|
3
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
4
|
+
s = arguments[i];
|
|
5
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
6
|
+
t[p] = s[p];
|
|
7
|
+
}
|
|
8
|
+
return t;
|
|
9
|
+
};
|
|
10
|
+
return __assign.apply(this, arguments);
|
|
11
|
+
};
|
|
12
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
13
|
+
import { createContext, useContext, useMemo } from "react";
|
|
14
|
+
import { useTheme } from "@mui/material/styles";
|
|
15
|
+
import { buildNiivueViewerTheme, CLOUDMR_NIIVUE_DEFAULT_ACCENT, resolveViewerAccentColor, } from "./niivueViewerTheme";
|
|
16
|
+
var NiivueViewerThemeContext = createContext(null);
|
|
17
|
+
export function NiivueViewerThemeProvider(_a) {
|
|
18
|
+
var accentColor = _a.accentColor, children = _a.children;
|
|
19
|
+
var muiTheme = useTheme();
|
|
20
|
+
var resolvedAccent = resolveViewerAccentColor(accentColor, muiTheme.palette.primary.main);
|
|
21
|
+
var theme = useMemo(function () { return buildNiivueViewerTheme(resolvedAccent); }, [resolvedAccent]);
|
|
22
|
+
return (_jsx(NiivueViewerThemeContext.Provider, __assign({ value: theme }, { children: children })));
|
|
23
|
+
}
|
|
24
|
+
/** Returns the viewer theme from context, or package defaults when outside a provider. */
|
|
25
|
+
export function useNiivueViewerTheme() {
|
|
26
|
+
var ctx = useContext(NiivueViewerThemeContext);
|
|
27
|
+
return ctx !== null && ctx !== void 0 ? ctx : buildNiivueViewerTheme(CLOUDMR_NIIVUE_DEFAULT_ACCENT);
|
|
28
|
+
}
|
|
29
|
+
export function resolveNiivueAccentColor(propAccent, theme) {
|
|
30
|
+
return propAccent !== null && propAccent !== void 0 ? propAccent : theme.accentColor;
|
|
31
|
+
}
|
|
@@ -22,8 +22,8 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
22
22
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
23
23
|
import { boundsToFreehandCorners, redrawFreehandDraft, redrawPolylineDraft, syncPolylineDraftToNv, translateFreehandDraft, translatePolylineVertices, updatePolylineVertex, } from "./penDraftUtils";
|
|
24
24
|
import { canvasDeltaToVoxDelta, clientToCanvasPos, voxToOverlayPos, voxUnderClient, } from "./shapeDraftUtils";
|
|
25
|
+
import { useNiivueViewerTheme } from "./NiivueViewerThemeContext";
|
|
25
26
|
var HANDLE_SIZE = 10;
|
|
26
|
-
var ACCENT = "#580f8b";
|
|
27
27
|
function cloneFreehandDraft(draft) {
|
|
28
28
|
return __assign(__assign({}, draft), { strokeVoxels: draft.strokeVoxels.map(function (v) { return __spreadArray([], v, true); }), bounds: draft.bounds ? __assign({}, draft.bounds) : draft.bounds });
|
|
29
29
|
}
|
|
@@ -33,6 +33,7 @@ function cloneFreehandDraft(draft) {
|
|
|
33
33
|
*/
|
|
34
34
|
export function PenDraftOverlay(_a) {
|
|
35
35
|
var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, onApplyDraft = _a.onApplyDraft, overlayKey = _a.overlayKey;
|
|
36
|
+
var theme = useNiivueViewerTheme();
|
|
36
37
|
var dragRef = useRef(null);
|
|
37
38
|
var draftRef = useRef(draft);
|
|
38
39
|
draftRef.current = draft;
|
|
@@ -187,7 +188,7 @@ export function PenDraftOverlay(_a) {
|
|
|
187
188
|
marginTop: -HANDLE_SIZE / 2,
|
|
188
189
|
borderRadius: "50%",
|
|
189
190
|
background: "#fff",
|
|
190
|
-
border: "2px solid ".concat(
|
|
191
|
+
border: "2px solid ".concat(theme.accentColor),
|
|
191
192
|
boxSizing: "border-box",
|
|
192
193
|
cursor: "pointer",
|
|
193
194
|
zIndex: 3,
|
|
@@ -206,8 +207,8 @@ export function PenDraftOverlay(_a) {
|
|
|
206
207
|
top: boxStyle.top,
|
|
207
208
|
width: boxStyle.width,
|
|
208
209
|
height: boxStyle.height,
|
|
209
|
-
border: "2px dashed ".concat(
|
|
210
|
-
background:
|
|
210
|
+
border: "2px dashed ".concat(theme.accentColor),
|
|
211
|
+
background: theme.accentMutedBgLight,
|
|
211
212
|
boxSizing: "border-box",
|
|
212
213
|
pointerEvents: "none"
|
|
213
214
|
} }), centerCss && (_jsx("div", { role: "presentation", onPointerDown: function (e) { return startDrag(e, "move"); }, style: __assign(__assign({}, handleStyle), { left: centerCss.x, top: centerCss.y, cursor: "move", borderRadius: 2, width: 12, height: 12, marginLeft: -6, marginTop: -6 }), title: "Move shape" })), isPolyline &&
|
|
@@ -21,8 +21,8 @@ var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
|
21
21
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
22
22
|
import React, { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
23
23
|
import { boundsToCorners, canvasDeltaToVoxDelta, clientToCanvasPos, normalizeBounds, redrawDraftShape, resizeDraftCorner, translatePt, voxToOverlayPos, voxUnderClient, } from "./shapeDraftUtils";
|
|
24
|
+
import { useNiivueViewerTheme } from "./NiivueViewerThemeContext";
|
|
24
25
|
var HANDLE_SIZE = 10;
|
|
25
|
-
var ACCENT = "#580f8b";
|
|
26
26
|
/**
|
|
27
27
|
* Overlay handles for adjusting a rectangle/ellipse draft before commit.
|
|
28
28
|
* @param {{ nv: any, draft: import('./shapeDraftUtils').ShapeDraft, onDraftChange: (d: any) => void, onApplyDraft?: () => void, overlayKey?: unknown }} props
|
|
@@ -30,6 +30,7 @@ var ACCENT = "#580f8b";
|
|
|
30
30
|
export function ShapeDraftOverlay(_a) {
|
|
31
31
|
var _b;
|
|
32
32
|
var nv = _a.nv, draft = _a.draft, onDraftChange = _a.onDraftChange, onApplyDraft = _a.onApplyDraft, overlayKey = _a.overlayKey;
|
|
33
|
+
var theme = useNiivueViewerTheme();
|
|
33
34
|
var dragRef = useRef(null);
|
|
34
35
|
var draftRef = useRef(draft);
|
|
35
36
|
draftRef.current = draft;
|
|
@@ -157,7 +158,7 @@ export function ShapeDraftOverlay(_a) {
|
|
|
157
158
|
marginTop: -HANDLE_SIZE / 2,
|
|
158
159
|
borderRadius: "50%",
|
|
159
160
|
background: "#fff",
|
|
160
|
-
border: "2px solid ".concat(
|
|
161
|
+
border: "2px solid ".concat(theme.accentColor),
|
|
161
162
|
boxSizing: "border-box",
|
|
162
163
|
cursor: "pointer",
|
|
163
164
|
zIndex: 3,
|
|
@@ -176,8 +177,8 @@ export function ShapeDraftOverlay(_a) {
|
|
|
176
177
|
top: boxStyle.top,
|
|
177
178
|
width: boxStyle.width,
|
|
178
179
|
height: boxStyle.height,
|
|
179
|
-
border: "2px dashed ".concat(
|
|
180
|
-
background:
|
|
180
|
+
border: "2px dashed ".concat(theme.accentColor),
|
|
181
|
+
background: theme.accentMutedBgLight,
|
|
181
182
|
boxSizing: "border-box",
|
|
182
183
|
pointerEvents: "none"
|
|
183
184
|
} }), centerCss && (_jsx("div", { role: "presentation", onPointerDown: function (e) { return startDrag(e, "move"); }, style: __assign(__assign({}, handleStyle), { left: centerCss.x, top: centerCss.y, cursor: "move", borderRadius: 2, width: 12, height: 12, marginLeft: -6, marginTop: -6 }), title: "Move shape" })), cornerCss.map(function (pos, i) { return (_jsx("div", { role: "presentation", onPointerDown: function (e) { return startDrag(e, "corner", i); }, style: __assign(__assign({}, handleStyle), { left: pos.x, top: pos.y, cursor: "nwse-resize" }), title: "Resize shape" }, "corner-".concat(i))); })] })));
|
|
@@ -14,7 +14,9 @@ import { Box } from "@mui/material";
|
|
|
14
14
|
import { Typography } from "@mui/material";
|
|
15
15
|
import { Switch } from "@mui/material";
|
|
16
16
|
import React from "react";
|
|
17
|
+
import { useNiivueViewerTheme } from "./NiivueViewerThemeContext";
|
|
17
18
|
export default function NVSwitch(props) {
|
|
19
|
+
var viewerTheme = useNiivueViewerTheme();
|
|
18
20
|
function handleChange() {
|
|
19
21
|
props.onChange();
|
|
20
22
|
}
|
|
@@ -23,5 +25,5 @@ export default function NVSwitch(props) {
|
|
|
23
25
|
alignItems: 'center'
|
|
24
26
|
}, m: 1 }, { children: [_jsx(Typography, __assign({ onClick: handleChange, style: {
|
|
25
27
|
marginRight: 'auto'
|
|
26
|
-
} }, { children: props.title })), _jsx(Switch, { checked: props.checked, onChange: handleChange })] })));
|
|
28
|
+
} }, { children: props.title })), _jsx(Switch, { checked: props.checked, onChange: handleChange, sx: viewerTheme.muiSwitchSx })] })));
|
|
27
29
|
}
|
|
@@ -59,9 +59,11 @@ import Brightness6Icon from '@mui/icons-material/Brightness6';
|
|
|
59
59
|
import DeleteIcon from "@mui/icons-material/Delete";
|
|
60
60
|
import CmrConfirmation from "../dialogue/Confirmation";
|
|
61
61
|
import axios from "axios";
|
|
62
|
+
import { useNiivueViewerTheme } from "./NiivueViewerThemeContext";
|
|
62
63
|
export default function Toolbar(props) {
|
|
63
64
|
var _this = this;
|
|
64
65
|
var saving = props.saving, setSaving = props.setSaving;
|
|
66
|
+
var viewerTheme = useNiivueViewerTheme();
|
|
65
67
|
function handleSliceTypeChange(e) {
|
|
66
68
|
var newSliceType = e.target.value;
|
|
67
69
|
var nvUpdateSliceType = props.nvUpdateSliceType;
|
|
@@ -222,22 +224,22 @@ export default function Toolbar(props) {
|
|
|
222
224
|
alignItems: 'center'
|
|
223
225
|
}, m: 1 }, { children: [_jsx(Typography, __assign({ style: {
|
|
224
226
|
marginRight: 'auto'
|
|
225
|
-
} }, { children: "Neurological" })), _jsx(Switch, { defaultChecked: false, checked: !props.radiological, onChange: props.toggleRadiological })] })), _jsxs(Box, __assign({ sx: {
|
|
227
|
+
} }, { children: "Neurological" })), _jsx(Switch, { defaultChecked: false, checked: !props.radiological, onChange: props.toggleRadiological, sx: viewerTheme.muiSwitchSx })] })), _jsxs(Box, __assign({ sx: {
|
|
226
228
|
display: 'flex',
|
|
227
229
|
alignItems: 'center'
|
|
228
230
|
}, m: 1 }, { children: [_jsx(Typography, __assign({ style: {
|
|
229
231
|
marginRight: 'auto'
|
|
230
|
-
} }, { children: "Show Crosshair" })), _jsx(Switch, { defaultChecked: true, checked: props.showCrosshair, onChange: props.toggleShowCrosshair })] })), _jsxs(Box, __assign({ sx: {
|
|
232
|
+
} }, { children: "Show Crosshair" })), _jsx(Switch, { defaultChecked: true, checked: props.showCrosshair, onChange: props.toggleShowCrosshair, sx: viewerTheme.muiSwitchSx })] })), _jsxs(Box, __assign({ sx: {
|
|
231
233
|
display: 'flex',
|
|
232
234
|
alignItems: 'center'
|
|
233
235
|
}, m: 1 }, { children: [_jsx(Typography, __assign({ style: {
|
|
234
236
|
marginRight: 'auto'
|
|
235
|
-
} }, { children: "Show Color Bar" })), _jsx(Switch, { checked: props.showColorBar, onChange: props.toggleColorBar })] })), _jsxs(Box, __assign({ sx: {
|
|
237
|
+
} }, { children: "Show Color Bar" })), _jsx(Switch, { checked: props.showColorBar, onChange: props.toggleColorBar, sx: viewerTheme.muiSwitchSx })] })), _jsxs(Box, __assign({ sx: {
|
|
236
238
|
display: 'flex',
|
|
237
239
|
alignItems: 'center'
|
|
238
240
|
}, m: 1 }, { children: [_jsx(Typography, __assign({ style: {
|
|
239
241
|
marginRight: 'auto'
|
|
240
|
-
} }, { children: "Labels Visible" })), _jsx(Switch, { defaultChecked: false, checked: props.labelsVisible, onChange: props.toggleLabelsVisible })] })), _jsx(Box, { sx: { flex: 1 } }), _jsxs(Stack, __assign({ flexDirection: 'row', alignItems: 'center', sx: { m: 2, gap: 0.5 } }, { children: [_jsx(Tooltip, __assign({ title: 'Reset Views', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () { return props.nv.resetScene(); } }, { children: _jsx(HomeIcon, {}) })) })), _jsx(Tooltip, __assign({ title: 'Recenter Views', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () { return props.nv.recenter(); } }, { children: _jsx(CenterFocusStrongIcon, {}) })) })), _jsx(Tooltip, __assign({ title: 'Reset Zooms', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () { return props.nv.resetZoom(); } }, { children: _jsx(ZoomInMapIcon, {}) })) })), _jsx(Tooltip, __assign({ title: 'Reset Contrast', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () {
|
|
242
|
+
} }, { children: "Labels Visible" })), _jsx(Switch, { defaultChecked: false, checked: props.labelsVisible, onChange: props.toggleLabelsVisible, sx: viewerTheme.muiSwitchSx })] })), _jsx(Box, { sx: { flex: 1 } }), _jsxs(Stack, __assign({ flexDirection: 'row', alignItems: 'center', sx: { m: 2, gap: 0.5 } }, { children: [_jsx(Tooltip, __assign({ title: 'Reset Views', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () { return props.nv.resetScene(); } }, { children: _jsx(HomeIcon, {}) })) })), _jsx(Tooltip, __assign({ title: 'Recenter Views', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () { return props.nv.recenter(); } }, { children: _jsx(CenterFocusStrongIcon, {}) })) })), _jsx(Tooltip, __assign({ title: 'Reset Zooms', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () { return props.nv.resetZoom(); } }, { children: _jsx(ZoomInMapIcon, {}) })) })), _jsx(Tooltip, __assign({ title: 'Reset Contrast', placement: 'right' }, { children: _jsx(IconButton, __assign({ onClick: function () {
|
|
241
243
|
var _a, _b;
|
|
242
244
|
props.nv.resetContrast();
|
|
243
245
|
props.nv.setGamma(1.0); // engine reset
|
|
@@ -35,6 +35,7 @@ import ClickAwayListener from "@mui/material/ClickAwayListener";
|
|
|
35
35
|
import DrawColorPlatte from "./DrawColorPlatte";
|
|
36
36
|
import EraserPlatte from "./EraserPlatte";
|
|
37
37
|
import MaskPlatte from "./MaskPlatte";
|
|
38
|
+
import { useNiivueViewerTheme } from "../NiivueViewerThemeContext";
|
|
38
39
|
/** True if the event target is the main NiiVue canvas (drawing surface). Clicks there must not exit draw mode. */
|
|
39
40
|
function clickTargetIsNiivueCanvas(target) {
|
|
40
41
|
if (typeof document === "undefined" || !(target instanceof Element))
|
|
@@ -61,10 +62,11 @@ function OpacityPlatte(_a) {
|
|
|
61
62
|
borderTopRightRadius: "6pt",
|
|
62
63
|
background: "#333",
|
|
63
64
|
width: 150
|
|
64
|
-
}, direction: "column" }, { children: _jsxs(Stack, __assign({ sx: { mb: 1 }, alignItems: "center" }, { children: [_jsxs(Typography, __assign({ color: "white", noWrap: true, gutterBottom: true, width: "100%", marginLeft: "10pt", fontSize: "11pt", alignItems: "start" }, { children: ["Opacity: ", drawingOpacity] })), _jsx(Slider, { sx: { width: "80%" }, value: drawingOpacity, step: 0.01, min: 0, max: 1, onChange: function (_e, value) { return setDrawingOpacity(value); } })] })) })));
|
|
65
|
+
}, direction: "column" }, { children: _jsxs(Stack, __assign({ sx: { mb: 1 }, alignItems: "center" }, { children: [_jsxs(Typography, __assign({ color: "white", noWrap: true, gutterBottom: true, width: "100%", marginLeft: "10pt", fontSize: "11pt", alignItems: "start" }, { children: ["Opacity: ", drawingOpacity] })), _jsx(Slider, { color: "primary", sx: { width: "80%" }, value: drawingOpacity, step: 0.01, min: 0, max: 1, onChange: function (_e, value) { return setDrawingOpacity(value); } })] })) })));
|
|
65
66
|
}
|
|
66
67
|
export function MroDrawToolkit(props) {
|
|
67
68
|
var _a;
|
|
69
|
+
var theme = useNiivueViewerTheme();
|
|
68
70
|
var drawShapeTool = props.drawShapeTool, onDrawShapeToolChange = props.onDrawShapeToolChange;
|
|
69
71
|
var _b = useState("n"), expandedOption = _b[0], setExpandedOption = _b[1];
|
|
70
72
|
var _c = useState(false), expandOpacityOptions = _c[0], setExpandOpacityOptions = _c[1];
|
|
@@ -86,9 +88,7 @@ export function MroDrawToolkit(props) {
|
|
|
86
88
|
setExpandedOption("d");
|
|
87
89
|
}, [props.shapeDraftActive, props.penDraftActive, drawShapeTool]);
|
|
88
90
|
var shapeSelectedSx = function (shape) {
|
|
89
|
-
return drawShapeTool === shape
|
|
90
|
-
? { backgroundColor: "rgba(88, 15, 139, 0.12)", color: "#580f8b" }
|
|
91
|
-
: {};
|
|
91
|
+
return drawShapeTool === shape ? theme.selectedToolSx : {};
|
|
92
92
|
};
|
|
93
93
|
var eraserActive = expandedOption === "e";
|
|
94
94
|
function leaveEraserIfActive() {
|
|
@@ -189,9 +189,7 @@ export function MroDrawToolkit(props) {
|
|
|
189
189
|
alignItems: "center",
|
|
190
190
|
gap: 4,
|
|
191
191
|
overflow: "visible"
|
|
192
|
-
} }, { children: [_jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "d" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Pen" }, { children: _jsx(IconButton, __assign({ "aria-label": "pen", size: "small", onClick: clickPen, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("pen")) }, { children: _jsx(DrawIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "d", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, showPenModes: true, penDrawMode: props.penDrawMode, onPenDrawModeChange: props.onPenDrawModeChange, polylineVertexCount: props.polylineVertexCount, onCancelPolyline: props.onCancelPolyline, penDraftActive: props.penDraftActive, penDraftKind: props.penDraftKind, penDraftFilled: props.penDraftFilled, onApplyPenDraft: props.onApplyPenDraft, onDeletePenDraft: props.onDeletePenDraft, onFillPenDraft: props.onFillPenDraft, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "r" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Rectangle" }, { children: _jsx(IconButton, __assign({ "aria-label": "rectangle", size: "small", onClick: clickRectangle, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("rectangle")) }, { children: _jsx(CropSquareOutlinedIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "r", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, shapeDraftActive: props.shapeDraftActive && drawShapeTool === "rectangle", onApplyShapeDraft: props.onApplyShapeDraft, onDeleteShapeDraft: props.onDeleteShapeDraft })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "l" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Ellipse" }, { children: _jsx(IconButton, __assign({ "aria-label": "ellipse", size: "small", onClick: clickEllipse, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("ellipse")) }, { children: _jsx(CircleOutlinedIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "l", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, shapeDraftActive: props.shapeDraftActive && drawShapeTool === "ellipse", onApplyShapeDraft: props.onApplyShapeDraft, onDeleteShapeDraft: props.onDeleteShapeDraft })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "e" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Eraser" }, { children: _jsx(IconButton, __assign({ "aria-label": "erase", size: "small", onClick: clickEraser, sx: __assign(__assign({}, toolBtnSx), (eraserActive
|
|
193
|
-
? { backgroundColor: "rgba(88, 15, 139, 0.12)", color: "#580f8b" }
|
|
194
|
-
: {})) }, { children: filled || !eraserActive ? (_jsx(EraserIcon, {})) : (_jsx(AutoFixNormalOutlinedIcon, { sx: { color: ICON_COLOR } })) })) })), _jsx(EraserPlatte, { expandEraseOptions: expandedOption === "e", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })), _jsx(Tooltip, __assign({ title: "Undo" }, { children: _jsx(IconButton, __assign({ "aria-label": "revert", size: "small", onClick: function () { return props.drawUndo(); }, sx: toolBtnSx }, { children: _jsx(ReplyIcon, { sx: { color: ICON_COLOR } }) })) })), _jsx(Tooltip, __assign({ title: "Save screenshot" }, { children: _jsx("span", { children: _jsx(IconButton, __assign({ "aria-label": "capture", size: "small", disabled: !vol, onClick: function () { return vol && props.nv.saveScene("".concat(vol.name, "_drawing.png")); }, sx: toolBtnSx }, { children: _jsx(CameraAltIcon, { sx: { color: ICON_COLOR } }) })) }) })), _jsx(Tooltip, __assign({ title: "Clear drawing" }, { children: _jsx(IconButton, __assign({ "aria-label": "delete", size: "small", onClick: function () {
|
|
192
|
+
} }, { children: [_jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "d" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Pen" }, { children: _jsx(IconButton, __assign({ "aria-label": "pen", size: "small", onClick: clickPen, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("pen")) }, { children: _jsx(DrawIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "d", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, showPenModes: true, penDrawMode: props.penDrawMode, onPenDrawModeChange: props.onPenDrawModeChange, polylineVertexCount: props.polylineVertexCount, onCancelPolyline: props.onCancelPolyline, penDraftActive: props.penDraftActive, penDraftKind: props.penDraftKind, penDraftFilled: props.penDraftFilled, onApplyPenDraft: props.onApplyPenDraft, onDeletePenDraft: props.onDeletePenDraft, onFillPenDraft: props.onFillPenDraft, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "r" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Rectangle" }, { children: _jsx(IconButton, __assign({ "aria-label": "rectangle", size: "small", onClick: clickRectangle, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("rectangle")) }, { children: _jsx(CropSquareOutlinedIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "r", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, shapeDraftActive: props.shapeDraftActive && drawShapeTool === "rectangle", onApplyShapeDraft: props.onApplyShapeDraft, onDeleteShapeDraft: props.onDeleteShapeDraft })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "l" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Ellipse" }, { children: _jsx(IconButton, __assign({ "aria-label": "ellipse", size: "small", onClick: clickEllipse, sx: __assign(__assign({}, toolBtnSx), shapeSelectedSx("ellipse")) }, { children: _jsx(CircleOutlinedIcon, { sx: { color: "inherit" } }) })) })), _jsx(DrawColorPlatte, { expanded: expandedOption === "l", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, shapeDraftActive: props.shapeDraftActive && drawShapeTool === "ellipse", onApplyShapeDraft: props.onApplyShapeDraft, onDeleteShapeDraft: props.onDeleteShapeDraft })] })), _jsxs(Box, __assign({ sx: { position: "relative", zIndex: expandedOption === "e" ? 1600 : "auto", display: "inline-flex", alignItems: "center" } }, { children: [_jsx(Tooltip, __assign({ title: "Eraser" }, { children: _jsx(IconButton, __assign({ "aria-label": "erase", size: "small", onClick: clickEraser, sx: __assign(__assign({}, toolBtnSx), (eraserActive ? theme.selectedToolSx : {})) }, { children: filled || !eraserActive ? (_jsx(EraserIcon, {})) : (_jsx(AutoFixNormalOutlinedIcon, { sx: { color: ICON_COLOR } })) })) })), _jsx(EraserPlatte, { expandEraseOptions: expandedOption === "e", updateDrawPen: props.updateDrawPen, setDrawingEnabled: props.setDrawingEnabled, brushSize: props.brushSize, updateBrushSize: props.updateBrushSize })] })), _jsx(Tooltip, __assign({ title: "Undo" }, { children: _jsx(IconButton, __assign({ "aria-label": "revert", size: "small", onClick: function () { return props.drawUndo(); }, sx: toolBtnSx }, { children: _jsx(ReplyIcon, { sx: { color: ICON_COLOR } }) })) })), _jsx(Tooltip, __assign({ title: "Save screenshot" }, { children: _jsx("span", { children: _jsx(IconButton, __assign({ "aria-label": "capture", size: "small", disabled: !vol, onClick: function () { return vol && props.nv.saveScene("".concat(vol.name, "_drawing.png")); }, sx: toolBtnSx }, { children: _jsx(CameraAltIcon, { sx: { color: ICON_COLOR } }) })) }) })), _jsx(Tooltip, __assign({ title: "Clear drawing" }, { children: _jsx(IconButton, __assign({ "aria-label": "delete", size: "small", onClick: function () {
|
|
195
193
|
var _a;
|
|
196
194
|
(_a = props.onClearDrawing) === null || _a === void 0 ? void 0 : _a.call(props);
|
|
197
195
|
setExpandedOption("n");
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import type { CSSProperties } from "react";
|
|
2
|
+
/** Host apps may set this on a root wrapper so linked cloudmr-ux reads the brand color without a shared MUI context. */
|
|
3
|
+
export declare const CMR_APP_PRIMARY_CSS_VAR = "--cmr-app-primary";
|
|
4
|
+
/** Default MROptimum / package purple accent for the Niivue viewer. */
|
|
5
|
+
export declare const CLOUDMR_NIIVUE_DEFAULT_ACCENT = "#580f8b";
|
|
6
|
+
/** Read brand primary exposed by the host shell (see {@link CMR_APP_PRIMARY_CSS_VAR}). */
|
|
7
|
+
export declare function readHostPrimaryFromCss(): string | undefined;
|
|
8
|
+
/**
|
|
9
|
+
* Resolve Niivue viewer accent color:
|
|
10
|
+
* 1. Explicit `accentColor` prop on {@link CloudMrNiivueViewer}
|
|
11
|
+
* 2. Host CSS var {@link CMR_APP_PRIMARY_CSS_VAR} (works with npm link / duplicate MUI)
|
|
12
|
+
* 3. Host MUI `palette.primary.main` when it differs from stock MUI primary
|
|
13
|
+
* 4. Package default purple {@link CLOUDMR_NIIVUE_DEFAULT_ACCENT}
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveViewerAccentColor(accentColorProp?: string, muiPrimaryMain?: string): string;
|
|
16
|
+
export interface NiivueViewerThemeTokens {
|
|
17
|
+
accentColor: string;
|
|
18
|
+
accentMutedBg: string;
|
|
19
|
+
accentMutedBgLight: string;
|
|
20
|
+
headerBgColor: string;
|
|
21
|
+
headerIconColor: string;
|
|
22
|
+
checkboxCheckedColor: string;
|
|
23
|
+
checkboxUncheckedColor: string;
|
|
24
|
+
selectedToolSx: {
|
|
25
|
+
backgroundColor: string;
|
|
26
|
+
color: string;
|
|
27
|
+
};
|
|
28
|
+
muiSwitchSx: Record<string, unknown>;
|
|
29
|
+
muiSliderSx: Record<string, unknown>;
|
|
30
|
+
cssVars: CSSProperties;
|
|
31
|
+
}
|
|
32
|
+
export declare function hexToRgb(hex: string): {
|
|
33
|
+
r: number;
|
|
34
|
+
g: number;
|
|
35
|
+
b: number;
|
|
36
|
+
};
|
|
37
|
+
export declare function buildNiivueViewerTheme(accentColor: string): NiivueViewerThemeTokens;
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { createTheme } from "@mui/material/styles";
|
|
2
|
+
/** Host apps may set this on a root wrapper so linked cloudmr-ux reads the brand color without a shared MUI context. */
|
|
3
|
+
export var CMR_APP_PRIMARY_CSS_VAR = "--cmr-app-primary";
|
|
4
|
+
/** Default MROptimum / package purple accent for the Niivue viewer. */
|
|
5
|
+
export var CLOUDMR_NIIVUE_DEFAULT_ACCENT = "#580f8b";
|
|
6
|
+
/** MUI stock `palette.primary.main` when the host does not customize primary. */
|
|
7
|
+
var muiDefaultPrimaryMain;
|
|
8
|
+
function getMuiDefaultPrimaryMain() {
|
|
9
|
+
if (!muiDefaultPrimaryMain) {
|
|
10
|
+
muiDefaultPrimaryMain = createTheme().palette.primary.main;
|
|
11
|
+
}
|
|
12
|
+
return muiDefaultPrimaryMain;
|
|
13
|
+
}
|
|
14
|
+
function normalizeHex(color) {
|
|
15
|
+
return color.trim().toLowerCase();
|
|
16
|
+
}
|
|
17
|
+
/** Read brand primary exposed by the host shell (see {@link CMR_APP_PRIMARY_CSS_VAR}). */
|
|
18
|
+
export function readHostPrimaryFromCss() {
|
|
19
|
+
if (typeof document === "undefined") {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
var val = getComputedStyle(document.documentElement)
|
|
23
|
+
.getPropertyValue(CMR_APP_PRIMARY_CSS_VAR)
|
|
24
|
+
.trim();
|
|
25
|
+
return val || undefined;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Resolve Niivue viewer accent color:
|
|
29
|
+
* 1. Explicit `accentColor` prop on {@link CloudMrNiivueViewer}
|
|
30
|
+
* 2. Host CSS var {@link CMR_APP_PRIMARY_CSS_VAR} (works with npm link / duplicate MUI)
|
|
31
|
+
* 3. Host MUI `palette.primary.main` when it differs from stock MUI primary
|
|
32
|
+
* 4. Package default purple {@link CLOUDMR_NIIVUE_DEFAULT_ACCENT}
|
|
33
|
+
*/
|
|
34
|
+
export function resolveViewerAccentColor(accentColorProp, muiPrimaryMain) {
|
|
35
|
+
if (accentColorProp) {
|
|
36
|
+
return accentColorProp;
|
|
37
|
+
}
|
|
38
|
+
var cssPrimary = readHostPrimaryFromCss();
|
|
39
|
+
if (cssPrimary) {
|
|
40
|
+
return cssPrimary;
|
|
41
|
+
}
|
|
42
|
+
var primary = muiPrimaryMain === null || muiPrimaryMain === void 0 ? void 0 : muiPrimaryMain.trim();
|
|
43
|
+
if (primary &&
|
|
44
|
+
normalizeHex(primary) !== normalizeHex(getMuiDefaultPrimaryMain())) {
|
|
45
|
+
return primary;
|
|
46
|
+
}
|
|
47
|
+
return CLOUDMR_NIIVUE_DEFAULT_ACCENT;
|
|
48
|
+
}
|
|
49
|
+
export function hexToRgb(hex) {
|
|
50
|
+
var h = hex.replace("#", "");
|
|
51
|
+
var full = h.length === 3 ? h.split("").map(function (c) { return c + c; }).join("") : h.slice(0, 6);
|
|
52
|
+
var n = parseInt(full, 16);
|
|
53
|
+
if (Number.isNaN(n)) {
|
|
54
|
+
return hexToRgb(CLOUDMR_NIIVUE_DEFAULT_ACCENT);
|
|
55
|
+
}
|
|
56
|
+
return { r: (n >> 16) & 255, g: (n >> 8) & 255, b: n & 255 };
|
|
57
|
+
}
|
|
58
|
+
/** Light header background tinted from accent (~8% accent, 92% white). */
|
|
59
|
+
function accentToHeaderBg(r, g, b) {
|
|
60
|
+
var mix = function (c) {
|
|
61
|
+
return Math.round(c * 0.08 + 255 * 0.92)
|
|
62
|
+
.toString(16)
|
|
63
|
+
.padStart(2, "0");
|
|
64
|
+
};
|
|
65
|
+
return "#".concat(mix(r)).concat(mix(g)).concat(mix(b));
|
|
66
|
+
}
|
|
67
|
+
export function buildNiivueViewerTheme(accentColor) {
|
|
68
|
+
var _a;
|
|
69
|
+
var _b = hexToRgb(accentColor), r = _b.r, g = _b.g, b = _b.b;
|
|
70
|
+
var accentMutedBg = "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", 0.12)");
|
|
71
|
+
var accentMutedBgLight = "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", 0.08)");
|
|
72
|
+
var checkboxUncheckedColor = "rgba(".concat(r, ", ").concat(g, ", ").concat(b, ", 0.54)");
|
|
73
|
+
return {
|
|
74
|
+
accentColor: accentColor,
|
|
75
|
+
accentMutedBg: accentMutedBg,
|
|
76
|
+
accentMutedBgLight: accentMutedBgLight,
|
|
77
|
+
headerBgColor: accentToHeaderBg(r, g, b),
|
|
78
|
+
headerIconColor: accentColor,
|
|
79
|
+
checkboxCheckedColor: accentColor,
|
|
80
|
+
checkboxUncheckedColor: checkboxUncheckedColor,
|
|
81
|
+
selectedToolSx: { backgroundColor: accentMutedBg, color: accentColor },
|
|
82
|
+
muiSwitchSx: {
|
|
83
|
+
"& .MuiSwitch-switchBase.Mui-checked": {
|
|
84
|
+
color: accentColor,
|
|
85
|
+
"&:hover": { backgroundColor: accentMutedBgLight },
|
|
86
|
+
"& + .MuiSwitch-track": { backgroundColor: accentColor, opacity: 1 }
|
|
87
|
+
},
|
|
88
|
+
"& .MuiSwitch-switchBase.Mui-checked.Mui-disabled": {
|
|
89
|
+
color: checkboxUncheckedColor,
|
|
90
|
+
"& + .MuiSwitch-track": {
|
|
91
|
+
backgroundColor: checkboxUncheckedColor,
|
|
92
|
+
opacity: 0.5
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
},
|
|
96
|
+
muiSliderSx: {
|
|
97
|
+
color: accentColor,
|
|
98
|
+
"& .MuiSlider-thumb": { backgroundColor: accentColor },
|
|
99
|
+
"& .MuiSlider-track": { backgroundColor: accentColor }
|
|
100
|
+
},
|
|
101
|
+
cssVars: (_a = {},
|
|
102
|
+
_a["--tkdr-accent"] = accentColor,
|
|
103
|
+
_a["--cmr-niivue-accent"] = accentColor,
|
|
104
|
+
_a)
|
|
105
|
+
};
|
|
106
|
+
}
|
package/dist/index.d.ts
CHANGED
|
@@ -35,6 +35,9 @@ export { NiivueRoiTable, DEFAULT_ROI_GROUP_TARGET_LABEL, } from "./CmrComponents
|
|
|
35
35
|
export type { NiivueRoiTableProps } from "./CmrComponents/niivue-roi-table/NiivueRoiTable";
|
|
36
36
|
export { default as CloudMrNiivueViewer, nv } from "./CmrComponents/niivue-viewer/CloudMrNiivueViewer.js";
|
|
37
37
|
export { CloudMrNiivuePanel } from "./CmrComponents/niivue-viewer/CloudMrNiivuePanel";
|
|
38
|
+
export { NiivueViewerThemeProvider, useNiivueViewerTheme, } from "./CmrComponents/niivue-viewer/NiivueViewerThemeContext";
|
|
39
|
+
export { CLOUDMR_NIIVUE_DEFAULT_ACCENT, CMR_APP_PRIMARY_CSS_VAR, buildNiivueViewerTheme, resolveViewerAccentColor, readHostPrimaryFromCss, } from "./CmrComponents/niivue-viewer/niivueViewerTheme";
|
|
40
|
+
export type { NiivueViewerThemeTokens } from "./CmrComponents/niivue-viewer/niivueViewerTheme";
|
|
38
41
|
export type { CloudMrNiivuePanelProps, CloudMrDrawToolkitProps, } from "./CmrComponents/niivue-viewer/CloudMrNiivuePanel";
|
|
39
42
|
import type { FC } from "react";
|
|
40
43
|
import type { CmrTableProps } from "./CmrTable/CmrTable";
|
package/dist/index.js
CHANGED
|
@@ -31,6 +31,8 @@ export { useNiivueRoiHistogram } from "./CmrComponents/niivue-roi-histogram/useN
|
|
|
31
31
|
export { NiivueRoiTable, DEFAULT_ROI_GROUP_TARGET_LABEL, } from "./CmrComponents/niivue-roi-table/NiivueRoiTable";
|
|
32
32
|
export { default as CloudMrNiivueViewer, nv } from "./CmrComponents/niivue-viewer/CloudMrNiivueViewer.js";
|
|
33
33
|
export { CloudMrNiivuePanel } from "./CmrComponents/niivue-viewer/CloudMrNiivuePanel";
|
|
34
|
+
export { NiivueViewerThemeProvider, useNiivueViewerTheme, } from "./CmrComponents/niivue-viewer/NiivueViewerThemeContext";
|
|
35
|
+
export { CLOUDMR_NIIVUE_DEFAULT_ACCENT, CMR_APP_PRIMARY_CSS_VAR, buildNiivueViewerTheme, resolveViewerAccentColor, readHostPrimaryFromCss, } from "./CmrComponents/niivue-viewer/niivueViewerTheme";
|
|
34
36
|
import CmrTableComponent, { CMR_TABLE_DEFAULT_HEADER_ICON } from "./CmrTable/CmrTable";
|
|
35
37
|
export var CmrTable = CmrTableComponent;
|
|
36
38
|
export { CMR_TABLE_DEFAULT_HEADER_ICON };
|