feat(app): Decouple colorbar UI from service and enable action menu programatic control (#5018)
This commit is contained in:
1 parent
f14d9ebdd7
commit
1445e12124
41 files changed
+1872
-659
No files matched your search
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
import React, {
|
||||
createContext,
|
||||
useContext,
|
||||
ReactNode,
|
||||
useState,
|
||||
useEffect,
|
||||
useCallback,
|
||||
} from 'react';
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
/**
|
||||
* A small container that can render multiple "corner" items (like icons, status)
|
||||
* in each corner of the viewport: top-left, top-right, bottom-left, bottom-right.
|
||||
*/
|
||||
export enum ViewportActionCornersLocations {
|
||||
topLeft,
|
||||
topRight,
|
||||
@@ -33,35 +35,102 @@ const locationClasses = {
|
||||
),
|
||||
};
|
||||
|
||||
function ViewportActionCorners({ cornerComponents }) {
|
||||
if (!cornerComponents) {
|
||||
return null;
|
||||
}
|
||||
const ViewportActionCornersContext = createContext<{
|
||||
registerCorner: (location: ViewportActionCornersLocations, children: ReactNode) => void;
|
||||
} | null>(null);
|
||||
|
||||
function Container({ children }: { children: ReactNode }) {
|
||||
const [corners, setCorners] = useState({
|
||||
[ViewportActionCornersLocations.topLeft]: null,
|
||||
[ViewportActionCornersLocations.topRight]: null,
|
||||
[ViewportActionCornersLocations.bottomLeft]: null,
|
||||
[ViewportActionCornersLocations.bottomRight]: null,
|
||||
});
|
||||
|
||||
const registerCorner = useCallback(
|
||||
(location: ViewportActionCornersLocations, children: ReactNode) => {
|
||||
setCorners(prev => {
|
||||
// Only update if the children are different to avoid unnecessary renders
|
||||
if (prev[location] === children) {
|
||||
return prev;
|
||||
}
|
||||
return {
|
||||
...prev,
|
||||
[location]: children,
|
||||
};
|
||||
});
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
className="pointer-events-none absolute h-full w-full select-none"
|
||||
onDoubleClick={event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{Object.entries(cornerComponents).map(([location, locationArray]) => (
|
||||
<div
|
||||
key={location}
|
||||
className={locationClasses[location]}
|
||||
>
|
||||
{locationArray.map(componentInfo => (
|
||||
<div key={componentInfo.id}>{componentInfo.component}</div>
|
||||
))}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<ViewportActionCornersContext.Provider value={{ registerCorner }}>
|
||||
{children}
|
||||
<div
|
||||
className="pointer-events-none absolute h-full w-full select-none"
|
||||
onDoubleClick={event => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}}
|
||||
>
|
||||
{Object.entries(corners).map(([location, children]) => {
|
||||
if (!children) {
|
||||
return null;
|
||||
}
|
||||
return (
|
||||
<div
|
||||
key={location}
|
||||
className={locationClasses[location]}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</ViewportActionCornersContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
ViewportActionCorners.propTypes = {
|
||||
cornerComponents: PropTypes.object.isRequired,
|
||||
};
|
||||
function Corner({
|
||||
location,
|
||||
children,
|
||||
}: {
|
||||
location: ViewportActionCornersLocations;
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const context = useContext(ViewportActionCornersContext);
|
||||
|
||||
export { ViewportActionCorners };
|
||||
if (!context) {
|
||||
throw new Error('Corner component must be used within a ViewportActionCorners.Container');
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
context.registerCorner(location, children);
|
||||
}, [context, location, children]);
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
function TopLeft({ children }: { children: ReactNode }) {
|
||||
return <Corner location={ViewportActionCornersLocations.topLeft}>{children}</Corner>;
|
||||
}
|
||||
|
||||
function TopRight({ children }: { children: ReactNode }) {
|
||||
return <Corner location={ViewportActionCornersLocations.topRight}>{children}</Corner>;
|
||||
}
|
||||
|
||||
function BottomLeft({ children }: { children: ReactNode }) {
|
||||
return <Corner location={ViewportActionCornersLocations.bottomLeft}>{children}</Corner>;
|
||||
}
|
||||
|
||||
function BottomRight({ children }: { children: ReactNode }) {
|
||||
return <Corner location={ViewportActionCornersLocations.bottomRight}>{children}</Corner>;
|
||||
}
|
||||
|
||||
export const ViewportActionCorners = {
|
||||
Container,
|
||||
TopLeft,
|
||||
TopRight,
|
||||
BottomLeft,
|
||||
BottomRight,
|
||||
};
|
||||
@@ -0,0 +1,550 @@
|
||||
import React, {
|
||||
createContext,
|
||||
useCallback,
|
||||
useContext,
|
||||
useEffect,
|
||||
useReducer,
|
||||
ReactNode,
|
||||
useMemo,
|
||||
} from 'react';
|
||||
import { ViewportActionCornersLocations } from '../components/Viewport/ViewportActionCorners';
|
||||
import { ActionComponentInfo, AlignAndSide } from '../types';
|
||||
|
||||
const DEFAULT_STATE = {
|
||||
viewports: {} as Record<string, Record<ViewportActionCornersLocations, ActionComponentInfo[]>>,
|
||||
};
|
||||
|
||||
/**
|
||||
* API for managing viewport action corner items.
|
||||
* These methods control the state and behavior of the corner items themselves,
|
||||
* not the content they might affect in the viewport.
|
||||
*/
|
||||
interface ViewportActionCornersApi {
|
||||
getState: () => typeof DEFAULT_STATE;
|
||||
addComponent: (component: ActionComponentInfo) => void;
|
||||
addComponents: (components: Array<ActionComponentInfo>) => void;
|
||||
clear: (viewportId: string) => void;
|
||||
getAlignAndSide: (location: ViewportActionCornersLocations) => AlignAndSide;
|
||||
lockItem: (viewportId: string, itemId: string) => void;
|
||||
unlockItem: (viewportId: string, itemId: string) => void;
|
||||
toggleLock: (viewportId: string, itemId: string) => void;
|
||||
isItemLocked: (viewportId: string, itemId: string) => boolean;
|
||||
showItem: (viewportId: string, itemId: string) => void;
|
||||
hideItem: (viewportId: string, itemId: string) => void;
|
||||
toggleVisibility: (viewportId: string, itemId: string) => void;
|
||||
isItemVisible: (viewportId: string, itemId: string) => boolean;
|
||||
openItem: (viewportId: string, itemId: string) => void;
|
||||
closeItem: (viewportId: string, itemId: string) => void;
|
||||
closeAllItems: (viewportId: string) => void;
|
||||
isItemOpen: (viewportId: string, itemId: string) => boolean;
|
||||
}
|
||||
|
||||
export const ViewportActionCornersContext = createContext<
|
||||
[typeof DEFAULT_STATE, ViewportActionCornersApi]
|
||||
>([DEFAULT_STATE, {} as ViewportActionCornersApi]);
|
||||
|
||||
interface ViewportActionCornersProviderProps {
|
||||
children: ReactNode;
|
||||
service: any;
|
||||
}
|
||||
|
||||
export function ViewportActionCornersProvider({
|
||||
children,
|
||||
service,
|
||||
}: ViewportActionCornersProviderProps) {
|
||||
const viewportActionCornersReducer = (state = DEFAULT_STATE, action) => {
|
||||
switch (action.type) {
|
||||
case 'ADD_COMPONENT': {
|
||||
const { viewportId, id, component, location, indexPriority = 0 } = action.payload;
|
||||
|
||||
const newState = { ...state };
|
||||
|
||||
if (!newState.viewports[viewportId]) {
|
||||
newState.viewports[viewportId] = {
|
||||
[ViewportActionCornersLocations.topLeft]: [],
|
||||
[ViewportActionCornersLocations.topRight]: [],
|
||||
[ViewportActionCornersLocations.bottomLeft]: [],
|
||||
[ViewportActionCornersLocations.bottomRight]: [],
|
||||
};
|
||||
}
|
||||
|
||||
if (!newState.viewports[viewportId][location]) {
|
||||
newState.viewports[viewportId][location] = [];
|
||||
}
|
||||
|
||||
const componentInfo = {
|
||||
id,
|
||||
component,
|
||||
indexPriority,
|
||||
isOpen: false,
|
||||
isVisible: true,
|
||||
isLocked: false,
|
||||
};
|
||||
|
||||
const components = [...newState.viewports[viewportId][location]];
|
||||
const index = components.findIndex(item => item.indexPriority > indexPriority);
|
||||
|
||||
if (index === -1) {
|
||||
components.push(componentInfo);
|
||||
} else {
|
||||
components.splice(index, 0, componentInfo);
|
||||
}
|
||||
|
||||
newState.viewports[viewportId][location] = components;
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
case 'ADD_COMPONENTS': {
|
||||
const components = action.payload;
|
||||
let newState = { ...state };
|
||||
|
||||
components.forEach(component => {
|
||||
newState = viewportActionCornersReducer(newState, {
|
||||
type: 'ADD_COMPONENT',
|
||||
payload: component,
|
||||
});
|
||||
});
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
case 'CLEAR': {
|
||||
const viewportId = action.payload;
|
||||
const newState = { ...state };
|
||||
|
||||
if (newState.viewports[viewportId]) {
|
||||
const newViewports = { ...newState.viewports };
|
||||
delete newViewports[viewportId];
|
||||
newState.viewports = newViewports;
|
||||
}
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
case 'SET_LOCKED': {
|
||||
const { viewportId, itemId, lockedStatus } = action.payload;
|
||||
const newState = { ...state };
|
||||
|
||||
if (!newState.viewports[viewportId]) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const viewportCopy = { ...newState.viewports[viewportId] };
|
||||
|
||||
Object.keys(viewportCopy).forEach(locationKey => {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = [...viewportCopy[location]];
|
||||
|
||||
const itemIndex = components.findIndex(item => item.id === itemId);
|
||||
if (itemIndex !== -1) {
|
||||
const updatedItem = { ...components[itemIndex], isLocked: lockedStatus };
|
||||
components[itemIndex] = updatedItem;
|
||||
viewportCopy[location] = components;
|
||||
}
|
||||
});
|
||||
|
||||
newState.viewports[viewportId] = viewportCopy;
|
||||
return newState;
|
||||
}
|
||||
|
||||
case 'SET_VISIBLE': {
|
||||
const { viewportId, itemId, visibleStatus } = action.payload;
|
||||
const newState = { ...state };
|
||||
|
||||
if (!newState.viewports[viewportId]) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const viewportCopy = { ...newState.viewports[viewportId] };
|
||||
|
||||
Object.keys(viewportCopy).forEach(locationKey => {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = [...viewportCopy[location]];
|
||||
|
||||
const itemIndex = components.findIndex(item => item.id === itemId);
|
||||
if (itemIndex !== -1) {
|
||||
const updatedItem = { ...components[itemIndex], isVisible: visibleStatus };
|
||||
components[itemIndex] = updatedItem;
|
||||
viewportCopy[location] = components;
|
||||
}
|
||||
});
|
||||
|
||||
newState.viewports[viewportId] = viewportCopy;
|
||||
return newState;
|
||||
}
|
||||
|
||||
case 'OPEN_ITEM': {
|
||||
const { viewportId, itemId } = action.payload;
|
||||
const newState = { ...state };
|
||||
|
||||
if (!newState.viewports[viewportId]) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const viewportCopy = { ...newState.viewports[viewportId] };
|
||||
|
||||
// Update isOpen flag for the component with matching id in any location
|
||||
Object.keys(viewportCopy).forEach(locationKey => {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = [...viewportCopy[location]];
|
||||
|
||||
const itemIndex = components.findIndex(item => item.id === itemId);
|
||||
if (itemIndex !== -1) {
|
||||
const updatedItem = { ...components[itemIndex], isOpen: true };
|
||||
components[itemIndex] = updatedItem;
|
||||
viewportCopy[location] = components;
|
||||
}
|
||||
});
|
||||
|
||||
newState.viewports[viewportId] = viewportCopy;
|
||||
return newState;
|
||||
}
|
||||
|
||||
case 'CLOSE_ITEM': {
|
||||
const { viewportId, itemId } = action.payload;
|
||||
const newState = { ...state };
|
||||
|
||||
if (!newState.viewports[viewportId]) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const viewportCopy = { ...newState.viewports[viewportId] };
|
||||
|
||||
// Update isOpen flag for the component with matching id in any location
|
||||
Object.keys(viewportCopy).forEach(locationKey => {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = [...viewportCopy[location]];
|
||||
|
||||
const itemIndex = components.findIndex(item => item.id === itemId);
|
||||
if (itemIndex !== -1) {
|
||||
const updatedItem = { ...components[itemIndex], isOpen: false };
|
||||
components[itemIndex] = updatedItem;
|
||||
viewportCopy[location] = components;
|
||||
}
|
||||
});
|
||||
|
||||
newState.viewports[viewportId] = viewportCopy;
|
||||
return newState;
|
||||
}
|
||||
|
||||
case 'CLOSE_ALL_ITEMS': {
|
||||
const viewportId = action.payload;
|
||||
const newState = { ...state };
|
||||
|
||||
if (!newState.viewports[viewportId]) {
|
||||
return state;
|
||||
}
|
||||
|
||||
const viewportCopy = { ...newState.viewports[viewportId] };
|
||||
|
||||
// Set isOpen to false for all components in the viewport
|
||||
Object.keys(viewportCopy).forEach(locationKey => {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = viewportCopy[location].map(item => ({
|
||||
...item,
|
||||
isOpen: false,
|
||||
}));
|
||||
|
||||
viewportCopy[location] = components;
|
||||
});
|
||||
|
||||
newState.viewports[viewportId] = viewportCopy;
|
||||
return newState;
|
||||
}
|
||||
|
||||
default:
|
||||
return state;
|
||||
}
|
||||
};
|
||||
|
||||
const [state, dispatch] = useReducer(viewportActionCornersReducer, DEFAULT_STATE);
|
||||
|
||||
const getState = useCallback(() => {
|
||||
return state;
|
||||
}, [state]);
|
||||
|
||||
const addComponent = useCallback(
|
||||
(component: ActionComponentInfo) => {
|
||||
dispatch({
|
||||
type: 'ADD_COMPONENT',
|
||||
payload: component,
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const addComponents = useCallback(
|
||||
(components: Array<ActionComponentInfo>) => {
|
||||
dispatch({
|
||||
type: 'ADD_COMPONENTS',
|
||||
payload: components,
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const clear = useCallback(
|
||||
(viewportId: string) => {
|
||||
dispatch({
|
||||
type: 'CLEAR',
|
||||
payload: viewportId,
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const lockItem = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
dispatch({
|
||||
type: 'SET_LOCKED',
|
||||
payload: { viewportId, itemId, lockedStatus: true },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const unlockItem = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
dispatch({
|
||||
type: 'SET_LOCKED',
|
||||
payload: { viewportId, itemId, lockedStatus: false },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const toggleLock = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
const currentLocked = isItemLocked(viewportId, itemId);
|
||||
dispatch({
|
||||
type: 'SET_LOCKED',
|
||||
payload: { viewportId, itemId, lockedStatus: !currentLocked },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const isItemLocked = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
if (!state.viewports[viewportId]) {
|
||||
return false; // Default to unlocked if viewport doesn't exist
|
||||
}
|
||||
|
||||
for (const locationKey in state.viewports[viewportId]) {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = state.viewports[viewportId][location];
|
||||
const item = components.find(item => item.id === itemId);
|
||||
|
||||
if (item && item.isLocked === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false; // Default to unlocked if item not found or isLocked is undefined
|
||||
},
|
||||
[state.viewports]
|
||||
);
|
||||
|
||||
const showItem = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
dispatch({
|
||||
type: 'SET_VISIBLE',
|
||||
payload: { viewportId, itemId, visibleStatus: true },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const hideItem = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
dispatch({
|
||||
type: 'SET_VISIBLE',
|
||||
payload: { viewportId, itemId, visibleStatus: false },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const toggleVisibility = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
const currentVisible = isItemVisible(viewportId, itemId);
|
||||
dispatch({
|
||||
type: 'SET_VISIBLE',
|
||||
payload: { viewportId, itemId, visibleStatus: !currentVisible },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const isItemVisible = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
if (!state.viewports[viewportId]) {
|
||||
return true; // Default to visible if viewport doesn't exist
|
||||
}
|
||||
|
||||
for (const locationKey in state.viewports[viewportId]) {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = state.viewports[viewportId][location];
|
||||
const item = components.find(item => item.id === itemId);
|
||||
|
||||
if (item && item.isVisible === false) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true; // Default to visible if item not found or isVisible is undefined
|
||||
},
|
||||
[state.viewports]
|
||||
);
|
||||
|
||||
const openItem = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
dispatch({
|
||||
type: 'OPEN_ITEM',
|
||||
payload: { viewportId, itemId },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const closeItem = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
dispatch({
|
||||
type: 'CLOSE_ITEM',
|
||||
payload: { viewportId, itemId },
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const closeAllItems = useCallback(
|
||||
(viewportId: string) => {
|
||||
dispatch({
|
||||
type: 'CLOSE_ALL_ITEMS',
|
||||
payload: viewportId,
|
||||
});
|
||||
},
|
||||
[dispatch]
|
||||
);
|
||||
|
||||
const isItemOpen = useCallback(
|
||||
(viewportId: string, itemId: string) => {
|
||||
if (!state.viewports[viewportId]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
for (const locationKey in state.viewports[viewportId]) {
|
||||
const location = Number(locationKey) as ViewportActionCornersLocations;
|
||||
const components = state.viewports[viewportId][location];
|
||||
const item = components.find(item => item.id === itemId);
|
||||
|
||||
if (item && item.isOpen === true) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
[state.viewports]
|
||||
);
|
||||
|
||||
const getAlignAndSide = useCallback(
|
||||
(location: ViewportActionCornersLocations) => {
|
||||
return service.getAlignAndSide(location);
|
||||
},
|
||||
[service]
|
||||
);
|
||||
|
||||
const api = useMemo(() => {
|
||||
return {
|
||||
getState,
|
||||
addComponent,
|
||||
addComponents,
|
||||
clear,
|
||||
getAlignAndSide,
|
||||
lockItem,
|
||||
unlockItem,
|
||||
toggleLock,
|
||||
isItemLocked,
|
||||
showItem,
|
||||
hideItem,
|
||||
toggleVisibility,
|
||||
isItemVisible,
|
||||
openItem,
|
||||
closeItem,
|
||||
closeAllItems,
|
||||
isItemOpen,
|
||||
};
|
||||
}, [
|
||||
getState,
|
||||
addComponent,
|
||||
addComponents,
|
||||
clear,
|
||||
getAlignAndSide,
|
||||
lockItem,
|
||||
unlockItem,
|
||||
toggleLock,
|
||||
isItemLocked,
|
||||
showItem,
|
||||
hideItem,
|
||||
toggleVisibility,
|
||||
isItemVisible,
|
||||
openItem,
|
||||
closeItem,
|
||||
closeAllItems,
|
||||
isItemOpen,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (service && service.setServiceImplementation) {
|
||||
const implementation = {
|
||||
getState,
|
||||
addComponent,
|
||||
addComponents,
|
||||
clear,
|
||||
lockItem,
|
||||
unlockItem,
|
||||
toggleLock,
|
||||
isItemLocked,
|
||||
showItem,
|
||||
hideItem,
|
||||
toggleVisibility,
|
||||
isItemVisible,
|
||||
openItem,
|
||||
closeItem,
|
||||
closeAllItems,
|
||||
isItemOpen,
|
||||
};
|
||||
|
||||
service.setServiceImplementation(implementation);
|
||||
}
|
||||
}, [
|
||||
service,
|
||||
getState,
|
||||
addComponent,
|
||||
addComponents,
|
||||
clear,
|
||||
lockItem,
|
||||
unlockItem,
|
||||
toggleLock,
|
||||
isItemLocked,
|
||||
showItem,
|
||||
hideItem,
|
||||
toggleVisibility,
|
||||
isItemVisible,
|
||||
openItem,
|
||||
closeItem,
|
||||
closeAllItems,
|
||||
isItemOpen,
|
||||
]);
|
||||
|
||||
return (
|
||||
<ViewportActionCornersContext.Provider value={[state, api]}>
|
||||
{children}
|
||||
</ViewportActionCornersContext.Provider>
|
||||
);
|
||||
}
|
||||
|
||||
// Custom hook to use the ViewportActionCorners context
|
||||
export const useViewportActionCorners = () => useContext(ViewportActionCornersContext);
|
||||
@@ -9,6 +9,10 @@ import { UserAuthenticationProvider, useUserAuthentication } from './UserAuthent
|
||||
import { ImageViewerContext, ImageViewerProvider, useImageViewer } from './ImageViewerProvider';
|
||||
import DragAndDropProvider from './DragAndDropProvider';
|
||||
import CineProvider, { useCine } from './CineProvider';
|
||||
import {
|
||||
ViewportActionCornersProvider,
|
||||
useViewportActionCorners,
|
||||
} from './ViewportActionCornersProvider';
|
||||
|
||||
export { useNotification, NotificationProvider };
|
||||
export { ViewportGridContext, ViewportGridProvider, useViewportGrid };
|
||||
@@ -20,3 +24,4 @@ export { UserAuthenticationProvider, useUserAuthentication };
|
||||
export { ImageViewerContext, ImageViewerProvider, useImageViewer };
|
||||
export { DragAndDropProvider };
|
||||
export { CineProvider, useCine };
|
||||
export { ViewportActionCornersProvider, useViewportActionCorners };
|
||||
@@ -0,0 +1,18 @@
|
||||
import { ReactNode } from 'react';
|
||||
import { ViewportActionCornersLocations } from '../components/Viewport/ViewportActionCorners';
|
||||
|
||||
export type ActionComponentInfo = {
|
||||
viewportId: string;
|
||||
id: string;
|
||||
component: ReactNode;
|
||||
location: ViewportActionCornersLocations;
|
||||
indexPriority?: number;
|
||||
isLocked?: boolean;
|
||||
isOpen?: boolean;
|
||||
isVisible?: boolean;
|
||||
};
|
||||
|
||||
export type AlignAndSide = {
|
||||
align: 'start' | 'end' | 'center';
|
||||
side: 'top' | 'bottom' | 'left' | 'right';
|
||||
};
|
||||
@@ -5,6 +5,7 @@ import ThumbnailType from './ThumbnailType';
|
||||
export * from './Predicate';
|
||||
export * from './ContextMenuItem';
|
||||
export * from './ViewportActionCornersTypes';
|
||||
export * from './ActionCorners';
|
||||
|
||||
/**
|
||||
* StringNumber often comes back from DICOMweb for integer valued items.
|
||||
|
||||
Reference in new issue
Block a user