Improve annotations (#5919)

* Text box/notes movement improvements 
* Fix the issue where hiding, then showing annotations looses progress 
* Fix the issue where hidig/showing annotations jumps you back up to the
top of your open document 
* Support ctrl+c and  ctrl+v and backspace to delete 
* Better handling when moving to different tool from annotate 
* Added a color picker eyedropper button  
* Auto-switch to Select after note/text placement, so users can quickly
place and type 
This commit is contained in:
EthanHealy01
2026-03-13 14:03:27 +00:00
committed by GitHub
parent 44e036da5a
commit c9d693f1eb
13 changed files with 409 additions and 245 deletions
@@ -1,5 +1,15 @@
import { ActionIcon, Tooltip, Popover, Stack, ColorSwatch, ColorPicker as MantineColorPicker } from '@mantine/core';
import { useState } from 'react';
import { ActionIcon, Tooltip, Popover, Stack, ColorSwatch, ColorPicker as MantineColorPicker, Group } from '@mantine/core';
import { useState, useCallback } from 'react';
import ColorizeIcon from '@mui/icons-material/Colorize';
// safari and firefox do not support the eye dropper API, only edge, chrome and opera do.
// the button is hidden in the UI if the API is not supported.
const supportsEyeDropper = typeof window !== 'undefined' && 'EyeDropper' in window;
interface EyeDropper {
open(): Promise<{ sRGBHex: string }>;
}
declare const EyeDropper: { new(): EyeDropper };
interface ColorControlProps {
value: string;
@@ -11,6 +21,17 @@ interface ColorControlProps {
export function ColorControl({ value, onChange, label, disabled = false }: ColorControlProps) {
const [opened, setOpened] = useState(false);
const handleEyeDropper = useCallback(async () => {
if (!supportsEyeDropper) return;
try {
const eyeDropper = new EyeDropper();
const result = await eyeDropper.open();
onChange(result.sRGBHex);
} catch {
// User cancelled or browser error — no-op
}
}, [onChange]);
return (
<Popover opened={opened} onChange={setOpened} position="bottom" withArrow withinPortal>
<Popover.Target>
@@ -52,6 +73,15 @@ export function ColorControl({ value, onChange, label, disabled = false }: Color
swatchesPerRow={5}
size="sm"
/>
{supportsEyeDropper && (
<Group justify="flex-end">
<Tooltip label="Pick colour from screen">
<ActionIcon variant="subtle" color="gray" size="sm" onClick={handleEyeDropper}>
<ColorizeIcon style={{ fontSize: 16 }} />
</ActionIcon>
</Tooltip>
</Group>
)}
</Stack>
</Popover.Dropdown>
</Popover>