test: floating text selection toolbar

This commit is contained in:
gosangam
2026-05-05 02:20:53 +05:30
parent eb2cba3af1
commit 1930f5e034
+46 -7
View File
@@ -710,12 +710,47 @@ function MorePopover({
function FloatingToolbar({ function FloatingToolbar({
position, position,
actions, actions,
isMobile,
}: { }: {
position: Position; position: Position;
actions: ToolbarAction[]; actions: ToolbarAction[];
isMobile: boolean;
}) { }) {
// Calculate position — center above the selection, clamp to viewport if (isMobile) {
const toolbarWidth = actions.length * 44 + 8; // approximate // Mobile: fixed bottom bar
return createPortal(
<div
className="fixed z-80 bottom-0 inset-x-0 border-t border-white/10 bg-black shadow-2xl px-3 py-2.5 pb-[max(0.75rem,env(safe-area-inset-bottom))] animate-in fade-in-0 slide-in-from-bottom-4 dark:bg-[#1a1a1a] dark:border-white/15"
onMouseDown={(e) => e.preventDefault()}
>
<div className="flex items-center justify-around gap-1">
{actions.map((action) => (
<button
key={action.key}
onClick={(e) => {
e.preventDefault();
e.stopPropagation();
action.onClick();
}}
onMouseDown={(e) => e.preventDefault()}
className={cn(
"flex flex-col items-center gap-1 px-3 py-2 rounded-lg text-xs font-medium transition-colors min-w-14",
action.className ??
"text-white/70 active:bg-white/10 active:text-white",
)}
>
{action.icon}
<span>{action.label}</span>
</button>
))}
</div>
</div>,
document.body,
);
}
// Desktop: floating above the selection
const toolbarWidth = actions.length * 44 + 8;
const left = Math.max( const left = Math.max(
8, 8,
Math.min( Math.min(
@@ -727,9 +762,9 @@ function FloatingToolbar({
return createPortal( return createPortal(
<div <div
className="fixed z-80 flex items-center gap-0.5 rounded-xl border border-white/10 bg-black shadow-2xl px-1.5 py-1 animate-in fade-in-0 zoom-in-95 slide-in-from-bottom-2 dark:bg-[#1a1a1a] dark:border-white/15" className="fixed z-80 flex items-center gap-1 rounded-xl border border-white/10 bg-black shadow-2xl px-2 py-1.5 animate-in fade-in-0 zoom-in-95 slide-in-from-bottom-2 dark:bg-[#1a1a1a] dark:border-white/15"
style={{ left, top }} style={{ left, top }}
onMouseDown={(e) => e.preventDefault()} // prevent losing selection onMouseDown={(e) => e.preventDefault()}
> >
{actions.map((action) => ( {actions.map((action) => (
<button <button
@@ -741,14 +776,14 @@ function FloatingToolbar({
}} }}
onMouseDown={(e) => e.preventDefault()} onMouseDown={(e) => e.preventDefault()}
className={cn( className={cn(
"flex items-center gap-1.5 px-2.5 py-1.5 rounded-md text-xs font-medium transition-colors", "flex items-center gap-1.5 px-3 py-2 rounded-lg text-sm font-medium transition-colors",
action.className ?? action.className ??
"text-white/70 hover:bg-white/10 hover:text-white", "text-white/70 hover:bg-white/10 hover:text-white",
)} )}
title={action.label} title={action.label}
> >
{action.icon} {action.icon}
<span className="hidden sm:inline">{action.label}</span> <span>{action.label}</span>
</button> </button>
))} ))}
</div>, </div>,
@@ -1008,7 +1043,11 @@ export function TextSelectionToolbar() {
return ( return (
<div data-selection-toolbar> <div data-selection-toolbar>
{/* Floating toolbar */} {/* Floating toolbar */}
<FloatingToolbar position={toolbarPos} actions={toolbarActions} /> <FloatingToolbar
position={toolbarPos}
actions={toolbarActions}
isMobile={isMobile}
/>
{/* More popover */} {/* More popover */}
<MorePopover <MorePopover