fix(segmentation): upgrade cs3d to fix various segmentation bugs (#3885)

This commit is contained in:
Alireza 2024-01-09 10:15:56 -05:00 committed by GitHub
parent a8a0bdb2df
commit b1efe40aa1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
26 changed files with 241 additions and 171 deletions

View File

@ -168,6 +168,8 @@ function OHIFCornerstoneRTViewport(props) {
}, [servicesManager, viewportId, rtDisplaySet, rtIsLoading]); }, [servicesManager, viewportId, rtDisplaySet, rtIsLoading]);
useEffect(() => { useEffect(() => {
// I'm not sure what is this, since in RT we support Overlapping segmnets
// via contours
const { unsubscribe } = segmentationService.subscribe( const { unsubscribe } = segmentationService.subscribe(
segmentationService.EVENTS.SEGMENTATION_LOADING_COMPLETE, segmentationService.EVENTS.SEGMENTATION_LOADING_COMPLETE,
evt => { evt => {

View File

@ -44,9 +44,9 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.40.3", "@cornerstonejs/adapters": "^1.43.7",
"@cornerstonejs/tools": "^1.40.3", "@cornerstonejs/tools": "^1.43.7",
"@kitware/vtk.js": "27.3.1", "@kitware/vtk.js": "29.3.0",
"react-color": "^2.19.3" "react-color": "^2.19.3"
} }
} }

View File

@ -189,6 +189,15 @@ async function _loadSegments({ extensionManager, servicesManager, segDisplaySet,
} }
}); });
if (results.overlappingSegments) {
uiNotificationService.show({
title: 'Overlapping Segments',
message:
'Unsupported overlapping segments detected, segmentation rendering results may be incorrect.',
type: 'warning',
});
}
if (!usedRecommendedDisplayCIELabValue) { if (!usedRecommendedDisplayCIELabValue) {
// Display a notification about the non-utilization of RecommendedDisplayCIELabValue // Display a notification about the non-utilization of RecommendedDisplayCIELabValue
uiNotificationService.show({ uiNotificationService.show({

View File

@ -1,7 +1,7 @@
import { createReportAsync } from '@ohif/extension-default'; import { createReportAsync } from '@ohif/extension-default';
import React, { useEffect, useState, useCallback } from 'react'; import React, { useEffect, useState, useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { SegmentationGroupTable, LegacyButtonGroup, LegacyButton } from '@ohif/ui'; import { SegmentationGroupTable } from '@ohif/ui';
import callInputDialog from './callInputDialog'; import callInputDialog from './callInputDialog';
import callColorPickerDialog from './colorPickerDialog'; import callColorPickerDialog from './colorPickerDialog';

View File

@ -37,7 +37,7 @@ const initialState = {
}, },
ThresholdBrush: { ThresholdBrush: {
brushSize: 15, brushSize: 15,
thresholdRange: [-500, 500], thresholdRange: null,
}, },
activeTool: null, activeTool: null,
}; };
@ -88,6 +88,8 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
const setToolActive = useCallback( const setToolActive = useCallback(
toolName => { toolName => {
initializeThresholdValue(toolName);
toolbarService.recordInteraction({ toolbarService.recordInteraction({
interactionType: 'tool', interactionType: 'tool',
commands: [ commands: [
@ -178,6 +180,24 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
[toolGroupService] [toolGroupService]
); );
function initializeThresholdValue(toolName: any) {
if (state.ThresholdBrush.thresholdRange === null) {
// set the default threshold range from the tool configuration
const toolGroupIds = toolGroupService.getToolGroupIds();
const toolGroupId = toolGroupIds[0];
const toolGroup = toolGroupService.getToolGroup(toolGroupId);
const toolConfig = toolGroup.getToolConfiguration(toolName);
const defaultThresholdRange = toolConfig?.strategySpecificConfiguration?.THRESHOLD?.threshold;
dispatch({
type: ACTIONS.SET_TOOL_CONFIG,
payload: {
tool: 'ThresholdBrush',
config: { thresholdRange: defaultThresholdRange },
},
});
}
}
const onBrushSizeChange = useCallback( const onBrushSizeChange = useCallback(
(valueAsStringOrNumber, toolCategory) => { (valueAsStringOrNumber, toolCategory) => {
const value = Number(valueAsStringOrNumber); const value = Number(valueAsStringOrNumber);
@ -200,8 +220,8 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
const handleRangeChange = useCallback( const handleRangeChange = useCallback(
newRange => { newRange => {
if ( if (
newRange[0] === state.ThresholdBrush.thresholdRange[0] && newRange[0] === state.ThresholdBrush.thresholdRange?.[0] &&
newRange[1] === state.ThresholdBrush.thresholdRange[1] newRange[1] === state.ThresholdBrush.thresholdRange?.[1]
) { ) {
return; return;
} }
@ -213,7 +233,7 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
const toolGroup = toolGroupService.getToolGroup(toolGroupId); const toolGroup = toolGroupService.getToolGroup(toolGroupId);
toolGroup.setToolConfiguration(toolName, { toolGroup.setToolConfiguration(toolName, {
strategySpecificConfiguration: { strategySpecificConfiguration: {
THRESHOLD_INSIDE_CIRCLE: { THRESHOLD: {
threshold: newRange, threshold: newRange,
}, },
}, },
@ -365,7 +385,7 @@ function SegmentationToolbox({ servicesManager, extensionManager }) {
<InputDoubleRange <InputDoubleRange
values={state.ThresholdBrush.thresholdRange} values={state.ThresholdBrush.thresholdRange}
onChange={handleRangeChange} onChange={handleRangeChange}
minValue={-1000} minValue={-1000} // Todo: these should be configurable
maxValue={1000} maxValue={1000}
step={1} step={1}
showLabel={true} showLabel={true}

View File

@ -172,14 +172,6 @@ function OHIFCornerstoneSEGViewport(props) {
if (evt.segDisplaySet.displaySetInstanceUID === segDisplaySet.displaySetInstanceUID) { if (evt.segDisplaySet.displaySetInstanceUID === segDisplaySet.displaySetInstanceUID) {
setSegIsLoading(false); setSegIsLoading(false);
} }
if (evt.overlappingSegments) {
uiNotificationService.show({
title: 'Overlapping Segments',
message: 'Overlapping segments detected which is not currently supported',
type: 'warning',
});
}
} }
); );

View File

@ -44,9 +44,9 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.40.3", "@cornerstonejs/adapters": "^1.43.7",
"@cornerstonejs/core": "^1.40.3", "@cornerstonejs/core": "^1.43.7",
"@cornerstonejs/tools": "^1.40.3", "@cornerstonejs/tools": "^1.43.7",
"classnames": "^2.3.2" "classnames": "^2.3.2"
} }
} }

View File

@ -36,7 +36,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2", "@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.40.3", "@cornerstonejs/dicom-image-loader": "^1.43.7",
"@ohif/core": "3.8.0-beta.42", "@ohif/core": "3.8.0-beta.42",
"@ohif/ui": "3.8.0-beta.42", "@ohif/ui": "3.8.0-beta.42",
"dcmjs": "^0.29.12", "dcmjs": "^0.29.12",
@ -52,11 +52,11 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@cornerstonejs/adapters": "^1.40.3", "@cornerstonejs/adapters": "^1.43.7",
"@cornerstonejs/core": "^1.40.3", "@cornerstonejs/core": "^1.43.7",
"@cornerstonejs/streaming-image-volume-loader": "^1.40.3", "@cornerstonejs/streaming-image-volume-loader": "^1.43.7",
"@cornerstonejs/tools": "^1.40.3", "@cornerstonejs/tools": "^1.43.7",
"@kitware/vtk.js": "27.3.1", "@kitware/vtk.js": "29.3.01",
"html2canvas": "^1.4.1", "html2canvas": "^1.4.1",
"lodash.debounce": "4.0.8", "lodash.debounce": "4.0.8",
"lodash.merge": "^4.6.2", "lodash.merge": "^4.6.2",

View File

@ -253,10 +253,10 @@ export default async function init({
/** /**
* Runs error handler for failed requests. * Runs error handler for failed requests.
* @param event * @param event
*/ */
const imageLoadFailedHandler = ({ detail }) => { const imageLoadFailedHandler = ({ detail }) => {
const handler = errorHandler.getHTTPErrorHandler() const handler = errorHandler.getHTTPErrorHandler();
handler(detail.error); handler(detail.error);
}; };
@ -290,7 +290,7 @@ export default async function init({
}); });
eventTarget.addEventListener(EVENTS.IMAGE_LOAD_FAILED, imageLoadFailedHandler); eventTarget.addEventListener(EVENTS.IMAGE_LOAD_FAILED, imageLoadFailedHandler);
eventTarget.addEventListener(EVENTS.IMAGE_LOAD_ERROR, imageLoadFailedHandler); eventTarget.addEventListener(EVENTS.IMAGE_LOAD_ERROR, imageLoadFailedHandler);
function elementEnabledHandler(evt) { function elementEnabledHandler(evt) {
const { element } = evt.detail; const { element } = evt.detail;

View File

@ -1,5 +1,3 @@
import cloneDeep from 'lodash.clonedeep';
import { Types as OhifTypes, ServicesManager, PubSubService } from '@ohif/core'; import { Types as OhifTypes, ServicesManager, PubSubService } from '@ohif/core';
import { import {
cache, cache,
@ -11,7 +9,6 @@ import {
volumeLoader, volumeLoader,
} from '@cornerstonejs/core'; } from '@cornerstonejs/core';
import { import {
CONSTANTS as cstConstants,
Enums as csToolsEnums, Enums as csToolsEnums,
segmentation as cstSegmentation, segmentation as cstSegmentation,
Types as cstTypes, Types as cstTypes,
@ -23,7 +20,6 @@ import { easeInOutBell, reverseEaseInOutBell } from '../../utils/transitions';
import { Segment, Segmentation, SegmentationConfig } from './SegmentationServiceTypes'; import { Segment, Segmentation, SegmentationConfig } from './SegmentationServiceTypes';
import { mapROIContoursToRTStructData } from './RTSTRUCT/mapROIContoursToRTStructData'; import { mapROIContoursToRTStructData } from './RTSTRUCT/mapROIContoursToRTStructData';
const { COLOR_LUT } = cstConstants;
const LABELMAP = csToolsEnums.SegmentationRepresentations.Labelmap; const LABELMAP = csToolsEnums.SegmentationRepresentations.Labelmap;
const CONTOUR = csToolsEnums.SegmentationRepresentations.Contour; const CONTOUR = csToolsEnums.SegmentationRepresentations.Contour;
@ -465,15 +461,6 @@ class SegmentationService extends PubSubService {
}, },
]); ]);
// if first segmentation, we can use the default colorLUT, otherwise
// we need to generate a new one and use a new colorLUT
const colorLUTIndex = 0;
if (Object.keys(this.segmentations).length !== 0) {
const newColorLUT = this.generateNewColorLUT();
const colorLUTIndex = this.getNextColorLUTIndex();
cstSegmentation.config.color.addColorLUT(newColorLUT, colorLUTIndex);
}
this.segmentations[segmentationId] = { this.segmentations[segmentationId] = {
...segmentation, ...segmentation,
label: segmentation.label || '', label: segmentation.label || '',
@ -482,7 +469,6 @@ class SegmentationService extends PubSubService {
segmentCount: segmentation.segmentCount ?? 0, segmentCount: segmentation.segmentCount ?? 0,
isActive: false, isActive: false,
isVisible: true, isVisible: true,
colorLUTIndex,
}; };
cachedSegmentation = this.segmentations[segmentationId]; cachedSegmentation = this.segmentations[segmentationId];
@ -1037,8 +1023,6 @@ class SegmentationService extends PubSubService {
segmentation.hydrated = true; segmentation.hydrated = true;
} }
const { colorLUTIndex } = segmentation;
// Based on the segmentationId, set the colorLUTIndex. // Based on the segmentationId, set the colorLUTIndex.
const segmentationRepresentationUIDs = await cstSegmentation.addSegmentationRepresentations( const segmentationRepresentationUIDs = await cstSegmentation.addSegmentationRepresentations(
toolGroupId, toolGroupId,
@ -1057,12 +1041,6 @@ class SegmentationService extends PubSubService {
segmentationRepresentationUIDs[0] segmentationRepresentationUIDs[0]
); );
cstSegmentation.config.color.setColorLUT(
toolGroupId,
segmentationRepresentationUIDs[0],
colorLUTIndex
);
// add the segmentation segments properly // add the segmentation segments properly
for (const segment of segmentation.segments) { for (const segment of segmentation.segments) {
if (segment === null || segment === undefined) { if (segment === null || segment === undefined) {
@ -1530,7 +1508,6 @@ class SegmentationService extends PubSubService {
segments: [], segments: [],
isVisible: true, isVisible: true,
isActive: false, isActive: false,
colorLUTIndex: 0,
}; };
} }
@ -2124,23 +2101,6 @@ class SegmentationService extends PubSubService {
return viewportInfo.getToolGroupId(); return viewportInfo.getToolGroupId();
}; };
private getNextColorLUTIndex = (): number => {
let i = 0;
while (true) {
if (cstSegmentation.state.getColorLUT(i) === undefined) {
return i;
}
i++;
}
};
private generateNewColorLUT() {
const newColorLUT = cloneDeep(COLOR_LUT);
return newColorLUT;
}
/** /**
* Converts object of objects to array. * Converts object of objects to array.
* *

View File

@ -1,5 +1,5 @@
import { Types, Enums } from '@cornerstonejs/core'; import { Types, Enums } from '@cornerstonejs/core';
import { Types as UITypes } from '@ohif/ui'; import { Types as CoreTypes } from '@ohif/core';
import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService'; import { StackViewportData, VolumeViewportData } from '../../types/CornerstoneCacheService';
import getCornerstoneBlendMode from '../../utils/getCornerstoneBlendMode'; import getCornerstoneBlendMode from '../../utils/getCornerstoneBlendMode';
import getCornerstoneOrientation from '../../utils/getCornerstoneOrientation'; import getCornerstoneOrientation from '../../utils/getCornerstoneOrientation';
@ -18,7 +18,7 @@ export type ViewportOptions = {
toolGroupId: string; toolGroupId: string;
viewportId: string; viewportId: string;
// Presentation ID to store/load presentation state from // Presentation ID to store/load presentation state from
presentationIds?: UITypes.PresentationIds; presentationIds?: CoreTypes.PresentationIds;
orientation?: Enums.OrientationAxis; orientation?: Enums.OrientationAxis;
background?: Types.Point3; background?: Types.Point3;
displayArea?: Types.DisplayArea; displayArea?: Types.DisplayArea;
@ -36,7 +36,7 @@ export type PublicViewportOptions = {
id?: string; id?: string;
viewportType?: string; viewportType?: string;
toolGroupId?: string; toolGroupId?: string;
presentationIds?: UITypes.PresentationIds; presentationIds?: CoreTypes.PresentationIds;
viewportId?: string; viewportId?: string;
orientation?: Enums.OrientationAxis; orientation?: Enums.OrientationAxis;
background?: Types.Point3; background?: Types.Point3;
@ -71,7 +71,7 @@ export type DisplaySetOptions = {
voiInverted: boolean; voiInverted: boolean;
blendMode?: Enums.BlendModes; blendMode?: Enums.BlendModes;
slabThickness?: number; slabThickness?: number;
colormap?: { name: string, opacity?: number }; colormap?: { name: string; opacity?: number };
displayPreset?: string; displayPreset?: string;
}; };

View File

@ -1,12 +1,12 @@
/** Store presentation data for either stack viewports or volume viewports */ /** Store presentation data for either stack viewports or volume viewports */
import { Types } from '@cornerstonejs/core'; import { Types } from '@cornerstonejs/core';
import { Types as UITypes } from '@ohif/ui'; import { Types as CoreTypes } from '@ohif/core';
/** /**
* Has information on the presentation of the viewport. * Has information on the presentation of the viewport.
*/ */
export interface Presentation extends Types.StackViewportProperties { export interface Presentation extends Types.StackViewportProperties {
presentationIds: UITypes.PresentationIds; presentationIds: CoreTypes.PresentationIds;
viewportType: string; viewportType: string;
initialImageIndex: number; initialImageIndex: number;
camera: Types.ICamera; camera: Types.ICamera;

View File

@ -30,8 +30,8 @@
"start": "yarn run dev" "start": "yarn run dev"
}, },
"peerDependencies": { "peerDependencies": {
"@cornerstonejs/core": "^1.40.3", "@cornerstonejs/core": "^1.43.7",
"@cornerstonejs/tools": "^1.40.3", "@cornerstonejs/tools": "^1.43.7",
"@ohif/core": "3.8.0-beta.42", "@ohif/core": "3.8.0-beta.42",
"@ohif/extension-cornerstone-dicom-sr": "3.8.0-beta.42", "@ohif/extension-cornerstone-dicom-sr": "3.8.0-beta.42",
"@ohif/ui": "3.8.0-beta.42", "@ohif/ui": "3.8.0-beta.42",

View File

@ -1,21 +1,3 @@
const brushInstanceNames = {
CircularBrush: 'CircularBrush',
CircularEraser: 'CircularEraser',
SphereBrush: 'SphereBrush',
SphereEraser: 'SphereEraser',
ThresholdCircularBrush: 'ThresholdCircularBrush',
ThresholdSphereBrush: 'ThresholdSphereBrush',
};
const brushStrategies = {
CircularBrush: 'FILL_INSIDE_CIRCLE',
CircularEraser: 'ERASE_INSIDE_CIRCLE',
SphereBrush: 'FILL_INSIDE_SPHERE',
SphereEraser: 'ERASE_INSIDE_SPHERE',
ThresholdCircularBrush: 'THRESHOLD_INSIDE_CIRCLE',
ThresholdSphereBrush: 'THRESHOLD_INSIDE_SPHERE',
};
function createTools(utilityModule) { function createTools(utilityModule) {
const { toolNames, Enums } = utilityModule.exports; const { toolNames, Enums } = utilityModule.exports;
return { return {
@ -25,22 +7,66 @@ function createTools(utilityModule) {
{ toolName: toolNames.Zoom, bindings: [{ mouseButton: Enums.MouseBindings.Secondary }] }, { toolName: toolNames.Zoom, bindings: [{ mouseButton: Enums.MouseBindings.Secondary }] },
{ toolName: toolNames.StackScrollMouseWheel, bindings: [] }, { toolName: toolNames.StackScrollMouseWheel, bindings: [] },
], ],
passive: Object.keys(brushInstanceNames) passive: [
.map(brushName => ({ {
toolName: brushName, toolName: 'CircularBrush',
parentTool: 'Brush', parentTool: 'Brush',
configuration: { configuration: {
activeStrategy: brushStrategies[brushName], activeStrategy: 'FILL_INSIDE_CIRCLE',
}, },
})) },
.concat([ {
{ toolName: toolNames.CircleScissors }, toolName: 'CircularEraser',
{ toolName: toolNames.RectangleScissors }, parentTool: 'Brush',
{ toolName: toolNames.SphereScissors }, configuration: {
{ toolName: toolNames.StackScroll }, activeStrategy: 'ERASE_INSIDE_CIRCLE',
{ toolName: toolNames.Magnify }, },
{ toolName: toolNames.SegmentationDisplay }, },
]), {
toolName: 'SphereBrush',
parentTool: 'Brush',
configuration: {
activeStrategy: 'FILL_INSIDE_SPHERE',
},
},
{
toolName: 'SphereEraser',
parentTool: 'Brush',
configuration: {
activeStrategy: 'ERASE_INSIDE_SPHERE',
},
},
{
toolName: 'ThresholdCircularBrush',
parentTool: 'Brush',
configuration: {
activeStrategy: 'THRESHOLD_INSIDE_CIRCLE',
strategySpecificConfiguration: {
THRESHOLD: {
threshold: [-500, 500],
},
},
},
},
{
toolName: 'ThresholdSphereBrush',
parentTool: 'Brush',
configuration: {
activeStrategy: 'THRESHOLD_INSIDE_SPHERE',
strategySpecificConfiguration: {
THRESHOLD: {
threshold: [-500, 500],
},
},
},
},
{ toolName: toolNames.CircleScissors },
{ toolName: toolNames.RectangleScissors },
{ toolName: toolNames.SphereScissors },
{ toolName: toolNames.StackScroll },
{ toolName: toolNames.Magnify },
{ toolName: toolNames.SegmentationDisplay },
],
disabled: [{ toolName: toolNames.ReferenceLines }], disabled: [{ toolName: toolNames.ReferenceLines }],
}; };
} }

View File

@ -57,7 +57,7 @@
}, },
"dependencies": { "dependencies": {
"@babel/runtime": "^7.20.13", "@babel/runtime": "^7.20.13",
"@kitware/vtk.js": "27.3.1", "@kitware/vtk.js": "29.3.0",
"core-js": "^3.2.1" "core-js": "^3.2.1"
}, },
"peerDependencies": { "peerDependencies": {

View File

@ -85,7 +85,7 @@ describe('OHIF Cornerstone Toolbar', () => {
// The exact text is slightly dependent on the viewport resolution, so leave a range // The exact text is slightly dependent on the viewport resolution, so leave a range
cy.get('@viewportInfoTopLeft').should($txt => { cy.get('@viewportInfoTopLeft').should($txt => {
const text = $txt.text(); const text = $txt.text();
expect(text).to.include('W:193').include('L:479'); expect(text).to.include('W:1185').include('L:479');
}); });
}); });

View File

@ -51,7 +51,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.5", "@cornerstonejs/codec-openjph": "^2.4.5",
"@cornerstonejs/dicom-image-loader": "^1.40.3", "@cornerstonejs/dicom-image-loader": "^1.43.7",
"@ohif/core": "3.8.0-beta.42", "@ohif/core": "3.8.0-beta.42",
"@ohif/extension-cornerstone": "3.8.0-beta.42", "@ohif/extension-cornerstone": "3.8.0-beta.42",
"@ohif/extension-cornerstone-dicom-rt": "3.8.0-beta.42", "@ohif/extension-cornerstone-dicom-rt": "3.8.0-beta.42",

View File

@ -1,4 +1,4 @@
import React, {useEffect, useCallback, useMemo} from 'react'; import React, { useEffect, useCallback } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { ServicesManager, Types, MeasurementService } from '@ohif/core'; import { ServicesManager, Types, MeasurementService } from '@ohif/core';
import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui'; import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui';
@ -9,6 +9,7 @@ import { useAppConfig } from '@state';
function ViewerViewportGrid(props) { function ViewerViewportGrid(props) {
const { servicesManager, viewportComponents, dataSource } = props; const { servicesManager, viewportComponents, dataSource } = props;
const [viewportGrid, viewportGridService] = useViewportGrid(); const [viewportGrid, viewportGridService] = useViewportGrid();
const [appConfig] = useAppConfig();
const { layout, activeViewportId, viewports } = viewportGrid; const { layout, activeViewportId, viewports } = viewportGrid;
const { numCols, numRows } = layout; const { numCols, numRows } = layout;
@ -18,18 +19,6 @@ function ViewerViewportGrid(props) {
servicesManager as ServicesManager servicesManager as ServicesManager
).services; ).services;
/**
* Determine whether users need to use the tools directly, or whether they need to click once to activate the viewport before using tools.
* If 'activateViewportBeforeInteraction' is available in the 'window.config' object, use its value;
* otherwise, default to true.
* If true, users need to click once to activate the viewport before using the tools.
* if false, tools can be used directly.
*/
const activateViewportBeforeInteraction = useMemo(() => {
const [appConfig] = useAppConfig();
return appConfig?.activateViewportBeforeInteraction ?? true;
}, []);
/** /**
* This callback runs after the viewports structure has changed in any way. * This callback runs after the viewports structure has changed in any way.
* On initial display, that means if it has changed by applying a HangingProtocol, * On initial display, that means if it has changed by applying a HangingProtocol,
@ -324,7 +313,8 @@ function ViewerViewportGrid(props) {
<div <div
data-cy="viewport-pane" data-cy="viewport-pane"
className={classNames('flex h-full w-full flex-col', { className={classNames('flex h-full w-full flex-col', {
'pointer-events-none': !isActive && activateViewportBeforeInteraction, 'pointer-events-none':
!isActive && (appConfig?.activateViewportBeforeInteraction ?? true),
})} })}
> >
<ViewportComponent <ViewportComponent

View File

@ -35,7 +35,7 @@
"@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2", "@cornerstonejs/codec-libjpeg-turbo-8bit": "^1.2.2",
"@cornerstonejs/codec-openjpeg": "^1.2.2", "@cornerstonejs/codec-openjpeg": "^1.2.2",
"@cornerstonejs/codec-openjph": "^2.4.2", "@cornerstonejs/codec-openjph": "^2.4.2",
"@cornerstonejs/dicom-image-loader": "^1.40.3", "@cornerstonejs/dicom-image-loader": "^1.43.7",
"@ohif/ui": "3.8.0-beta.42", "@ohif/ui": "3.8.0-beta.42",
"cornerstone-math": "0.1.9", "cornerstone-math": "0.1.9",
"dicom-parser": "^1.8.21" "dicom-parser": "^1.8.21"

View File

@ -1,3 +1,5 @@
import ViewportGridService from './ViewportGridService'; import ViewportGridService from './ViewportGridService';
import type { PresentationIds } from './ViewportGridService';
export default ViewportGridService; export default ViewportGridService;
export type { PresentationIds };

View File

@ -7,6 +7,7 @@ import type {
BaseDataSourceConfigurationAPI, BaseDataSourceConfigurationAPI,
BaseDataSourceConfigurationAPIItem, BaseDataSourceConfigurationAPIItem,
} from './DataSourceConfigurationAPI'; } from './DataSourceConfigurationAPI';
import type { PresentationIds } from '../services/ViewportGridService';
export type * from '../services/CustomizationService/types'; export type * from '../services/CustomizationService/types';
// Separate out some generic types // Separate out some generic types
@ -34,4 +35,5 @@ export {
DataSourceDefinition, DataSourceDefinition,
BaseDataSourceConfigurationAPI, BaseDataSourceConfigurationAPI,
BaseDataSourceConfigurationAPIItem, BaseDataSourceConfigurationAPIItem,
PresentationIds,
}; };

View File

@ -60,10 +60,10 @@ module.exports = {
? // Deploy preview: keep it fast! ? // Deploy preview: keep it fast!
['en'] ['en']
: isI18nStaging : isI18nStaging
? // Staging locales: https://docusaurus-i18n-staging.netlify.app/ ? // Staging locales: https://docusaurus-i18n-staging.netlify.app/
['en'] ['en']
: // Production locales : // Production locales
['en'], ['en'],
}, },
onBrokenLinks: 'warn', onBrokenLinks: 'warn',
onBrokenMarkdownLinks: 'warn', onBrokenMarkdownLinks: 'warn',
@ -88,7 +88,7 @@ module.exports = {
}, },
}), }),
path.resolve(__dirname, './pluginOHIFWebpackConfig.js'), path.resolve(__dirname, './pluginOHIFWebpackConfig.js'),
'plugin-image-zoom', // 3rd party plugin for image click to pop 'docusaurus-plugin-image-zoom', // 3rd party plugin for image click to pop
[ [
'@docusaurus/plugin-client-redirects', '@docusaurus/plugin-client-redirects',
{ {
@ -281,6 +281,16 @@ module.exports = {
apiKey: 'c220dd24fe4f86248eea3b1238a1fb60', apiKey: 'c220dd24fe4f86248eea3b1238a1fb60',
indexName: 'ohif', indexName: 'ohif',
}, },
// zoom: {
// selector: '.markdown > img',
// background: {
// light: 'rgb(255, 255, 255)',
// dark: 'rgb(50, 50, 50)',
// },
// config: {
// // options you can specify via https://github.com/francoischalifour/medium-zoom#usage
// },
// },
navbar: { navbar: {
hideOnScroll: false, hideOnScroll: false,
logo: { logo: {

View File

@ -35,12 +35,13 @@
"@docusaurus/preset-classic": "2.4.3", "@docusaurus/preset-classic": "2.4.3",
"@docusaurus/remark-plugin-npm2yarn": "2.4.3", "@docusaurus/remark-plugin-npm2yarn": "2.4.3",
"@docusaurus/theme-live-codeblock": "2.4.3", "@docusaurus/theme-live-codeblock": "2.4.3",
"docusaurus-plugin-image-zoom": "^1.0.1",
"@docusaurus/theme-classic": "2.4.3",
"@mdx-js/react": "^1.6.21", "@mdx-js/react": "^1.6.21",
"@svgr/webpack": "^5.5.0", "@svgr/webpack": "^5.5.0",
"classnames": "^2.3.2", "classnames": "^2.3.2",
"clsx": "^1.1.1", "clsx": "^1.1.1",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"plugin-image-zoom": "ataft/plugin-image-zoom",
"url-loader": "^4.1.1" "url-loader": "^4.1.1"
}, },
"peerDependencies": { "peerDependencies": {

View File

@ -45,7 +45,7 @@ function ToolSettings({ options }) {
onChange={e => option.onChange(e)} onChange={e => option.onChange(e)}
allowNumberEdit={true} allowNumberEdit={true}
showAdjustmentArrows={false} showAdjustmentArrows={false}
inputClassName="ml-1 w-4/5" inputClassName="ml-1 w-4/5 cursor-pointer"
/> />
</div> </div>
</div> </div>

View File

@ -1,6 +1,5 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import ThumbnailType from './ThumbnailType'; import ThumbnailType from './ThumbnailType';
import type { PresentationIds } from '../contextProviders/getPresentationIds';
// A few miscellaneous types declared inline here. // A few miscellaneous types declared inline here.

131
yarn.lock
View File

@ -1394,7 +1394,7 @@
core-js-pure "^3.30.2" core-js-pure "^3.30.2"
regenerator-runtime "^0.14.0" regenerator-runtime "^0.14.0"
"@babel/runtime@7.17.9", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2": "@babel/runtime@7.22.11", "@babel/runtime@^7.0.0", "@babel/runtime@^7.1.2", "@babel/runtime@^7.10.3", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.0", "@babel/runtime@^7.12.13", "@babel/runtime@^7.12.5", "@babel/runtime@^7.13.10", "@babel/runtime@^7.17.8", "@babel/runtime@^7.18.3", "@babel/runtime@^7.18.6", "@babel/runtime@^7.20.13", "@babel/runtime@^7.20.6", "@babel/runtime@^7.23.2", "@babel/runtime@^7.3.1", "@babel/runtime@^7.4.5", "@babel/runtime@^7.5.5", "@babel/runtime@^7.7.4", "@babel/runtime@^7.7.6", "@babel/runtime@^7.8.4", "@babel/runtime@^7.8.7", "@babel/runtime@^7.9.2":
version "7.23.6" version "7.23.6"
resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.6.tgz#c05e610dc228855dc92ef1b53d07389ed8ab521d" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.6.tgz#c05e610dc228855dc92ef1b53d07389ed8ab521d"
integrity sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ== integrity sha512-zHd0eUrf5GZoOWVCXp6koAKQTfZV07eit6bGPmJgnZdnSAvvZee6zniW2XMF7Cmc4ISOOnPy3QaSiIJGJkVEDQ==
@ -1450,10 +1450,10 @@
resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9" resolved "https://registry.yarnpkg.com/@colors/colors/-/colors-1.5.0.tgz#bb504579c1cae923e6576a4f5da43d25f97bdbd9"
integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ== integrity sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==
"@cornerstonejs/adapters@^1.40.3": "@cornerstonejs/adapters@^1.43.7":
version "1.40.3" version "1.43.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.40.3.tgz#aaf9e86e648bf3e6531f1d16d9439be48aee40f5" resolved "https://registry.yarnpkg.com/@cornerstonejs/adapters/-/adapters-1.43.7.tgz#920344cd6548cfa26ebe05db01ea94ef9121dc5e"
integrity sha512-StTYbq1RWBHI9yd2Xax6ebk0PX/pvKDmA4j9+WkBTh1MNnNGxABGpRHSdRKa96YlhGnVM1z5u0Ox5BmBMIAy2w== integrity sha512-X6tQDcT9PeXXrmEoDaCb/hHjWEk+h7svz4XRfCWJKqbTRNmpTWmr70KY2lMRMm/FVPC+Ix2KdHStBN2/9zLDsg==
dependencies: dependencies:
"@babel/runtime-corejs2" "^7.17.8" "@babel/runtime-corejs2" "^7.17.8"
buffer "^6.0.3" buffer "^6.0.3"
@ -1502,45 +1502,45 @@
resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0" resolved "https://registry.yarnpkg.com/@cornerstonejs/codec-openjph/-/codec-openjph-2.4.5.tgz#8690b61a86fa53ef38a70eee9d665a79229517c0"
integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg== integrity sha512-MZCUy8VG0VG5Nl1l58+g+kH3LujAzLYTfJqkwpWI2gjSrGXnP6lgwyy4GmPRZWVoS40/B1LDNALK905cNWm+sg==
"@cornerstonejs/core@^1.40.3": "@cornerstonejs/core@^1.43.7":
version "1.40.3" version "1.43.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.40.3.tgz#b591434fa9b80397f97541e4380c09b5cb4b28a0" resolved "https://registry.yarnpkg.com/@cornerstonejs/core/-/core-1.43.7.tgz#6da8c3598fc79b99357f1bc039b385447179ab67"
integrity sha512-7YgEJM02zZLJZNP4RHp+X1xg+i70ZnV5TkhQaOZSCaoKTEup1I7w3ywMDCrvMMXdE+D8qB6dmvSamJjtWDzKbg== integrity sha512-36jYRnIxIGHyEL2pngpHiLX3HQINXabzi8P8K6BMf7HcWv9sgbWwmglUv71+gCo2my3Ai+vDUWrpoGIrmu+RGA==
dependencies: dependencies:
"@kitware/vtk.js" "27.3.1" "@kitware/vtk.js" "29.3.0"
comlink "^4.4.1" comlink "^4.4.1"
detect-gpu "^5.0.22" detect-gpu "^5.0.22"
gl-matrix "^3.4.3" gl-matrix "^3.4.3"
lodash.clonedeep "4.5.0" lodash.clonedeep "4.5.0"
"@cornerstonejs/dicom-image-loader@^1.40.3": "@cornerstonejs/dicom-image-loader@^1.43.7":
version "1.40.3" version "1.43.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.40.3.tgz#2a397bcb306231bf8ead1826d3cb98bc9614ed66" resolved "https://registry.yarnpkg.com/@cornerstonejs/dicom-image-loader/-/dicom-image-loader-1.43.7.tgz#76b013815f7c5688604f76c7473a292397ad31ad"
integrity sha512-GaxI9kYmbc8NtbqQAuyv5Ofu91L/ASxcNDKbNVX6rFQ3HQ0n0OspxsarMLKn4oTY0hRFf+3dJYgM+cTmd8obtw== integrity sha512-9wvXOx0S4TgIU+2SdYJUnGjv5yM4ylVJWt2q1q6yV6FuCEyhd1NB6cvAJSF61DlqWwS3oSiQRqU6wRf7wh73Jw==
dependencies: dependencies:
"@cornerstonejs/codec-charls" "^1.2.3" "@cornerstonejs/codec-charls" "^1.2.3"
"@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2" "@cornerstonejs/codec-libjpeg-turbo-8bit" "^1.2.2"
"@cornerstonejs/codec-openjpeg" "^1.2.2" "@cornerstonejs/codec-openjpeg" "^1.2.2"
"@cornerstonejs/codec-openjph" "^2.4.5" "@cornerstonejs/codec-openjph" "^2.4.5"
"@cornerstonejs/core" "^1.40.3" "@cornerstonejs/core" "^1.43.7"
dicom-parser "^1.8.9" dicom-parser "^1.8.9"
pako "^2.0.4" pako "^2.0.4"
uuid "^9.0.0" uuid "^9.0.0"
"@cornerstonejs/streaming-image-volume-loader@^1.40.3": "@cornerstonejs/streaming-image-volume-loader@^1.43.7":
version "1.40.3" version "1.43.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.40.3.tgz#bf3f5e53a9986c2400dc62d8d13ee138fc192b4a" resolved "https://registry.yarnpkg.com/@cornerstonejs/streaming-image-volume-loader/-/streaming-image-volume-loader-1.43.7.tgz#972f675bd6de81cb6e65d495f0243013c17062bf"
integrity sha512-QYgdlKOvJxDyoD+2LxlY1EAaxKza0b/2dD65u1055qWvfWWJe8sqipGUbuDtShlcDdCSZLe6oPCHV5IVFhI5cQ== integrity sha512-0FmGeLzFub4TSLhhxq8fDRAj20UF2C7lM9EA4UvEc/iR/B65ly9lGiMONB58Wodl9HamHHkmr4moD1Sjn3sfBg==
dependencies: dependencies:
"@cornerstonejs/core" "^1.40.3" "@cornerstonejs/core" "^1.43.7"
comlink "^4.4.1" comlink "^4.4.1"
"@cornerstonejs/tools@^1.40.3": "@cornerstonejs/tools@^1.43.7":
version "1.40.3" version "1.43.7"
resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.40.3.tgz#2878185a5b848bd07e0a90482a2661525c2e2df8" resolved "https://registry.yarnpkg.com/@cornerstonejs/tools/-/tools-1.43.7.tgz#70c3e75636bde19f6fa7d9c86ef61ececf8a2b9c"
integrity sha512-h5+AibxT19nUPg5mTJ0v6xwyjUcN+a4Y1tLo9/mZmzjqLEUk4VljNAtcIj+bRPplNqET5sygZ/StOwC94fFItQ== integrity sha512-4yhWGeNsSF2F06T6sGLjARX7F7atUwUNv5qnMqFVZ7b/TfQbpdB8zkXHA0Rhz/YB3ebr/zWvRxDtzah+5VMxnQ==
dependencies: dependencies:
"@cornerstonejs/core" "^1.40.3" "@cornerstonejs/core" "^1.43.7"
comlink "^4.4.1" comlink "^4.4.1"
lodash.clonedeep "4.5.0" lodash.clonedeep "4.5.0"
lodash.get "^4.4.2" lodash.get "^4.4.2"
@ -2789,12 +2789,35 @@
resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60" resolved "https://registry.yarnpkg.com/@juggle/resize-observer/-/resize-observer-3.4.0.tgz#08d6c5e20cf7e4cc02fd181c4b0c225cd31dbb60"
integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA== integrity sha512-dfLbk+PwWvFzSxwk3n5ySL0hfBog779o8h68wK/7/APo/7cgyWp5jcXockbxdk5kFRkbeXWm4Fbi9FrdN381sA==
"@kitware/vtk.js@27.3.1": "@kitware/vtk.js@29.3.0":
version "27.3.1" version "29.3.0"
resolved "https://registry.yarnpkg.com/@kitware/vtk.js/-/vtk.js-27.3.1.tgz#65004b041642663da94e6a488ebb813576e7de7d" resolved "https://registry.yarnpkg.com/@kitware/vtk.js/-/vtk.js-29.3.0.tgz#8601e07cde3da61c285aabfcb3484ae1ffb1074b"
integrity sha512-GvAXdOKtDDbkaSdO+UhKnDST4CW1C3fHgaDvA0wn1ZWTLm/6SFAMzarTjpzsVGYCPoEYIhCAAlBQ7K7aDcu3Vg== integrity sha512-EofIxo6Qcfhh8SRx8Xp7B8HGM//2tzjQbhrMQsiaoPgs3yhtrqm+CBFmqboxt+waF8qUKxuUQb+DzM8cX2ivAg==
dependencies: dependencies:
"@babel/runtime" "7.17.9" "@babel/runtime" "7.22.11"
"@types/webxr" "^0.5.5"
commander "9.2.0"
d3-scale "4.0.2"
fast-deep-equal "^3.1.3"
fflate "0.7.3"
gl-matrix "3.4.3"
globalthis "1.0.3"
seedrandom "3.0.5"
shader-loader "1.3.1"
shelljs "0.8.5"
spark-md5 "3.0.2"
stream-browserify "3.0.0"
webworker-promise "0.5.0"
worker-loader "3.0.8"
xmlbuilder2 "3.0.2"
"@kitware/vtk.js@29.3.01":
version "29.3.1"
resolved "https://registry.yarnpkg.com/@kitware/vtk.js/-/vtk.js-29.3.1.tgz#007df75c1f4744b4779087b9306a667c6acdc3c8"
integrity sha512-TM3uBVwJWdMIU+VD+OnSxQU45lJiJiOxxkx56Du6K4d18u5fHi7nBkSlNhTtOCX5H8amwIofaPCKRnYRNkjosA==
dependencies:
"@babel/runtime" "7.22.11"
"@types/webxr" "^0.5.5"
commander "9.2.0" commander "9.2.0"
d3-scale "4.0.2" d3-scale "4.0.2"
fast-deep-equal "^3.1.3" fast-deep-equal "^3.1.3"
@ -5459,6 +5482,11 @@
anymatch "^3.0.0" anymatch "^3.0.0"
source-map "^0.6.0" source-map "^0.6.0"
"@types/webxr@^0.5.5":
version "0.5.10"
resolved "https://registry.yarnpkg.com/@types/webxr/-/webxr-0.5.10.tgz#19c76208ec015ca3f139505e14d94d6b740f518a"
integrity sha512-n3u5sqXQJhf1CS68mw3Wf16FQ4cRPNBBwdYLFzq3UddiADOim1Pn3Y6PBdDilz1vOJF3ybLxJ8ZEDlLIzrOQZg==
"@types/ws@^8.2.2", "@types/ws@^8.5.5": "@types/ws@^8.2.2", "@types/ws@^8.5.5":
version "8.5.10" version "8.5.10"
resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787" resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.10.tgz#4acfb517970853fa6574a3a6886791d04a396787"
@ -8936,6 +8964,14 @@ document.contains@^1.0.1:
dependencies: dependencies:
define-properties "^1.1.3" define-properties "^1.1.3"
docusaurus-plugin-image-zoom@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/docusaurus-plugin-image-zoom/-/docusaurus-plugin-image-zoom-1.0.1.tgz#17afec39f2e630cac50a4ed3a8bbdad8d0aa8b9d"
integrity sha512-96IpSKUx2RWy3db9aZ0s673OQo5DWgV9UVWouS+CPOSIVEdCWh6HKmWf6tB9rsoaiIF3oNn9keiyv6neEyKb1Q==
dependencies:
medium-zoom "^1.0.6"
validate-peer-dependencies "^2.2.0"
dom-converter@^0.2.0: dom-converter@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768" resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
@ -14217,7 +14253,7 @@ media-typer@0.3.0:
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ== integrity sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==
medium-zoom@^1.0.8: medium-zoom@^1.0.6:
version "1.1.0" version "1.1.0"
resolved "https://registry.yarnpkg.com/medium-zoom/-/medium-zoom-1.1.0.tgz#6efb6bbda861a02064ee71a2617a8dc4381ecc71" resolved "https://registry.yarnpkg.com/medium-zoom/-/medium-zoom-1.1.0.tgz#6efb6bbda861a02064ee71a2617a8dc4381ecc71"
integrity sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ== integrity sha512-ewyDsp7k4InCUp3jRmwHBRFGyjBimKps/AJLjRSox+2q/2H4p/PNpQf+pwONWlJiOudkBXtbdmVbFjqyybfTmQ==
@ -15974,6 +16010,18 @@ path-parse@^1.0.6, path-parse@^1.0.7:
resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735"
integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==
path-root-regex@^0.1.0:
version "0.1.2"
resolved "https://registry.yarnpkg.com/path-root-regex/-/path-root-regex-0.1.2.tgz#bfccdc8df5b12dc52c8b43ec38d18d72c04ba96d"
integrity sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==
path-root@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/path-root/-/path-root-0.1.1.tgz#9a4a6814cac1c0cd73360a95f32083c8ea4745b7"
integrity sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==
dependencies:
path-root-regex "^0.1.0"
path-scurry@^1.10.1, path-scurry@^1.6.1: path-scurry@^1.10.1, path-scurry@^1.6.1:
version "1.10.1" version "1.10.1"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698" resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.1.tgz#9ba6bf5aa8500fe9fd67df4f0d9483b2b0bfc698"
@ -16164,12 +16212,6 @@ please-upgrade-node@^3.1.1, please-upgrade-node@^3.2.0:
dependencies: dependencies:
semver-compare "^1.0.0" semver-compare "^1.0.0"
plugin-image-zoom@ataft/plugin-image-zoom:
version "1.1.0"
resolved "https://codeload.github.com/ataft/plugin-image-zoom/tar.gz/8e1b866c79ed6d42cefc4c52f851f1dfd1d0c7de"
dependencies:
medium-zoom "^1.0.4"
polished@^4.2.2: polished@^4.2.2:
version "4.2.2" version "4.2.2"
resolved "https://registry.yarnpkg.com/polished/-/polished-4.2.2.tgz#2529bb7c3198945373c52e34618c8fe7b1aa84d1" resolved "https://registry.yarnpkg.com/polished/-/polished-4.2.2.tgz#2529bb7c3198945373c52e34618c8fe7b1aa84d1"
@ -18189,6 +18231,13 @@ resolve-from@^4.0.0:
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
resolve-package-path@^4.0.3:
version "4.0.3"
resolved "https://registry.yarnpkg.com/resolve-package-path/-/resolve-package-path-4.0.3.tgz#31dab6897236ea6613c72b83658d88898a9040aa"
integrity sha512-SRpNAPW4kewOaNUt8VPqhJ0UMxawMwzJD8V7m1cJfdSTK9ieZwS6K7Dabsm4bmLFM96Z5Y/UznrpG5kt1im8yA==
dependencies:
path-root "^0.1.1"
resolve-pathname@^3.0.0: resolve-pathname@^3.0.0:
version "3.0.0" version "3.0.0"
resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd" resolved "https://registry.yarnpkg.com/resolve-pathname/-/resolve-pathname-3.0.0.tgz#99d02224d3cf263689becbb393bc560313025dcd"
@ -20691,6 +20740,14 @@ validate-npm-package-name@^3.0.0:
dependencies: dependencies:
builtins "^1.0.3" builtins "^1.0.3"
validate-peer-dependencies@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/validate-peer-dependencies/-/validate-peer-dependencies-2.2.0.tgz#47b8ff008f66a66fc5d8699123844522c1d874f4"
integrity sha512-8X1OWlERjiUY6P6tdeU9E0EwO8RA3bahoOVG7ulOZT5MqgNDUO/BQoVjYiHPcNe+v8glsboZRIw9iToMAA2zAA==
dependencies:
resolve-package-path "^4.0.3"
semver "^7.3.8"
validate.js@^0.12.0: validate.js@^0.12.0:
version "0.12.0" version "0.12.0"
resolved "https://registry.yarnpkg.com/validate.js/-/validate.js-0.12.0.tgz#17f989e37c192ea2f826bbf19bf4e97e6e4be68f" resolved "https://registry.yarnpkg.com/validate.js/-/validate.js-0.12.0.tgz#17f989e37c192ea2f826bbf19bf4e97e6e4be68f"