feat(ui): move to React 18 and base for using shadcn/ui (#4174)
Co-authored-by: IbrahimCSAE <ibrahim.mdev@gmail.com>
This commit is contained in:
parent
72b63dcd6a
commit
70f2c797f4
@ -42,6 +42,7 @@ jobs:
|
||||
###
|
||||
UNIT_TESTS:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
# Update yarn
|
||||
- run: yarn -v
|
||||
@ -98,6 +99,7 @@ jobs:
|
||||
###
|
||||
BUILD:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
# Checkout code and ALL Git Tags
|
||||
- checkout
|
||||
@ -146,6 +148,7 @@ jobs:
|
||||
# just to make sure later on we can publish them
|
||||
BUILD_PACKAGES_QUICK:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
- run: yarn -v
|
||||
# Checkout code and ALL Git Tags
|
||||
@ -195,6 +198,7 @@ jobs:
|
||||
###
|
||||
NPM_PUBLISH:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
- run: yarn -v
|
||||
# Checkout code and ALL Git Tags
|
||||
@ -264,6 +268,7 @@ jobs:
|
||||
|
||||
DOCKER_RELEASE_PUBLISH:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
@ -293,6 +298,7 @@ jobs:
|
||||
|
||||
DOCKER_BETA_PUBLISH:
|
||||
<<: *defaults
|
||||
resource_class: large
|
||||
steps:
|
||||
- attach_workspace:
|
||||
at: ~/repo
|
||||
@ -397,6 +403,7 @@ jobs:
|
||||
default: ''
|
||||
description: Directory containing package.json
|
||||
type: string
|
||||
resource_class: large
|
||||
steps:
|
||||
- cypress/install:
|
||||
cypress-cache-key: << parameters.cypress-cache-key >>
|
||||
|
||||
@ -98,6 +98,38 @@ module.exports = (env, argv, { SRC_DIR, ENTRY }) => {
|
||||
module: {
|
||||
noParse: [/(codec)/, /(dicomicc)/],
|
||||
rules: [
|
||||
{
|
||||
test: /\.svg?$/,
|
||||
oneOf: [
|
||||
{
|
||||
use: [
|
||||
{
|
||||
loader: '@svgr/webpack',
|
||||
options: {
|
||||
svgoConfig: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
prettier: false,
|
||||
svgo: true,
|
||||
titleProp: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
issuer: {
|
||||
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.js$/,
|
||||
enforce: 'pre',
|
||||
|
||||
@ -5,23 +5,6 @@ module.exports = {
|
||||
babelrcRoots: ['./platform/*', './extensions/*', './modes/*'],
|
||||
presets: ['@babel/preset-env', '@babel/preset-react', '@babel/preset-typescript'],
|
||||
plugins: [
|
||||
[
|
||||
'inline-react-svg',
|
||||
{
|
||||
svgo: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
['@babel/plugin-proposal-class-properties', { loose: true }],
|
||||
'@babel/plugin-transform-typescript',
|
||||
['@babel/plugin-proposal-private-property-in-object', { loose: true }],
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
|
||||
@ -38,8 +38,8 @@
|
||||
"@ohif/extension-default": "3.9.0-beta.21",
|
||||
"@ohif/i18n": "3.9.0-beta.21",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^10.11.0",
|
||||
"react-router": "^6.3.0",
|
||||
"react-router-dom": "^6.3.0"
|
||||
|
||||
@ -358,11 +358,6 @@ OHIFCornerstoneRTViewport.propTypes = {
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
customProps: PropTypes.object,
|
||||
};
|
||||
|
||||
OHIFCornerstoneRTViewport.defaultProps = {
|
||||
customProps: {},
|
||||
};
|
||||
|
||||
function _getReferencedDisplaySetMetadata(referencedDisplaySet) {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
|
||||
@ -38,8 +38,8 @@
|
||||
"@ohif/extension-default": "3.9.0-beta.21",
|
||||
"@ohif/i18n": "3.9.0-beta.21",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^12.2.2",
|
||||
"react-router": "^6.8.1",
|
||||
"react-router-dom": "^6.8.1"
|
||||
|
||||
@ -367,11 +367,6 @@ OHIFCornerstoneSEGViewport.propTypes = {
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
customProps: PropTypes.object,
|
||||
};
|
||||
|
||||
OHIFCornerstoneSEGViewport.defaultProps = {
|
||||
customProps: {},
|
||||
};
|
||||
|
||||
function _getReferencedDisplaySetMetadata(referencedDisplaySet, segDisplaySet) {
|
||||
|
||||
@ -42,7 +42,7 @@
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2"
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
|
||||
@ -367,16 +367,11 @@ OHIFCornerstoneSRViewport.propTypes = {
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
viewportLabel: PropTypes.string,
|
||||
customProps: PropTypes.object,
|
||||
viewportOptions: PropTypes.object,
|
||||
servicesManager: PropTypes.object.isRequired,
|
||||
extensionManager: PropTypes.instanceOf(ExtensionManager).isRequired,
|
||||
};
|
||||
|
||||
OHIFCornerstoneSRViewport.defaultProps = {
|
||||
customProps: {},
|
||||
};
|
||||
|
||||
async function _getViewportReferencedDisplaySetData(
|
||||
displaySet,
|
||||
measurementSelected,
|
||||
|
||||
@ -38,7 +38,7 @@
|
||||
"dicom-parser": "^1.8.21",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2"
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
|
||||
@ -46,9 +46,9 @@
|
||||
"dicom-parser": "^1.8.21",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-resize-detector": "^6.7.6"
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-resize-detector": "^10.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"lodash": "^4.17.21"
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useRef, useCallback, useState } from 'react';
|
||||
import ReactResizeDetector from 'react-resize-detector';
|
||||
import { useResizeDetector } from 'react-resize-detector';
|
||||
import PropTypes from 'prop-types';
|
||||
import * as cs3DTools from '@cornerstonejs/tools';
|
||||
import {
|
||||
@ -109,7 +109,7 @@ const OHIFCornerstoneViewport = React.memo((props: withAppTypes) => {
|
||||
onElementEnabled,
|
||||
// eslint-disable-next-line react/prop-types
|
||||
onElementDisabled,
|
||||
isJumpToMeasurementDisabled,
|
||||
isJumpToMeasurementDisabled = false,
|
||||
// Note: you SHOULD NOT use the initialImageIdOrIndex for manipulation
|
||||
// of the imageData in the OHIFCornerstoneViewport. This prop is used
|
||||
// to set the initial state of the viewport's first image to render
|
||||
@ -140,7 +140,7 @@ const OHIFCornerstoneViewport = React.memo((props: withAppTypes) => {
|
||||
|
||||
const [scrollbarHeight, setScrollbarHeight] = useState('100px');
|
||||
const [enabledVPElement, setEnabledVPElement] = useState(null);
|
||||
const elementRef = useRef();
|
||||
const elementRef = useRef() as React.MutableRefObject<HTMLDivElement>;
|
||||
const [appConfig] = useAppConfig();
|
||||
|
||||
const {
|
||||
@ -417,19 +417,21 @@ const OHIFCornerstoneViewport = React.memo((props: withAppTypes) => {
|
||||
});
|
||||
}, [displaySets, viewportId, viewportActionCornersService, servicesManager, commandsManager]);
|
||||
|
||||
const { ref: resizeRef } = useResizeDetector({
|
||||
onResize,
|
||||
});
|
||||
return (
|
||||
<React.Fragment>
|
||||
<div className="viewport-wrapper">
|
||||
<ReactResizeDetector
|
||||
onResize={onResize}
|
||||
targetRef={elementRef.current}
|
||||
/>
|
||||
<div
|
||||
className="cornerstone-viewport-element"
|
||||
style={{ height: '100%', width: '100%' }}
|
||||
onContextMenu={e => e.preventDefault()}
|
||||
onMouseDown={e => e.preventDefault()}
|
||||
ref={elementRef}
|
||||
ref={el => {
|
||||
resizeRef.current = el;
|
||||
elementRef.current = el;
|
||||
}}
|
||||
></div>
|
||||
<CornerstoneOverlays
|
||||
viewportId={viewportId}
|
||||
@ -683,10 +685,6 @@ function _rehydrateSynchronizers(
|
||||
// Component displayName
|
||||
OHIFCornerstoneViewport.displayName = 'OHIFCornerstoneViewport';
|
||||
|
||||
OHIFCornerstoneViewport.defaultProps = {
|
||||
isJumpToMeasurementDisabled: false,
|
||||
};
|
||||
|
||||
OHIFCornerstoneViewport.propTypes = {
|
||||
displaySets: PropTypes.array.isRequired,
|
||||
dataSource: PropTypes.object.isRequired,
|
||||
|
||||
@ -78,14 +78,8 @@ function ViewportImageSliceLoadingIndicator({ viewportData, element }) {
|
||||
}
|
||||
|
||||
ViewportImageSliceLoadingIndicator.propTypes = {
|
||||
percentComplete: PropTypes.number,
|
||||
error: PropTypes.object,
|
||||
element: PropTypes.object,
|
||||
};
|
||||
|
||||
ViewportImageSliceLoadingIndicator.defaultProps = {
|
||||
percentComplete: 0,
|
||||
error: null,
|
||||
};
|
||||
|
||||
export default ViewportImageSliceLoadingIndicator;
|
||||
|
||||
@ -136,16 +136,6 @@ function ViewportOrientationMarkers({
|
||||
return <div className="ViewportOrientationMarkers select-none">{markers}</div>;
|
||||
}
|
||||
|
||||
ViewportOrientationMarkers.propTypes = {
|
||||
percentComplete: PropTypes.number,
|
||||
error: PropTypes.object,
|
||||
};
|
||||
|
||||
ViewportOrientationMarkers.defaultProps = {
|
||||
percentComplete: 0,
|
||||
error: null,
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
* Computes the orientation labels on a Cornerstone-enabled Viewport element
|
||||
|
||||
@ -6,7 +6,7 @@ function _getVolumesFromViewport(viewport) {
|
||||
}
|
||||
|
||||
function _getVolumeFromViewport(viewport) {
|
||||
const volumes = _getVolumesFromViewport(viewport);
|
||||
const volumes = _getVolumesFromViewport(viewport).filter(volume => volume);
|
||||
const dynamicVolume = volumes.find(volume => volume.isDynamicVolume());
|
||||
|
||||
return dynamicVolume ?? volumes[0];
|
||||
|
||||
@ -37,8 +37,8 @@
|
||||
"dcmjs": "^0.29.12",
|
||||
"dicomweb-client": "^0.10.4",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^12.2.2",
|
||||
"react-window": "^1.8.9",
|
||||
"webpack": "^5.50.0",
|
||||
|
||||
@ -2,7 +2,13 @@ import React, { useEffect, useState, useCallback } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { LayoutSelector as OHIFLayoutSelector, ToolbarButton } from '@ohif/ui';
|
||||
|
||||
function LegacyLayoutSelectorWithServices({ servicesManager, ...props }: withAppTypes) {
|
||||
function LegacyLayoutSelectorWithServices({
|
||||
servicesManager,
|
||||
rows = 3,
|
||||
columns = 3,
|
||||
onLayoutChange = () => {},
|
||||
...props
|
||||
}) {
|
||||
const { toolbarService } = servicesManager.services;
|
||||
|
||||
const onSelection = useCallback(
|
||||
@ -78,10 +84,4 @@ LayoutSelector.propTypes = {
|
||||
servicesManager: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
LayoutSelector.defaultProps = {
|
||||
rows: 3,
|
||||
columns: 3,
|
||||
onLayoutChange: () => {},
|
||||
};
|
||||
|
||||
export default LegacyLayoutSelectorWithServices;
|
||||
|
||||
@ -124,8 +124,9 @@ function ToolbarLayoutSelectorWithServices({
|
||||
}
|
||||
|
||||
function LayoutSelector({
|
||||
rows,
|
||||
columns,
|
||||
rows = 3,
|
||||
columns = 4,
|
||||
onLayoutChange = () => {},
|
||||
className,
|
||||
onSelection,
|
||||
onSelectionPreset,
|
||||
@ -242,10 +243,4 @@ LayoutSelector.propTypes = {
|
||||
servicesManager: PropTypes.object.isRequired,
|
||||
};
|
||||
|
||||
LayoutSelector.defaultProps = {
|
||||
columns: 4,
|
||||
rows: 3,
|
||||
onLayoutChange: () => {},
|
||||
};
|
||||
|
||||
export default ToolbarLayoutSelectorWithServices;
|
||||
|
||||
@ -54,7 +54,6 @@ function ToolbarSplitButtonWithServices({
|
||||
}
|
||||
|
||||
ToolbarSplitButtonWithServices.propTypes = {
|
||||
isRadio: PropTypes.bool,
|
||||
groupId: PropTypes.string,
|
||||
primary: PropTypes.shape({
|
||||
id: PropTypes.string.isRequired,
|
||||
@ -87,9 +86,4 @@ ToolbarSplitButtonWithServices.propTypes = {
|
||||
}),
|
||||
};
|
||||
|
||||
ToolbarSplitButtonWithServices.defaultProps = {
|
||||
isRadio: false,
|
||||
isAction: false,
|
||||
};
|
||||
|
||||
export default ToolbarSplitButtonWithServices;
|
||||
|
||||
@ -2,7 +2,7 @@ import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { ToolbarButton } from '@ohif/ui';
|
||||
|
||||
function NestedMenu({ children, label, icon, isActive }) {
|
||||
function NestedMenu({ children, label = 'More', icon = 'tool-more-menu', isActive }) {
|
||||
const [isOpen, setIsOpen] = useState(false);
|
||||
|
||||
const toggleNestedMenu = () => setIsOpen(!isOpen);
|
||||
@ -39,9 +39,4 @@ NestedMenu.propTypes = {
|
||||
label: PropTypes.string,
|
||||
};
|
||||
|
||||
NestedMenu.defaultProps = {
|
||||
icon: 'tool-more-menu',
|
||||
label: 'More',
|
||||
};
|
||||
|
||||
export default NestedMenu;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
|
||||
@ -35,8 +35,8 @@
|
||||
"@ohif/i18n": "3.9.0-beta.21",
|
||||
"@ohif/ui": "3.9.0-beta.21",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^10.11.0",
|
||||
"react-router": "^6.8.1",
|
||||
"react-router-dom": "^6.8.1"
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
import React, { Component } from 'react';
|
||||
import ReactResizeDetector from 'react-resize-detector';
|
||||
import PropTypes from 'prop-types';
|
||||
import debounce from 'lodash.debounce';
|
||||
import { LoadingIndicatorProgress } from '@ohif/ui';
|
||||
|
||||
import './DicomMicroscopyViewport.css';
|
||||
@ -23,18 +21,12 @@ class DicomMicroscopyViewport extends Component {
|
||||
|
||||
container = React.createRef();
|
||||
overlayElement = React.createRef();
|
||||
debouncedResize: () => any;
|
||||
|
||||
constructor(props: any) {
|
||||
super(props);
|
||||
|
||||
const { microscopyService } = this.props.servicesManager.services;
|
||||
this.microscopyService = microscopyService;
|
||||
this.debouncedResize = debounce(() => {
|
||||
if (this.viewer) {
|
||||
this.viewer.resize();
|
||||
}
|
||||
}, 100);
|
||||
}
|
||||
|
||||
static propTypes = {
|
||||
@ -54,6 +46,7 @@ class DicomMicroscopyViewport extends Component {
|
||||
servicesManager: PropTypes.object,
|
||||
extensionManager: PropTypes.object,
|
||||
commandsManager: PropTypes.object,
|
||||
resizeRef: PropTypes.oneOfType([PropTypes.func, PropTypes.shape({ current: PropTypes.any })]),
|
||||
};
|
||||
|
||||
/**
|
||||
@ -298,13 +291,16 @@ class DicomMicroscopyViewport extends Component {
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{ReactResizeDetector && (
|
||||
<ReactResizeDetector handleWidth handleHeight onResize={this.onWindowResize} />
|
||||
)}
|
||||
{this.state.error ? (
|
||||
<h2>{JSON.stringify(this.state.error)}</h2>
|
||||
) : (
|
||||
<div style={style} ref={this.container} />
|
||||
<div
|
||||
style={style}
|
||||
ref={(ref: any) => {
|
||||
this.container.current = ref;
|
||||
this.props.resizeRef.current = ref;
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
{this.state.isLoaded ? null : (
|
||||
<LoadingIndicatorProgress className={'h-full w-full bg-black'} />
|
||||
@ -312,10 +308,6 @@ class DicomMicroscopyViewport extends Component {
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
onWindowResize = () => {
|
||||
this.debouncedResize();
|
||||
};
|
||||
}
|
||||
|
||||
export default DicomMicroscopyViewport;
|
||||
|
||||
@ -8,6 +8,8 @@ import { useViewportGrid } from '@ohif/ui';
|
||||
import getDicomMicroscopySopClassHandler from './DicomMicroscopySopClassHandler';
|
||||
import getDicomMicroscopySRSopClassHandler from './DicomMicroscopySRSopClassHandler';
|
||||
import MicroscopyService from './services/MicroscopyService';
|
||||
import { useResizeDetector } from 'react-resize-detector';
|
||||
import debounce from 'lodash.debounce';
|
||||
|
||||
const Component = React.lazy(() => {
|
||||
return import('./DicomMicroscopyViewport');
|
||||
@ -59,14 +61,25 @@ const extension: Types.Extensions.Extension = {
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const { activeViewportId } = viewportGrid;
|
||||
|
||||
// a unique identifier based on the contents of displaySets.
|
||||
// since we changed our rendering pipeline and if there is no
|
||||
// element size change nor viewportId change we won't re-render
|
||||
// we need a way to force re-rendering when displaySets change.
|
||||
const displaySetsKey = useMemo(() => {
|
||||
return props.displaySets.map(ds => ds.displaySetInstanceUID).join('-');
|
||||
}, [props.displaySets]);
|
||||
|
||||
const onResize = debounce(() => {
|
||||
const { microscopyService } = servicesManager.services;
|
||||
const managedViewer = microscopyService.getAllManagedViewers();
|
||||
|
||||
if (managedViewer && managedViewer.length > 0) {
|
||||
managedViewer[0].viewer.resize();
|
||||
}
|
||||
}, 100);
|
||||
|
||||
const { ref: resizeRef } = useResizeDetector({
|
||||
onResize,
|
||||
handleHeight: true,
|
||||
handleWidth: true,
|
||||
});
|
||||
|
||||
return (
|
||||
<MicroscopyViewport
|
||||
key={displaySetsKey}
|
||||
@ -78,6 +91,7 @@ const extension: Types.Extensions.Extension = {
|
||||
viewportGridService.setActiveViewportId(viewportId);
|
||||
}}
|
||||
viewportData={viewportOptions}
|
||||
resizeRef={resizeRef}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
@ -628,6 +628,15 @@ export default class MicroscopyService extends PubSubService {
|
||||
setROIStyle(uid, styleOptions) {
|
||||
this.managedViewers.forEach(mv => mv.setROIStyle(uid, styleOptions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all managed viewers
|
||||
*
|
||||
* @returns {Array} managedViewers
|
||||
*/
|
||||
getAllManagedViewers() {
|
||||
return Array.from(this.managedViewers);
|
||||
}
|
||||
}
|
||||
|
||||
export { EVENTS };
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2"
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2"
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
|
||||
@ -41,8 +41,8 @@
|
||||
"dcmjs": "^0.29.12",
|
||||
"lodash.debounce": "^4.17.21",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"webpack": "^5.50.0",
|
||||
"webpack-merge": "^5.7.3"
|
||||
},
|
||||
|
||||
@ -242,11 +242,6 @@ TrackedCornerstoneViewport.propTypes = {
|
||||
viewportId: PropTypes.string.isRequired,
|
||||
dataSource: PropTypes.object,
|
||||
children: PropTypes.node,
|
||||
customProps: PropTypes.object,
|
||||
};
|
||||
|
||||
TrackedCornerstoneViewport.defaultProps = {
|
||||
customProps: {},
|
||||
};
|
||||
|
||||
function _getNextMeasurementUID(
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2"
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
"dicom-parser": "^1.8.9",
|
||||
"hammerjs": "^2.0.8",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2"
|
||||
"react": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.20.13",
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
|
||||
@ -51,6 +51,38 @@ const config = {
|
||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.svg?$/,
|
||||
oneOf: [
|
||||
{
|
||||
use: [
|
||||
{
|
||||
loader: '@svgr/webpack',
|
||||
options: {
|
||||
svgoConfig: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
prettier: false,
|
||||
svgo: true,
|
||||
titleProp: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
issuer: {
|
||||
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'],
|
||||
plugins: [ '@babel/plugin-proposal-class-properties'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
|
||||
@ -63,7 +63,7 @@
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"babel-eslint": "^10.1.0",
|
||||
"babel-loader": "^8.0.0-beta.4",
|
||||
"babel-plugin-inline-react-svg": "^2.0.1",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^10.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
|
||||
@ -65,8 +65,8 @@
|
||||
"core-js": "^3.2.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/core": "^7.23.2",
|
||||
@ -82,13 +82,13 @@
|
||||
"@babel/preset-env": "^7.23.2",
|
||||
"@babel/preset-react": "^7.16.7",
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@types/jest": "^27.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.3.0",
|
||||
"@typescript-eslint/parser": "^6.3.0",
|
||||
"autoprefixer": "^10.4.4",
|
||||
"babel-eslint": "9.x",
|
||||
"babel-loader": "^8.2.4",
|
||||
"babel-plugin-inline-react-svg": "^2.0.2",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
"clean-webpack-plugin": "^3.0.0",
|
||||
"copy-webpack-plugin": "^9.0.1",
|
||||
|
||||
@ -28,6 +28,7 @@ export default defineConfig({
|
||||
defaultCommandTimeout: 10000,
|
||||
requestTimeout: 10000,
|
||||
responseTimeout: 10000,
|
||||
pageLoadTimeout: 10000,
|
||||
specPattern: 'cypress/integration/**/*.spec.[jt]s',
|
||||
projectId: '4oe38f',
|
||||
video: true,
|
||||
|
||||
@ -78,8 +78,8 @@ describe('OHIF MPR', () => {
|
||||
const fOR = Object.keys(fORMap)[0];
|
||||
const fORAnnotation = fORMap[fOR];
|
||||
|
||||
// it should have crosshairs as the only key
|
||||
expect(Object.keys(fORAnnotation)).to.have.length(1);
|
||||
// it should have crosshairs as the only key (references lines make this 2)
|
||||
expect(Object.keys(fORAnnotation)).to.have.length(2);
|
||||
|
||||
const crosshairs = fORAnnotation.Crosshairs;
|
||||
|
||||
|
||||
@ -61,8 +61,8 @@ export function initStudyListAliasesOnDesktop() {
|
||||
|
||||
// We can't use data attributes (e.g. data--cy) for these since
|
||||
// they are using third party libraries (i.e. react-dates, react-select)
|
||||
cy.get('#date-range-studyDate-start-date').as('studyListStartDate');
|
||||
cy.get('#date-range-studyDate-end-date').as('studyListEndDate');
|
||||
cy.get('[data-cy="input-date-range-start"').as('studyListStartDate');
|
||||
cy.get('[data-cy="input-date-range-end"').as('studyListEndDate');
|
||||
cy.get('#input-modalities').as('modalities');
|
||||
}
|
||||
|
||||
|
||||
@ -71,7 +71,9 @@
|
||||
"@ohif/mode-microscopy": "3.9.0-beta.21",
|
||||
"@ohif/mode-test": "3.9.0-beta.21",
|
||||
"@ohif/ui": "3.9.0-beta.21",
|
||||
"@types/react": "^17.0.38",
|
||||
"@ohif/ui-next": "3.9.0-beta.14",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"@types/react": "^18.3.3",
|
||||
"classnames": "^2.3.2",
|
||||
"core-js": "^3.16.1",
|
||||
"cornerstone-math": "^0.1.9",
|
||||
@ -87,11 +89,11 @@
|
||||
"oidc-client": "1.11.5",
|
||||
"prop-types": "^15.7.2",
|
||||
"query-string": "^6.12.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-dropzone": "^10.1.7",
|
||||
"react-i18next": "^12.2.2",
|
||||
"react-resize-detector": "^9.1.0",
|
||||
"react-resize-detector": "^10.0.1",
|
||||
"react-router": "^6.8.1",
|
||||
"react-router-dom": "^6.8.1"
|
||||
},
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
// External
|
||||
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import i18n from '@ohif/i18n';
|
||||
@ -23,6 +24,7 @@ import {
|
||||
UserAuthenticationProvider,
|
||||
ToolboxProvider,
|
||||
} from '@ohif/ui';
|
||||
import { ThemeWrapper as ThemeWrapperNext, NotificationProvider } from '@ohif/ui-next';
|
||||
// Viewer Project
|
||||
// TODO: Should this influence study list?
|
||||
import { AppConfigProvider } from '@state';
|
||||
@ -36,7 +38,27 @@ let commandsManager: CommandsManager,
|
||||
serviceProvidersManager: ServiceProvidersManager,
|
||||
hotkeysManager: HotkeysManager;
|
||||
|
||||
function App({ config, defaultExtensions, defaultModes }) {
|
||||
function App({
|
||||
config = {
|
||||
/**
|
||||
* Relative route from domain root that OHIF instance is installed at.
|
||||
* For example:
|
||||
*
|
||||
* Hosted at: https://ohif.org/where-i-host-the/viewer/
|
||||
* Value: `/where-i-host-the/viewer/`
|
||||
* */
|
||||
routerBaseName: '/',
|
||||
/**
|
||||
*
|
||||
*/
|
||||
showLoadingIndicator: true,
|
||||
showStudyList: true,
|
||||
oidc: [],
|
||||
extensions: [],
|
||||
},
|
||||
defaultExtensions = [],
|
||||
defaultModes = [],
|
||||
}) {
|
||||
const [init, setInit] = useState(null);
|
||||
useEffect(() => {
|
||||
const run = async () => {
|
||||
@ -83,11 +105,13 @@ function App({ config, defaultExtensions, defaultModes }) {
|
||||
[AppConfigProvider, { value: appConfigState }],
|
||||
[UserAuthenticationProvider, { service: userAuthenticationService }],
|
||||
[I18nextProvider, { i18n }],
|
||||
[ThemeWrapperNext],
|
||||
[ThemeWrapper],
|
||||
[ToolboxProvider],
|
||||
[ViewportGridProvider, { service: viewportGridService }],
|
||||
[ViewportDialogProvider, { service: uiViewportDialogService }],
|
||||
[CineProvider, { service: cineService }],
|
||||
// [NotificationProvider, { service: uiNotificationService }],
|
||||
[SnackbarProvider, { service: uiNotificationService }],
|
||||
[DialogProvider, { service: uiDialogService }],
|
||||
[ModalProvider, { service: uiModalService, modal: Modal }],
|
||||
@ -153,27 +177,9 @@ App.propTypes = {
|
||||
/* Extensions that are "bundled" or "baked-in" to the application.
|
||||
* These would be provided at build time as part of they entry point. */
|
||||
defaultExtensions: PropTypes.array,
|
||||
};
|
||||
|
||||
App.defaultProps = {
|
||||
config: {
|
||||
/**
|
||||
* Relative route from domain root that OHIF instance is installed at.
|
||||
* For example:
|
||||
*
|
||||
* Hosted at: https://ohif.org/where-i-host-the/viewer/
|
||||
* Value: `/where-i-host-the/viewer/`
|
||||
* */
|
||||
routerBaseName: '/',
|
||||
/**
|
||||
*
|
||||
*/
|
||||
showLoadingIndicator: true,
|
||||
showStudyList: true,
|
||||
oidc: [],
|
||||
extensions: [],
|
||||
},
|
||||
defaultExtensions: [],
|
||||
/* Modes that are "bundled" or "baked-in" to the application.
|
||||
* These would be provided at build time as part of they entry point. */
|
||||
defaultModes: PropTypes.array,
|
||||
};
|
||||
|
||||
export default App;
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import React, { useEffect, useCallback, useRef, useState } from 'react';
|
||||
import ReactResizeDetector from 'react-resize-detector';
|
||||
import { useResizeDetector } from 'react-resize-detector';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Types, MeasurementService } from '@ohif/core';
|
||||
import { ViewportGrid, ViewportPane, useViewportGrid } from '@ohif/ui';
|
||||
@ -8,16 +8,22 @@ import classNames from 'classnames';
|
||||
import { useAppConfig } from '@state';
|
||||
|
||||
function ViewerViewportGrid(props: withAppTypes) {
|
||||
const { servicesManager, viewportComponents, dataSource } = props;
|
||||
const { servicesManager, viewportComponents = [], dataSource } = props;
|
||||
const [viewportGrid, viewportGridService] = useViewportGrid();
|
||||
const [appConfig] = useAppConfig();
|
||||
|
||||
const { layout, activeViewportId, viewports, isHangingProtocolLayout } = viewportGrid;
|
||||
const { numCols, numRows } = layout;
|
||||
const elementRef = useRef(null);
|
||||
const { ref: resizeRef } = useResizeDetector({
|
||||
refreshMode: 'debounce',
|
||||
refreshRate: 7,
|
||||
refreshOptions: { leading: true },
|
||||
onResize: () => {
|
||||
viewportGridService.setViewportGridSizeChanged();
|
||||
},
|
||||
});
|
||||
const layoutHash = useRef(null);
|
||||
|
||||
// TODO -> Need some way of selecting which displaySets hit the viewports.
|
||||
const { displaySetService, measurementService, hangingProtocolService, uiNotificationService } =
|
||||
servicesManager.services;
|
||||
|
||||
@ -198,50 +204,6 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
};
|
||||
}, [viewports]);
|
||||
|
||||
/**
|
||||
const onDoubleClick = viewportId => {
|
||||
// TODO -> Disabled for now.
|
||||
// onNewImage on a cornerstone viewport is firing setDisplaySetsForViewport.
|
||||
// Which it really really shouldn't. We need a larger fix for jump to
|
||||
// measurements and all cornerstone "imageIndex" state to fix this.
|
||||
if (cachedLayout) {
|
||||
viewportGridService.set({
|
||||
numCols: cachedLayout.numCols,
|
||||
numRows: cachedLayout.numRows,
|
||||
activeViewportId: cachedLayout.activeViewportId,
|
||||
viewports: cachedLayout.viewports,
|
||||
cachedLayout: null,
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const cachedViewports = viewports.map(viewport => {
|
||||
return {
|
||||
displaySetInstanceUID: viewport.displaySetInstanceUID,
|
||||
};
|
||||
});
|
||||
|
||||
viewportGridService.set({
|
||||
numCols: 1,
|
||||
numRows: 1,
|
||||
activeViewportId: 0,
|
||||
viewports: [
|
||||
{
|
||||
displaySetInstanceUID: viewports[viewportId].displaySetInstanceUID,
|
||||
imageIndex: undefined,
|
||||
},
|
||||
],
|
||||
cachedLayout: {
|
||||
numCols,
|
||||
numRows,
|
||||
viewports: cachedViewports,
|
||||
activeViewportId: viewportId,
|
||||
},
|
||||
});
|
||||
};
|
||||
*/
|
||||
|
||||
const onDropHandler = (viewportId, { displaySetInstanceUID }) => {
|
||||
const updatedViewports = _getUpdatedViewports(viewportId, displaySetInstanceUID);
|
||||
viewportGridService.setDisplaySetsForViewports(updatedViewports);
|
||||
@ -363,21 +325,13 @@ function ViewerViewportGrid(props: withAppTypes) {
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={elementRef}
|
||||
ref={resizeRef}
|
||||
className="h-full w-full"
|
||||
>
|
||||
<ViewportGrid
|
||||
numRows={numRows}
|
||||
numCols={numCols}
|
||||
>
|
||||
<ReactResizeDetector
|
||||
refreshMode="debounce"
|
||||
refreshRate={7} // ms seems to be fine for 10 viewports
|
||||
onResize={() => {
|
||||
viewportGridService.setViewportGridSizeChanged();
|
||||
}}
|
||||
targetRef={elementRef.current}
|
||||
/>
|
||||
{getViewportPanes()}
|
||||
</ViewportGrid>
|
||||
</div>
|
||||
@ -389,10 +343,6 @@ ViewerViewportGrid.propTypes = {
|
||||
servicesManager: PropTypes.instanceOf(Object).isRequired,
|
||||
};
|
||||
|
||||
ViewerViewportGrid.defaultProps = {
|
||||
viewportComponents: [],
|
||||
};
|
||||
|
||||
function _getViewportComponent(displaySets, viewportComponents, uiNotificationService) {
|
||||
if (!displaySets || !displaySets.length) {
|
||||
return EmptyViewport;
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
* Entry point for development and production PWA builds.
|
||||
*/
|
||||
import 'regenerator-runtime/runtime';
|
||||
import { createRoot } from 'react-dom/client';
|
||||
import App from './App';
|
||||
import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
@ -35,10 +36,10 @@ loadDynamicConfig(window.config).then(config_json => {
|
||||
defaultModes,
|
||||
};
|
||||
|
||||
/** Create App */
|
||||
const app = React.createElement(App, appProps, null);
|
||||
/** Render */
|
||||
ReactDOM.render(app, document.getElementById('root'));
|
||||
const container = document.getElementById('root');
|
||||
|
||||
const root = createRoot(container);
|
||||
root.render(React.createElement(App, appProps));
|
||||
});
|
||||
|
||||
export { history };
|
||||
|
||||
@ -306,9 +306,11 @@ export default function ModeRoute({
|
||||
}
|
||||
// The unsubscriptions must occur before the extension onModeExit
|
||||
// in order to prevent exceptions during cleanup caused by spurious events
|
||||
unsubscriptions.forEach(unsub => {
|
||||
unsub();
|
||||
});
|
||||
if (unsubscriptions) {
|
||||
unsubscriptions.forEach(unsub => {
|
||||
unsub();
|
||||
});
|
||||
}
|
||||
// The extension manager must be called after the mode, this is
|
||||
// expected to cleanup the state to a standard setup.
|
||||
extensionManager.onModeExit();
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
// Todo: we probably should add external installed extensions/modes here as well.
|
||||
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
// Note: in Tailwind 3.0, JIT will purge unused styles by default
|
||||
// but in development, it is often useful to disable this to see
|
||||
@ -7,6 +6,7 @@ module.exports = {
|
||||
// ...(process.env.NODE_ENV === 'development' && {
|
||||
// safelist: [{ pattern: /.*/ }],
|
||||
// }),
|
||||
presets: [require('../ui/tailwind.config.js'), require('../ui-next/tailwind.config.js')],
|
||||
content: [
|
||||
'./src/**/*.{jsx,js,ts,tsx, css}',
|
||||
'../../extensions/**/*.{jsx,js,ts,tsx, css}',
|
||||
@ -14,256 +14,10 @@ module.exports = {
|
||||
'../../modes/**/*.{jsx,js,ts,tsx, css}',
|
||||
'./node_modules/@ohif/ui/src/**/*.{js,jsx,ts,tsx, css}',
|
||||
'../../node_modules/@ohif/ui/src/**/*.{js,jsx,ts,tsx,css}',
|
||||
'../../node_modules/@ohif/ui/src/**/*.{js,jsx,ts,tsx,css}',
|
||||
'../../node_modules/@ohif/ui-next/src/**/*.{js,jsx,ts,tsx,css}',
|
||||
'../../node_modules/@ohif/extension-*/src/**/*.{js,jsx,css, ts,tsx}',
|
||||
],
|
||||
theme: {
|
||||
screens: {
|
||||
sm: '640px',
|
||||
md: '768px',
|
||||
lg: '1024px',
|
||||
xl: '1280px',
|
||||
},
|
||||
colors: {
|
||||
overlay: 'rgba(0, 0, 0, 0.8)',
|
||||
transparent: 'transparent',
|
||||
black: '#000',
|
||||
white: '#fff',
|
||||
initial: 'initial',
|
||||
inherit: 'inherit',
|
||||
|
||||
indigo: {
|
||||
dark: '#0b1a42',
|
||||
},
|
||||
aqua: {
|
||||
pale: '#7bb2ce',
|
||||
},
|
||||
|
||||
primary: {
|
||||
light: '#5acce6',
|
||||
main: '#0944b3',
|
||||
dark: '#090c29',
|
||||
active: '#348cfd',
|
||||
},
|
||||
|
||||
inputfield: {
|
||||
main: '#3a3f99',
|
||||
disabled: '#2b166b',
|
||||
focus: '#5acce6',
|
||||
placeholder: '#39383f',
|
||||
},
|
||||
|
||||
secondary: {
|
||||
light: '#3a3f99',
|
||||
main: '#2b166b',
|
||||
dark: '#041c4a',
|
||||
active: '#1f1f27',
|
||||
},
|
||||
|
||||
common: {
|
||||
bright: '#e1e1e1',
|
||||
light: '#a19fad',
|
||||
main: '#fff',
|
||||
dark: '#726f7e',
|
||||
active: '#2c3074',
|
||||
},
|
||||
|
||||
customgreen: {
|
||||
100: '#05D97C',
|
||||
200: '#0FD97C',
|
||||
},
|
||||
|
||||
customblue: {
|
||||
10: '#0A163F',
|
||||
20: '#0B1F54',
|
||||
30: '#09286e',
|
||||
40: '#0E307F',
|
||||
50: '#0F3A94',
|
||||
80: '#1454D4',
|
||||
100: '#c4fdff',
|
||||
200: '#38daff',
|
||||
300: '#1D204D',
|
||||
400: '#90A0C1',
|
||||
},
|
||||
|
||||
customgray: {
|
||||
100: '#262943',
|
||||
},
|
||||
|
||||
gray: {
|
||||
100: '#f7fafc',
|
||||
200: '#edf2f7',
|
||||
300: '#e2e8f0',
|
||||
400: '#cbd5e0',
|
||||
500: '#a0aec0',
|
||||
600: '#718096',
|
||||
700: '#4a5568',
|
||||
800: '#2d3748',
|
||||
900: '#1a202c',
|
||||
},
|
||||
red: {
|
||||
100: '#fff5f5',
|
||||
200: '#fed7d7',
|
||||
300: '#feb2b2',
|
||||
400: '#fc8181',
|
||||
500: '#f56565',
|
||||
600: '#e53e3e',
|
||||
700: '#c53030',
|
||||
800: '#9b2c2c',
|
||||
900: '#742a2a',
|
||||
},
|
||||
orange: {
|
||||
100: '#fffaf0',
|
||||
200: '#feebc8',
|
||||
300: '#fbd38d',
|
||||
400: '#f6ad55',
|
||||
500: '#ed8936',
|
||||
600: '#dd6b20',
|
||||
700: '#c05621',
|
||||
800: '#9c4221',
|
||||
900: '#7b341e',
|
||||
},
|
||||
yellow: {
|
||||
100: '#fffff0',
|
||||
200: '#fefcbf',
|
||||
300: '#faf089',
|
||||
400: '#f6e05e',
|
||||
500: '#ecc94b',
|
||||
600: '#d69e2e',
|
||||
700: '#b7791f',
|
||||
800: '#975a16',
|
||||
900: '#744210',
|
||||
},
|
||||
green: {
|
||||
100: '#f0fff4',
|
||||
200: '#c6f6d5',
|
||||
300: '#9ae6b4',
|
||||
400: '#68d391',
|
||||
500: '#48bb78',
|
||||
600: '#38a169',
|
||||
700: '#2f855a',
|
||||
800: '#276749',
|
||||
900: '#22543d',
|
||||
},
|
||||
teal: {
|
||||
100: '#e6fffa',
|
||||
200: '#b2f5ea',
|
||||
300: '#81e6d9',
|
||||
400: '#4fd1c5',
|
||||
500: '#38b2ac',
|
||||
600: '#319795',
|
||||
700: '#2c7a7b',
|
||||
800: '#285e61',
|
||||
900: '#234e52',
|
||||
},
|
||||
blue: {
|
||||
100: '#ebf8ff',
|
||||
200: '#bee3f8',
|
||||
300: '#90cdf4',
|
||||
400: '#63b3ed',
|
||||
500: '#4299e1',
|
||||
600: '#3182ce',
|
||||
700: '#2b6cb0',
|
||||
800: '#2c5282',
|
||||
900: '#2a4365',
|
||||
},
|
||||
indigo: {
|
||||
100: '#ebf4ff',
|
||||
200: '#c3dafe',
|
||||
300: '#a3bffa',
|
||||
400: '#7f9cf5',
|
||||
500: '#667eea',
|
||||
600: '#5a67d8',
|
||||
700: '#4c51bf',
|
||||
800: '#434190',
|
||||
900: '#3c366b',
|
||||
},
|
||||
purple: {
|
||||
100: '#faf5ff',
|
||||
200: '#e9d8fd',
|
||||
300: '#d6bcfa',
|
||||
400: '#b794f4',
|
||||
500: '#9f7aea',
|
||||
600: '#805ad5',
|
||||
700: '#6b46c1',
|
||||
800: '#553c9a',
|
||||
900: '#44337a',
|
||||
},
|
||||
pink: {
|
||||
100: '#fff5f7',
|
||||
200: '#fed7e2',
|
||||
300: '#fbb6ce',
|
||||
400: '#f687b3',
|
||||
500: '#ed64a6',
|
||||
600: '#d53f8c',
|
||||
700: '#b83280',
|
||||
800: '#97266d',
|
||||
900: '#702459',
|
||||
},
|
||||
},
|
||||
backgroundColor: theme => theme('colors'),
|
||||
backgroundPosition: {
|
||||
bottom: 'bottom',
|
||||
center: 'center',
|
||||
left: 'left',
|
||||
'left-bottom': 'left bottom',
|
||||
'left-top': 'left top',
|
||||
right: 'right',
|
||||
'right-bottom': 'right bottom',
|
||||
'right-top': 'right top',
|
||||
top: 'top',
|
||||
},
|
||||
backgroundSize: {
|
||||
auto: 'auto',
|
||||
cover: 'cover',
|
||||
contain: 'contain',
|
||||
},
|
||||
borderColor: theme => ({
|
||||
...theme('colors'),
|
||||
DEFAULT: theme('colors.gray.300', 'currentColor'),
|
||||
}),
|
||||
boxShadow: {
|
||||
xs: '0 0 0 1px rgba(0, 0, 0, 0.05)',
|
||||
sm: '0 1px 2px 0 rgba(0, 0, 0, 0.05)',
|
||||
DEFAULT: '0 1px 3px 0 rgba(0, 0, 0, 0.1), 0 1px 2px 0 rgba(0, 0, 0, 0.06)',
|
||||
md: '0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)',
|
||||
lg: '0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05)',
|
||||
xl: '0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04)',
|
||||
'2xl': '0 25px 50px -12px rgba(0, 0, 0, 0.25)',
|
||||
inner: 'inset 0 2px 4px 0 rgba(0, 0, 0, 0.06)',
|
||||
outline: '0 0 0 3px rgba(66, 153, 225, 0.5)',
|
||||
none: 'none',
|
||||
},
|
||||
container: {},
|
||||
cursor: {
|
||||
auto: 'auto',
|
||||
default: 'default',
|
||||
pointer: 'pointer',
|
||||
wait: 'wait',
|
||||
text: 'text',
|
||||
move: 'move',
|
||||
'not-allowed': 'not-allowed',
|
||||
},
|
||||
fill: {
|
||||
current: 'currentColor',
|
||||
},
|
||||
flex: {
|
||||
1: '1 1 0%',
|
||||
0.3: '0.3 0.3 0%',
|
||||
0.5: '0.5 0.5 0%',
|
||||
auto: '1 1 auto',
|
||||
initial: '0 1 auto',
|
||||
none: 'none',
|
||||
static: '0 0 auto',
|
||||
},
|
||||
flexGrow: {
|
||||
0: '0',
|
||||
DEFAULT: '1',
|
||||
},
|
||||
flexShrink: {
|
||||
0: '0',
|
||||
DEFAULT: '1',
|
||||
},
|
||||
fontFamily: {
|
||||
sans: [
|
||||
'Inter',
|
||||
@ -296,500 +50,5 @@ module.exports = {
|
||||
'5xl': '3rem',
|
||||
'6xl': '4rem',
|
||||
},
|
||||
fontWeight: {
|
||||
hairline: '100',
|
||||
thin: '200',
|
||||
light: '300',
|
||||
normal: '300',
|
||||
medium: '500',
|
||||
semibold: '600',
|
||||
bold: '700',
|
||||
extrabold: '800',
|
||||
black: '900',
|
||||
},
|
||||
height: theme => ({
|
||||
auto: 'auto',
|
||||
...theme('spacing'),
|
||||
full: '100%',
|
||||
screen: '100vh',
|
||||
inherit: 'inherit',
|
||||
}),
|
||||
inset: theme => ({
|
||||
...theme('spacing'),
|
||||
0: '0',
|
||||
auto: 'auto',
|
||||
full: '100%',
|
||||
viewport: '0.5rem',
|
||||
'1/2': '50%',
|
||||
'viewport-scrollbar': '1.3rem',
|
||||
}),
|
||||
minHeight: theme => ({
|
||||
...theme('spacing'),
|
||||
0: '0',
|
||||
full: '100%',
|
||||
screen: '100vh',
|
||||
}),
|
||||
letterSpacing: {
|
||||
tighter: '-0.05em',
|
||||
tight: '-0.025em',
|
||||
normal: '0',
|
||||
wide: '0.025em',
|
||||
wider: '0.05em',
|
||||
widest: '0.1em',
|
||||
},
|
||||
lineHeight: {
|
||||
none: '1',
|
||||
tight: '1.25',
|
||||
snug: '1.375',
|
||||
normal: '1.5',
|
||||
relaxed: '1.625',
|
||||
loose: '2',
|
||||
3: '.75rem',
|
||||
4: '1rem',
|
||||
5: '1.25rem',
|
||||
6: '1.5rem',
|
||||
7: '1.75rem',
|
||||
8: '2rem',
|
||||
9: '2.25rem',
|
||||
10: '2.5rem',
|
||||
},
|
||||
listStyleType: {
|
||||
none: 'none',
|
||||
disc: 'disc',
|
||||
decimal: 'decimal',
|
||||
},
|
||||
margin: (theme, { negative }) => ({
|
||||
auto: 'auto',
|
||||
...theme('spacing'),
|
||||
...negative(theme('spacing')),
|
||||
}),
|
||||
maxHeight: theme => ({
|
||||
full: '100%',
|
||||
screen: '100vh',
|
||||
...theme('spacing'),
|
||||
}),
|
||||
maxWidth: (theme, { breakpoints }) => ({
|
||||
none: 'none',
|
||||
xs: '20rem',
|
||||
sm: '24rem',
|
||||
md: '28rem',
|
||||
lg: '32rem',
|
||||
xl: '36rem',
|
||||
'2xl': '42rem',
|
||||
'3xl': '48rem',
|
||||
'4xl': '56rem',
|
||||
'5xl': '64rem',
|
||||
'6xl': '72rem',
|
||||
full: '100%',
|
||||
...breakpoints(theme('screens')),
|
||||
...theme('spacing'),
|
||||
}),
|
||||
minWidth: theme => ({
|
||||
...theme('spacing'),
|
||||
0: '0',
|
||||
xs: '2rem',
|
||||
sm: '4rem',
|
||||
md: '6rem',
|
||||
lg: '8rem',
|
||||
xl: '10rem',
|
||||
full: '100%',
|
||||
}),
|
||||
objectPosition: {
|
||||
bottom: 'bottom',
|
||||
center: 'center',
|
||||
left: 'left',
|
||||
'left-bottom': 'left bottom',
|
||||
'left-top': 'left top',
|
||||
right: 'right',
|
||||
'right-bottom': 'right bottom',
|
||||
'right-top': 'right top',
|
||||
top: 'top',
|
||||
},
|
||||
opacity: {
|
||||
0: '0',
|
||||
5: '.5',
|
||||
10: '.10',
|
||||
15: '.15',
|
||||
20: '.20',
|
||||
25: '.25',
|
||||
30: '.30',
|
||||
35: '.35',
|
||||
40: '.40',
|
||||
45: '.45',
|
||||
50: '.50',
|
||||
55: '.55',
|
||||
60: '.60',
|
||||
65: '.65',
|
||||
70: '.70',
|
||||
75: '.75',
|
||||
80: '.80',
|
||||
85: '.85',
|
||||
90: '.90',
|
||||
95: '.95',
|
||||
100: '1',
|
||||
},
|
||||
order: {
|
||||
first: '-9999',
|
||||
last: '9999',
|
||||
none: '0',
|
||||
1: '1',
|
||||
2: '2',
|
||||
3: '3',
|
||||
4: '4',
|
||||
5: '5',
|
||||
6: '6',
|
||||
7: '7',
|
||||
8: '8',
|
||||
9: '9',
|
||||
10: '10',
|
||||
11: '11',
|
||||
12: '12',
|
||||
},
|
||||
padding: theme => theme('spacing'),
|
||||
placeholderColor: theme => theme('colors'),
|
||||
stroke: theme => ({
|
||||
...theme('colors'),
|
||||
current: 'currentColor',
|
||||
}),
|
||||
strokeWidth: {
|
||||
0: '0',
|
||||
1: '1',
|
||||
2: '2',
|
||||
},
|
||||
textColor: theme => theme('colors'),
|
||||
width: theme => ({
|
||||
auto: 'auto',
|
||||
...theme('spacing'),
|
||||
'1/2': '50%',
|
||||
'1/3': '33.333333%',
|
||||
'2/3': '66.666667%',
|
||||
'1/4': '25%',
|
||||
'2/4': '50%',
|
||||
'3/4': '75%',
|
||||
'1/5': '20%',
|
||||
'2/5': '40%',
|
||||
'3/5': '60%',
|
||||
'4/5': '80%',
|
||||
'1/6': '16.666667%',
|
||||
'2/6': '33.333333%',
|
||||
'3/6': '50%',
|
||||
'4/6': '66.666667%',
|
||||
'5/6': '83.333333%',
|
||||
'1/12': '8.333333%',
|
||||
'2/12': '16.666667%',
|
||||
'3/12': '25%',
|
||||
'4/12': '33.333333%',
|
||||
'5/12': '41.666667%',
|
||||
'6/12': '50%',
|
||||
'7/12': '58.333333%',
|
||||
'8/12': '66.666667%',
|
||||
'9/12': '75%',
|
||||
'10/12': '83.333333%',
|
||||
'11/12': '91.666667%',
|
||||
'1/24': '4.166666667%',
|
||||
'2/24': '8.333333333%',
|
||||
'3/24': '12.5%',
|
||||
'4/24': '16.66666667%',
|
||||
'5/24': '20.83333333%',
|
||||
'6/24': '25%',
|
||||
'7/24': '29.16666667%',
|
||||
'8/24': '33.33333333%',
|
||||
'9/24': '37.5%',
|
||||
'10/24': '41.66666667%',
|
||||
'11/24': '45.83333333%',
|
||||
'12/24': '50%',
|
||||
'13/24': '54.16666667%',
|
||||
'14/24': '58.33333333%',
|
||||
'15/24': '62.5%',
|
||||
'16/24': '66.66666667%',
|
||||
'17/24': '70.83333333%',
|
||||
'18/24': '75%',
|
||||
'19/24': '79.16666667%',
|
||||
'20/24': '83.33333333%',
|
||||
'21/24': '87.5%',
|
||||
'22/24': '91.66666667%',
|
||||
'23/24': '95.83333333%',
|
||||
full: '100%',
|
||||
screen: '100vw',
|
||||
'max-content': 'max-content',
|
||||
}),
|
||||
zIndex: {
|
||||
auto: 'auto',
|
||||
0: '0',
|
||||
10: '10',
|
||||
20: '20',
|
||||
30: '30',
|
||||
40: '40',
|
||||
50: '50',
|
||||
},
|
||||
gap: theme => theme('spacing'),
|
||||
gridTemplateColumns: {
|
||||
none: 'none',
|
||||
1: 'repeat(1, minmax(0, 1fr))',
|
||||
2: 'repeat(2, minmax(0, 1fr))',
|
||||
3: 'repeat(3, minmax(0, 1fr))',
|
||||
4: 'repeat(4, minmax(0, 1fr))',
|
||||
5: 'repeat(5, minmax(0, 1fr))',
|
||||
6: 'repeat(6, minmax(0, 1fr))',
|
||||
7: 'repeat(7, minmax(0, 1fr))',
|
||||
8: 'repeat(8, minmax(0, 1fr))',
|
||||
9: 'repeat(9, minmax(0, 1fr))',
|
||||
10: 'repeat(10, minmax(0, 1fr))',
|
||||
11: 'repeat(11, minmax(0, 1fr))',
|
||||
12: 'repeat(12, minmax(0, 1fr))',
|
||||
},
|
||||
gridColumn: {
|
||||
auto: 'auto',
|
||||
'span-1': 'span 1 / span 1',
|
||||
'span-2': 'span 2 / span 2',
|
||||
'span-3': 'span 3 / span 3',
|
||||
'span-4': 'span 4 / span 4',
|
||||
'span-5': 'span 5 / span 5',
|
||||
'span-6': 'span 6 / span 6',
|
||||
'span-7': 'span 7 / span 7',
|
||||
'span-8': 'span 8 / span 8',
|
||||
'span-9': 'span 9 / span 9',
|
||||
'span-10': 'span 10 / span 10',
|
||||
'span-11': 'span 11 / span 11',
|
||||
'span-12': 'span 12 / span 12',
|
||||
},
|
||||
gridColumnStart: {
|
||||
auto: 'auto',
|
||||
1: '1',
|
||||
2: '2',
|
||||
3: '3',
|
||||
4: '4',
|
||||
5: '5',
|
||||
6: '6',
|
||||
7: '7',
|
||||
8: '8',
|
||||
9: '9',
|
||||
10: '10',
|
||||
11: '11',
|
||||
12: '12',
|
||||
13: '13',
|
||||
},
|
||||
gridColumnEnd: {
|
||||
auto: 'auto',
|
||||
1: '1',
|
||||
2: '2',
|
||||
3: '3',
|
||||
4: '4',
|
||||
5: '5',
|
||||
6: '6',
|
||||
7: '7',
|
||||
8: '8',
|
||||
9: '9',
|
||||
10: '10',
|
||||
11: '11',
|
||||
12: '12',
|
||||
13: '13',
|
||||
},
|
||||
gridTemplateRows: {
|
||||
none: 'none',
|
||||
1: 'repeat(1, minmax(0, 1fr))',
|
||||
2: 'repeat(2, minmax(0, 1fr))',
|
||||
3: 'repeat(3, minmax(0, 1fr))',
|
||||
4: 'repeat(4, minmax(0, 1fr))',
|
||||
5: 'repeat(5, minmax(0, 1fr))',
|
||||
6: 'repeat(6, minmax(0, 1fr))',
|
||||
},
|
||||
gridRow: {
|
||||
auto: 'auto',
|
||||
'span-1': 'span 1 / span 1',
|
||||
'span-2': 'span 2 / span 2',
|
||||
'span-3': 'span 3 / span 3',
|
||||
'span-4': 'span 4 / span 4',
|
||||
'span-5': 'span 5 / span 5',
|
||||
'span-6': 'span 6 / span 6',
|
||||
},
|
||||
gridRowStart: {
|
||||
auto: 'auto',
|
||||
1: '1',
|
||||
2: '2',
|
||||
3: '3',
|
||||
4: '4',
|
||||
5: '5',
|
||||
6: '6',
|
||||
7: '7',
|
||||
},
|
||||
gridRowEnd: {
|
||||
auto: 'auto',
|
||||
1: '1',
|
||||
2: '2',
|
||||
3: '3',
|
||||
4: '4',
|
||||
5: '5',
|
||||
6: '6',
|
||||
7: '7',
|
||||
},
|
||||
transformOrigin: {
|
||||
center: 'center',
|
||||
top: 'top',
|
||||
'top-right': 'top right',
|
||||
right: 'right',
|
||||
'bottom-right': 'bottom right',
|
||||
bottom: 'bottom',
|
||||
'bottom-left': 'bottom left',
|
||||
left: 'left',
|
||||
'top-left': 'top left',
|
||||
},
|
||||
scale: {
|
||||
0: '0',
|
||||
50: '.5',
|
||||
75: '.75',
|
||||
90: '.9',
|
||||
95: '.95',
|
||||
100: '1',
|
||||
105: '1.05',
|
||||
110: '1.1',
|
||||
125: '1.25',
|
||||
150: '1.5',
|
||||
},
|
||||
rotate: {
|
||||
'-180': '-180deg',
|
||||
'-90': '-90deg',
|
||||
'-45': '-45deg',
|
||||
0: '0',
|
||||
45: '45deg',
|
||||
90: '90deg',
|
||||
180: '180deg',
|
||||
},
|
||||
translate: (theme, { negative }) => ({
|
||||
...theme('spacing'),
|
||||
...negative(theme('spacing')),
|
||||
'-full': '-100%',
|
||||
'-1/2': '-50%',
|
||||
'1/2': '50%',
|
||||
full: '100%',
|
||||
}),
|
||||
skew: {
|
||||
'-12': '-12deg',
|
||||
'-6': '-6deg',
|
||||
'-3': '-3deg',
|
||||
0: '0',
|
||||
3: '3deg',
|
||||
6: '6deg',
|
||||
12: '12deg',
|
||||
},
|
||||
transitionProperty: {
|
||||
none: 'none',
|
||||
all: 'all',
|
||||
height: 'height',
|
||||
DEFAULT:
|
||||
'background-color, border-color, color, fill, stroke, opacity, box-shadow, transform',
|
||||
colors: 'background-color, border-color, color, fill, stroke',
|
||||
opacity: 'opacity',
|
||||
shadow: 'box-shadow',
|
||||
transform: 'transform',
|
||||
},
|
||||
transitionTimingFunction: {
|
||||
linear: 'linear',
|
||||
in: 'cubic-bezier(0.4, 0, 1, 1)',
|
||||
out: 'cubic-bezier(0, 0, 0.2, 1)',
|
||||
'in-out': 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
},
|
||||
transitionDuration: {
|
||||
75: '75ms',
|
||||
100: '100ms',
|
||||
150: '150ms',
|
||||
200: '200ms',
|
||||
300: '300ms',
|
||||
500: '500ms',
|
||||
700: '700ms',
|
||||
1000: '1000ms',
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
accessibility: ['responsive', 'focus'],
|
||||
alignContent: ['responsive'],
|
||||
alignItems: ['responsive'],
|
||||
alignSelf: ['responsive'],
|
||||
appearance: ['responsive'],
|
||||
backgroundAttachment: ['responsive'],
|
||||
backgroundColor: ['responsive', 'hover', 'focus', 'active', 'group-focus', 'group-hover'],
|
||||
backgroundPosition: ['responsive'],
|
||||
backgroundRepeat: ['responsive'],
|
||||
backgroundSize: ['responsive'],
|
||||
borderCollapse: ['responsive'],
|
||||
borderColor: ['responsive', 'hover', 'focus', 'active', 'group-focus', 'group-hover'],
|
||||
borderRadius: ['responsive', 'focus', 'first', 'last'],
|
||||
borderStyle: ['responsive', 'focus'],
|
||||
borderWidth: ['responsive', 'focus', 'first', 'last'],
|
||||
boxShadow: ['responsive', 'hover', 'focus'],
|
||||
boxSizing: ['responsive'],
|
||||
cursor: ['responsive'],
|
||||
display: ['responsive'],
|
||||
fill: ['responsive'],
|
||||
flex: ['responsive'],
|
||||
flexDirection: ['responsive'],
|
||||
flexGrow: ['responsive'],
|
||||
flexShrink: ['responsive'],
|
||||
flexWrap: ['responsive'],
|
||||
float: ['responsive'],
|
||||
clear: ['responsive'],
|
||||
fontFamily: ['responsive'],
|
||||
fontSize: ['responsive'],
|
||||
fontSmoothing: ['responsive'],
|
||||
fontStyle: ['responsive'],
|
||||
fontWeight: ['responsive', 'hover', 'focus'],
|
||||
height: ['responsive'],
|
||||
inset: ['responsive'],
|
||||
justifyContent: ['responsive'],
|
||||
letterSpacing: ['responsive'],
|
||||
lineHeight: ['responsive'],
|
||||
listStylePosition: ['responsive'],
|
||||
listStyleType: ['responsive'],
|
||||
margin: ['responsive'],
|
||||
maxHeight: ['responsive'],
|
||||
maxWidth: ['responsive'],
|
||||
minHeight: ['responsive'],
|
||||
minWidth: ['responsive'],
|
||||
objectFit: ['responsive'],
|
||||
objectPosition: ['responsive'],
|
||||
opacity: ['responsive', 'hover', 'focus', 'active'],
|
||||
order: ['responsive'],
|
||||
outline: ['responsive', 'focus'],
|
||||
overflow: ['responsive'],
|
||||
padding: ['responsive', 'first'],
|
||||
placeholderColor: ['responsive', 'focus'],
|
||||
pointerEvents: ['responsive'],
|
||||
position: ['responsive'],
|
||||
resize: ['responsive'],
|
||||
stroke: ['responsive'],
|
||||
strokeWidth: ['responsive'],
|
||||
tableLayout: ['responsive'],
|
||||
textAlign: ['responsive'],
|
||||
textColor: ['responsive', 'hover', 'focus', 'active', 'group-hover'],
|
||||
textDecoration: ['responsive', 'hover', 'focus'],
|
||||
textTransform: ['responsive'],
|
||||
userSelect: ['responsive'],
|
||||
verticalAlign: ['responsive'],
|
||||
visibility: ['responsive'],
|
||||
whitespace: ['responsive'],
|
||||
width: ['responsive'],
|
||||
wordBreak: ['responsive'],
|
||||
zIndex: ['responsive'],
|
||||
gap: ['responsive'],
|
||||
gridAutoFlow: ['responsive'],
|
||||
gridTemplateColumns: ['responsive'],
|
||||
gridColumn: ['responsive'],
|
||||
gridColumnStart: ['responsive'],
|
||||
gridColumnEnd: ['responsive'],
|
||||
gridTemplateRows: ['responsive'],
|
||||
gridRow: ['responsive'],
|
||||
gridRowStart: ['responsive'],
|
||||
gridRowEnd: ['responsive'],
|
||||
transform: ['responsive'],
|
||||
transformOrigin: ['responsive'],
|
||||
scale: ['responsive', 'hover', 'focus'],
|
||||
rotate: ['responsive', 'hover', 'focus'],
|
||||
translate: ['responsive', 'hover', 'focus'],
|
||||
skew: ['responsive', 'hover', 'focus'],
|
||||
transitionProperty: ['responsive'],
|
||||
transitionTimingFunction: ['responsive'],
|
||||
transitionDuration: ['responsive'],
|
||||
},
|
||||
corePlugins: {},
|
||||
plugins: [],
|
||||
};
|
||||
|
||||
@ -43,7 +43,40 @@ const config = {
|
||||
},
|
||||
],
|
||||
module: {
|
||||
|
||||
rules: [
|
||||
{
|
||||
test: /\.svg?$/,
|
||||
oneOf: [
|
||||
{
|
||||
use: [
|
||||
{
|
||||
loader: '@svgr/webpack',
|
||||
options: {
|
||||
svgoConfig: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
prettier: false,
|
||||
svgo: true,
|
||||
titleProp: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
issuer: {
|
||||
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /(\.jsx|\.js|\.tsx|\.ts)$/,
|
||||
loader: 'babel-loader',
|
||||
|
||||
@ -1,21 +1,5 @@
|
||||
// https://babeljs.io/docs/en/options#babelrcroots
|
||||
const { extendDefaultPlugins } = require('svgo');
|
||||
|
||||
module.exports = {
|
||||
plugins: [
|
||||
[
|
||||
'inline-react-svg',
|
||||
{
|
||||
svgo: {
|
||||
plugins: extendDefaultPlugins([
|
||||
{
|
||||
name: 'removeViewBox',
|
||||
active: false,
|
||||
},
|
||||
]),
|
||||
},
|
||||
},
|
||||
],
|
||||
['@babel/plugin-proposal-class-properties', { loose: true }],
|
||||
'@babel/plugin-transform-typescript',
|
||||
['@babel/plugin-proposal-private-property-in-object', { loose: true }],
|
||||
|
||||
@ -20,8 +20,8 @@
|
||||
"@ohif/extension-cornerstone": "^3.0.0",
|
||||
"@ohif/i18n": "^1.0.0",
|
||||
"prop-types": "^15.6.2",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^12.2.2",
|
||||
"react-router": "^6.8.1",
|
||||
"react-router-dom": "^6.8.1",
|
||||
@ -47,7 +47,7 @@
|
||||
"@babel/plugin-proposal-private-property-in-object": "7.21.11",
|
||||
"babel-eslint": "9.x",
|
||||
"babel-loader": "^8.2.4",
|
||||
"babel-plugin-inline-react-svg": "^2.0.2",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^10.2.0",
|
||||
|
||||
@ -49,6 +49,38 @@ const config = {
|
||||
],
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.svg?$/,
|
||||
oneOf: [
|
||||
{
|
||||
use: [
|
||||
{
|
||||
loader: '@svgr/webpack',
|
||||
options: {
|
||||
svgoConfig: {
|
||||
plugins: [
|
||||
{
|
||||
name: 'preset-default',
|
||||
params: {
|
||||
overrides: {
|
||||
removeViewBox: false
|
||||
},
|
||||
},
|
||||
},
|
||||
]
|
||||
},
|
||||
prettier: false,
|
||||
svgo: true,
|
||||
titleProp: true,
|
||||
},
|
||||
},
|
||||
],
|
||||
issuer: {
|
||||
and: [/\.(ts|tsx|js|jsx|md|mdx)$/],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /(\.jsx|\.js|\.tsx|\.ts)$/,
|
||||
loader: 'babel-loader',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
module.exports = {
|
||||
plugins: ['inline-react-svg', '@babel/plugin-proposal-class-properties'],
|
||||
plugins: ['@babel/plugin-proposal-class-properties'],
|
||||
env: {
|
||||
test: {
|
||||
presets: [
|
||||
|
||||
@ -37,7 +37,7 @@
|
||||
"@babel/preset-typescript": "^7.13.0",
|
||||
"babel-eslint": "^8.0.3",
|
||||
"babel-loader": "^8.0.0-beta.4",
|
||||
"babel-plugin-inline-react-svg": "^2.0.1",
|
||||
"@svgr/webpack": "^8.1.0",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^10.2.0",
|
||||
"cross-env": "^7.0.3",
|
||||
|
||||
@ -47,8 +47,8 @@
|
||||
"url-loader": "^4.1.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2"
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
|
||||
@ -33,8 +33,8 @@
|
||||
"peerDependencies": {
|
||||
"i18next": "^17.0.3",
|
||||
"i18next-browser-languagedetector": "^3.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^12.2.2"
|
||||
},
|
||||
"dependencies": {
|
||||
@ -46,8 +46,8 @@
|
||||
"devDependencies": {
|
||||
"i18next": "^17.0.3",
|
||||
"i18next-browser-languagedetector": "^3.0.1",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-i18next": "^12.2.2",
|
||||
"webpack-merge": "^5.7.3"
|
||||
}
|
||||
|
||||
17
platform/ui-next/components.json
Normal file
17
platform/ui-next/components.json
Normal file
@ -0,0 +1,17 @@
|
||||
{
|
||||
"$schema": "https://ui.shadcn.com/schema.json",
|
||||
"style": "new-york",
|
||||
"rsc": false,
|
||||
"tsx": true,
|
||||
"tailwind": {
|
||||
"config": "tailwind.config.js",
|
||||
"css": "src/tailwind.css",
|
||||
"baseColor": "slate",
|
||||
"cssVariables": true,
|
||||
"prefix": ""
|
||||
},
|
||||
"aliases": {
|
||||
"components": "src/components",
|
||||
"utils": "src/lib/utils"
|
||||
}
|
||||
}
|
||||
37
platform/ui-next/package.json
Normal file
37
platform/ui-next/package.json
Normal file
@ -0,0 +1,37 @@
|
||||
{
|
||||
"name": "@ohif/ui-next",
|
||||
"version": "3.9.0-beta.14",
|
||||
"description": "Next version of OHIF Viewers UI, more customizable using shadcn/ui",
|
||||
"main": "index.ts",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"exports": {
|
||||
"./tailwind.config": "./tailwind.config.ts",
|
||||
"./lib/*": "./src/lib/*.ts",
|
||||
"./components/*": "./src/components/*.tsx",
|
||||
".": "./src/index.ts"
|
||||
},
|
||||
"dependencies": {
|
||||
"@radix-ui/react-dialog": "^1.0.5",
|
||||
"@radix-ui/react-icons": "^1.3.0",
|
||||
"@radix-ui/react-popover": "^1.0.7",
|
||||
"@radix-ui/react-slot": "^1.0.2",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cmdk": "^1.0.0",
|
||||
"date-fns": "^3.6.0",
|
||||
"framer-motion": "6.2.4",
|
||||
"lucide-react": "^0.379.0",
|
||||
"next-themes": "^0.3.0",
|
||||
"react": "^18.3.1",
|
||||
"react-day-picker": "^8.10.1",
|
||||
"sonner": "^1.4.41",
|
||||
"tailwind-merge": "^2.3.0",
|
||||
"tailwindcss": "3.2.4",
|
||||
"tailwindcss-animate": "^1.0.7"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "OHIF",
|
||||
"license": "MIT"
|
||||
}
|
||||
54
platform/ui-next/src/components/Button/Button.tsx
Normal file
54
platform/ui-next/src/components/Button/Button.tsx
Normal file
@ -0,0 +1,54 @@
|
||||
import * as React from 'react';
|
||||
import { Slot } from '@radix-ui/react-slot';
|
||||
import { cva, type VariantProps } from 'class-variance-authority';
|
||||
|
||||
import { cn } from '../../lib/utils';
|
||||
|
||||
const buttonVariants = cva(
|
||||
'inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50',
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
|
||||
destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
|
||||
outline:
|
||||
'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
|
||||
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
|
||||
ghost: 'hover:bg-accent hover:text-accent-foreground',
|
||||
link: 'text-primary underline-offset-4 hover:underline',
|
||||
},
|
||||
size: {
|
||||
default: 'h-9 px-4 py-2',
|
||||
sm: 'h-8 rounded-md px-3 text-xs',
|
||||
lg: 'h-10 rounded-md px-8',
|
||||
icon: 'h-9 w-9',
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: 'default',
|
||||
size: 'default',
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
export interface ButtonProps
|
||||
extends React.ButtonHTMLAttributes<HTMLButtonElement>,
|
||||
VariantProps<typeof buttonVariants> {
|
||||
asChild?: boolean;
|
||||
}
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, asChild = false, ...props }, ref) => {
|
||||
const Comp = asChild ? Slot : 'button';
|
||||
return (
|
||||
<Comp
|
||||
className={cn(buttonVariants({ variant, size, className }))}
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
);
|
||||
Button.displayName = 'Button';
|
||||
|
||||
export { Button, buttonVariants };
|
||||
1
platform/ui-next/src/components/Button/index.ts
Normal file
1
platform/ui-next/src/components/Button/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { Button , buttonVariants} from "./Button"
|
||||
61
platform/ui-next/src/components/Calendar/Calendar.tsx
Normal file
61
platform/ui-next/src/components/Calendar/Calendar.tsx
Normal file
@ -0,0 +1,61 @@
|
||||
import * as React from 'react';
|
||||
import { ChevronLeft, ChevronRight } from 'lucide-react';
|
||||
import { DayPicker } from 'react-day-picker';
|
||||
|
||||
import { cn } from '../../lib/utils';
|
||||
|
||||
import { buttonVariants } from '../Button';
|
||||
|
||||
export type CalendarProps = React.ComponentProps<typeof DayPicker>;
|
||||
|
||||
function Calendar({ className, classNames, showOutsideDays = true, ...props }: CalendarProps) {
|
||||
return (
|
||||
<DayPicker
|
||||
showOutsideDays={showOutsideDays}
|
||||
className={cn('p-3', className)}
|
||||
captionLayout="dropdown"
|
||||
fromYear={1945}
|
||||
toYear={2024}
|
||||
labels={{
|
||||
labelMonthDropdown: () => undefined,
|
||||
labelYearDropdown: () => undefined,
|
||||
}}
|
||||
classNames={{
|
||||
months: 'flex flex-col sm:flex-row space-y-4 sm:space-x-4 sm:space-y-0',
|
||||
month: 'space-y-4',
|
||||
caption: 'flex justify-between items-center px-2',
|
||||
|
||||
caption_dropdowns: 'flex space-x-2',
|
||||
caption_label: 'hidden',
|
||||
nav: 'space-x-1 flex items-center',
|
||||
table: 'w-full border-collapse space-y-1',
|
||||
head_row: 'flex',
|
||||
head_cell: 'text-muted-foreground rounded-md w-9 font-normal text-[0.8rem]',
|
||||
row: 'flex w-full mt-2',
|
||||
cell: 'h-9 w-9 text-center text-sm p-0 relative [&:has([aria-selected].day-range-end)]:rounded-r-md [&:has([aria-selected].day-outside)]:bg-accent/50 [&:has([aria-selected])]:bg-accent first:[&:has([aria-selected])]:rounded-l-md last:[&:has([aria-selected])]:rounded-r-md focus-within:relative focus-within:z-20',
|
||||
day: cn(
|
||||
buttonVariants({ variant: 'ghost' }),
|
||||
'h-9 w-9 p-0 font-normal aria-selected:opacity-100'
|
||||
),
|
||||
day_range_end: 'day-range-end',
|
||||
day_selected:
|
||||
'bg-primary text-primary-foreground hover:bg-primary hover:text-primary-foreground focus:bg-primary focus:text-primary-foreground',
|
||||
day_today: 'bg-accent text-accent-foreground',
|
||||
day_outside:
|
||||
'day-outside text-muted-foreground opacity-50 aria-selected:bg-accent/50 aria-selected:text-muted-foreground aria-selected:opacity-30',
|
||||
day_disabled: 'text-muted-foreground opacity-50',
|
||||
day_range_middle: 'aria-selected:bg-accent aria-selected:text-accent-foreground',
|
||||
day_hidden: 'invisible',
|
||||
...classNames,
|
||||
}}
|
||||
components={{
|
||||
IconLeft: ({ ...props }) => <ChevronLeft className="h-4 w-4" />,
|
||||
IconRight: ({ ...props }) => <ChevronRight className="h-4 w-4" />,
|
||||
}}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Calendar.displayName = 'Calendar';
|
||||
|
||||
export { Calendar };
|
||||
3
platform/ui-next/src/components/Calendar/index.tsx
Normal file
3
platform/ui-next/src/components/Calendar/index.tsx
Normal file
@ -0,0 +1,3 @@
|
||||
import { Calendar } from './Calendar';
|
||||
|
||||
export default Calendar;
|
||||
66
platform/ui-next/src/components/Combobox/Combobox.tsx
Normal file
66
platform/ui-next/src/components/Combobox/Combobox.tsx
Normal file
@ -0,0 +1,66 @@
|
||||
import * as React from 'react';
|
||||
import { Check, ChevronsUpDown } from 'lucide-react';
|
||||
|
||||
import { cn } from '../../lib/utils';
|
||||
import { Button } from '../Button/Button';
|
||||
import {
|
||||
Command,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandInput,
|
||||
CommandItem,
|
||||
CommandList,
|
||||
} from '../Command/Command';
|
||||
import { Popover, PopoverContent, PopoverTrigger } from '../Popover/Popover';
|
||||
|
||||
export function Combobox({ data = [], placeholder = 'Select item...' }) {
|
||||
const [open, setOpen] = React.useState(false);
|
||||
const [value, setValue] = React.useState('');
|
||||
|
||||
return (
|
||||
<Popover
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
>
|
||||
<PopoverTrigger asChild>
|
||||
<Button
|
||||
variant="outline"
|
||||
role="combobox"
|
||||
aria-expanded={open}
|
||||
className="w-[200px] justify-between"
|
||||
>
|
||||
{value ? data.find(item => item.value === value)?.label : placeholder}
|
||||
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
</Button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent className="w-[200px] p-0">
|
||||
<Command>
|
||||
<CommandInput placeholder={`Search ${placeholder.toLowerCase()}...`} />
|
||||
<CommandEmpty>No {placeholder.toLowerCase()} found.</CommandEmpty>
|
||||
<CommandList>
|
||||
<CommandGroup>
|
||||
{data.map(item => (
|
||||
<CommandItem
|
||||
key={item.value}
|
||||
value={item.value}
|
||||
onSelect={currentValue => {
|
||||
setValue(currentValue === value ? '' : currentValue);
|
||||
setOpen(false);
|
||||
}}
|
||||
>
|
||||
<Check
|
||||
className={cn(
|
||||
'mr-2 h-4 w-4',
|
||||
value === item.value ? 'opacity-100' : 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
{item.label}
|
||||
</CommandItem>
|
||||
))}
|
||||
</CommandGroup>
|
||||
</CommandList>
|
||||
</Command>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
}
|
||||
3
platform/ui-next/src/components/Combobox/index.ts
Normal file
3
platform/ui-next/src/components/Combobox/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { Combobox } from './Combobox';
|
||||
|
||||
export default Combobox;
|
||||
150
platform/ui-next/src/components/Command/Command.tsx
Normal file
150
platform/ui-next/src/components/Command/Command.tsx
Normal file
@ -0,0 +1,150 @@
|
||||
import * as React from 'react';
|
||||
import { type DialogProps } from '@radix-ui/react-dialog';
|
||||
import { MagnifyingGlassIcon } from '@radix-ui/react-icons';
|
||||
import { Command as CommandPrimitive } from 'cmdk';
|
||||
|
||||
import { cn } from '../../lib/utils';
|
||||
import { Dialog, DialogContent } from '../Dialog/Dialog';
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'bg-popover text-popover-foreground flex h-full w-full flex-col overflow-hidden rounded-md',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
Command.displayName = CommandPrimitive.displayName;
|
||||
|
||||
interface CommandDialogProps extends DialogProps {}
|
||||
|
||||
const CommandDialog = ({ children, ...props }: CommandDialogProps) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0">
|
||||
<Command className="[&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
</DialogContent>
|
||||
</Dialog>
|
||||
);
|
||||
};
|
||||
|
||||
const CommandInput = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Input>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Input>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<div
|
||||
className="flex items-center border-b px-3"
|
||||
cmdk-input-wrapper=""
|
||||
>
|
||||
<MagnifyingGlassIcon className="mr-2 h-4 w-4 shrink-0 opacity-50" />
|
||||
<CommandPrimitive.Input
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'placeholder:text-muted-foreground flex h-10 w-full rounded-md bg-transparent py-3 text-sm outline-none disabled:cursor-not-allowed disabled:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</div>
|
||||
));
|
||||
|
||||
CommandInput.displayName = CommandPrimitive.Input.displayName;
|
||||
|
||||
const CommandList = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.List
|
||||
ref={ref}
|
||||
className={cn('max-h-[300px] overflow-y-auto overflow-x-hidden', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
CommandList.displayName = CommandPrimitive.List.displayName;
|
||||
|
||||
const CommandEmpty = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Empty>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Empty>
|
||||
>((props, ref) => (
|
||||
<CommandPrimitive.Empty
|
||||
ref={ref}
|
||||
className="py-6 text-center text-sm"
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
CommandEmpty.displayName = CommandPrimitive.Empty.displayName;
|
||||
|
||||
const CommandGroup = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Group>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Group>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Group
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'text-foreground [&_[cmdk-group-heading]]:text-muted-foreground overflow-hidden p-1 [&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:py-1.5 [&_[cmdk-group-heading]]:text-xs [&_[cmdk-group-heading]]:font-medium',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
CommandGroup.displayName = CommandPrimitive.Group.displayName;
|
||||
|
||||
const CommandSeparator = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Separator>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Separator>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Separator
|
||||
ref={ref}
|
||||
className={cn('bg-border -mx-1 h-px', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
CommandSeparator.displayName = CommandPrimitive.Separator.displayName;
|
||||
|
||||
const CommandItem = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive.Item>,
|
||||
React.ComponentPropsWithoutRef<typeof CommandPrimitive.Item>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<CommandPrimitive.Item
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'aria-selected:bg-accent aria-selected:text-accent-foreground relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
||||
CommandItem.displayName = CommandPrimitive.Item.displayName;
|
||||
|
||||
const CommandShortcut = ({ className, ...props }: React.HTMLAttributes<HTMLSpanElement>) => {
|
||||
return (
|
||||
<span
|
||||
className={cn('text-muted-foreground ml-auto text-xs tracking-widest', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
};
|
||||
CommandShortcut.displayName = 'CommandShortcut';
|
||||
|
||||
export {
|
||||
Command,
|
||||
CommandDialog,
|
||||
CommandInput,
|
||||
CommandList,
|
||||
CommandEmpty,
|
||||
CommandGroup,
|
||||
CommandItem,
|
||||
CommandShortcut,
|
||||
CommandSeparator,
|
||||
};
|
||||
3
platform/ui-next/src/components/Command/index.ts
Normal file
3
platform/ui-next/src/components/Command/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import * as CommandComponents from './Command';
|
||||
|
||||
export default CommandComponents;
|
||||
153
platform/ui-next/src/components/DateRange/DateRange.tsx
Normal file
153
platform/ui-next/src/components/DateRange/DateRange.tsx
Normal file
@ -0,0 +1,153 @@
|
||||
import * as React from 'react';
|
||||
import { format, parse, isValid } from 'date-fns';
|
||||
import { Calendar as CalendarIcon } from 'lucide-react';
|
||||
import { cn } from '../../lib/utils';
|
||||
import Calendar from '../Calendar';
|
||||
import Popover from '../Popover';
|
||||
|
||||
export type DatePickerWithRangeProps = {
|
||||
id: string;
|
||||
/** YYYYMMDD (19921022) */
|
||||
startDate: string;
|
||||
/** YYYYMMDD (19921022) */
|
||||
endDate: string;
|
||||
/** Callback that received { startDate: string(YYYYMMDD), endDate: string(YYYYMMDD)} */
|
||||
onChange: (value: { startDate: string; endDate: string }) => void;
|
||||
};
|
||||
|
||||
export function DatePickerWithRange({
|
||||
className,
|
||||
id,
|
||||
startDate,
|
||||
endDate,
|
||||
onChange,
|
||||
...props
|
||||
}: React.HTMLAttributes<HTMLDivElement> & DatePickerWithRangeProps) {
|
||||
const [start, setStart] = React.useState<string>(
|
||||
startDate ? format(parse(startDate, 'yyyyMMdd', new Date()), 'yyyy-MM-dd') : ''
|
||||
);
|
||||
const [end, setEnd] = React.useState<string>(
|
||||
endDate ? format(parse(endDate, 'yyyyMMdd', new Date()), 'yyyy-MM-dd') : ''
|
||||
);
|
||||
const [openEnd, setOpenEnd] = React.useState(false);
|
||||
|
||||
const handleStartSelect = (selectedDate: Date | undefined) => {
|
||||
if (selectedDate) {
|
||||
const formattedDate = format(selectedDate, 'yyyy-MM-dd');
|
||||
setStart(formattedDate);
|
||||
setOpenEnd(true);
|
||||
onChange({
|
||||
startDate: format(selectedDate, 'yyyyMMdd'),
|
||||
endDate: end.replace(/-/g, ''),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleEndSelect = (selectedDate: Date | undefined) => {
|
||||
if (selectedDate) {
|
||||
const formattedDate = format(selectedDate, 'yyyy-MM-dd');
|
||||
setEnd(formattedDate);
|
||||
setOpenEnd(false);
|
||||
onChange({
|
||||
startDate: start.replace(/-/g, ''),
|
||||
endDate: format(selectedDate, 'yyyyMMdd'),
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>, type: 'start' | 'end') => {
|
||||
const value = e.target.value;
|
||||
const date = parse(value, 'yyyy-MM-dd', new Date());
|
||||
if (type === 'start') {
|
||||
setStart(value);
|
||||
if (isValid(date)) {
|
||||
handleStartSelect(date);
|
||||
}
|
||||
} else {
|
||||
setEnd(value);
|
||||
if (isValid(date)) {
|
||||
handleEndSelect(date);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
React.useEffect(() => {
|
||||
setStart(startDate ? format(parse(startDate, 'yyyyMMdd', new Date()), 'yyyy-MM-dd') : '');
|
||||
setEnd(endDate ? format(parse(endDate, 'yyyyMMdd', new Date()), 'yyyy-MM-dd') : '');
|
||||
}, [startDate, endDate]);
|
||||
|
||||
return (
|
||||
<div className={cn('flex gap-2', className)}>
|
||||
<Popover.Popover>
|
||||
<Popover.PopoverTrigger asChild>
|
||||
<div className="relative w-full">
|
||||
<CalendarIcon className="absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 transform text-white" />
|
||||
<input
|
||||
id={`${id}-start`}
|
||||
type="text"
|
||||
placeholder="Start date"
|
||||
autoComplete="off"
|
||||
value={start}
|
||||
onChange={e => handleInputChange(e, 'start')}
|
||||
className={cn(
|
||||
'border-inputfield-main focus:border-inputfield-focus h-full w-full justify-start rounded border bg-black py-[6.5px] pl-[6.5px] pr-[6.5px] text-left text-sm font-normal hover:bg-black hover:text-white',
|
||||
!start && 'text-muted-foreground'
|
||||
)}
|
||||
data-cy="input-date-range-start"
|
||||
/>
|
||||
</div>
|
||||
</Popover.PopoverTrigger>
|
||||
<Popover.PopoverContent
|
||||
className="w-auto p-0"
|
||||
align="start"
|
||||
>
|
||||
<Calendar
|
||||
initialFocus
|
||||
mode="single"
|
||||
defaultMonth={start ? parse(start, 'yyyy-MM-dd', new Date()) : new Date()}
|
||||
selected={start ? parse(start, 'yyyy-MM-dd', new Date()) : undefined}
|
||||
onSelect={handleStartSelect}
|
||||
numberOfMonths={1}
|
||||
/>
|
||||
</Popover.PopoverContent>
|
||||
</Popover.Popover>
|
||||
|
||||
<Popover.Popover
|
||||
open={openEnd}
|
||||
onOpenChange={setOpenEnd}
|
||||
>
|
||||
<Popover.PopoverTrigger asChild>
|
||||
<div className="relative w-full">
|
||||
<CalendarIcon className="absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 transform text-white" />
|
||||
<input
|
||||
id={`${id}-end`}
|
||||
type="text"
|
||||
placeholder="End date"
|
||||
autoComplete="off"
|
||||
value={end}
|
||||
onChange={e => handleInputChange(e, 'end')}
|
||||
className={cn(
|
||||
'border-inputfield-main focus:border-inputfield-focus h-full w-full justify-start rounded border bg-black py-[6.5px] pl-[6.5px] pr-[6.5px] text-left text-sm font-normal hover:bg-black hover:text-white',
|
||||
!end && 'text-muted-foreground'
|
||||
)}
|
||||
data-cy="input-date-range-end"
|
||||
/>
|
||||
</div>
|
||||
</Popover.PopoverTrigger>
|
||||
<Popover.PopoverContent
|
||||
className="w-auto p-0"
|
||||
align="start"
|
||||
>
|
||||
<Calendar
|
||||
initialFocus
|
||||
mode="single"
|
||||
defaultMonth={start ? parse(start, 'yyyy-MM-dd', new Date()) : new Date()}
|
||||
selected={end ? parse(end, 'yyyy-MM-dd', new Date()) : undefined}
|
||||
onSelect={handleEndSelect}
|
||||
numberOfMonths={1}
|
||||
/>
|
||||
</Popover.PopoverContent>
|
||||
</Popover.Popover>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
3
platform/ui-next/src/components/DateRange/index.ts
Normal file
3
platform/ui-next/src/components/DateRange/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import { DatePickerWithRange } from "./DateRange";
|
||||
|
||||
export default DatePickerWithRange;
|
||||
105
platform/ui-next/src/components/Dialog/Dialog.tsx
Normal file
105
platform/ui-next/src/components/Dialog/Dialog.tsx
Normal file
@ -0,0 +1,105 @@
|
||||
import * as React from 'react';
|
||||
import * as DialogPrimitive from '@radix-ui/react-dialog';
|
||||
import { Cross2Icon } from '@radix-ui/react-icons';
|
||||
|
||||
import { cn } from '../../lib/utils';
|
||||
|
||||
const Dialog = DialogPrimitive.Root;
|
||||
|
||||
const DialogTrigger = DialogPrimitive.Trigger;
|
||||
|
||||
const DialogPortal = DialogPrimitive.Portal;
|
||||
|
||||
const DialogClose = DialogPrimitive.Close;
|
||||
|
||||
const DialogOverlay = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Overlay>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Overlay>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Overlay
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 fixed inset-0 z-50 bg-black/80',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
||||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
ref={ref}
|
||||
className={cn(
|
||||
'bg-background data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[state=closed]:slide-out-to-left-1/2 data-[state=closed]:slide-out-to-top-[48%] data-[state=open]:slide-in-from-left-1/2 data-[state=open]:slide-in-from-top-[48%] fixed left-[50%] top-[50%] z-50 grid w-full max-w-lg translate-x-[-50%] translate-y-[-50%] gap-4 border p-6 shadow-lg duration-200 sm:rounded-lg',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="ring-offset-background focus:ring-ring data-[state=open]:bg-accent data-[state=open]:text-muted-foreground absolute right-4 top-4 rounded-sm opacity-70 transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-offset-2 disabled:pointer-events-none">
|
||||
<Cross2Icon className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
));
|
||||
DialogContent.displayName = DialogPrimitive.Content.displayName;
|
||||
|
||||
const DialogHeader = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn('flex flex-col space-y-1.5 text-center sm:text-left', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
DialogHeader.displayName = 'DialogHeader';
|
||||
|
||||
const DialogFooter = ({ className, ...props }: React.HTMLAttributes<HTMLDivElement>) => (
|
||||
<div
|
||||
className={cn('flex flex-col-reverse sm:flex-row sm:justify-end sm:space-x-2', className)}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
DialogFooter.displayName = 'DialogFooter';
|
||||
|
||||
const DialogTitle = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Title>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Title>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Title
|
||||
ref={ref}
|
||||
className={cn('text-lg font-semibold leading-none tracking-tight', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DialogTitle.displayName = DialogPrimitive.Title.displayName;
|
||||
|
||||
const DialogDescription = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Description>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Description>
|
||||
>(({ className, ...props }, ref) => (
|
||||
<DialogPrimitive.Description
|
||||
ref={ref}
|
||||
className={cn('text-muted-foreground text-sm', className)}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
DialogDescription.displayName = DialogPrimitive.Description.displayName;
|
||||
|
||||
export {
|
||||
Dialog,
|
||||
DialogPortal,
|
||||
DialogOverlay,
|
||||
DialogTrigger,
|
||||
DialogClose,
|
||||
DialogContent,
|
||||
DialogHeader,
|
||||
DialogFooter,
|
||||
DialogTitle,
|
||||
DialogDescription,
|
||||
};
|
||||
3
platform/ui-next/src/components/Dialog/index.ts
Normal file
3
platform/ui-next/src/components/Dialog/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import * as DialogComponents from './Dialog';
|
||||
|
||||
export default DialogComponents;
|
||||
31
platform/ui-next/src/components/Popover/Popover.tsx
Normal file
31
platform/ui-next/src/components/Popover/Popover.tsx
Normal file
@ -0,0 +1,31 @@
|
||||
import * as React from 'react';
|
||||
import * as PopoverPrimitive from '@radix-ui/react-popover';
|
||||
|
||||
import { cn } from '../../lib/utils';
|
||||
|
||||
const Popover = PopoverPrimitive.Root;
|
||||
|
||||
const PopoverTrigger = PopoverPrimitive.Trigger;
|
||||
|
||||
const PopoverAnchor = PopoverPrimitive.Anchor;
|
||||
|
||||
const PopoverContent = React.forwardRef<
|
||||
React.ElementRef<typeof PopoverPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof PopoverPrimitive.Content>
|
||||
>(({ className, align = 'center', sideOffset = 4, ...props }, ref) => (
|
||||
<PopoverPrimitive.Portal>
|
||||
<PopoverPrimitive.Content
|
||||
ref={ref}
|
||||
align={align}
|
||||
sideOffset={sideOffset}
|
||||
className={cn(
|
||||
'bg-popover text-popover-foreground data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95 data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2 z-50 w-72 rounded-md border p-4 shadow-md outline-none',
|
||||
className
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
</PopoverPrimitive.Portal>
|
||||
));
|
||||
PopoverContent.displayName = PopoverPrimitive.Content.displayName;
|
||||
|
||||
export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor };
|
||||
3
platform/ui-next/src/components/Popover/index.ts
Normal file
3
platform/ui-next/src/components/Popover/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import * as Popover from './Popover';
|
||||
|
||||
export default Popover;
|
||||
@ -0,0 +1,4 @@
|
||||
import React from 'react';
|
||||
import '../../tailwind.css';
|
||||
|
||||
export const ThemeWrapper = ({ children }) => <React.Fragment>{children}</React.Fragment>;
|
||||
1
platform/ui-next/src/components/ThemeWrapper/index.ts
Normal file
1
platform/ui-next/src/components/ThemeWrapper/index.ts
Normal file
@ -0,0 +1 @@
|
||||
export { ThemeWrapper } from './ThemeWrapper';
|
||||
10
platform/ui-next/src/components/index.ts
Normal file
10
platform/ui-next/src/components/index.ts
Normal file
@ -0,0 +1,10 @@
|
||||
import { Button, buttonVariants } from './Button';
|
||||
import { ThemeWrapper } from './ThemeWrapper';
|
||||
import Command from './Command';
|
||||
import Dialog from './Dialog';
|
||||
import Combobox from './Combobox';
|
||||
import Popover from './Popover';
|
||||
import Calendar from './Calendar';
|
||||
import DatePickerWithRange from './DateRange';
|
||||
|
||||
export { Button, buttonVariants, ThemeWrapper, Command, Dialog, Combobox, Popover, Calendar, DatePickerWithRange};
|
||||
@ -0,0 +1,85 @@
|
||||
import React, { useState, createContext, useContext, useCallback, useEffect } from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { Toaster, toast } from 'sonner';
|
||||
|
||||
const NotificationContext = createContext(null);
|
||||
|
||||
export const useNotification = () => useContext(NotificationContext);
|
||||
|
||||
const NotificationProvider = ({ children, service }) => {
|
||||
const DEFAULT_OPTIONS = {
|
||||
title: '',
|
||||
message: '',
|
||||
duration: 5000,
|
||||
position: 'bottom-right', // Aligning to Sonner's positioning system
|
||||
type: 'info', // info, success, error
|
||||
};
|
||||
|
||||
const [notificationItems, setNotificationItems] = useState([]);
|
||||
|
||||
const show = useCallback(options => {
|
||||
const { title, message, duration, position, type } = { ...DEFAULT_OPTIONS, ...options };
|
||||
const id = toast[type](message, {
|
||||
duration,
|
||||
position,
|
||||
render: () => (
|
||||
<div>
|
||||
<strong>{title}</strong>
|
||||
<p>{message}</p>
|
||||
</div>
|
||||
),
|
||||
});
|
||||
|
||||
setNotificationItems(state => [...state, { id, ...options }]);
|
||||
}, []);
|
||||
|
||||
const hide = useCallback(id => {
|
||||
toast.dismiss(id);
|
||||
setNotificationItems(state => state.filter(item => item.id !== id));
|
||||
}, []);
|
||||
|
||||
const hideAll = useCallback(() => {
|
||||
toast.dismiss();
|
||||
setNotificationItems([]);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
window.notification = { show, hide, hideAll };
|
||||
}, [show, hide, hideAll]);
|
||||
|
||||
/**
|
||||
* Sets the implementation of a notification service that can be used by extensions.
|
||||
*
|
||||
* @returns void
|
||||
*/
|
||||
useEffect(() => {
|
||||
if (service) {
|
||||
service.setServiceImplementation({ hide, show });
|
||||
}
|
||||
}, [service, hide, show]);
|
||||
|
||||
return (
|
||||
<NotificationContext.Provider value={{ show, hide, hideAll, notificationItems }}>
|
||||
<Toaster position="bottom-right" />
|
||||
{children}
|
||||
</NotificationContext.Provider>
|
||||
);
|
||||
};
|
||||
|
||||
NotificationProvider.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
};
|
||||
|
||||
export const withNotification = Component => {
|
||||
return function WrappedComponent(props) {
|
||||
const notificationContext = useNotification();
|
||||
return (
|
||||
<Component
|
||||
{...props}
|
||||
notificationContext={notificationContext}
|
||||
/>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
export default NotificationProvider;
|
||||
3
platform/ui-next/src/contextProviders/index.ts
Normal file
3
platform/ui-next/src/contextProviders/index.ts
Normal file
@ -0,0 +1,3 @@
|
||||
import NotificationProvider, { useNotification } from './NotificationProvider';
|
||||
|
||||
export { useNotification, NotificationProvider };
|
||||
28
platform/ui-next/src/index.ts
Normal file
28
platform/ui-next/src/index.ts
Normal file
@ -0,0 +1,28 @@
|
||||
import {
|
||||
Button,
|
||||
buttonVariants,
|
||||
ThemeWrapper,
|
||||
Dialog,
|
||||
Command,
|
||||
Popover,
|
||||
Combobox,
|
||||
Calendar,
|
||||
DatePickerWithRange,
|
||||
} from './components';
|
||||
import { useNotification, NotificationProvider } from './contextProviders';
|
||||
|
||||
export {
|
||||
// components
|
||||
Button,
|
||||
Dialog,
|
||||
Command,
|
||||
Popover,
|
||||
Combobox,
|
||||
buttonVariants,
|
||||
ThemeWrapper,
|
||||
Calendar,
|
||||
DatePickerWithRange,
|
||||
// contextProviders
|
||||
NotificationProvider,
|
||||
useNotification,
|
||||
};
|
||||
6
platform/ui-next/src/lib/utils.ts
Normal file
6
platform/ui-next/src/lib/utils.ts
Normal file
@ -0,0 +1,6 @@
|
||||
import { type ClassValue, clsx } from 'clsx';
|
||||
import { twMerge } from 'tailwind-merge';
|
||||
|
||||
export function cn(...inputs: ClassValue[]) {
|
||||
return twMerge(clsx(inputs));
|
||||
}
|
||||
67
platform/ui-next/src/tailwind.css
Normal file
67
platform/ui-next/src/tailwind.css
Normal file
@ -0,0 +1,67 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
|
||||
@layer base {
|
||||
:root {
|
||||
--background: 0 0% 100%;
|
||||
--foreground: 222.2 84% 4.9%;
|
||||
|
||||
--card: 0 0% 100%;
|
||||
--card-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--popover: 0 0% 100%;
|
||||
--popover-foreground: 222.2 84% 4.9%;
|
||||
|
||||
--primary: 222.2 47.4% 11.2%;
|
||||
--primary-foreground: 210 40% 98%;
|
||||
|
||||
--secondary: 210 40% 96.1%;
|
||||
--secondary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--muted: 210 40% 96.1%;
|
||||
--muted-foreground: 215.4 16.3% 46.9%;
|
||||
|
||||
--accent: 210 40% 96.1%;
|
||||
--accent-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--destructive: 0 84.2% 60.2%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 214.3 31.8% 91.4%;
|
||||
--input: 214.3 31.8% 91.4%;
|
||||
--ring: 222.2 84% 4.9%;
|
||||
|
||||
--radius: 0.5rem;
|
||||
}
|
||||
|
||||
.dark {
|
||||
--background: 222.2 84% 4.9%;
|
||||
--foreground: 210 40% 98%;
|
||||
|
||||
--card: 222.2 84% 4.9%;
|
||||
--card-foreground: 210 40% 98%;
|
||||
|
||||
--popover: 222.2 84% 4.9%;
|
||||
--popover-foreground: 210 40% 98%;
|
||||
|
||||
--primary: 210 40% 98%;
|
||||
--primary-foreground: 222.2 47.4% 11.2%;
|
||||
|
||||
--secondary: 217.2 32.6% 17.5%;
|
||||
--secondary-foreground: 210 40% 98%;
|
||||
|
||||
--muted: 217.2 32.6% 17.5%;
|
||||
--muted-foreground: 215 20.2% 65.1%;
|
||||
|
||||
--accent: 217.2 32.6% 17.5%;
|
||||
--accent-foreground: 210 40% 98%;
|
||||
|
||||
--destructive: 0 62.8% 30.6%;
|
||||
--destructive-foreground: 210 40% 98%;
|
||||
|
||||
--border: 217.2 32.6% 17.5%;
|
||||
--input: 217.2 32.6% 17.5%;
|
||||
--ring: 212.7 26.8% 83.9%;
|
||||
}
|
||||
}
|
||||
70
platform/ui-next/tailwind.config.js
Normal file
70
platform/ui-next/tailwind.config.js
Normal file
@ -0,0 +1,70 @@
|
||||
/** @type {import('tailwindcss').Config} */
|
||||
module.exports = {
|
||||
presets: [require('../ui/tailwind.config.js')],
|
||||
content: [
|
||||
'./pages/**/*.{ts,tsx}',
|
||||
'./components/**/*.{ts,tsx}',
|
||||
'./app/**/*.{ts,tsx}',
|
||||
'./src/**/*.{ts,tsx}',
|
||||
],
|
||||
prefix: '',
|
||||
theme: {
|
||||
extend: {
|
||||
colors: {
|
||||
border: 'hsl(var(--border))',
|
||||
input: 'hsl(var(--input))',
|
||||
ring: 'hsl(var(--ring))',
|
||||
background: 'hsl(var(--background))',
|
||||
foreground: 'hsl(var(--foreground))',
|
||||
primary: {
|
||||
DEFAULT: 'hsl(var(--primary))',
|
||||
foreground: 'hsl(var(--primary-foreground))',
|
||||
},
|
||||
secondary: {
|
||||
DEFAULT: 'hsl(var(--secondary))',
|
||||
foreground: 'hsl(var(--secondary-foreground))',
|
||||
},
|
||||
destructive: {
|
||||
DEFAULT: 'hsl(var(--destructive))',
|
||||
foreground: 'hsl(var(--destructive-foreground))',
|
||||
},
|
||||
muted: {
|
||||
DEFAULT: 'hsl(var(--muted))',
|
||||
foreground: 'hsl(var(--muted-foreground))',
|
||||
},
|
||||
accent: {
|
||||
DEFAULT: 'hsl(var(--accent))',
|
||||
foreground: 'hsl(var(--accent-foreground))',
|
||||
},
|
||||
popover: {
|
||||
DEFAULT: 'hsl(var(--popover))',
|
||||
foreground: 'hsl(var(--popover-foreground))',
|
||||
},
|
||||
card: {
|
||||
DEFAULT: 'hsl(var(--card))',
|
||||
foreground: 'hsl(var(--card-foreground))',
|
||||
},
|
||||
},
|
||||
borderRadius: {
|
||||
lg: 'var(--radius)',
|
||||
md: 'calc(var(--radius) - 2px)',
|
||||
sm: 'calc(var(--radius) - 4px)',
|
||||
},
|
||||
keyframes: {
|
||||
'accordion-down': {
|
||||
from: { height: '0' },
|
||||
to: { height: 'var(--radix-accordion-content-height)' },
|
||||
},
|
||||
'accordion-up': {
|
||||
from: { height: 'var(--radix-accordion-content-height)' },
|
||||
to: { height: '0' },
|
||||
},
|
||||
},
|
||||
animation: {
|
||||
'accordion-down': 'accordion-down 0.2s ease-out',
|
||||
'accordion-up': 'accordion-up 0.2s ease-out',
|
||||
},
|
||||
},
|
||||
},
|
||||
plugins: [require('tailwindcss-animate')],
|
||||
};
|
||||
11
platform/ui-next/tsconfig.json
Normal file
11
platform/ui-next/tsconfig.json
Normal file
@ -0,0 +1,11 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@ui/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules"]
|
||||
}
|
||||
@ -29,8 +29,8 @@
|
||||
"build-storybook": "storybook build"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2"
|
||||
"react": "^18.3.1",
|
||||
"react-dom": "^18.3.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@testing-library/react-hooks": "^3.2.1",
|
||||
@ -46,11 +46,11 @@
|
||||
"lodash.debounce": "4.0.8",
|
||||
"moment": "2.29.4",
|
||||
"mousetrap": "^1.6.5",
|
||||
"react": "^17.0.2",
|
||||
"react": "^18.3.1",
|
||||
"react-dates": "^21.8.0",
|
||||
"react-dnd": "14.0.2",
|
||||
"react-dnd-html5-backend": "14.0.0",
|
||||
"react-dom": "^17.0.2",
|
||||
"react-dom": "^18.3.1",
|
||||
"react-draggable": "4.4.3",
|
||||
"react-error-boundary": "^3.1.3",
|
||||
"react-modal": "3.11.2",
|
||||
|
||||
@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import { Button, ButtonEnums } from '../../components';
|
||||
|
||||
function ActionButtons({ actions, disabled, t }) {
|
||||
function ActionButtons({ actions, disabled = false, t }) {
|
||||
return (
|
||||
<React.Fragment>
|
||||
{actions.map((action, index) => (
|
||||
@ -33,8 +33,4 @@ ActionButtons.propTypes = {
|
||||
disabled: PropTypes.bool,
|
||||
};
|
||||
|
||||
ActionButtons.defaultProps = {
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export default ActionButtons;
|
||||
|
||||
@ -58,7 +58,7 @@ const defaults = {
|
||||
};
|
||||
|
||||
const Button = ({
|
||||
children,
|
||||
children = '',
|
||||
size = defaults.size,
|
||||
disabled = defaults.disabled,
|
||||
type = defaults.type,
|
||||
@ -66,7 +66,7 @@ const Button = ({
|
||||
endIcon: endIconProp,
|
||||
name,
|
||||
className,
|
||||
onClick,
|
||||
onClick = () => {},
|
||||
dataCY,
|
||||
startIconTooltip = null,
|
||||
endIconTooltip = null,
|
||||
@ -121,14 +121,6 @@ const Button = ({
|
||||
);
|
||||
};
|
||||
|
||||
Button.defaultProps = {
|
||||
disabled: false,
|
||||
children: '',
|
||||
onClick: () => {},
|
||||
type: defaults.type,
|
||||
size: defaults.size,
|
||||
};
|
||||
|
||||
Button.propTypes = {
|
||||
/** What is inside the button, can be text or react component */
|
||||
children: PropTypes.node,
|
||||
|
||||
@ -31,15 +31,15 @@ const fpsButtonClassNames =
|
||||
|
||||
const CinePlayer: React.FC<CinePlayerProps> = ({
|
||||
className,
|
||||
isPlaying,
|
||||
minFrameRate,
|
||||
maxFrameRate,
|
||||
stepFrameRate,
|
||||
frameRate: defaultFrameRate,
|
||||
isPlaying = false,
|
||||
minFrameRate = 1,
|
||||
maxFrameRate = 90,
|
||||
stepFrameRate = 1,
|
||||
frameRate: defaultFrameRate = 24,
|
||||
onFrameRateChange = () => {},
|
||||
onPlayPauseChange = () => {},
|
||||
onClose = () => {},
|
||||
dynamicInfo = {},
|
||||
onFrameRateChange,
|
||||
onPlayPauseChange,
|
||||
onClose,
|
||||
updateDynamicInfo,
|
||||
}) => {
|
||||
const isDynamic = !!dynamicInfo?.numTimePoints;
|
||||
@ -163,21 +163,6 @@ const CinePlayer: React.FC<CinePlayerProps> = ({
|
||||
);
|
||||
};
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
CinePlayer.defaultProps = {
|
||||
isPlaying: false,
|
||||
minFrameRate: 1,
|
||||
maxFrameRate: 90,
|
||||
stepFrameRate: 1,
|
||||
frameRate: 24,
|
||||
onPlayPauseChange: noop,
|
||||
onFrameRateChange: noop,
|
||||
onClose: noop,
|
||||
isDynamic: false,
|
||||
dynamicInfo: {},
|
||||
};
|
||||
|
||||
CinePlayer.propTypes = {
|
||||
/** Minimum value for range slider */
|
||||
minFrameRate: PropTypes.number,
|
||||
|
||||
@ -29,7 +29,7 @@ const renderYearsOptions = () => {
|
||||
};
|
||||
|
||||
const DateRange = props => {
|
||||
const { id, onChange, startDate, endDate } = props;
|
||||
const { id = '', onChange, startDate = null, endDate = null } = props;
|
||||
const [focusedInput, setFocusedInput] = useState(null);
|
||||
const renderYearsOptionsCallback = useCallback(renderYearsOptions, []);
|
||||
const { t } = useTranslation('DatePicker');
|
||||
@ -165,12 +165,6 @@ const DateRange = props => {
|
||||
);
|
||||
};
|
||||
|
||||
DateRange.defaultProps = {
|
||||
id: '',
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
};
|
||||
|
||||
DateRange.propTypes = {
|
||||
id: PropTypes.string,
|
||||
/** YYYYMMDD (19921022) */
|
||||
|
||||
@ -15,10 +15,10 @@ const Dialog = ({
|
||||
actions,
|
||||
onShow,
|
||||
onSubmit,
|
||||
header: HeaderComponent,
|
||||
body: BodyComponent,
|
||||
footer: FooterComponent,
|
||||
value: defaultValue,
|
||||
header: HeaderComponent = Header,
|
||||
body: BodyComponent = Body,
|
||||
footer: FooterComponent = Footer,
|
||||
value: defaultValue = {},
|
||||
}) => {
|
||||
const [value, setValue] = useState(defaultValue);
|
||||
|
||||
@ -78,13 +78,7 @@ Dialog.propTypes = {
|
||||
type: PropTypes.oneOf(['primary', 'secondary', 'cancel']).isRequired,
|
||||
})
|
||||
).isRequired,
|
||||
};
|
||||
|
||||
Dialog.defaultProps = {
|
||||
header: Header,
|
||||
footer: Footer,
|
||||
body: Body,
|
||||
value: {},
|
||||
onShow: PropTypes.func,
|
||||
};
|
||||
|
||||
export default Dialog;
|
||||
|
||||
@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||
|
||||
import Button, { ButtonEnums } from '../Button';
|
||||
|
||||
const Footer = ({ actions, className, onSubmit, value }) => {
|
||||
const Footer = ({ actions = [], className, onSubmit = () => {}, value }) => {
|
||||
const flex = 'flex items-center justify-end';
|
||||
const padding = 'pt-[20px]';
|
||||
|
||||
@ -47,9 +47,4 @@ Footer.propTypes = {
|
||||
).isRequired,
|
||||
};
|
||||
|
||||
Footer.defaultProps = {
|
||||
onSubmit: noop,
|
||||
actions: [],
|
||||
};
|
||||
|
||||
export default Footer;
|
||||
|
||||
@ -20,7 +20,7 @@ CloseButton.propTypes = {
|
||||
onClick: PropTypes.func,
|
||||
};
|
||||
|
||||
const Header = ({ title, noCloseButton, onClose }) => {
|
||||
const Header = ({ title, noCloseButton = false, onClose }) => {
|
||||
const theme = 'bg-primary-dark';
|
||||
const flex = 'flex items-center justify-between';
|
||||
const padding = 'pb-[20px]';
|
||||
@ -46,8 +46,4 @@ Header.propTypes = {
|
||||
onClose: PropTypes.func,
|
||||
};
|
||||
|
||||
Header.defaultProps = {
|
||||
noCloseButton: false,
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
||||
@ -11,15 +11,15 @@ const borderStyle = 'border-b last:border-b-0 border-secondary-main';
|
||||
const Dropdown = ({
|
||||
id,
|
||||
children,
|
||||
showDropdownIcon,
|
||||
showDropdownIcon = true,
|
||||
list,
|
||||
itemsClassName,
|
||||
titleClassName,
|
||||
showBorders,
|
||||
showBorders = true,
|
||||
alignment,
|
||||
// By default the max characters per line is the longest title
|
||||
// if you wish to override this, you can pass in a number
|
||||
maxCharactersPerLine,
|
||||
maxCharactersPerLine = 20,
|
||||
}) => {
|
||||
const [open, setOpen] = useState(false);
|
||||
const elementRef = useRef(null);
|
||||
@ -199,11 +199,6 @@ const Dropdown = ({
|
||||
</div>
|
||||
);
|
||||
};
|
||||
Dropdown.defaultProps = {
|
||||
showDropdownIcon: true,
|
||||
maxCharactersPerLine: 20,
|
||||
showBorders: true,
|
||||
};
|
||||
|
||||
Dropdown.propTypes = {
|
||||
id: PropTypes.string,
|
||||
|
||||
@ -7,7 +7,7 @@ import Icon from '../Icon';
|
||||
import Typography from '../Typography';
|
||||
|
||||
// TODO: Add loading spinner to OHIF + use it here.
|
||||
const EmptyStudies = ({ className }) => {
|
||||
const EmptyStudies = ({ className = '' }) => {
|
||||
const { t } = useTranslation('StudyList');
|
||||
return (
|
||||
<div className={classnames('inline-flex flex-col items-center', className)}>
|
||||
@ -25,10 +25,6 @@ const EmptyStudies = ({ className }) => {
|
||||
);
|
||||
};
|
||||
|
||||
EmptyStudies.defaultProps = {
|
||||
className: '',
|
||||
};
|
||||
|
||||
EmptyStudies.propTypes = {
|
||||
className: PropTypes.string,
|
||||
};
|
||||
|
||||
@ -10,7 +10,7 @@ import IconButton from '../IconButton';
|
||||
|
||||
const isProduction = process.env.NODE_ENV === 'production';
|
||||
|
||||
const DefaultFallback = ({ error, context, resetErrorBoundary, fallbackRoute }) => {
|
||||
const DefaultFallback = ({ error, context, resetErrorBoundary = () => {}, fallbackRoute }) => {
|
||||
const { t } = useTranslation('ErrorBoundary');
|
||||
const [showDetails, setShowDetails] = useState(false);
|
||||
const title = `${t('Something went wrong')}${!isProduction && ` ${t('in')} ${context}`}.`;
|
||||
@ -57,25 +57,19 @@ const DefaultFallback = ({ error, context, resetErrorBoundary, fallbackRoute })
|
||||
);
|
||||
};
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
DefaultFallback.propTypes = {
|
||||
error: PropTypes.object.isRequired,
|
||||
resetErrorBoundary: PropTypes.func,
|
||||
componentStack: PropTypes.string,
|
||||
};
|
||||
|
||||
DefaultFallback.defaultProps = {
|
||||
resetErrorBoundary: noop,
|
||||
};
|
||||
|
||||
const ErrorBoundary = ({
|
||||
context,
|
||||
onReset,
|
||||
onError,
|
||||
fallbackComponent: FallbackComponent,
|
||||
context = 'OHIF',
|
||||
onReset = () => {},
|
||||
onError = () => {},
|
||||
fallbackComponent: FallbackComponent = DefaultFallback,
|
||||
children,
|
||||
fallbackRoute,
|
||||
fallbackRoute = null,
|
||||
isPage,
|
||||
}) => {
|
||||
const [isOpen, setIsOpen] = useState(true);
|
||||
@ -132,12 +126,4 @@ ErrorBoundary.propTypes = {
|
||||
fallbackRoute: PropTypes.string,
|
||||
};
|
||||
|
||||
ErrorBoundary.defaultProps = {
|
||||
context: 'OHIF',
|
||||
onReset: noop,
|
||||
onError: noop,
|
||||
fallbackComponent: DefaultFallback,
|
||||
fallbackRoute: null,
|
||||
};
|
||||
|
||||
export default ErrorBoundary;
|
||||
|
||||
@ -8,14 +8,14 @@ import Icon from '../Icon';
|
||||
import './ExpandableToolbarButton.css';
|
||||
|
||||
const ExpandableToolbarButton = ({
|
||||
type,
|
||||
id,
|
||||
isActive,
|
||||
onClick,
|
||||
icon,
|
||||
type = 'primary',
|
||||
id = '',
|
||||
isActive = false,
|
||||
onClick = () => {},
|
||||
icon = 'clipboard',
|
||||
className,
|
||||
content: Content,
|
||||
contentProps,
|
||||
content: Content = null,
|
||||
contentProps = {},
|
||||
}) => {
|
||||
const classes = {
|
||||
type: {
|
||||
@ -71,15 +71,6 @@ const ExpandableToolbarButton = ({
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
ExpandableToolbarButton.defaultProps = {
|
||||
id: '',
|
||||
icon: 'clipboard',
|
||||
isActive: false,
|
||||
type: 'primary',
|
||||
content: null,
|
||||
onClick: noop,
|
||||
};
|
||||
|
||||
ExpandableToolbarButton.propTypes = {
|
||||
/* Influences background/hover styling */
|
||||
type: PropTypes.oneOf(['primary', 'secondary']),
|
||||
|
||||
@ -14,9 +14,9 @@ import { PatientInfoVisibility } from '../../types/PatientInfoVisibility';
|
||||
function Header({
|
||||
children,
|
||||
menuOptions,
|
||||
isReturnEnabled,
|
||||
isReturnEnabled = true,
|
||||
onClickReturnButton,
|
||||
isSticky,
|
||||
isSticky = false,
|
||||
WhiteLabeling,
|
||||
showPatientInfo = PatientInfoVisibility.VISIBLE_COLLAPSED,
|
||||
servicesManager,
|
||||
@ -113,9 +113,4 @@ Header.propTypes = {
|
||||
servicesManager: PropTypes.object,
|
||||
};
|
||||
|
||||
Header.defaultProps = {
|
||||
isReturnEnabled: true,
|
||||
isSticky: false,
|
||||
};
|
||||
|
||||
export default Header;
|
||||
|
||||
@ -15,7 +15,7 @@ import { getKeys, formatKeysForInput } from './utils';
|
||||
* @param {string} props.className input classes
|
||||
* @param {Array[]} props.modifierKeys
|
||||
*/
|
||||
const HotkeyField = ({ disabled, keys, onChange, className, modifierKeys, hotkeys }) => {
|
||||
const HotkeyField = ({ disabled = false, keys, onChange, className, modifierKeys, hotkeys }) => {
|
||||
const inputValue = formatKeysForInput(keys);
|
||||
|
||||
const onInputKeyDown = event => {
|
||||
@ -58,8 +58,4 @@ HotkeyField.propTypes = {
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
HotkeyField.defaultProps = {
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export default HotkeyField;
|
||||
|
||||
@ -11,10 +11,10 @@ import { MODIFIER_KEYS } from './hotkeysConfig';
|
||||
import { validate, splitHotkeyDefinitionsAndCreateTuples } from './utils';
|
||||
|
||||
const HotkeysPreferences = ({
|
||||
disabled,
|
||||
disabled = false,
|
||||
hotkeyDefinitions,
|
||||
errors: controlledErrors,
|
||||
onChange,
|
||||
onChange = () => {},
|
||||
hotkeysModule,
|
||||
}) => {
|
||||
const { t } = useTranslation('UserPreferencesModal');
|
||||
@ -127,8 +127,6 @@ const HotkeysPreferences = ({
|
||||
);
|
||||
};
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
HotkeysPreferences.propTypes = {
|
||||
onChange: PropTypes.func,
|
||||
disabled: PropTypes.bool,
|
||||
@ -142,9 +140,4 @@ HotkeysPreferences.propTypes = {
|
||||
}).isRequired,
|
||||
};
|
||||
|
||||
HotkeysPreferences.defaultProps = {
|
||||
onChange: noop,
|
||||
disabled: false,
|
||||
};
|
||||
|
||||
export default HotkeysPreferences;
|
||||
|
||||
@ -1,179 +1,179 @@
|
||||
import React from 'react';
|
||||
// Icons
|
||||
|
||||
import arrowDown from './../../assets/icons/arrow-down.svg';
|
||||
import arrowLeft from './../../assets/icons/arrow-left.svg';
|
||||
import arrowRight from './../../assets/icons/arrow-right.svg';
|
||||
import arrowLeftSmall from './../../assets/icons/arrow-left-small.svg';
|
||||
import arrowRightSmall from './../../assets/icons/arrow-right-small.svg';
|
||||
import calendar from './../../assets/icons/calendar.svg';
|
||||
import cancel from './../../assets/icons/cancel.svg';
|
||||
import clipboard from './../../assets/icons/clipboard.svg';
|
||||
import close from './../../assets/icons/closeIcon.svg';
|
||||
import dottedCircle from './../../assets/icons/dotted-circle.svg';
|
||||
import circledCheckmark from './../../assets/icons/circled-checkmark.svg';
|
||||
import chevronDown from './../../assets/icons/chevron-down.svg';
|
||||
import chevronLeft from './../../assets/icons/chevron-left.svg';
|
||||
import chevronMenu from './../../assets/icons/chevron-menu.svg';
|
||||
import chevronNext from './../../assets/icons/chevron-next.svg';
|
||||
import chevronPrev from './../../assets/icons/chevron-prev.svg';
|
||||
import chevronRight from './../../assets/icons/chevron-right.svg';
|
||||
import contentNext from './../../assets/icons/content-next.svg';
|
||||
import contentPrev from './../../assets/icons/content-prev.svg';
|
||||
import eyeVisible from './../../assets/icons/eye-visible.svg';
|
||||
import eyeHidden from './../../assets/icons/eye-hidden.svg';
|
||||
import exclamation from './../../assets/icons/exclamation.svg';
|
||||
import externalLink from './../../assets/icons/external-link.svg';
|
||||
import groupLayers from './../../assets/icons/group-layers.svg';
|
||||
import info from './../../assets/icons/info.svg';
|
||||
import infoAction from './../../assets/icons/info-action.svg';
|
||||
import infoLink from './../../assets/icons/info-link.svg';
|
||||
import launchArrow from './../../assets/icons/launch-arrow.svg';
|
||||
import launchInfo from './../../assets/icons/launch-info.svg';
|
||||
import link from './../../assets/icons/tool-stack-image-sync.svg';
|
||||
import listBullets from './../../assets/icons/list-bullets.svg';
|
||||
import lock from './../../assets/icons/lock.svg';
|
||||
import logoOhifSmall from './../../assets/icons/logo-ohif-small.svg';
|
||||
import logoDarkBackGround from './../../assets/icons/ohif-logo-color-darkbg.svg';
|
||||
import magnifier from './../../assets/icons/magnifier.svg';
|
||||
import notificationwarningDiamond from './../../assets/icons/notificationwarning-diamond.svg';
|
||||
import pencil from './../../assets/icons/pencil.svg';
|
||||
import powerOff from './../../assets/icons/power-off.svg';
|
||||
import profile from './../../assets/icons/profile.svg';
|
||||
import pushLeft from './../../assets/icons/push-left.svg';
|
||||
import pushRight from './../../assets/icons/push-right.svg';
|
||||
import settings from './../../assets/icons/settings.svg';
|
||||
import sidePanelCloseLeft from './../../assets/icons/side-panel-close-left.svg';
|
||||
import sidePanelCloseRight from './../../assets/icons/side-panel-close-right.svg';
|
||||
import sorting from './../../assets/icons/sorting.svg';
|
||||
import sortingActiveDown from './../../assets/icons/sorting-active-down.svg';
|
||||
import sortingActiveUp from './../../assets/icons/sorting-active-up.svg';
|
||||
import statusAlertWarning from './../../assets/icons/status-alert-warning.svg';
|
||||
import statusAlert from './../../assets/icons/status-alert.svg';
|
||||
import statusLocked from './../../assets/icons/status-locked.svg';
|
||||
import statusTracked from './../../assets/icons/status-tracked.svg';
|
||||
import statusUntracked from './../../assets/icons/status-untracked.svg';
|
||||
import tracked from './../../assets/icons/tracked.svg';
|
||||
import unlink from './../../assets/icons/unlink.svg';
|
||||
import checkboxChecked from './../../assets/icons/checkbox-checked.svg';
|
||||
import checkboxUnchecked from './../../assets/icons/checkbox-unchecked.svg';
|
||||
import iconAlertOutline from './../../assets/icons/icons-alert-outline.svg';
|
||||
import iconAlertSmall from './../../assets/icons/icon-alert-small.svg';
|
||||
import iconClose from './../../assets/icons/icon-close.svg';
|
||||
import iconClearField from './../../assets/icons/icon-clear-field.svg';
|
||||
import iconNextInactive from './../../assets/icons/icon-next-inactive.svg';
|
||||
import iconNext from './../../assets/icons/icon-next.svg';
|
||||
import iconPlay from './../../assets/icons/icon-play.svg';
|
||||
import iconPause from './../../assets/icons/icon-pause.svg';
|
||||
import iconPrevInactive from './../../assets/icons/icon-prev-inactive.svg';
|
||||
import iconPrev from './../../assets/icons/icon-prev.svg';
|
||||
import iconSearch from './../../assets/icons/icon-search.svg';
|
||||
import iconStatusAlert from './../../assets/icons/icon-status-alert.svg';
|
||||
import iconTransferring from './../../assets/icons/icon-transferring.svg';
|
||||
import iconUpload from './../../assets/icons/icon-upload.svg';
|
||||
import navigationPanelRightHide from './../../assets/icons/navigation-panel-right-hide.svg';
|
||||
import navigationPanelRightReveal from './../../assets/icons/navigation-panel-right-reveal.svg';
|
||||
import tabLinear from './../../assets/icons/tab-linear.svg';
|
||||
import tabPatientInfo from './../../assets/icons/tab-patient-info.svg';
|
||||
import tabROIThreshold from './../../assets/icons/tab-roi-threshold.svg';
|
||||
import tabSegmentation from './../../assets/icons/tab-segmentation.svg';
|
||||
import tabStudies from './../../assets/icons/tab-studies.svg';
|
||||
import uiArrowDown from './../../assets/icons/ui-arrow-down.svg';
|
||||
import uiArrowUp from './../../assets/icons/ui-arrow-up.svg';
|
||||
import uiArrowLeft from './../../assets/icons/ui-arrow-left.svg';
|
||||
import uiArrowRight from './../../assets/icons/ui-arrow-right.svg';
|
||||
import loadingOHIFMark from './../../assets/icons/loading-ohif-mark.svg';
|
||||
import notificationsInfo from './../../assets/icons/notifications-info.svg';
|
||||
import notificationsWarning from './../../assets/icons/notifications-warning.svg';
|
||||
import notificationsError from './../../assets/icons/notifications-error.svg';
|
||||
import notificationsSuccess from './../../assets/icons/notifications-success.svg';
|
||||
import nextArrow from './../../assets/icons/next-arrow.svg';
|
||||
import prevArrow from './../../assets/icons/prev-arrow.svg';
|
||||
import viewportStatusTracked from './../../assets/icons/viewport-status-tracked.svg';
|
||||
import { ReactComponent as arrowDown } from './../../assets/icons/arrow-down.svg';
|
||||
import { ReactComponent as arrowLeft } from './../../assets/icons/arrow-left.svg';
|
||||
import { ReactComponent as arrowRight } from './../../assets/icons/arrow-right.svg';
|
||||
import { ReactComponent as arrowLeftSmall } from './../../assets/icons/arrow-left-small.svg';
|
||||
import { ReactComponent as arrowRightSmall } from './../../assets/icons/arrow-right-small.svg';
|
||||
import { ReactComponent as calendar } from './../../assets/icons/calendar.svg';
|
||||
import { ReactComponent as cancel } from './../../assets/icons/cancel.svg';
|
||||
import { ReactComponent as clipboard } from './../../assets/icons/clipboard.svg';
|
||||
import { ReactComponent as close } from './../../assets/icons/closeIcon.svg';
|
||||
import { ReactComponent as dottedCircle } from './../../assets/icons/dotted-circle.svg';
|
||||
import { ReactComponent as circledCheckmark } from './../../assets/icons/circled-checkmark.svg';
|
||||
import { ReactComponent as chevronDown } from './../../assets/icons/chevron-down.svg';
|
||||
import { ReactComponent as chevronLeft } from './../../assets/icons/chevron-left.svg';
|
||||
import { ReactComponent as chevronMenu } from './../../assets/icons/chevron-menu.svg';
|
||||
import { ReactComponent as chevronNext } from './../../assets/icons/chevron-next.svg';
|
||||
import { ReactComponent as chevronPrev } from './../../assets/icons/chevron-prev.svg';
|
||||
import { ReactComponent as chevronRight } from './../../assets/icons/chevron-right.svg';
|
||||
import { ReactComponent as contentNext } from './../../assets/icons/content-next.svg';
|
||||
import { ReactComponent as contentPrev } from './../../assets/icons/content-prev.svg';
|
||||
import { ReactComponent as eyeVisible } from './../../assets/icons/eye-visible.svg';
|
||||
import { ReactComponent as eyeHidden } from './../../assets/icons/eye-hidden.svg';
|
||||
import { ReactComponent as exclamation } from './../../assets/icons/exclamation.svg';
|
||||
import { ReactComponent as externalLink } from './../../assets/icons/external-link.svg';
|
||||
import { ReactComponent as groupLayers } from './../../assets/icons/group-layers.svg';
|
||||
import { ReactComponent as info } from './../../assets/icons/info.svg';
|
||||
import { ReactComponent as infoAction } from './../../assets/icons/info-action.svg';
|
||||
import { ReactComponent as infoLink } from './../../assets/icons/info-link.svg';
|
||||
import { ReactComponent as launchArrow } from './../../assets/icons/launch-arrow.svg';
|
||||
import { ReactComponent as launchInfo } from './../../assets/icons/launch-info.svg';
|
||||
import { ReactComponent as link } from './../../assets/icons/tool-stack-image-sync.svg';
|
||||
import { ReactComponent as listBullets } from './../../assets/icons/list-bullets.svg';
|
||||
import { ReactComponent as lock } from './../../assets/icons/lock.svg';
|
||||
import { ReactComponent as logoOhifSmall } from './../../assets/icons/logo-ohif-small.svg';
|
||||
import { ReactComponent as logoDarkBackGround } from './../../assets/icons/ohif-logo-color-darkbg.svg';
|
||||
import { ReactComponent as magnifier } from './../../assets/icons/magnifier.svg';
|
||||
import { ReactComponent as notificationwarningDiamond } from './../../assets/icons/notificationwarning-diamond.svg';
|
||||
import { ReactComponent as pencil } from './../../assets/icons/pencil.svg';
|
||||
import { ReactComponent as powerOff } from './../../assets/icons/power-off.svg';
|
||||
import { ReactComponent as profile } from './../../assets/icons/profile.svg';
|
||||
import { ReactComponent as pushLeft } from './../../assets/icons/push-left.svg';
|
||||
import { ReactComponent as pushRight } from './../../assets/icons/push-right.svg';
|
||||
import { ReactComponent as settings } from './../../assets/icons/settings.svg';
|
||||
import { ReactComponent as sidePanelCloseLeft } from './../../assets/icons/side-panel-close-left.svg';
|
||||
import { ReactComponent as sidePanelCloseRight } from './../../assets/icons/side-panel-close-right.svg';
|
||||
import { ReactComponent as sorting } from './../../assets/icons/sorting.svg';
|
||||
import { ReactComponent as sortingActiveDown } from './../../assets/icons/sorting-active-down.svg';
|
||||
import { ReactComponent as sortingActiveUp } from './../../assets/icons/sorting-active-up.svg';
|
||||
import { ReactComponent as statusAlertWarning } from './../../assets/icons/status-alert-warning.svg';
|
||||
import { ReactComponent as statusAlert } from './../../assets/icons/status-alert.svg';
|
||||
import { ReactComponent as statusLocked } from './../../assets/icons/status-locked.svg';
|
||||
import { ReactComponent as statusTracked } from './../../assets/icons/status-tracked.svg';
|
||||
import { ReactComponent as statusUntracked } from './../../assets/icons/status-untracked.svg';
|
||||
import { ReactComponent as tracked } from './../../assets/icons/tracked.svg';
|
||||
import { ReactComponent as unlink } from './../../assets/icons/unlink.svg';
|
||||
import { ReactComponent as checkboxChecked } from './../../assets/icons/checkbox-checked.svg';
|
||||
import { ReactComponent as checkboxUnchecked } from './../../assets/icons/checkbox-unchecked.svg';
|
||||
import { ReactComponent as iconAlertOutline } from './../../assets/icons/icons-alert-outline.svg';
|
||||
import { ReactComponent as iconAlertSmall } from './../../assets/icons/icon-alert-small.svg';
|
||||
import { ReactComponent as iconClose } from './../../assets/icons/icon-close.svg';
|
||||
import { ReactComponent as iconClearField } from './../../assets/icons/icon-clear-field.svg';
|
||||
import { ReactComponent as iconNextInactive } from './../../assets/icons/icon-next-inactive.svg';
|
||||
import { ReactComponent as iconNext } from './../../assets/icons/icon-next.svg';
|
||||
import { ReactComponent as iconPlay } from './../../assets/icons/icon-play.svg';
|
||||
import { ReactComponent as iconPause } from './../../assets/icons/icon-pause.svg';
|
||||
import { ReactComponent as iconPrevInactive } from './../../assets/icons/icon-prev-inactive.svg';
|
||||
import { ReactComponent as iconPrev } from './../../assets/icons/icon-prev.svg';
|
||||
import { ReactComponent as iconSearch } from './../../assets/icons/icon-search.svg';
|
||||
import { ReactComponent as iconStatusAlert } from './../../assets/icons/icon-status-alert.svg';
|
||||
import { ReactComponent as iconTransferring } from './../../assets/icons/icon-transferring.svg';
|
||||
import { ReactComponent as iconUpload } from './../../assets/icons/icon-upload.svg';
|
||||
import { ReactComponent as navigationPanelRightHide } from './../../assets/icons/navigation-panel-right-hide.svg';
|
||||
import { ReactComponent as navigationPanelRightReveal } from './../../assets/icons/navigation-panel-right-reveal.svg';
|
||||
import { ReactComponent as tabLinear } from './../../assets/icons/tab-linear.svg';
|
||||
import { ReactComponent as tabPatientInfo } from './../../assets/icons/tab-patient-info.svg';
|
||||
import { ReactComponent as tabROIThreshold } from './../../assets/icons/tab-roi-threshold.svg';
|
||||
import { ReactComponent as tabSegmentation } from './../../assets/icons/tab-segmentation.svg';
|
||||
import { ReactComponent as tabStudies } from './../../assets/icons/tab-studies.svg';
|
||||
import { ReactComponent as uiArrowDown } from './../../assets/icons/ui-arrow-down.svg';
|
||||
import { ReactComponent as uiArrowUp } from './../../assets/icons/ui-arrow-up.svg';
|
||||
import { ReactComponent as uiArrowLeft } from './../../assets/icons/ui-arrow-left.svg';
|
||||
import { ReactComponent as uiArrowRight } from './../../assets/icons/ui-arrow-right.svg';
|
||||
import { ReactComponent as loadingOHIFMark } from './../../assets/icons/loading-ohif-mark.svg';
|
||||
import { ReactComponent as notificationsInfo } from './../../assets/icons/notifications-info.svg';
|
||||
import { ReactComponent as notificationsWarning } from './../../assets/icons/notifications-warning.svg';
|
||||
import { ReactComponent as notificationsError } from './../../assets/icons/notifications-error.svg';
|
||||
import { ReactComponent as notificationsSuccess } from './../../assets/icons/notifications-success.svg';
|
||||
import { ReactComponent as nextArrow } from './../../assets/icons/next-arrow.svg';
|
||||
import { ReactComponent as prevArrow } from './../../assets/icons/prev-arrow.svg';
|
||||
import { ReactComponent as viewportStatusTracked } from './../../assets/icons/viewport-status-tracked.svg';
|
||||
import { ReactComponent as toggleDicomOverlay } from './../../assets/icons/tool-toggle-dicom-overlay.svg';
|
||||
import { ReactComponent as toolZoom } from './../../assets/icons/tool-zoom.svg';
|
||||
import { ReactComponent as toolCapture } from './../../assets/icons/tool-capture.svg';
|
||||
import { ReactComponent as toolLayout } from './../../assets/icons/tool-layout-default.svg';
|
||||
import { ReactComponent as toolMore } from './../../assets/icons/tool-more-menu.svg';
|
||||
import { ReactComponent as toolMove } from './../../assets/icons/tool-move.svg';
|
||||
import { ReactComponent as toolWindow } from './../../assets/icons/tool-window-level.svg';
|
||||
import { ReactComponent as toolAnnotate } from './../../assets/icons/tool-annotate.svg';
|
||||
import { ReactComponent as toolBidirectional } from './../../assets/icons/tool-bidirectional.svg';
|
||||
import { ReactComponent as toolElipse } from './../../assets/icons/tool-measure-elipse.svg';
|
||||
import { ReactComponent as toolCircle } from './../../assets/icons/tool-circle.svg';
|
||||
import { ReactComponent as toolLength } from './../../assets/icons/tool-length.svg';
|
||||
import { ReactComponent as toolStackScroll } from './../../assets/icons/tool-stack-scroll.svg';
|
||||
import { ReactComponent as toolMagnify } from './../../assets/icons/tool-quick-magnify.svg';
|
||||
import { ReactComponent as toolFlipHorizontal } from './../../assets/icons/tool-flip-horizontal.svg';
|
||||
import { ReactComponent as toolInvert } from './../../assets/icons/tool-invert.svg';
|
||||
import { ReactComponent as toolRotateRight } from './../../assets/icons/tool-rotate-right.svg';
|
||||
import { ReactComponent as toolCine } from './../../assets/icons/tool-cine.svg';
|
||||
import { ReactComponent as toolCrosshair } from './../../assets/icons/tool-crosshair.svg';
|
||||
import { ReactComponent as toolProbe } from './../../assets/icons/focus-frame-target.svg';
|
||||
import { ReactComponent as toolAngle } from './../../assets/icons/tool-angle.svg';
|
||||
import { ReactComponent as toolReset } from './../../assets/icons/tool-reset.svg';
|
||||
import { ReactComponent as toolRectangle } from './../../assets/icons/tool-rectangle.svg';
|
||||
import { ReactComponent as toolFusionColor } from './../../assets/icons/tool-fusion-color.svg';
|
||||
import { ReactComponent as toolCreateThreshold } from './../../assets/icons/tool-create-threshold.svg';
|
||||
import { ReactComponent as toolCalibration } from './../../assets/icons/tool-calibrate.svg';
|
||||
import { ReactComponent as toolFreehand } from './../../assets/icons/tool-freehand.svg';
|
||||
import { ReactComponent as toolFreehandPolygon } from './../../assets/icons/tool-freehand-polygon.svg';
|
||||
import { ReactComponent as toolPolygon } from './../../assets/icons/tool-polygon.svg';
|
||||
import { ReactComponent as editPatient } from './../../assets/icons/edit-patient.svg';
|
||||
import { ReactComponent as panelGroupMore } from './../../assets/icons/panel-group-more.svg';
|
||||
import { ReactComponent as panelGroupOpenClose } from './../../assets/icons/panel-group-open-close.svg';
|
||||
import { ReactComponent as rowAdd } from './../../assets/icons/row-add.svg';
|
||||
import { ReactComponent as rowEdit } from './../../assets/icons/row-edit.svg';
|
||||
import { ReactComponent as rowHidden } from './../../assets/icons/row-hidden.svg';
|
||||
import { ReactComponent as rowShown } from './../../assets/icons/row-shown.svg';
|
||||
import { ReactComponent as rowLock } from './../../assets/icons/row-lock.svg';
|
||||
import { ReactComponent as rowUnlock } from './../../assets/icons/row-unlock.svg';
|
||||
import { ReactComponent as iconMPR } from './../../assets/icons/icon-mpr-alt.svg';
|
||||
import { ReactComponent as checkboxDefault } from './../../assets/icons/checkbox-default.svg';
|
||||
import { ReactComponent as checkboxActive } from './../../assets/icons/checkbox-active.svg';
|
||||
import { ReactComponent as referenceLines } from './../../assets/icons/tool-reference-lines.svg';
|
||||
import { ReactComponent as chevronDownNew } from './../../assets/icons/icon-disclosure-close.svg';
|
||||
import { ReactComponent as chevronLeftNew } from './../../assets/icons/icon-disclosure-open.svg';
|
||||
import { ReactComponent as settingsBars } from './../../assets/icons/icon-display-settings.svg';
|
||||
import { ReactComponent as iconAdd } from './../../assets/icons/icon-add.svg';
|
||||
import { ReactComponent as iconRename } from './../../assets/icons/icon-rename.svg';
|
||||
import { ReactComponent as iconDelete } from './../../assets/icons/icon-delete.svg';
|
||||
import { ReactComponent as iconMoreMenu } from './../../assets/icons/icon-more-menu.svg';
|
||||
import { ReactComponent as iconToolBrush } from './../../assets/icons/tool-seg-brush.svg';
|
||||
import { ReactComponent as iconToolEraser } from './../../assets/icons/tool-seg-eraser.svg';
|
||||
import { ReactComponent as iconToolScissor } from './../../assets/icons/icon-tool-scissor.svg';
|
||||
import { ReactComponent as iconToolShape } from './../../assets/icons/tool-seg-shape.svg';
|
||||
import { ReactComponent as iconToolThreshold } from './../../assets/icons/tool-seg-threshold.svg';
|
||||
import { ReactComponent as viewportWindowLevel } from './../../assets/icons/viewport-window-level.svg';
|
||||
import { ReactComponent as dicomTagBrowser } from './../../assets/icons/tool-dicom-tag-browser.svg';
|
||||
import { ReactComponent as iconToolFreehandRoi } from './../../assets/icons/tool-freehand-roi.svg';
|
||||
import { ReactComponent as iconToolLivewire } from './../../assets/icons/tool-magnetic-roi.svg';
|
||||
import { ReactComponent as iconToolSplineRoi } from './../../assets/icons/tool-spline-roi.svg';
|
||||
import { ReactComponent as iconToolUltrasoundBidirectional } from './../../assets/icons/tool-ultrasound-bidirectional.svg';
|
||||
import { ReactComponent as iconToolLoupe } from './../../assets/icons/tool-magnify.svg';
|
||||
import { ReactComponent as oldTrash } from './../../assets/icons/old-trash.svg';
|
||||
import { ReactComponent as oldPlay } from './../../assets/icons/old-play.svg';
|
||||
import { ReactComponent as oldStop } from './../../assets/icons/old-stop.svg';
|
||||
import { ReactComponent as iconColorLUT } from './../../assets/icons/icon-color-lut.svg';
|
||||
import { ReactComponent as iconChevronPatient } from './../../assets/icons/icon-chevron-patient.svg';
|
||||
import { ReactComponent as iconPatient } from './../../assets/icons/icon-patient.svg';
|
||||
import { ReactComponent as iconSettings } from './../../assets/icons/icon-settings.svg';
|
||||
import { ReactComponent as iconToolbarBack } from './../../assets/icons/icon-toolbar-back.svg';
|
||||
import { ReactComponent as iconMultiplePatients } from './../../assets/icons/icon-multiple-patients.svg';
|
||||
import { ReactComponent as layoutAdvanced3DFourUp } from './../../assets/icons/layout-advanced-3d-four-up.svg';
|
||||
import { ReactComponent as layoutAdvanced3DMain } from './../../assets/icons/layout-advanced-3d-main.svg';
|
||||
import { ReactComponent as layoutAdvanced3DOnly } from './../../assets/icons/layout-advanced-3d-only.svg';
|
||||
import { ReactComponent as layoutAdvanced3DPrimary } from './../../assets/icons/layout-advanced-3d-primary.svg';
|
||||
import { ReactComponent as layoutAdvancedAxialPrimary } from './../../assets/icons/layout-advanced-axial-primary.svg';
|
||||
import { ReactComponent as layoutAdvancedMPR } from './../../assets/icons/layout-advanced-mpr.svg';
|
||||
import { ReactComponent as layoutCommon1x1 } from './../../assets/icons/layout-common-1x1.svg';
|
||||
import { ReactComponent as layoutCommon1x2 } from './../../assets/icons/layout-common-1x2.svg';
|
||||
import { ReactComponent as layoutCommon2x2 } from './../../assets/icons/layout-common-2x2.svg';
|
||||
import { ReactComponent as layoutCommon2x3 } from './../../assets/icons/layout-common-2x3.svg';
|
||||
import { ReactComponent as iconToolRotate } from './../../assets/icons/tool-3d-rotate.svg';
|
||||
import { ReactComponent as tab4D } from './../../assets/icons/tab-4d.svg';
|
||||
import { ReactComponent as investigationalUse } from './../../assets/icons/illustration-investigational-use.svg';
|
||||
import { ReactComponent as actionNewDialog } from './../../assets/icons/action-new-dialog.svg';
|
||||
|
||||
/** Tools */
|
||||
import toggleDicomOverlay from './../../assets/icons/tool-toggle-dicom-overlay.svg';
|
||||
import toolZoom from './../../assets/icons/tool-zoom.svg';
|
||||
import toolCapture from './../../assets/icons/tool-capture.svg';
|
||||
import toolLayout from './../../assets/icons/tool-layout-default.svg';
|
||||
import toolMore from './../../assets/icons/tool-more-menu.svg';
|
||||
import toolMove from './../../assets/icons/tool-move.svg';
|
||||
import toolWindow from './../../assets/icons/tool-window-level.svg';
|
||||
import toolAnnotate from './../../assets/icons/tool-annotate.svg';
|
||||
import toolBidirectional from './../../assets/icons/tool-bidirectional.svg';
|
||||
import toolElipse from './../../assets/icons/tool-measure-elipse.svg';
|
||||
import toolCircle from './../../assets/icons/tool-circle.svg';
|
||||
import toolLength from './../../assets/icons/tool-length.svg';
|
||||
import toolStackScroll from './../../assets/icons/tool-stack-scroll.svg';
|
||||
import toolMagnify from './../../assets/icons/tool-quick-magnify.svg';
|
||||
import toolFlipHorizontal from './../../assets/icons/tool-flip-horizontal.svg';
|
||||
import toolInvert from './../../assets/icons/tool-invert.svg';
|
||||
import toolRotateRight from './../../assets/icons/tool-rotate-right.svg';
|
||||
import toolCine from './../../assets/icons/tool-cine.svg';
|
||||
import toolCrosshair from './../../assets/icons/tool-crosshair.svg';
|
||||
import toolProbe from './../../assets/icons/focus-frame-target.svg';
|
||||
import toolAngle from './../../assets/icons/tool-angle.svg';
|
||||
import toolReset from './../../assets/icons/tool-reset.svg';
|
||||
import toolRectangle from './../../assets/icons/tool-rectangle.svg';
|
||||
import toolFusionColor from './../../assets/icons/tool-fusion-color.svg';
|
||||
import toolCreateThreshold from './../../assets/icons/tool-create-threshold.svg';
|
||||
import toolCalibration from './../../assets/icons/tool-calibrate.svg';
|
||||
import toolFreehand from './../../assets/icons/tool-freehand.svg';
|
||||
import toolFreehandPolygon from './../../assets/icons/tool-freehand-polygon.svg';
|
||||
import toolPolygon from './../../assets/icons/tool-polygon.svg';
|
||||
import toolBrush from './../../assets/icons/tool-brush.svg';
|
||||
import toolEraser from './../../assets/icons/tool-eraser.svg';
|
||||
import toolScissorRect from './../../assets/icons/tool-scissor-rect.svg';
|
||||
import toolScissorCircle from './../../assets/icons/tool-scissor-circle.svg';
|
||||
import toolPaintFill from './../../assets/icons/tool-paint-fill.svg';
|
||||
import editPatient from './../../assets/icons/edit-patient.svg';
|
||||
import panelGroupMore from './../../assets/icons/panel-group-more.svg';
|
||||
import panelGroupOpenClose from './../../assets/icons/panel-group-open-close.svg';
|
||||
import rowAdd from './../../assets/icons/row-add.svg';
|
||||
import rowEdit from './../../assets/icons/row-edit.svg';
|
||||
import rowHidden from './../../assets/icons/row-hidden.svg';
|
||||
import rowShown from './../../assets/icons/row-shown.svg';
|
||||
import rowLock from './../../assets/icons/row-lock.svg';
|
||||
import rowUnlock from './../../assets/icons/row-unlock.svg';
|
||||
import iconMPR from './../../assets/icons/icon-mpr-alt.svg';
|
||||
import checkboxDefault from './../../assets/icons/checkbox-default.svg';
|
||||
import checkboxActive from './../../assets/icons/checkbox-active.svg';
|
||||
import referenceLines from './../../assets/icons/tool-reference-lines.svg';
|
||||
import chevronDownNew from './../../assets/icons/icon-disclosure-close.svg';
|
||||
import chevronLeftNew from './../../assets/icons/icon-disclosure-open.svg';
|
||||
import settingsBars from './../../assets/icons/icon-display-settings.svg';
|
||||
import iconAdd from './../../assets/icons/icon-add.svg';
|
||||
import iconRename from './../../assets/icons/icon-rename.svg';
|
||||
import iconDelete from './../../assets/icons/icon-delete.svg';
|
||||
import iconMoreMenu from './../../assets/icons/icon-more-menu.svg';
|
||||
import iconToolBrush from './../../assets/icons/tool-seg-brush.svg';
|
||||
import iconToolEraser from './../../assets/icons/tool-seg-eraser.svg';
|
||||
import iconToolScissor from './../../assets/icons/icon-tool-scissor.svg';
|
||||
import iconToolShape from './../../assets/icons/tool-seg-shape.svg';
|
||||
import iconToolThreshold from './../../assets/icons/tool-seg-threshold.svg';
|
||||
import viewportWindowLevel from './../../assets/icons/viewport-window-level.svg';
|
||||
import dicomTagBrowser from './../../assets/icons/tool-dicom-tag-browser.svg';
|
||||
import iconToolFreehandRoi from './../../assets/icons/tool-freehand-roi.svg';
|
||||
import iconToolLivewire from './../../assets/icons/tool-magnetic-roi.svg';
|
||||
import iconToolSplineRoi from './../../assets/icons/tool-spline-roi.svg';
|
||||
import iconToolUltrasoundBidirectional from './../../assets/icons/tool-ultrasound-bidirectional.svg';
|
||||
import iconToolLoupe from './../../assets/icons/tool-magnify.svg';
|
||||
/** Old OHIF */
|
||||
import oldTrash from './../../assets/icons/old-trash.svg';
|
||||
import oldPlay from './../../assets/icons/old-play.svg';
|
||||
import oldStop from './../../assets/icons/old-stop.svg';
|
||||
|
||||
/** ColorLut */
|
||||
import iconColorLUT from './../../assets/icons/icon-color-lut.svg';
|
||||
|
||||
/** New Patient Info Toolbar */
|
||||
import iconChevronPatient from './../../assets/icons/icon-chevron-patient.svg';
|
||||
import iconPatient from './../../assets/icons/icon-patient.svg';
|
||||
import iconSettings from './../../assets/icons/icon-settings.svg';
|
||||
import iconToolbarBack from './../../assets/icons/icon-toolbar-back.svg';
|
||||
import iconMultiplePatients from './../../assets/icons/icon-multiple-patients.svg';
|
||||
|
||||
/** Volume Rendering */
|
||||
import CTAAA from './../../assets/icons/CT-AAA.png';
|
||||
import CTAAA2 from './../../assets/icons/CT-AAA2.png';
|
||||
import CTAir from './../../assets/icons/CT-Air.png';
|
||||
@ -201,27 +201,6 @@ import MRDefault from './../../assets/icons/MR-Default.png';
|
||||
import MRMIP from './../../assets/icons/MR-MIP.png';
|
||||
import MRT2Brain from './../../assets/icons/MR-T2-Brain.png';
|
||||
import VolumeRendering from './../../assets/icons/VolumeRendering.png';
|
||||
import actionNewDialog from './../../assets/icons/action-new-dialog.svg';
|
||||
|
||||
/** LAYOUT */
|
||||
|
||||
import layoutAdvanced3DFourUp from './../../assets/icons/layout-advanced-3d-four-up.svg';
|
||||
import layoutAdvanced3DMain from './../../assets/icons/layout-advanced-3d-main.svg';
|
||||
import layoutAdvanced3DOnly from './../../assets/icons/layout-advanced-3d-only.svg';
|
||||
import layoutAdvanced3DPrimary from './../../assets/icons/layout-advanced-3d-primary.svg';
|
||||
import layoutAdvancedAxialPrimary from './../../assets/icons/layout-advanced-axial-primary.svg';
|
||||
import layoutAdvancedMPR from './../../assets/icons/layout-advanced-mpr.svg';
|
||||
import layoutCommon1x1 from './../../assets/icons/layout-common-1x1.svg';
|
||||
import layoutCommon1x2 from './../../assets/icons/layout-common-1x2.svg';
|
||||
import layoutCommon2x2 from './../../assets/icons/layout-common-2x2.svg';
|
||||
import layoutCommon2x3 from './../../assets/icons/layout-common-2x3.svg';
|
||||
import iconToolRotate from './../../assets/icons/tool-3d-rotate.svg';
|
||||
|
||||
//
|
||||
import tab4D from './../../assets/icons/tab-4d.svg';
|
||||
|
||||
/** New investigational use */
|
||||
import investigationalUse from './../../assets/icons/illustration-investigational-use.svg';
|
||||
|
||||
const ICONS = {
|
||||
'arrow-down': arrowDown,
|
||||
|
||||
@ -74,14 +74,14 @@ const fullWidthClasses = {
|
||||
|
||||
const IconButton = ({
|
||||
children,
|
||||
variant,
|
||||
color,
|
||||
size,
|
||||
rounded,
|
||||
disabled,
|
||||
type,
|
||||
fullWidth,
|
||||
onClick,
|
||||
variant = 'contained',
|
||||
color = 'default',
|
||||
size = 'medium',
|
||||
rounded = 'medium',
|
||||
disabled = false,
|
||||
type = 'button',
|
||||
fullWidth = false,
|
||||
onClick = () => {},
|
||||
className,
|
||||
id,
|
||||
...rest
|
||||
@ -122,17 +122,6 @@ const IconButton = ({
|
||||
);
|
||||
};
|
||||
|
||||
IconButton.defaultProps = {
|
||||
onClick: () => {},
|
||||
color: 'default',
|
||||
disabled: false,
|
||||
fullWidth: false,
|
||||
rounded: 'medium',
|
||||
size: 'medium',
|
||||
type: 'button',
|
||||
variant: 'contained',
|
||||
};
|
||||
|
||||
IconButton.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
size: PropTypes.oneOf(['small', 'medium', 'large', 'initial', 'toolbar', 'toolbox']),
|
||||
|
||||
@ -20,10 +20,12 @@ class ImageScrollbar extends PureComponent {
|
||||
width: `${this.props.height}`,
|
||||
};
|
||||
|
||||
const { onContextMenu = e => e.preventDefault() } = this.props;
|
||||
|
||||
return (
|
||||
<div
|
||||
className="scroll"
|
||||
onContextMenu={this.props.onContextMenu}
|
||||
onContextMenu={onContextMenu}
|
||||
>
|
||||
<div className="scroll-holder">
|
||||
<input
|
||||
@ -70,8 +72,4 @@ class ImageScrollbar extends PureComponent {
|
||||
};
|
||||
}
|
||||
|
||||
ImageScrollbar.defaultProps = {
|
||||
onContextMenu: e => e.preventDefault(),
|
||||
};
|
||||
|
||||
export default ImageScrollbar;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user