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:
@@ -441,12 +441,17 @@ export default function BlockEditor({
|
|||||||
// qu'elle se trouve dans un contentEditable de l'éditeur.
|
// qu'elle se trouve dans un contentEditable de l'éditeur.
|
||||||
const [toolbar, setToolbar] = useState(null);
|
const [toolbar, setToolbar] = useState(null);
|
||||||
// { blockId, start, end, rect, marks }
|
// { blockId, start, end, rect, marks }
|
||||||
|
const toolbarPinnedRef = useRef(false);
|
||||||
|
|
||||||
const updateToolbar = useCallback(() => {
|
const updateToolbar = useCallback(() => {
|
||||||
if (disabled) {
|
if (disabled) {
|
||||||
setToolbar(null);
|
setToolbar(null);
|
||||||
return;
|
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;
|
const sel = typeof window !== 'undefined' ? window.getSelection() : null;
|
||||||
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) {
|
if (!sel || sel.rangeCount === 0 || sel.isCollapsed) {
|
||||||
setToolbar(null);
|
setToolbar(null);
|
||||||
@@ -837,6 +842,7 @@ export default function BlockEditor({
|
|||||||
rect={toolbar.rect}
|
rect={toolbar.rect}
|
||||||
activeMarks={marks}
|
activeMarks={marks}
|
||||||
onToggleMark={applyToggleMark}
|
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]' },
|
{ 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 ref = useRef(null);
|
||||||
const [pos, setPos] = useState({ top: 0, left: 0, flipped: false });
|
const [pos, setPos] = useState({ top: 0, left: 0, flipped: false });
|
||||||
const [popover, setPopover] = useState(null); // 'color' | 'highlight' | 'link' | null
|
const [popover, setPopover] = useState(null); // 'color' | 'highlight' | 'link' | null
|
||||||
const [linkUrl, setLinkUrl] = useState('');
|
const [linkUrl, setLinkUrl] = useState('');
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
onPinChange?.(popover !== null);
|
||||||
|
}, [popover, onPinChange]);
|
||||||
|
|
||||||
useLayoutEffect(() => {
|
useLayoutEffect(() => {
|
||||||
if (!rect || typeof window === 'undefined') return;
|
if (!rect || typeof window === 'undefined') return;
|
||||||
const width = ref.current?.offsetWidth ?? 280;
|
const width = ref.current?.offsetWidth ?? 280;
|
||||||
@@ -47,8 +51,6 @@ export default function InlineToolbar({ rect, activeMarks, onToggleMark }) {
|
|||||||
setPos({ top, left, flipped: flipBelow });
|
setPos({ top, left, flipped: flipBelow });
|
||||||
}, [rect]);
|
}, [rect]);
|
||||||
|
|
||||||
// Ferme un popover ouvert quand la sélection change (rect change).
|
|
||||||
useEffect(() => { setPopover(null); }, [rect?.top, rect?.left]);
|
|
||||||
|
|
||||||
function isActive(type, payloadKey) {
|
function isActive(type, payloadKey) {
|
||||||
if (!Array.isArray(activeMarks)) return false;
|
if (!Array.isArray(activeMarks)) return false;
|
||||||
|
|||||||
Reference in New Issue
Block a user