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,
|
||||
concatInline,
|
||||
toggleMark,
|
||||
setMark,
|
||||
removeAllMarks,
|
||||
marksInRange,
|
||||
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() {
|
||||
if (!toolbar) return;
|
||||
const { blockId, start, end } = toolbar;
|
||||
@@ -1073,6 +1088,7 @@ export default function BlockEditor({
|
||||
activeMarks={marks}
|
||||
usedColors={usedColors}
|
||||
onToggleMark={applyToggleMark}
|
||||
onSetMark={applySetMark}
|
||||
onClearMarks={applyRemoveAllMarks}
|
||||
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: '' },
|
||||
];
|
||||
|
||||
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 [pos, setPos] = useState({ top: 0, left: 0, flipped: false });
|
||||
const [popover, setPopover] = useState(null); // 'color' | 'highlight' | 'link' | null
|
||||
@@ -75,9 +75,9 @@ export default function InlineToolbar({ rect, activeMarks, onToggleMark, onClear
|
||||
}
|
||||
|
||||
function handleLinkSubmit(e) {
|
||||
e.preventDefault();
|
||||
e.preventDefault?.();
|
||||
if (!linkUrl) return;
|
||||
onToggleMark?.({ type: 'link', href: linkUrl, newTab: linkNewTab });
|
||||
onSetMark?.({ type: 'link', href: linkUrl, newTab: linkNewTab });
|
||||
setLinkUrl('');
|
||||
setPopover(null);
|
||||
}
|
||||
|
||||
@@ -304,6 +304,13 @@ export function removeMark(nodes, start, end, 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),
|
||||
// on la retire ; sinon on l'applique partout.
|
||||
export function toggleMark(nodes, start, end, mark) {
|
||||
|
||||
Reference in New Issue
Block a user