ui(component): Tooltip component ui-next (#4635)
Co-authored-by: sedghi <ar.sedghi@gmail.com>
This commit is contained in:
1 parent
03ad79eaed
commit
b54f2075ec
18 files changed
+342
-100
No files matched your search
@@ -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 (
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="cursor-pointer truncate">{textValue}</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{textValue}
|
||||
<Clipboard>{textValue}</Clipboard>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
|
||||
return {
|
||||
dataCY: `studyRow-${studyInstanceUid}`,
|
||||
clickableCY: studyInstanceUid,
|
||||
row: [
|
||||
{
|
||||
key: 'patientName',
|
||||
content: patientName ? (
|
||||
<TooltipClipboard>{patientName}</TooltipClipboard>
|
||||
) : (
|
||||
<span className="text-gray-700">(Empty)</span>
|
||||
),
|
||||
content: patientName ? makeCopyTooltipCell(patientName) : null,
|
||||
gridCol: 4,
|
||||
},
|
||||
{
|
||||
key: 'mrn',
|
||||
content: <TooltipClipboard>{mrn}</TooltipClipboard>,
|
||||
content: makeCopyTooltipCell(mrn),
|
||||
gridCol: 3,
|
||||
},
|
||||
{
|
||||
@@ -305,7 +326,7 @@ function WorkList({
|
||||
},
|
||||
{
|
||||
key: 'description',
|
||||
content: <TooltipClipboard>{description}</TooltipClipboard>,
|
||||
content: makeCopyTooltipCell(description),
|
||||
gridCol: 4,
|
||||
},
|
||||
{
|
||||
@@ -316,7 +337,7 @@ function WorkList({
|
||||
},
|
||||
{
|
||||
key: 'accession',
|
||||
content: <TooltipClipboard>{accession}</TooltipClipboard>,
|
||||
content: makeCopyTooltipCell(accession),
|
||||
gridCol: 3,
|
||||
},
|
||||
{
|
||||
@@ -392,6 +413,7 @@ function WorkList({
|
||||
query.append('configUrl', filterValues.configUrl);
|
||||
}
|
||||
query.append('StudyInstanceUIDs', studyInstanceUid);
|
||||
|
||||
return (
|
||||
mode.displayName && (
|
||||
<Link
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
---
|
||||
title: General
|
||||
---
|
||||
|
||||
## HTML Template Update
|
||||
We have modified the `template.html` file so if you are using a custom template, you will need to update it.
|
||||
|
||||
Here are the key changes needed in the migration:
|
||||
|
||||
1. Added `window.PUBLIC_URL` declaration:
|
||||
```javascript
|
||||
window.PUBLIC_URL = '<%= PUBLIC_URL %>';
|
||||
```
|
||||
|
||||
Was added before the `<!-- EXTENSIONS -->` comment block.
|
||||
+1
-2
@@ -1,6 +1,5 @@
|
||||
---
|
||||
sidebar_position: 2
|
||||
sidebar_label: Icons
|
||||
title: Icons
|
||||
---
|
||||
|
||||
## Migration Guide: Icon Component Updates
|
||||
@@ -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 content={<div>Tooltip Message</div>} position="bottom-left">
|
||||
<Component />
|
||||
</Tooltip>
|
||||
|
||||
// After
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<Component />
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
Tooltip Message
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
```
|
||||
|
||||
|
||||
3. TooltipClipboard Replacement:
|
||||
The `TooltipClipboard` component has been removed. Instead, use the `Clipboard` component inside `TooltipContent` for copying text functionality.
|
||||
|
||||
#### Before:
|
||||
```tsx
|
||||
<TooltipClipboard>{text}</TooltipClipboard>
|
||||
```
|
||||
|
||||
#### After:
|
||||
```tsx
|
||||
<Tooltip>
|
||||
<TooltipTrigger asChild>
|
||||
<span className="cursor-pointer truncate">{text}</span>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent side="bottom">
|
||||
<div className="flex items-center justify-between gap-2">
|
||||
{text}
|
||||
<Clipboard>{text}</Clipboard>
|
||||
</div>
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
```
|
||||
@@ -4,3 +4,6 @@ sidebar_label: 3.9 -> 3.10 beta
|
||||
---
|
||||
|
||||
# Migration Guide
|
||||
|
||||
|
||||
## General
|
||||
@@ -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<ClipboardProps> = ({ 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 (
|
||||
<Button
|
||||
variant="ghost"
|
||||
size="icon"
|
||||
onClick={e => {
|
||||
e.stopPropagation();
|
||||
handleCopy();
|
||||
}}
|
||||
className="text-white"
|
||||
title="Copy"
|
||||
>
|
||||
{copyState === 'idle' && <Icons.Copy className="h-6 w-6" />}
|
||||
{copyState === 'success' && <Icons.FeedbackComplete className="h-6 w-6 text-white" />}
|
||||
{copyState === 'error' && (
|
||||
<Icons.ByName
|
||||
name="Error"
|
||||
className="h-6 w-6 text-white"
|
||||
/>
|
||||
)}
|
||||
</Button>
|
||||
);
|
||||
};
|
||||
|
||||
export { Clipboard };
|
||||
@@ -0,0 +1,3 @@
|
||||
import { Clipboard } from './Clipboard';
|
||||
|
||||
export { Clipboard };
|
||||
@@ -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,
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import React from 'react';
|
||||
import type { IconProps } from '../types';
|
||||
|
||||
export const Copy = (props: IconProps) => (
|
||||
<svg
|
||||
width="24px"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
id="Copy"
|
||||
stroke="none"
|
||||
strokeWidth="1"
|
||||
fill="none"
|
||||
fillRule="evenodd"
|
||||
>
|
||||
<rect
|
||||
id="Rectangle"
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
></rect>
|
||||
<rect
|
||||
id="Rectangle"
|
||||
stroke="currentColor"
|
||||
x="8.95205173"
|
||||
y="4.5"
|
||||
width="10"
|
||||
height="10"
|
||||
rx="2"
|
||||
></rect>
|
||||
<path
|
||||
d="M7.05569885,9.5 L5.5,9.5 C4.67157288,9.5 4,10.1715729 4,11 L4,17.8271183 C4,18.6555454 4.67157288,19.3271183 5.5,19.3271183 L12.4520517,19.3271183 C13.2804789,19.3271183 13.9520517,18.6555454 13.9520517,17.8271183 L13.9520517,16.3489489 L13.9520517,16.3489489"
|
||||
id="Path-4"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default Copy;
|
||||
@@ -0,0 +1,35 @@
|
||||
import React from 'react';
|
||||
import type { IconProps } from '../types';
|
||||
|
||||
export const FeedbackComplete = (props: IconProps) => (
|
||||
<svg
|
||||
width="24px"
|
||||
height="24px"
|
||||
viewBox="0 0 24 24"
|
||||
{...props}
|
||||
>
|
||||
<g
|
||||
id="FeedbackComplete"
|
||||
stroke="none"
|
||||
strokeWidth="1"
|
||||
fill="none"
|
||||
fillRule="evenodd"
|
||||
>
|
||||
<rect
|
||||
id="Rectangle"
|
||||
x="0"
|
||||
y="0"
|
||||
width="24"
|
||||
height="24"
|
||||
></rect>
|
||||
<path
|
||||
d="M6.5,12.5497794 L10.0873523,16.1371317 C10.4778766,16.527656 11.1110415,16.527656 11.5015658,16.1371317 C11.5482206,16.0904769 11.5901435,16.0393192 11.6267216,15.9844066 L17.6113609,7 L17.6113609,7"
|
||||
id="Path-3"
|
||||
stroke="currentColor"
|
||||
strokeLinecap="round"
|
||||
></path>
|
||||
</g>
|
||||
</svg>
|
||||
);
|
||||
|
||||
export default FeedbackComplete;
|
||||
@@ -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}
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -12,6 +12,7 @@ import {
|
||||
Tabs,
|
||||
TabsContent,
|
||||
TabsList,
|
||||
Clipboard,
|
||||
TabsTrigger,
|
||||
Toggle,
|
||||
toggleVariants,
|
||||
@@ -99,6 +100,7 @@ export {
|
||||
ThemeWrapper,
|
||||
Calendar,
|
||||
DatePickerWithRange,
|
||||
Clipboard,
|
||||
// contextProviders
|
||||
NotificationProvider,
|
||||
useNotification,
|
||||
|
||||
Reference in new issue
Block a user