Update nodes

This commit is contained in:
Nate Kelley 2025-07-28 22:49:44 -06:00
parent d323df1f0f
commit c5794a2593
No known key found for this signature in database
GPG Key ID: FD90372AB8D98B4F
6 changed files with 147 additions and 200 deletions

View File

@ -236,32 +236,35 @@ export function ToolbarSplitButtonSecondary({
);
}
export function ToolbarToggleItem({
className,
size = 'sm',
variant,
...props
}: React.ComponentProps<typeof ToolbarPrimitive.ToggleItem> &
VariantProps<typeof toolbarButtonVariants>) {
export const ToolbarToggleItem = React.forwardRef<
React.ElementRef<typeof ToolbarPrimitive.ToggleItem>,
React.ComponentProps<typeof ToolbarPrimitive.ToggleItem> &
VariantProps<typeof toolbarButtonVariants>
>(function ToolbarToggleItem({ className, size = 'sm', variant, ...props }, ref) {
return (
<ToolbarPrimitive.ToggleItem
ref={ref}
className={cn(toolbarButtonVariants({ size, variant }), className)}
{...props}
/>
);
}
});
export function ToolbarGroup({ children, className }: React.ComponentProps<'div'>) {
return (
<div className={cn('group/toolbar-group', 'relative hidden has-[button]:flex', className)}>
<div className="flex items-center">{children}</div>
export const ToolbarGroup = React.forwardRef<HTMLDivElement, React.ComponentProps<'div'>>(
function ToolbarGroup({ children, className }, ref) {
return (
<div
ref={ref}
className={cn('group/toolbar-group', 'relative hidden has-[button]:flex', className)}>
<div className="flex items-center">{children}</div>
<div className="mx-1.5 py-0.5 group-last/toolbar-group:hidden!">
<Separator orientation="vertical" />
<div className="mx-1.5 py-0.5 group-last/toolbar-group:hidden!">
<Separator orientation="vertical" />
</div>
</div>
</div>
);
}
);
}
);
type TooltipProps<T extends React.ElementType> = {
tooltip?: React.ReactNode;

View File

@ -19,7 +19,7 @@ import {
import { useSelected } from 'platejs/react';
import { Button } from '@/components/ui/buttons';
import { TooltipBase, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { Tooltip, TooltipBase, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
import { expandListItemsWithChildren } from '@platejs/list';
@ -185,54 +185,51 @@ const DragHandle = React.memo(function DragHandle({
const editor = useEditorRef();
const element = useElement();
return (
<TooltipBase>
<TooltipTrigger asChild>
<div
className="flex size-full items-center justify-center"
onClick={() => {
editor.getApi(BlockSelectionPlugin).blockSelection.set(element.id as string);
}}
onMouseDown={(e) => {
resetPreview();
if (e.button !== 0 || e.shiftKey) return; // Only left mouse button
const elements = createDragPreviewElements(editor, {
currentBlock: element
<Tooltip title="Drag to move">
<div
className="flex size-full items-center justify-center"
onClick={() => {
editor.getApi(BlockSelectionPlugin).blockSelection.set(element.id as string);
}}
onMouseDown={(e) => {
resetPreview();
if (e.button !== 0 || e.shiftKey) return; // Only left mouse button
const elements = createDragPreviewElements(editor, {
currentBlock: element
});
previewRef.current?.append(...elements);
previewRef.current?.classList.remove('hidden');
editor.setOption(DndPlugin, 'multiplePreviewRef', previewRef);
}}
onMouseEnter={() => {
if (isDragging) return;
const blockSelection = editor
.getApi(BlockSelectionPlugin)
.blockSelection.getNodes({ sort: true });
const selectedBlocks =
blockSelection.length > 0 ? blockSelection : editor.api.blocks({ mode: 'highest' });
// Process selection to include list children
const processedBlocks = expandListItemsWithChildren(editor, selectedBlocks);
const ids = processedBlocks.map((block) => block[0].id as string);
if (ids.length > 1 && ids.includes(element.id as string)) {
const previewTop = calculatePreviewTop(editor, {
blocks: processedBlocks.map((block) => block[0]),
element
});
previewRef.current?.append(...elements);
previewRef.current?.classList.remove('hidden');
editor.setOption(DndPlugin, 'multiplePreviewRef', previewRef);
}}
onMouseEnter={() => {
if (isDragging) return;
const blockSelection = editor
.getApi(BlockSelectionPlugin)
.blockSelection.getNodes({ sort: true });
const selectedBlocks =
blockSelection.length > 0 ? blockSelection : editor.api.blocks({ mode: 'highest' });
// Process selection to include list children
const processedBlocks = expandListItemsWithChildren(editor, selectedBlocks);
const ids = processedBlocks.map((block) => block[0].id as string);
if (ids.length > 1 && ids.includes(element.id as string)) {
const previewTop = calculatePreviewTop(editor, {
blocks: processedBlocks.map((block) => block[0]),
element
});
setPreviewTop(previewTop);
} else {
setPreviewTop(0);
}
}}
onMouseUp={() => {
resetPreview();
}}
role="button">
<div className="text-muted-foreground">
<GripDotsVertical />
</div>
setPreviewTop(previewTop);
} else {
setPreviewTop(0);
}
}}
onMouseUp={() => {
resetPreview();
}}
role="button">
<div className="text-muted-foreground">
<GripDotsVertical />
</div>
</TooltipTrigger>
<TooltipContent>Drag to move</TooltipContent>
</TooltipBase>
</div>
</Tooltip>
);
});
const DropLine = React.memo(function DropLine({

View File

@ -27,6 +27,7 @@ import { Button } from '@/components/ui/buttons';
import { PopoverBase, PopoverContent, PopoverAnchor } from '@/components/ui/popover';
import { Separator } from '@/components/ui/separator';
import {
Tooltip,
TooltipBase,
TooltipContent,
TooltipProvider,
@ -86,22 +87,13 @@ export const ColumnElement = withHOC(
const ColumnDragHandle = React.memo(function ColumnDragHandle() {
return (
<TooltipProvider>
<TooltipBase>
<TooltipTrigger asChild>
<Button variant="ghost" className="h-5 !px-1">
<div
className="text-icon-color"
onClick={(event) => {
event.stopPropagation();
event.preventDefault();
}}>
<GripDots />
</div>
</Button>
</TooltipTrigger>
<TooltipContent>Drag to move column</TooltipContent>
</TooltipBase>
<Tooltip title="Drag to move column">
<Button
variant="ghost"
className="h-5 !px-1"
onClick={(e) => e.stopPropagation()}
prefix={<GripDots />}></Button>
</Tooltip>
</TooltipProvider>
);
});

View File

@ -33,6 +33,7 @@ import {
import { Button } from '@/components/ui/buttons';
import {
Tooltip,
TooltipBase,
TooltipContent,
TooltipProvider,
@ -458,26 +459,23 @@ function EmojiPickerNavigation({
.getGrid()
.sections()
.map(({ id }) => (
<TooltipBase key={id}>
<TooltipTrigger asChild>
<button
className={cn(
'text-muted-foreground hover:bg-muted hover:text-muted-foreground flex min-h-5 items-center justify-center rounded-full fill-current p-1.5',
id === focusedCategory &&
'bg-accent text-accent-foreground pointer-events-none fill-current'
)}
onClick={() => {
onClick(id);
}}
aria-label={i18n.categories[id]}
type="button">
<div className="inline-flex size-5 items-center justify-center text-lg">
{icons.categories[id].outline}
</div>
</button>
</TooltipTrigger>
<TooltipContent side="bottom">{i18n.categories[id]}</TooltipContent>
</TooltipBase>
<Tooltip key={id} title={i18n.categories[id]}>
<button
className={cn(
'text-muted-foreground hover:bg-muted hover:text-muted-foreground flex min-h-5 items-center justify-center rounded-full fill-current p-1.5',
id === focusedCategory &&
'bg-accent text-accent-foreground pointer-events-none fill-current'
)}
onClick={() => {
onClick(id);
}}
aria-label={i18n.categories[id]}
type="button">
<div className="inline-flex size-5 items-center justify-center text-lg">
{icons.categories[id].outline}
</div>
</button>
</Tooltip>
))}
</div>
</nav>

View File

@ -17,6 +17,7 @@ import {
DropdownMenuTrigger
} from '@/components/ui/dropdown-menu';
import {
Tooltip,
TooltipBase,
TooltipContent,
TooltipProvider,
@ -333,14 +334,7 @@ function ColorDropdownMenuItem({
/>
);
return name ? (
<TooltipBase>
<TooltipTrigger>{content}</TooltipTrigger>
<TooltipContent className="mb-1 capitalize">{name}</TooltipContent>
</TooltipBase>
) : (
content
);
return name ? <Tooltip title={name}>{content}</Tooltip> : content;
}
export function ColorDropdownMenuItems({

View File

@ -13,7 +13,7 @@ import {
DropdownMenuSeparator
} from '@/components/ui/dropdown-menu';
import { Separator } from '@/components/ui/separator';
import { TooltipBase, TooltipTrigger } from '@/components/ui/tooltip';
import { Tooltip } from '@/components/ui/tooltip';
import { cn } from '@/lib/utils';
export const Toolbar = React.forwardRef<
@ -31,17 +31,18 @@ export const Toolbar = React.forwardRef<
Toolbar.displayName = 'Toolbar';
export function ToolbarToggleGroup({
className,
...props
}: React.ComponentProps<typeof ToolbarPrimitive.ToolbarToggleGroup>) {
export const ToolbarToggleGroup = React.forwardRef<
React.ElementRef<typeof ToolbarPrimitive.ToolbarToggleGroup>,
React.ComponentProps<typeof ToolbarPrimitive.ToolbarToggleGroup>
>(function ToolbarToggleGroup({ className, ...props }, ref) {
return (
<ToolbarPrimitive.ToolbarToggleGroup
ref={ref}
className={cn('flex items-center', className)}
{...props}
/>
);
}
});
export function ToolbarLink({
className,
@ -121,55 +122,54 @@ type ToolbarButtonProps = {
} & Omit<React.ComponentPropsWithoutRef<typeof ToolbarToggleItem>, 'asChild' | 'value'> &
VariantProps<typeof toolbarButtonVariants>;
export const ToolbarButton = withTooltip(function ToolbarButton({
children,
className,
isDropdown,
pressed,
size = 'sm',
variant,
...props
}: ToolbarButtonProps) {
return typeof pressed === 'boolean' ? (
<ToolbarToggleGroup disabled={props.disabled} value="single" type="single">
<ToolbarToggleItem
export const ToolbarButton = withTooltip(
React.forwardRef<HTMLButtonElement, ToolbarButtonProps>(function ToolbarButton(
{ children, className, isDropdown, pressed, size = 'sm', variant, ...props },
ref
) {
return typeof pressed === 'boolean' ? (
<ToolbarToggleGroup disabled={props.disabled} value="single" type="single">
<ToolbarToggleItem
ref={ref}
className={cn(
toolbarButtonVariants({
size,
variant
}),
isDropdown && 'justify-between gap-1 pr-1',
className
)}
value={pressed ? 'single' : ''}
{...props}>
{isDropdown ? (
<>
<div className="flex flex-1 items-center gap-2 whitespace-nowrap">{children}</div>
<div className="text-muted-foreground size-3.5" data-icon>
<ChevronDown />
</div>
</>
) : (
children
)}
</ToolbarToggleItem>
</ToolbarToggleGroup>
) : (
<ToolbarPrimitive.Button
ref={ref}
className={cn(
toolbarButtonVariants({
size,
variant
}),
isDropdown && 'justify-between gap-1 pr-1',
isDropdown && 'pr-1',
className
)}
value={pressed ? 'single' : ''}
{...props}>
{isDropdown ? (
<>
<div className="flex flex-1 items-center gap-2 whitespace-nowrap">{children}</div>
<div className="text-muted-foreground size-3.5" data-icon>
<ChevronDown />
</div>
</>
) : (
children
)}
</ToolbarToggleItem>
</ToolbarToggleGroup>
) : (
<ToolbarPrimitive.Button
className={cn(
toolbarButtonVariants({
size,
variant
}),
isDropdown && 'pr-1',
className
)}
{...props}>
{children}
</ToolbarPrimitive.Button>
);
});
{children}
</ToolbarPrimitive.Button>
);
})
);
export function ToolbarSplitButton({
className,
@ -239,20 +239,19 @@ export function ToolbarSplitButtonSecondary({
);
}
export function ToolbarToggleItem({
className,
size = 'sm',
variant,
...props
}: React.ComponentProps<typeof ToolbarPrimitive.ToggleItem> &
VariantProps<typeof toolbarButtonVariants>) {
export const ToolbarToggleItem = React.forwardRef<
React.ElementRef<typeof ToolbarPrimitive.ToggleItem>,
React.ComponentProps<typeof ToolbarPrimitive.ToggleItem> &
VariantProps<typeof toolbarButtonVariants>
>(function ToolbarToggleItem({ className, size = 'sm', variant, ...props }, ref) {
return (
<ToolbarPrimitive.ToggleItem
ref={ref}
className={cn(toolbarButtonVariants({ size, variant }), className)}
{...props}
/>
);
}
});
export function ToolbarGroup({ children, className }: React.ComponentProps<'div'>) {
return (
@ -268,9 +267,6 @@ export function ToolbarGroup({ children, className }: React.ComponentProps<'div'
type TooltipProps<T extends React.ElementType> = {
tooltip?: React.ReactNode;
tooltipContentProps?: Omit<React.ComponentPropsWithoutRef<typeof TooltipContent>, 'children'>;
tooltipProps?: Omit<React.ComponentPropsWithoutRef<typeof TooltipBase>, 'children'>;
tooltipTriggerProps?: React.ComponentPropsWithoutRef<typeof TooltipTrigger>;
} & React.ComponentProps<T>;
function withTooltip<T extends React.ElementType>(Component: T) {
@ -290,15 +286,7 @@ function withTooltip<T extends React.ElementType>(Component: T) {
const component = React.createElement(Component, componentProps);
if (tooltip && mounted) {
return (
<TooltipBase {...tooltipProps}>
<TooltipTrigger asChild {...tooltipTriggerProps}>
{component}
</TooltipTrigger>
<TooltipContent {...tooltipContentProps}>{tooltip}</TooltipContent>
</TooltipBase>
);
return <Tooltip title={tooltip}>{component}</Tooltip>;
}
return component;
@ -310,31 +298,6 @@ function withTooltip<T extends React.ElementType>(Component: T) {
return ExtendComponent;
}
function TooltipContent({
children,
className,
// CHANGE
sideOffset = 4,
...props
}: React.ComponentProps<typeof TooltipPrimitive.Content>) {
return (
<TooltipPrimitive.Portal>
<TooltipPrimitive.Content
className={cn(
'bg-primary text-primary-foreground z-50 w-fit origin-(--radix-tooltip-content-transform-origin) rounded-md px-3 py-1.5 text-xs text-balance',
className
)}
data-slot="tooltip-content"
sideOffset={sideOffset}
{...props}>
{children}
{/* CHANGE */}
{/* <TooltipPrimitive.Arrow className="z-50 size-2.5 translate-y-[calc(-50%_-_2px)] rotate-45 rounded-[2px] bg-primary fill-primary" /> */}
</TooltipPrimitive.Content>
</TooltipPrimitive.Portal>
);
}
export function ToolbarMenuGroup({
children,
className,