diff --git a/docs/pages/experiments/rich-tooltip.tsx b/docs/pages/experiments/rich-tooltip.tsx new file mode 100644 index 00000000000000..53095b34f3f55d --- /dev/null +++ b/docs/pages/experiments/rich-tooltip.tsx @@ -0,0 +1,232 @@ +'use client'; +import * as React from 'react'; +import Box from '@mui/material/Box'; +import Stack from '@mui/material/Stack'; +import Tooltip, { tooltipClasses } from '@mui/material/Tooltip'; +import type { TooltipProps } from '@mui/material/Tooltip'; +import Typography from '@mui/material/Typography'; +import IconButton from '@mui/material/IconButton'; +import FileUploadOutlinedIcon from '@mui/icons-material/FileUploadOutlined'; +import ContentCopyIcon from '@mui/icons-material/ContentCopy'; +import SettingsIcon from '@mui/icons-material/Settings'; +import { createTheme, ThemeProvider, styled } from '@mui/material/styles'; + +const theme = createTheme({}); + +const Shortcut = styled('kbd')(({ theme: t }) => ({ + display: 'inline-flex', + alignItems: 'center', + gap: 2, + font: 'inherit', + fontSize: t.typography.pxToRem(12), + lineHeight: 1, + padding: '4px 8px', + borderRadius: 6, + color: (t.vars || t).palette.common.white, + backgroundColor: t.alpha((t.vars || t).palette.common.white, 0.16), +})); + +function RichCard({ + title, + shortcut, + description, +}: { + title: React.ReactNode; + shortcut?: React.ReactNode; + description?: React.ReactNode; +}) { + return ( + // Rounding/clipping/elevation live here, not on the tooltip slot — the arrow + // is a sibling of this card at the slot level, so slot-level `overflow: hidden` + // would clip it. + + + + {title} + + {shortcut ? {shortcut} : null} + + {description ? ( + + {description} + + ) : null} + + ); +} + +const richSlotProps: TooltipProps['slotProps'] = { + tooltip: { + sx: { + p: 0, + maxWidth: 320, + bgcolor: 'transparent', + color: 'text.primary', + }, + }, + arrow: { + // Match the dark header, not the body surface. + sx: { color: 'grey.900' }, + }, +}; + +// Replaces the default tooltip slot. Mirrors the popper-placement margins + +// transform-origins from Tooltip's own slot (lost when swapping the component) +// and colors the arrow to match the dark header. +const RichTooltipRoot = styled('div')(({ theme: t }) => ({ + position: 'relative', + maxWidth: 320, + margin: 2, + color: (t.vars || t).palette.text.primary, + [`& .${tooltipClasses.arrow}`]: { + color: (t.vars || t).palette.grey[900], + }, + [`.${tooltipClasses.popper}[data-popper-placement*="left"] &`]: { + transformOrigin: 'right center', + marginInlineEnd: '14px', + }, + [`.${tooltipClasses.popper}[data-popper-placement*="right"] &`]: { + transformOrigin: 'left center', + marginInlineStart: '14px', + }, + [`.${tooltipClasses.popper}[data-popper-placement*="top"] &`]: { + transformOrigin: 'center bottom', + marginBottom: '14px', + }, + [`.${tooltipClasses.popper}[data-popper-placement*="bottom"] &`]: { + transformOrigin: 'center top', + marginTop: '14px', + }, +})); + +interface RichTooltipProps extends React.HTMLAttributes { + shortcut?: React.ReactNode; + description?: React.ReactNode; +} + +const RichTooltip = React.forwardRef(function RichTooltip( + { children, shortcut, description, ...other }, + ref, +) { + // Tooltip appends the arrow as a slot child after `title`. Split it back out so + // the title fills the card while the arrow stays a sibling (kept unclipped). + const items = React.Children.toArray(children); + const arrow = items.find((child) => React.isValidElement(child)); + const title = items.filter((child) => !React.isValidElement(child)); + + return ( + + + {arrow} + + ); +}); + +const triggerSx = { + border: '1px solid', + borderColor: 'divider', + borderRadius: 1.5, +} as const; + +export default function App() { + return ( + + + + Rich Tooltip — header + shortcut + description (existing Tooltip, no new component) + + + + + + P + + } + description="Upload the latest reviewed model version to Autodesk Construction Cloud." + /> + } + > + + + + + + + Hover the icons below (default open state off) + + + + + + C + + } + description="Copy a shareable link to this item to your clipboard." + /> + } + > + + + + + + + + + + + + + + ); +}