feat(BlockEditor): add setMark utility and wire link submission to it
- add `setMark` helper in `types.js` that removes then applies a mark, replacing existing marks of the same type without toggling - expose `applySetMark` in `BlockEditor.client.js` and pass it as `onSetMark` prop to `InlineToolbar` - switch `handleLinkSubmit` in `Toolbar.client.js` to use `onSetMark` instead of `onToggleMark` so re-submitting a link always applies the new href
This commit is contained in:
@@ -13,6 +13,7 @@ import {
|
|||||||
sliceInline,
|
sliceInline,
|
||||||
concatInline,
|
concatInline,
|
||||||
toggleMark,
|
toggleMark,
|
||||||
|
setMark,
|
||||||
removeAllMarks,
|
removeAllMarks,
|
||||||
marksInRange,
|
marksInRange,
|
||||||
collectUsedColors,
|
collectUsedColors,
|
||||||
@@ -625,6 +626,20 @@ export default function BlockEditor({
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function applySetMark(mark) {
|
||||||
|
if (!toolbar) return;
|
||||||
|
const { blockId, start, end } = toolbar;
|
||||||
|
const block = blocks.find(b => b.id === blockId);
|
||||||
|
if (!block) return;
|
||||||
|
const next = setMark(block.content ?? [], start, end, mark);
|
||||||
|
const nextBlocks = blocks.map(b => (b.id === blockId ? { ...b, content: next } : b));
|
||||||
|
commitChange(nextBlocks, { immediate: true });
|
||||||
|
requestAnimationFrame(() => {
|
||||||
|
const ref = blockRefs.current.get(blockId);
|
||||||
|
ref?.setCaretRange?.(start, end);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
function applyRemoveAllMarks() {
|
function applyRemoveAllMarks() {
|
||||||
if (!toolbar) return;
|
if (!toolbar) return;
|
||||||
const { blockId, start, end } = toolbar;
|
const { blockId, start, end } = toolbar;
|
||||||
@@ -1073,6 +1088,7 @@ export default function BlockEditor({
|
|||||||
activeMarks={marks}
|
activeMarks={marks}
|
||||||
usedColors={usedColors}
|
usedColors={usedColors}
|
||||||
onToggleMark={applyToggleMark}
|
onToggleMark={applyToggleMark}
|
||||||
|
onSetMark={applySetMark}
|
||||||
onClearMarks={applyRemoveAllMarks}
|
onClearMarks={applyRemoveAllMarks}
|
||||||
onPinChange={(p) => { toolbarPinnedRef.current = p; }}
|
onPinChange={(p) => { toolbarPinnedRef.current = p; }}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ const SIMPLE_BUTTONS = [
|
|||||||
{ type: 'code', label: <CodeSimpleIcon width={15} height={15} />, title: 'Code (Ctrl+E)', className: '' },
|
{ type: 'code', label: <CodeSimpleIcon width={15} height={15} />, title: 'Code (Ctrl+E)', className: '' },
|
||||||
];
|
];
|
||||||
|
|
||||||
export default function InlineToolbar({ rect, activeMarks, onToggleMark, onClearMarks, onPinChange, usedColors }) {
|
export default function InlineToolbar({ rect, activeMarks, onToggleMark, onSetMark, onClearMarks, onPinChange, usedColors }) {
|
||||||
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
|
||||||
@@ -75,9 +75,9 @@ export default function InlineToolbar({ rect, activeMarks, onToggleMark, onClear
|
|||||||
}
|
}
|
||||||
|
|
||||||
function handleLinkSubmit(e) {
|
function handleLinkSubmit(e) {
|
||||||
e.preventDefault();
|
e.preventDefault?.();
|
||||||
if (!linkUrl) return;
|
if (!linkUrl) return;
|
||||||
onToggleMark?.({ type: 'link', href: linkUrl, newTab: linkNewTab });
|
onSetMark?.({ type: 'link', href: linkUrl, newTab: linkNewTab });
|
||||||
setLinkUrl('');
|
setLinkUrl('');
|
||||||
setPopover(null);
|
setPopover(null);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -304,6 +304,13 @@ export function removeMark(nodes, start, end, type) {
|
|||||||
return mapRange(nodes, start, end, n => removeMarkFromNode(n, type));
|
return mapRange(nodes, start, end, n => removeMarkFromNode(n, type));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Retire le type existant et applique la nouvelle mark — utile pour remplacer
|
||||||
|
// un lien sans passer par le toggle (qui retirerait si même href).
|
||||||
|
export function setMark(nodes, start, end, mark) {
|
||||||
|
const removed = removeMark(nodes, start, end, mark.type);
|
||||||
|
return applyMark(removed, start, end, mark);
|
||||||
|
}
|
||||||
|
|
||||||
// Toggle : si toute la plage porte déjà la mark (au sens markKey strict),
|
// Toggle : si toute la plage porte déjà la mark (au sens markKey strict),
|
||||||
// on la retire ; sinon on l'applique partout.
|
// on la retire ; sinon on l'applique partout.
|
||||||
export function toggleMark(nodes, start, end, mark) {
|
export function toggleMark(nodes, start, end, mark) {
|
||||||
|
|||||||
Reference in New Issue
Block a user