fix(ui): keep inline toolbar visible when popover is open

- add `toolbarPinnedRef` in BlockEditor to prevent toolbar from closing while a popover is focused
- pass `onPinChange` callback to InlineToolbar to toggle the pinned state
- notify parent via `onPinChange` whenever popover state changes
- remove rect-change effect that was incorrectly closing popovers on selection update
This commit is contained in:
2026-04-25 18:30:02 -04:00
parent d9fbe29031
commit 7b6bf67f36
2 changed files with 11 additions and 3 deletions
@@ -441,12 +441,17 @@ export default function BlockEditor({
// qu'elle se trouve dans un contentEditable de l'éditeur.
const [toolbar, setToolbar] = useState(null);
// { blockId, start, end, rect, marks }
const toolbarPinnedRef = useRef(false);
const updateToolbar = useCallback(() => {
if (disabled) {
setToolbar(null);
return;
}
// Quand un popover du toolbar est ouvert (lien, couleur…), le focus
// passe sur l'input/bouton et la sélection peut paraître hors-bloc :
// on garde la toolbar visible.
if (toolbarPinnedRef.current) return;
const sel = typeof window !== 'undefined' ? window.getSelection() : null;
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) {
setToolbar(null);
@@ -837,6 +842,7 @@ export default function BlockEditor({
rect={toolbar.rect}
activeMarks={marks}
onToggleMark={applyToggleMark}
onPinChange={(p) => { toolbarPinnedRef.current = p; }}
/>
);
})()}
@@ -22,12 +22,16 @@ const SIMPLE_BUTTONS = [
{ type: 'code', label: '</>', title: 'Code (Ctrl+E)', className: 'font-mono text-[11px]' },
];
export default function InlineToolbar({ rect, activeMarks, onToggleMark }) {
export default function InlineToolbar({ rect, activeMarks, onToggleMark, onPinChange }) {
const ref = useRef(null);
const [pos, setPos] = useState({ top: 0, left: 0, flipped: false });
const [popover, setPopover] = useState(null); // 'color' | 'highlight' | 'link' | null
const [linkUrl, setLinkUrl] = useState('');
useEffect(() => {
onPinChange?.(popover !== null);
}, [popover, onPinChange]);
useLayoutEffect(() => {
if (!rect || typeof window === 'undefined') return;
const width = ref.current?.offsetWidth ?? 280;
@@ -47,8 +51,6 @@ export default function InlineToolbar({ rect, activeMarks, onToggleMark }) {
setPos({ top, left, flipped: flipBelow });
}, [rect]);
// Ferme un popover ouvert quand la sélection change (rect change).
useEffect(() => { setPopover(null); }, [rect?.top, rect?.left]);
function isActive(type, payloadKey) {
if (!Array.isArray(activeMarks)) return false;