Commit 9ed36052 by Яков

выравнивание картинки, обтекание текста, ресайз

parent 2b0a2301
{
"name": "react-ag-qeditor",
"version": "1.0.85",
"version": "1.0.86",
"description": "WYSIWYG html editor",
"author": "atma",
"license": "MIT",
......
......@@ -20,6 +20,7 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos }) => {
aspectRatio: 1
});
// Добавляем прозрачный нулевой пробел после изображения
useEffect(() => {
if (!editor || !getPos) return;
......@@ -29,21 +30,16 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos }) => {
if (doc.nodeSize > pos && doc.nodeAt(pos)?.textContent !== '\u200B') {
editor.commands.insertContentAt(pos, {
type: 'text',
text: '\u200B'
text: '\u200B' // Невидимый нулевой пробел
});
}
}, [editor, getPos]);
// Инициализация размеров
useEffect(() => {
if (imgRef.current && !isInitialized.current) {
if (node.attrs.width && node.attrs.height) {
isInitialized.current = true;
return;
}
const width = imgRef.current.naturalWidth;
const height = imgRef.current.naturalHeight;
const width = node.attrs.width || imgRef.current.naturalWidth;
const height = node.attrs.height || imgRef.current.naturalHeight;
updateAttributes({
width: Math.round(width),
height: Math.round(height)
......@@ -56,8 +52,8 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos }) => {
e.preventDefault();
e.stopPropagation();
const currentWidth = node.attrs.width;
const currentHeight = node.attrs.height;
const currentWidth = node.attrs.width || imgRef.current.naturalWidth;
const currentHeight = node.attrs.height || imgRef.current.naturalHeight;
resizeData.current = {
startWidth: currentWidth,
......@@ -77,16 +73,20 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos }) => {
let newWidth, newHeight;
if (node.attrs.align === 'center') {
// Особый случай для центрированного изображения
if (direction.includes('n') || direction.includes('s')) {
// Только вертикальный ресайз с сохранением пропорций
const scale = direction.includes('s') ? 1 : -1;
newHeight = Math.max(startHeight + deltaY * scale, MIN_WIDTH);
newWidth = Math.round(newHeight * aspectRatio);
} else {
// Горизонтальный ресайз с сохранением пропорций
const scale = direction.includes('e') ? 1 : -1;
newWidth = Math.max(startWidth + deltaX * scale, MIN_WIDTH);
newHeight = Math.round(newWidth / aspectRatio);
}
} else {
// Обычный ресайз для других выравниваний
if (direction.includes('e') || direction.includes('w')) {
const scale = direction.includes('e') ? 1 : -1;
newWidth = Math.max(startWidth + deltaX * scale, MIN_WIDTH);
......@@ -123,6 +123,8 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos }) => {
const getWrapperStyle = () => {
const baseStyle = {
display: 'inline-block',
lineHeight: 0,
margin: '0.5rem 0',
position: 'relative',
outline: editing ? `1px dashed ${BORDER_COLOR}` : 'none',
verticalAlign: 'top',
......@@ -131,33 +133,39 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos }) => {
switch(node.attrs.align) {
case 'left':
return {
...baseStyle,
float: 'left',
margin: '0 1rem 1rem 0'
};
return { ...baseStyle, float: 'left', marginRight: '1rem' };
case 'right':
return {
...baseStyle,
float: 'right',
margin: '0 0 1rem 1rem'
};
return { ...baseStyle, float: 'right', marginLeft: '1rem' };
case 'center':
return {
...baseStyle,
display: 'block',
margin: '0 auto',
float: 'none',
marginLeft: 'auto',
marginRight: 'auto',
textAlign: 'center'
};
case 'wrap-left':
return { ...baseStyle, float: 'left', margin: '0 1rem 1rem 0', shapeOutside: 'margin-box' };
case 'wrap-right':
return { ...baseStyle, float: 'right', margin: '0 0 1rem 1rem', shapeOutside: 'margin-box' };
default:
return baseStyle;
}
};
const getImageStyle = () => ({
width: node.attrs.width ? `${node.attrs.width}px` : 'auto',
height: node.attrs.height ? `${node.attrs.height}px` : 'auto',
maxWidth: '100%',
display: 'block',
cursor: 'default',
userSelect: 'none',
margin: node.attrs.align === 'center' ? '0 auto' : '0'
});
return (
<NodeViewWrapper
as="span"
as="div"
style={getWrapperStyle()}
ref={wrapperRef}
onClick={(e) => {
......@@ -170,18 +178,9 @@ const ResizableImageTemplate = ({ node, updateAttributes, editor, getPos }) => {
<img
{...node.attrs}
ref={imgRef}
style={{
width: `${node.attrs.width}px`,
height: `${node.attrs.height}px`,
maxWidth: '100%',
display: 'block',
margin: '0 auto', // Центрируем изображение внутри wrapper'а
cursor: 'default',
userSelect: 'none'
}}
style={getImageStyle()}
onLoad={() => {
if (imgRef.current && !isInitialized.current &&
(!node.attrs.width || !node.attrs.height)) {
if (imgRef.current && !isInitialized.current) {
const width = imgRef.current.naturalWidth;
const height = imgRef.current.naturalHeight;
updateAttributes({
......@@ -313,26 +312,27 @@ const ResizableImageExtension = TipTapImage.extend({
renderHTML({ HTMLAttributes }) {
const align = HTMLAttributes.align || 'left';
const isWrap = ['wrap-left', 'wrap-right'].includes(align);
const floatDirection = isWrap ? align.split('-')[1] : ['left', 'right'].includes(align) ? align : 'none';
return ['span', {
'data-type': 'resizable-image',
'data-image-wrapper': true,
style: `
display: ${align === 'center' ? 'block' : 'inline-block'};
float: ${['left', 'right'].includes(align) ? align : 'none'};
float: ${floatDirection};
margin: ${align === 'left' ? '0 1rem 1rem 0' :
align === 'right' ? '0 0 1rem 1rem' :
align === 'center' ? '0 auto' : '0'};
text-align: ${align === 'center' ? 'center' : 'left'};
align === 'wrap-left' ? '0 1rem 1rem 0' :
align === 'wrap-right' ? '0 0 1rem 1rem' :
align === 'center' ? '0.5rem auto' : '0'};
shape-outside: ${isWrap ? 'margin-box' : 'none'};
vertical-align: top;
position: relative;
z-index: 1;
`,
'data-align': align
}, ['img', {
...HTMLAttributes,
style: `width:${HTMLAttributes.width}px;height:${HTMLAttributes.height}px;max-width:100%;display:block;margin:0 auto;`
}]];
}, ['img', HTMLAttributes]];
},
addNodeView() {
......@@ -342,7 +342,7 @@ const ResizableImageExtension = TipTapImage.extend({
inline: true,
group: 'inline',
draggable: true,
selectable: false
selectable: false // Важно отключить выделение изображения
});
export default ResizableImageExtension;
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment