Merge pull request #1846 from OHIF/OHIF-200
[OHIF-200] - Add callouts to all DICOM SR read only measurements.
This commit is contained in:
commit
cc55d46b37
@ -28,7 +28,7 @@
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.50.0",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.11.0",
|
||||
"react-dom": "^16.11.0"
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-tools": "4.16.1",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
|
||||
@ -31,7 +31,7 @@
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-core": "^2.2.8",
|
||||
"cornerstone-tools": "4.16.1",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.8.6",
|
||||
"react-dom": "^16.8.6"
|
||||
|
||||
@ -35,7 +35,7 @@
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.16.1",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
|
||||
@ -26,12 +26,16 @@ const CodeNameCodeSequenceValues = {
|
||||
ImageLibraryGroup: '126200',
|
||||
TrackingUniqueIdentifier: '112040',
|
||||
TrackingIdentifier: '112039',
|
||||
Finding: '121071',
|
||||
};
|
||||
|
||||
const RELATIONSHIP_TYPE = {
|
||||
INFERRED_FROM: 'INFERRED FROM',
|
||||
};
|
||||
|
||||
const CORNERSTONE_CODING_SCHEME_DESIGNATOR = 'CST4';
|
||||
const CORNERSTONE_FREETEXT_CODE_VALUE = 'CORNERSTONEFREETEXT';
|
||||
|
||||
/**
|
||||
* Basic SOPClassHandler:
|
||||
* - For all Image types that are stackable, create
|
||||
@ -68,8 +72,9 @@ function _getDisplaySetsFromSeries(
|
||||
const { ConceptNameCodeSequence, ContentSequence } = instance;
|
||||
|
||||
if (
|
||||
!ConceptNameCodeSequence ||
|
||||
ConceptNameCodeSequence.CodeValue !==
|
||||
CodeNameCodeSequenceValues.ImagingMeasurementReport
|
||||
CodeNameCodeSequenceValues.ImagingMeasurementReport
|
||||
) {
|
||||
console.warn(
|
||||
'Only support Imaging Measurement Report SRs (TID1500) for now'
|
||||
@ -416,6 +421,12 @@ function _processNonGeometricallyDefinedMeasurement(mergedContentSequence) {
|
||||
CodeNameCodeSequenceValues.TrackingIdentifier
|
||||
);
|
||||
|
||||
const Findings = mergedContentSequence.filter(
|
||||
item =>
|
||||
item.ConceptNameCodeSequence.CodeValue ===
|
||||
CodeNameCodeSequenceValues.Finding
|
||||
);
|
||||
|
||||
const measurement = {
|
||||
loaded: false,
|
||||
labels: [],
|
||||
@ -424,6 +435,23 @@ function _processNonGeometricallyDefinedMeasurement(mergedContentSequence) {
|
||||
TrackingIdentifier: TrackingIdentifierContentItem.TextValue,
|
||||
};
|
||||
|
||||
if (Findings.length) {
|
||||
// TODO -> Pull in labels when we have them, just free text for now.
|
||||
const cornerstoneFreeTextFinding = Findings.find(
|
||||
Finding =>
|
||||
Finding.ConceptCodeSequence.CodingSchemeDesignator ===
|
||||
CORNERSTONE_CODING_SCHEME_DESIGNATOR &&
|
||||
Finding.ConceptCodeSequence.CodeValue ===
|
||||
CORNERSTONE_FREETEXT_CODE_VALUE
|
||||
);
|
||||
if (cornerstoneFreeTextFinding) {
|
||||
measurement.labels.push({
|
||||
label: CORNERSTONE_FREETEXT_CODE_VALUE,
|
||||
value: cornerstoneFreeTextFinding.ConceptCodeSequence.CodeMeaning,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
NUMContentItems.forEach(item => {
|
||||
const {
|
||||
ConceptNameCodeSequence,
|
||||
@ -495,7 +523,16 @@ function _getLabelFromMeasuredValueSequence(
|
||||
const { NumericValue, MeasurementUnitsCodeSequence } = MeasuredValueSequence;
|
||||
const { CodeValue } = MeasurementUnitsCodeSequence;
|
||||
|
||||
return { label: CodeMeaning, value: `${NumericValue} ${CodeValue}` }; // E.g. Long Axis: 31.0 mm
|
||||
debugger;
|
||||
|
||||
const formatedNumericValue = NumericValue
|
||||
? Number(NumericValue).toFixed(2)
|
||||
: '';
|
||||
|
||||
return {
|
||||
label: CodeMeaning,
|
||||
value: `${formatedNumericValue} ${CodeValue}`,
|
||||
}; // E.g. Long Axis: 31.0 mm
|
||||
}
|
||||
|
||||
function _getReferencedImagesList(ImagingMeasurementReportContentSequence) {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
import { importInternal, getToolState, toolColors } from 'cornerstone-tools';
|
||||
import { pixelToCanvas } from 'cornerstone-core';
|
||||
|
||||
import TOOL_NAMES from '../constants/toolNames';
|
||||
import SCOORD_TYPES from '../constants/scoordTypes';
|
||||
@ -10,8 +11,10 @@ const drawJoinedLines = importInternal('drawing/drawJoinedLines');
|
||||
const drawCircle = importInternal('drawing/drawCircle');
|
||||
const drawEllipse = importInternal('drawing/drawEllipse');
|
||||
const drawHandles = importInternal('drawing/drawHandles');
|
||||
const drawArrow = importInternal('drawing/drawArrow');
|
||||
const getNewContext = importInternal('drawing/getNewContext');
|
||||
const BaseTool = importInternal('base/BaseTool');
|
||||
const drawLinkedTextBox = importInternal('drawing/drawLinkedTextBox');
|
||||
|
||||
/**
|
||||
* @class DICOMSRDisplayTool - Renders DICOMSR data in a read only manner (i.e. as an overlay).
|
||||
@ -59,18 +62,20 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
||||
trackingUniqueIdentifiers.includes(td.TrackingUniqueIdentifier)
|
||||
);
|
||||
|
||||
let shouldRepositionTextBoxes = false;
|
||||
|
||||
for (let i = 0; i < filteredToolData.length; i++) {
|
||||
const data = filteredToolData[i];
|
||||
const { renderableData } = data;
|
||||
const { renderableData, labels } = data;
|
||||
|
||||
const color =
|
||||
data.TrackingUniqueIdentifier === activeTrackingUniqueIdentifier
|
||||
? toolColors.getActiveColor()
|
||||
: toolColors.getToolColor();
|
||||
|
||||
const lineWidth = 2;
|
||||
const options = {
|
||||
color,
|
||||
lineWidth: 2,
|
||||
lineWidth,
|
||||
handleRadius: 6,
|
||||
};
|
||||
|
||||
@ -79,8 +84,10 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
||||
|
||||
switch (GraphicType) {
|
||||
case SCOORD_TYPES.POINT:
|
||||
this.renderPoint(renderableDataForGraphicType, eventData, options);
|
||||
break;
|
||||
case SCOORD_TYPES.MULTIPOINT:
|
||||
this.renderPointOrMultipoint(
|
||||
this.renderMultipoint(
|
||||
renderableDataForGraphicType,
|
||||
eventData,
|
||||
options
|
||||
@ -105,9 +112,84 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
const { element } = eventData;
|
||||
const context = getNewContext(eventData.canvasContext.canvas);
|
||||
|
||||
if (!data.handles || !data.handles.textBox) {
|
||||
const textBox = {
|
||||
active: false,
|
||||
hasMoved: true,
|
||||
movesIndependently: false,
|
||||
drawnIndependently: true,
|
||||
allowedOutsideImage: true,
|
||||
hasBoundingBox: true,
|
||||
};
|
||||
|
||||
const anchorPoints = _getTextBoxAnchorPointsForRenderableData(
|
||||
renderableData,
|
||||
eventData
|
||||
);
|
||||
textBox.anchorPoints = anchorPoints;
|
||||
|
||||
const bottomRight = {
|
||||
x: Math.max(...anchorPoints.map(point => point.x)),
|
||||
y: Math.max(...anchorPoints.map(point => point.y)),
|
||||
};
|
||||
|
||||
textBox.x = bottomRight.x;
|
||||
textBox.y = bottomRight.y;
|
||||
|
||||
data.handles = {};
|
||||
data.handles.textBox = textBox;
|
||||
|
||||
shouldRepositionTextBoxes = true;
|
||||
}
|
||||
|
||||
const text = _getTextBoxLinesFromLabels(labels);
|
||||
|
||||
function textBoxAnchorPoints() {
|
||||
return data.handles.textBox.anchorPoints;
|
||||
}
|
||||
|
||||
draw(context, context => {
|
||||
drawLinkedTextBox(
|
||||
context,
|
||||
element,
|
||||
data.handles.textBox,
|
||||
text,
|
||||
data.handles,
|
||||
textBoxAnchorPoints,
|
||||
color,
|
||||
lineWidth,
|
||||
0,
|
||||
true
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// TOOD -> text boxes may overlap with other annotations at the moment.
|
||||
// To be fixed after we get requirements.
|
||||
// if (shouldRepositionTextBoxes) {
|
||||
// this.repositionTextBox(filteredToolData, eventData);
|
||||
// }
|
||||
}
|
||||
|
||||
// repositionTextBox(toolData, eventData) {
|
||||
// const toolBoundingBoxes = [];
|
||||
|
||||
// for (let i = 0; i < toolData.length; i++) {
|
||||
// const toolDataI = toolData[i];
|
||||
|
||||
// const { textBox } = toolDataI.handles;
|
||||
// const { anchorPoints } = textBox;
|
||||
|
||||
// const boundingBox = _getBoundingBoxFromAnchorPoints(anchorPoints);
|
||||
// // Get the textbox bounding locations.
|
||||
// // Get the tool extents.
|
||||
// }
|
||||
// }
|
||||
|
||||
renderPolyLine(renderableData, eventData, options) {
|
||||
const { element } = eventData;
|
||||
const context = getNewContext(eventData.canvasContext.canvas);
|
||||
@ -119,7 +201,7 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
||||
});
|
||||
}
|
||||
|
||||
renderPointOrMultipoint(renderableData, eventData, options) {
|
||||
renderMultipoint(renderableData, eventData, options) {
|
||||
const context = getNewContext(eventData.canvasContext.canvas);
|
||||
|
||||
renderableData.forEach(points => {
|
||||
@ -129,6 +211,41 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
||||
});
|
||||
}
|
||||
|
||||
renderPoint(renderableData, eventData, options) {
|
||||
// Render single point as an arrow.
|
||||
const { element, image } = eventData;
|
||||
const { rows, columns } = image;
|
||||
const context = getNewContext(eventData.canvasContext.canvas);
|
||||
|
||||
const { color, lineWidth } = options;
|
||||
|
||||
// Find a suitable length for the image size.
|
||||
|
||||
const xOffset = columns / 10;
|
||||
const yOffset = rows / 10;
|
||||
|
||||
renderableData.forEach(points => {
|
||||
const point = points[0]; // The SCOORD type is POINT so the array length is 1.
|
||||
draw(context, context => {
|
||||
// Draw the arrow
|
||||
const handleStartCanvas = pixelToCanvas(element, point);
|
||||
const handleEndCanvas = pixelToCanvas(element, {
|
||||
x: point.x + xOffset,
|
||||
y: point.y + yOffset,
|
||||
});
|
||||
|
||||
drawArrow(
|
||||
context,
|
||||
handleEndCanvas,
|
||||
handleStartCanvas,
|
||||
color,
|
||||
lineWidth,
|
||||
false
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
renderCircle(renderableData, eventData, options) {
|
||||
const { element } = eventData;
|
||||
|
||||
@ -161,3 +278,123 @@ export default class DICOMSRDisplayTool extends BaseTool {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function _getTextBoxLinesFromLabels(labels) {
|
||||
// TODO -> max 2 for now, need a generic solution for this!
|
||||
|
||||
const labelLength = Math.min(labels.length, 2);
|
||||
|
||||
const lines = [];
|
||||
|
||||
for (let i = 0; i < labelLength; i++) {
|
||||
const labelEntry = labels[i];
|
||||
lines.push(`${_labelToShorthand(labelEntry.label)}${labelEntry.value}`);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
const SHORT_HAND_MAP = {
|
||||
'Short Axis': 'S ',
|
||||
'Long Axis': 'L ',
|
||||
AREA: 'Area ',
|
||||
Length: '',
|
||||
CORNERSTONEFREETEXT: '',
|
||||
};
|
||||
|
||||
function _labelToShorthand(label) {
|
||||
const shortHand = SHORT_HAND_MAP[label];
|
||||
|
||||
if (shortHand !== undefined) {
|
||||
return shortHand;
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
function _getTextBoxAnchorPointsForRenderableData(renderableData, eventData) {
|
||||
let anchorPoints = [];
|
||||
|
||||
Object.keys(renderableData).forEach(GraphicType => {
|
||||
const renderableDataForGraphicType = renderableData[GraphicType];
|
||||
|
||||
switch (GraphicType) {
|
||||
case SCOORD_TYPES.POINT:
|
||||
renderableDataForGraphicType.forEach(points => {
|
||||
anchorPoints = [...anchorPoints, ...points];
|
||||
|
||||
// Add other arrow point based on image size.
|
||||
const { image } = eventData;
|
||||
const { rows, columns } = image;
|
||||
|
||||
const xOffset = columns / 10;
|
||||
const yOffset = rows / 10;
|
||||
const point = points[0];
|
||||
|
||||
anchorPoints.push({ x: point.x + xOffset, y: point.y + yOffset });
|
||||
});
|
||||
|
||||
break;
|
||||
case SCOORD_TYPES.MULTIPOINT:
|
||||
case SCOORD_TYPES.POLYLINE:
|
||||
renderableDataForGraphicType.forEach(points => {
|
||||
anchorPoints = [...anchorPoints, ...points];
|
||||
});
|
||||
break;
|
||||
case SCOORD_TYPES.CIRCLE:
|
||||
renderableDataForGraphicType.forEach(circle => {
|
||||
const { center, radius } = circle;
|
||||
|
||||
anchorPoints.push({ x: center.x + radius, y: center.y });
|
||||
anchorPoints.push({ x: center.x - radius, y: center.y });
|
||||
anchorPoints.push({ x: center.x, y: center.y + radius });
|
||||
anchorPoints.push({ x: center.x, y: center.y - radius });
|
||||
});
|
||||
|
||||
break;
|
||||
case SCOORD_TYPES.ELLIPSE:
|
||||
renderableDataForGraphicType.forEach(ellipse => {
|
||||
const { corner1, corner2 } = ellipse;
|
||||
|
||||
const halfWidth = Math.abs(corner1.x - corner2.x) / 2;
|
||||
const halfHeight = Math.abs(corner1.y - corner2.y) / 2;
|
||||
|
||||
const center = {
|
||||
x: (corner1.x + corner2.x) / 2,
|
||||
y: (corner1.y + corner2.y) / 2,
|
||||
};
|
||||
|
||||
anchorPoints.push({ x: center.x + halfWidth, y: center.y });
|
||||
anchorPoints.push({ x: center.x - halfWidth, y: center.y });
|
||||
anchorPoints.push({ x: center.x, y: center.y + halfHeight });
|
||||
anchorPoints.push({ x: center.x, y: center.y - halfHeight });
|
||||
});
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
return anchorPoints;
|
||||
}
|
||||
|
||||
function _getBoundingBoxFromAnchorPoints(anchorPoints) {
|
||||
let minX = Infinity;
|
||||
let maxX = -Infinity;
|
||||
let minY = Infinity;
|
||||
let maxY = -Infinity;
|
||||
|
||||
anchorPoints.forEach(point => {
|
||||
const { x, y } = point;
|
||||
|
||||
if (x > maxX) {
|
||||
maxX = x;
|
||||
} else if (x < minX) {
|
||||
minX = x;
|
||||
}
|
||||
|
||||
if (y > maxX) {
|
||||
maxY = y;
|
||||
} else if (y < minY) {
|
||||
minY = y;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -14,11 +14,6 @@ export default function addMeasurement(
|
||||
imageId,
|
||||
displaySetInstanceUID
|
||||
) {
|
||||
console.log('== ADD MEASUREMENT TO CST ==');
|
||||
console.log(measurement);
|
||||
console.log(imageId);
|
||||
console.log('============================');
|
||||
|
||||
// TODO -> Render rotated ellipse .
|
||||
|
||||
const toolName = TOOL_NAMES.DICOM_SR_DISPLAY_TOOL;
|
||||
@ -26,6 +21,7 @@ export default function addMeasurement(
|
||||
const measurementData = {
|
||||
TrackingUniqueIdentifier: measurement.TrackingUniqueIdentifier,
|
||||
renderableData: {},
|
||||
labels: measurement.labels,
|
||||
};
|
||||
|
||||
measurement.coords.forEach(coord => {
|
||||
|
||||
@ -29,7 +29,7 @@
|
||||
"peerDependencies": {
|
||||
"@ohif/core": "^0.50.0",
|
||||
"cornerstone-tools": "4.16.1",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
|
||||
@ -65,6 +65,7 @@ const machineConfiguration = {
|
||||
cond: 'isNewSeries',
|
||||
},
|
||||
],
|
||||
|
||||
UNTRACK_SERIES: [
|
||||
{
|
||||
target: 'tracking',
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
"@ohif/ui": "^2.0.0",
|
||||
"cornerstone-core": "^2.3.0",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"i18next": "^17.0.3",
|
||||
"i18next-browser-languagedetector": "^3.0.1",
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
"dependencies": {
|
||||
"@babel/runtime": "7.7.6",
|
||||
"ajv": "^6.10.0",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"dicomweb-client": "^0.6.0",
|
||||
"immer": "6.0.2",
|
||||
"isomorphic-base64": "^1.0.2",
|
||||
|
||||
@ -69,7 +69,7 @@
|
||||
"cornerstone-math": "^0.1.8",
|
||||
"cornerstone-tools": "4.16.1",
|
||||
"cornerstone-wado-image-loader": "^3.1.2",
|
||||
"dcmjs": "0.14.0",
|
||||
"dcmjs": "0.14.1",
|
||||
"dicom-parser": "^1.8.3",
|
||||
"dicomweb-client": "^0.4.4",
|
||||
"dotenv-webpack": "^1.7.0",
|
||||
|
||||
29
yarn.lock
29
yarn.lock
@ -2679,6 +2679,17 @@
|
||||
dependencies:
|
||||
"@types/node" ">= 8"
|
||||
|
||||
"@ohif/extension-cornerstone@^2.4.0":
|
||||
version "2.8.2"
|
||||
resolved "https://registry.yarnpkg.com/@ohif/extension-cornerstone/-/extension-cornerstone-2.8.2.tgz#b8d95610b91eb43c05f84adcdd699183918a57ff"
|
||||
integrity sha512-fIkPPQdDCkoVHCYTUFB4UhmdL9VJRyYawa6FxXiKXjj9OcUsrkXj+BORYgzcEkLWTLmrB+66qtIqpQ7FyXlzJQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.5.5"
|
||||
classnames "^2.2.6"
|
||||
lodash.merge "^4.6.2"
|
||||
lodash.throttle "^4.1.1"
|
||||
react-cornerstone-viewport "2.3.9"
|
||||
|
||||
"@ohif/extension-lesion-tracker@^0.2.0":
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/@ohif/extension-lesion-tracker/-/extension-lesion-tracker-0.2.0.tgz#37fda345204041539051750fad17551846fba40f"
|
||||
@ -7353,10 +7364,10 @@ dateformat@^3.0.0:
|
||||
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
|
||||
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
|
||||
|
||||
dcmjs@0.14.0:
|
||||
version "0.14.0"
|
||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.14.0.tgz#0dc6cb2d15ddcff759bc9002f2a9704537735d1c"
|
||||
integrity sha512-VL/Ibxe5RDsc5j5SEv3aEqdlKuBXz81/bBuW59Or0cos9vgK3XnVl3rr0ct6DWXJGK8vGIUMBOguyd/NRvlN0w==
|
||||
dcmjs@0.14.1:
|
||||
version "0.14.1"
|
||||
resolved "https://registry.yarnpkg.com/dcmjs/-/dcmjs-0.14.1.tgz#4a4f18d1e5332d38429e2d77340a6ad0052ec71e"
|
||||
integrity sha512-GGGQt4zjX7Fp0rLO5rcIQgmxZdLsEwBSZ1T74iXeJG5W32P1yiodJfBW900tNZCKj3zWamO3f5jDC1Xkv81fdg==
|
||||
dependencies:
|
||||
"@babel/polyfill" "^7.8.3"
|
||||
"@babel/runtime" "^7.8.4"
|
||||
@ -17889,6 +17900,16 @@ react-cornerstone-viewport@2.3.8:
|
||||
prop-types "^15.7.2"
|
||||
react-resize-detector "^4.2.1"
|
||||
|
||||
react-cornerstone-viewport@2.3.9:
|
||||
version "2.3.9"
|
||||
resolved "https://registry.yarnpkg.com/react-cornerstone-viewport/-/react-cornerstone-viewport-2.3.9.tgz#f9761da8e536f0a217137c6ca1a983f5882249f9"
|
||||
integrity sha512-qrhq8CbX/jq6b93cQjV2qC/mhHOvFBpxzxcHlvHzEQZt/rmRMcaYxCqjpNaNbUmmBu61wNkxesUVsggkPTTcqg==
|
||||
dependencies:
|
||||
classnames "^2.2.6"
|
||||
date-fns "^2.2.1"
|
||||
prop-types "^15.7.2"
|
||||
react-resize-detector "^4.2.1"
|
||||
|
||||
react-dates@21.2.1:
|
||||
version "21.2.1"
|
||||
resolved "https://registry.yarnpkg.com/react-dates/-/react-dates-21.2.1.tgz#a979ed6876326ccfbf754a019bc95458cc061ad8"
|
||||
|
||||
Loading…
Reference in New Issue
Block a user