diff --git a/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx b/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx
index d270f278d..78b36ca63 100644
--- a/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx
+++ b/extensions/cornerstone-dicom-rt/src/viewports/_getStatusComponent.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
-import { Icon, Tooltip, ViewportActionButton } from '@ohif/ui';
-import { Icons } from '@ohif/ui-next';
+import { ViewportActionButton } from '@ohif/ui';
+import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
export default function _getStatusComponent({ isHydrated, onStatusClick }) {
let ToolTipMessage = null;
@@ -10,7 +10,6 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
switch (isHydrated) {
case true:
StatusIcon = () => ;
-
ToolTipMessage = () =>
This Segmentation is loaded in the segmentation panel
;
break;
case false:
@@ -20,7 +19,6 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
name="status-untracked"
/>
);
-
ToolTipMessage = () => Click LOAD to load RTSTRUCT.
;
}
@@ -44,14 +42,18 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
return (
<>
{ToolTipMessage && (
- }
- position="bottom-left"
- >
-
+
+
+
+
+
+
+
+
+
)}
{!ToolTipMessage && }
>
);
-}
+}
\ No newline at end of file
diff --git a/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx b/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx
index 234337ede..836dca5bb 100644
--- a/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx
+++ b/extensions/cornerstone-dicom-seg/src/viewports/_getStatusComponent.tsx
@@ -1,7 +1,7 @@
import React from 'react';
import { useTranslation } from 'react-i18next';
-import { Tooltip, ViewportActionButton } from '@ohif/ui';
-import { Icons } from '@ohif/ui-next';
+import { ViewportActionButton } from '@ohif/ui';
+import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
export default function _getStatusComponent({ isHydrated, onStatusClick }) {
let ToolTipMessage = null;
@@ -10,7 +10,6 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
switch (isHydrated) {
case true:
StatusIcon = () => ;
-
ToolTipMessage = () => This Segmentation is loaded in the segmentation panel
;
break;
case false:
@@ -20,7 +19,6 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
name="status-untracked"
/>
);
-
ToolTipMessage = () => Click LOAD to load segmentation.
;
}
@@ -44,14 +42,18 @@ export default function _getStatusComponent({ isHydrated, onStatusClick }) {
return (
<>
{ToolTipMessage && (
- }
- position="bottom-left"
- >
-
+
+
+
+
+
+
+
+
+
)}
{!ToolTipMessage && }
>
);
-}
+}
\ No newline at end of file
diff --git a/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx b/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx
index 48f8e8652..f028b225e 100644
--- a/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx
+++ b/extensions/cornerstone-dicom-sr/src/components/OHIFCornerstoneSRMeasurementViewport.tsx
@@ -5,10 +5,11 @@ import { ExtensionManager, useToolbar } from '@ohif/core';
import { setTrackingUniqueIdentifiersForElement } from '../tools/modules/dicomSRModule';
-import { Icon, Tooltip, useViewportGrid, ViewportActionArrows } from '@ohif/ui';
import createReferencedImageDisplaySet from '../utils/createReferencedImageDisplaySet';
import { usePositionPresentationStore } from '@ohif/extension-cornerstone';
-import { Icons } from '@ohif/ui-next';
+import { useViewportGrid, ViewportActionArrows } from '@ohif/ui';
+import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
+
const MEASUREMENT_TRACKING_EXTENSION_ID = '@ohif/extension-measurement-tracking';
const SR_TOOLGROUP_BASE_NAME = 'SRToolGroup';
@@ -467,11 +468,18 @@ function _getStatusComponent({
return (
<>
{ToolTipMessage && (
- }
- position="bottom-left"
- >
-
+
+
+
+
+
+
+
+
+
)}
{!ToolTipMessage && }
diff --git a/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx b/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx
index b632dfce7..f5dfa07cc 100644
--- a/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx
+++ b/extensions/cornerstone-dynamic-volume/src/panels/DynamicVolumeControls.tsx
@@ -1,8 +1,6 @@
import React, { useState } from 'react';
-import { Button, PanelSection, ButtonGroup, IconButton, InputNumber, Tooltip } from '@ohif/ui';
-
-import { DoubleSlider, Icons } from '@ohif/ui-next';
-
+import { Button, PanelSection, ButtonGroup, IconButton, InputNumber } from '@ohif/ui';
+import { DoubleSlider, Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
import { Enums } from '@cornerstonejs/core';
const controlClassNames = {
@@ -13,16 +11,18 @@ const controlClassNames = {
const Header = ({ title, tooltip }) => (
- {tooltip}
}
- position="bottom-left"
- tight={true}
- tooltipBoxClassName="max-w-xs p-2"
- >
-
+
+
+
+
+
+
+
+ {tooltip}
+
{title}
@@ -45,9 +45,7 @@ const DynamicVolumeControls = ({
onDynamicClick,
}) => {
const [computedView, setComputedView] = useState(false);
-
const [computeViewMode, setComputeViewMode] = useState(Enums.DynamicOperatorType.SUM);
-
const [sliderRangeValues, setSliderRangeValues] = useState([0, framesLength - 1]);
const handleSliderChange = newValues => {
@@ -113,15 +111,14 @@ const DynamicVolumeControls = ({
Operation Buttons (SUM, AVERAGE, SUBTRACT): Select the mathematical operation to be
applied to the data set.
- Range Slider: Choose the numeric range within which the operation will be
+ Range Slider: Choose the numeric range within which the operation will be
performed.
- Generate Button: Execute the chosen operation on the specified range of
- data.{' '}
+ Generate Button: Execute the chosen operation on the specified range of data.
}
/>
- Play/Pause Button: Begin or pause the animation of the 4D visualization. Frame
- Selector: Navigate through individual frames of the 4D data. FPS (Frames Per
+ Play/Pause Button: Begin or pause the animation of the 4D visualization. Frame
+ Selector: Navigate through individual frames of the 4D data. FPS (Frames Per
Second) Selector: Adjust the playback speed of the animation.
}
@@ -225,4 +222,4 @@ function FrameControls({
);
-}
+}
\ No newline at end of file
diff --git a/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx b/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx
index 6690ee5a7..1d08250fe 100644
--- a/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx
+++ b/extensions/measurement-tracking/src/viewports/TrackedCornerstoneViewport.tsx
@@ -1,8 +1,8 @@
import React, { useState, useEffect, useCallback } from 'react';
import PropTypes from 'prop-types';
-import { Tooltip, ViewportActionArrows, useViewportGrid } from '@ohif/ui';
-import { Icons } from '@ohif/ui-next';
+import { ViewportActionArrows, useViewportGrid } from '@ohif/ui';
+import { Icons, Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
import { annotation } from '@cornerstonejs/tools';
import { useTrackedMeasurements } from './../getContextModule';
@@ -235,11 +235,9 @@ function TrackedCornerstoneViewport(
};
return (
- <>
-
- {getCornerstoneViewport()}
-
- >
+
+ {getCornerstoneViewport()}
+
);
}
@@ -312,7 +310,7 @@ const _getArrowsComponent = (isTracked, switchMeasurement, isActiveViewport) =>
switchMeasurement(direction)}
className={isActiveViewport ? 'visible' : 'invisible group-hover/pane:visible'}
- >
+ />
);
};
@@ -322,33 +320,23 @@ function _getStatusComponent(isTracked, t) {
}
return (
-
-
-
-
-
-
-
- {isTracked ? (
- <>{t('Series is tracked and can be viewed in the measurement panel')}>
- ) : (
- <>
- {t(
- 'Measurements for untracked series will not be shown in the measurements panel'
- )}
- >
- )}
-
-
-
- }
+
+
+
+
+
+
+
-
-
-
+ {isTracked ? (
+ <>{t('Series is tracked and can be viewed in the measurement panel')}>
+ ) : (
+ <>{t('Measurements for untracked series will not be shown in the measurements panel')}>
+ )}
+
+
);
}
diff --git a/platform/app/src/routes/WorkList/WorkList.tsx b/platform/app/src/routes/WorkList/WorkList.tsx
index 22d1e59b6..3d9c8b38c 100644
--- a/platform/app/src/routes/WorkList/WorkList.tsx
+++ b/platform/app/src/routes/WorkList/WorkList.tsx
@@ -14,13 +14,11 @@ import { utils, hotkeys } from '@ohif/core';
import publicUrl from '../../utils/publicUrl';
import {
- Icon,
StudyListExpandedRow,
EmptyStudies,
StudyListTable,
StudyListPagination,
StudyListFilter,
- TooltipClipboard,
useModal,
AboutModal,
UserPreferences,
@@ -31,12 +29,20 @@ import {
ButtonEnums,
} from '@ohif/ui';
-import { Header, Icons } from '@ohif/ui-next';
+import {
+ Header,
+ Icons,
+ Tooltip,
+ TooltipTrigger,
+ TooltipContent,
+ Clipboard,
+ Onboarding,
+ ScrollArea,
+} from '@ohif/ui-next';
import { Types } from '@ohif/ui';
import i18n from '@ohif/i18n';
-import { Onboarding, ScrollArea } from '@ohif/ui-next';
const PatientInfoVisibility = Types.PatientInfoVisibility;
@@ -274,22 +280,37 @@ function WorkList({
t('Common:localTimeFormat', 'hh:mm A')
);
+ const makeCopyTooltipCell = textValue => {
+ if (!textValue) {
+ return '';
+ }
+ return (
+
+
+ {textValue}
+
+
+
+ {textValue}
+ {textValue}
+
+
+
+ );
+ };
+
return {
dataCY: `studyRow-${studyInstanceUid}`,
clickableCY: studyInstanceUid,
row: [
{
key: 'patientName',
- content: patientName ? (
- {patientName}
- ) : (
- (Empty)
- ),
+ content: patientName ? makeCopyTooltipCell(patientName) : null,
gridCol: 4,
},
{
key: 'mrn',
- content: {mrn} ,
+ content: makeCopyTooltipCell(mrn),
gridCol: 3,
},
{
@@ -305,7 +326,7 @@ function WorkList({
},
{
key: 'description',
- content: {description} ,
+ content: makeCopyTooltipCell(description),
gridCol: 4,
},
{
@@ -316,7 +337,7 @@ function WorkList({
},
{
key: 'accession',
- content: {accession} ,
+ content: makeCopyTooltipCell(accession),
gridCol: 3,
},
{
@@ -392,6 +413,7 @@ function WorkList({
query.append('configUrl', filterValues.configUrl);
}
query.append('StudyInstanceUIDs', studyInstanceUid);
+
return (
mode.displayName && (
';
+```
+
+Was added before the `` comment block.
diff --git a/platform/docs/docs/migration-guide/3p9-to-3p10/Icons.md b/platform/docs/docs/migration-guide/3p9-to-3p10/UI/Migration-Icons.md
similarity index 99%
rename from platform/docs/docs/migration-guide/3p9-to-3p10/Icons.md
rename to platform/docs/docs/migration-guide/3p9-to-3p10/UI/Migration-Icons.md
index ee57e7181..7a2afed4d 100644
--- a/platform/docs/docs/migration-guide/3p9-to-3p10/Icons.md
+++ b/platform/docs/docs/migration-guide/3p9-to-3p10/UI/Migration-Icons.md
@@ -1,6 +1,5 @@
---
-sidebar_position: 2
-sidebar_label: Icons
+title: Icons
---
## Migration Guide: Icon Component Updates
diff --git a/platform/docs/docs/migration-guide/3p9-to-3p10/UI/Migration-Tooltip.md b/platform/docs/docs/migration-guide/3p9-to-3p10/UI/Migration-Tooltip.md
new file mode 100644
index 000000000..80a33acaa
--- /dev/null
+++ b/platform/docs/docs/migration-guide/3p9-to-3p10/UI/Migration-Tooltip.md
@@ -0,0 +1,62 @@
+---
+title: Tooltip
+---
+
+## Tooltip Updates
+
+### Changes:
+- Updated Tooltip structure to use `Tooltip`, `TooltipTrigger`, and `TooltipContent`.
+- Removed deprecated `TooltipClipboard` and inline `content`/`position` properties.
+
+### Migration Steps:
+1. Replace imports:
+ ```tsx
+ // Before
+ import { Tooltip } from '@ohif/ui';
+ import { TooltipClipboard } from '@ohif/ui';
+
+ // After
+ import { Tooltip, TooltipTrigger, TooltipContent } from '@ohif/ui-next';
+ ```
+
+2. Update Tooltip usage:
+ ```tsx
+ // Before
+ Tooltip Message} position="bottom-left">
+
+
+
+ // After
+
+
+
+
+
+ Tooltip Message
+
+
+ ```
+
+
+3. TooltipClipboard Replacement:
+The `TooltipClipboard` component has been removed. Instead, use the `Clipboard` component inside `TooltipContent` for copying text functionality.
+
+#### Before:
+```tsx
+{text}
+```
+
+#### After:
+```tsx
+
+
+ {text}
+
+
+
+ {text}
+ {text}
+
+
+
+```
diff --git a/platform/docs/docs/migration-guide/3p9-to-3p10/index.md b/platform/docs/docs/migration-guide/3p9-to-3p10/index.md
index 81316bf29..3709d5fee 100644
--- a/platform/docs/docs/migration-guide/3p9-to-3p10/index.md
+++ b/platform/docs/docs/migration-guide/3p9-to-3p10/index.md
@@ -4,3 +4,6 @@ sidebar_label: 3.9 -> 3.10 beta
---
# Migration Guide
+
+
+## General
diff --git a/platform/ui-next/src/components/Clipboard/Clipboard.tsx b/platform/ui-next/src/components/Clipboard/Clipboard.tsx
new file mode 100644
index 000000000..0b515d868
--- /dev/null
+++ b/platform/ui-next/src/components/Clipboard/Clipboard.tsx
@@ -0,0 +1,55 @@
+import React, { ReactNode } from 'react';
+import { Button } from '../Button';
+import { Icons } from '../Icons';
+
+interface ClipboardProps {
+ children: ReactNode;
+}
+
+const Clipboard: React.FC = ({ children }) => {
+ const [copyState, setCopyState] = React.useState<'idle' | 'success' | 'error'>('idle');
+ const copyText = React.useMemo(() => {
+ if (typeof children === 'string') {
+ return children.trim();
+ }
+ return '';
+ }, [children]);
+
+ const handleCopy = React.useCallback(async () => {
+ if (!copyText) {
+ return;
+ }
+ try {
+ await navigator.clipboard.writeText(copyText);
+ setCopyState('success');
+ } catch {
+ setCopyState('error');
+ } finally {
+ setTimeout(() => setCopyState('idle'), 1500); // Reset state after feedback
+ }
+ }, [copyText]);
+
+ return (
+ {
+ e.stopPropagation();
+ handleCopy();
+ }}
+ className="text-white"
+ title="Copy"
+ >
+ {copyState === 'idle' && }
+ {copyState === 'success' && }
+ {copyState === 'error' && (
+
+ )}
+
+ );
+};
+
+export { Clipboard };
diff --git a/platform/ui-next/src/components/Clipboard/index.tsx b/platform/ui-next/src/components/Clipboard/index.tsx
new file mode 100644
index 000000000..0c7b4238b
--- /dev/null
+++ b/platform/ui-next/src/components/Clipboard/index.tsx
@@ -0,0 +1,3 @@
+import { Clipboard } from './Clipboard';
+
+export { Clipboard };
diff --git a/platform/ui-next/src/components/Icons/Icons.tsx b/platform/ui-next/src/components/Icons/Icons.tsx
index 349a4686e..bf9e6d910 100644
--- a/platform/ui-next/src/components/Icons/Icons.tsx
+++ b/platform/ui-next/src/components/Icons/Icons.tsx
@@ -7,6 +7,7 @@ import ChevronOpen from './Sources/ChevronOpen';
import Code from './Sources/Code';
import ColorChange from './Sources/ColorChange';
import Controls from './Sources/Controls';
+import Copy from './Sources/Copy';
import Delete from './Sources/Delete';
import DicomTagBrowser from './Sources/DicomTagBrowser';
import DisplayFillAndOutline from './Sources/DisplayFillAndOutline';
@@ -16,6 +17,7 @@ import Download from './Sources/Download';
import Export from './Sources/Export';
import EyeHidden from './Sources/EyeHidden';
import EyeVisible from './Sources/EyeVisible';
+import FeedbackComplete from './Sources/FeedbackComplete';
import GearSettings from './Sources/GearSettings';
import Hide from './Sources/Hide';
import IconMPR from './Sources/IconMPR';
@@ -418,6 +420,7 @@ export const Icons = {
Code,
ColorChange,
Controls,
+ Copy,
Delete,
DicomTagBrowser,
DisplayFillAndOutline,
@@ -430,6 +433,7 @@ export const Icons = {
Export,
EyeHidden,
EyeVisible,
+ FeedbackComplete,
GearSettings,
Hide,
IconMPR,
diff --git a/platform/ui-next/src/components/Icons/Sources/Copy.tsx b/platform/ui-next/src/components/Icons/Sources/Copy.tsx
new file mode 100644
index 000000000..35198c4ea
--- /dev/null
+++ b/platform/ui-next/src/components/Icons/Sources/Copy.tsx
@@ -0,0 +1,44 @@
+import React from 'react';
+import type { IconProps } from '../types';
+
+export const Copy = (props: IconProps) => (
+
+
+
+
+
+
+
+);
+
+export default Copy;
diff --git a/platform/ui-next/src/components/Icons/Sources/FeedbackComplete.tsx b/platform/ui-next/src/components/Icons/Sources/FeedbackComplete.tsx
new file mode 100644
index 000000000..a3df59a85
--- /dev/null
+++ b/platform/ui-next/src/components/Icons/Sources/FeedbackComplete.tsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import type { IconProps } from '../types';
+
+export const FeedbackComplete = (props: IconProps) => (
+
+
+
+
+
+
+);
+
+export default FeedbackComplete;
diff --git a/platform/ui-next/src/components/Tooltip/Tooltip.tsx b/platform/ui-next/src/components/Tooltip/Tooltip.tsx
index 93f940555..ad8151fb6 100644
--- a/platform/ui-next/src/components/Tooltip/Tooltip.tsx
+++ b/platform/ui-next/src/components/Tooltip/Tooltip.tsx
@@ -17,7 +17,7 @@ const TooltipContent = React.forwardRef<
ref={ref}
sideOffset={sideOffset}
className={cn(
- 'bg-primary-dark border-secondary-light text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 overflow-hidden rounded border px-3 py-1.5 text-sm',
+ 'bg-primary-dark border-secondary-light text-primary-foreground animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-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 overflow-hidden rounded border px-2 py-1.5 text-sm',
className
)}
{...props}
diff --git a/platform/ui-next/src/components/index.ts b/platform/ui-next/src/components/index.ts
index c4f8307c0..42ef70024 100644
--- a/platform/ui-next/src/components/index.ts
+++ b/platform/ui-next/src/components/index.ts
@@ -24,7 +24,7 @@ import {
DialogDescription,
} from './Dialog';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './Select';
-
+import { Clipboard } from './Clipboard';
import { Combobox } from './Combobox';
import { Popover, PopoverContent, PopoverTrigger, PopoverAnchor } from './Popover';
import { Calendar } from './Calendar';
@@ -183,4 +183,5 @@ export {
CardTitle,
CardDescription,
CardContent,
+ Clipboard,
};
diff --git a/platform/ui-next/src/index.ts b/platform/ui-next/src/index.ts
index e20cb012a..597f3540e 100644
--- a/platform/ui-next/src/index.ts
+++ b/platform/ui-next/src/index.ts
@@ -12,6 +12,7 @@ import {
Tabs,
TabsContent,
TabsList,
+ Clipboard,
TabsTrigger,
Toggle,
toggleVariants,
@@ -99,6 +100,7 @@ export {
ThemeWrapper,
Calendar,
DatePickerWithRange,
+ Clipboard,
// contextProviders
NotificationProvider,
useNotification,