feat(BlockEditor): add image alignment, link, and replace/delete controls
- add align (left/center/right/full), href, newTab fields to image block - render floating toolbar on image hover with alignment buttons and link popover - add replace and delete actions to image toolbar - wrap image in <a> in disabled mode and HTML export when href is set - update htmlToBlocks/blocksToHtml to serialize/parse align, href, newTab - guard handleContainerMouseDown to prevent multi-block selection on input/textarea focus - add alignment and link icons to shared icons index - update README with image block spec and toolbar behaviour
This commit is contained in:
@@ -89,10 +89,31 @@ function blockToElement(block) {
|
||||
}
|
||||
if (block.type === 'image') {
|
||||
const fig = document.createElement('figure');
|
||||
const align = block.align || 'center';
|
||||
fig.setAttribute('data-align', align);
|
||||
if (align === 'left' || align === 'right' || align === 'center') {
|
||||
// CSS inline minimal pour les destinations qui ignorent data-align.
|
||||
fig.setAttribute('style',
|
||||
align === 'center' ? 'text-align:center'
|
||||
: align === 'left' ? 'text-align:left'
|
||||
: 'text-align:right');
|
||||
}
|
||||
const img = document.createElement('img');
|
||||
img.setAttribute('src', block.src || '');
|
||||
if (block.alt) img.setAttribute('alt', block.alt);
|
||||
fig.appendChild(img);
|
||||
if (align === 'full') img.setAttribute('width', '100%');
|
||||
let imgHost = img;
|
||||
if (block.href) {
|
||||
const a = document.createElement('a');
|
||||
a.setAttribute('href', block.href);
|
||||
if (block.newTab) {
|
||||
a.setAttribute('target', '_blank');
|
||||
a.setAttribute('rel', 'noopener noreferrer');
|
||||
}
|
||||
a.appendChild(img);
|
||||
imgHost = a;
|
||||
}
|
||||
fig.appendChild(imgHost);
|
||||
if (block.caption) {
|
||||
const cap = document.createElement('figcaption');
|
||||
cap.textContent = block.caption;
|
||||
@@ -270,12 +291,20 @@ function parseChildren(node, out) {
|
||||
const img = child.querySelector('img');
|
||||
if (img) {
|
||||
const cap = child.querySelector('figcaption');
|
||||
const linkEl = img.parentElement?.tagName === 'A' ? img.parentElement : null;
|
||||
const dataAlign = child.getAttribute('data-align');
|
||||
const align = ['left', 'center', 'right', 'full'].includes(dataAlign) ? dataAlign : 'center';
|
||||
const href = linkEl?.getAttribute('href') || '';
|
||||
const newTab = !!href && linkEl?.getAttribute('target') === '_blank';
|
||||
out.push({
|
||||
id: newBlockId(),
|
||||
type: 'image',
|
||||
src: img.getAttribute('src') || '',
|
||||
alt: img.getAttribute('alt') || '',
|
||||
caption: cap?.textContent?.trim() || '',
|
||||
align,
|
||||
href,
|
||||
newTab,
|
||||
});
|
||||
}
|
||||
continue;
|
||||
@@ -289,6 +318,9 @@ function parseChildren(node, out) {
|
||||
src: child.getAttribute('src') || '',
|
||||
alt: child.getAttribute('alt') || '',
|
||||
caption: '',
|
||||
align: 'center',
|
||||
href: '',
|
||||
newTab: false,
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user