Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@
@import './placeholder.css';
@import './mention.css';
@import './comments.css';
@import './noderesizer.css';
87 changes: 87 additions & 0 deletions packages/super-editor/src/assets/styles/extensions/noderesizer.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/* Resize handles container */
.sd-editor-resize-container {
position: absolute;
pointer-events: none;
z-index: 11;
}

/* Resize handles */
.sd-editor-resize-handle {
position: absolute;
width: 12px;
height: 12px;
background-color: #4dabf7;
border: 2px solid #fff;
border-radius: 50%;
box-shadow: 0 0 4px rgba(0, 0, 0, 0.3);
pointer-events: auto;
transition: all 0.1s ease;
}

.sd-editor-resize-handle:hover {
background-color: #228be6;
transform: scale(1.1);
box-shadow: 0 0 6px rgba(0, 0, 0, 0.4);
}

/* Handle positions */
.sd-editor-resize-handle-nw {
top: -6px;
left: -6px;
cursor: nwse-resize;
}

.sd-editor-resize-handle-ne {
top: -6px;
right: -6px;
cursor: nesw-resize;
}

.sd-editor-resize-handle-sw {
bottom: -6px;
left: -6px;
cursor: nesw-resize;
}

.sd-editor-resize-handle-se {
bottom: -6px;
right: -6px;
cursor: nwse-resize;
}

/* Hide handles when editor loses focus */
.ProseMirror:not(.ProseMirror-focused) .sd-editor-resize-container {
display: none;
}

/* Smooth transitions for resizing */
.sd-editor-resizable-wrapper * {
transition: none;
}

.sd-editor-resizable-wrapper *:not([style*='width']) {
transition: all 0.2s ease;
}

/* Resize feedback indicator */
.sd-editor-resizable-wrapper::after {
content: 'Drag corners to resize';
position: absolute;
bottom: -25px;
left: 50%;
transform: translateX(-50%);
background-color: rgba(77, 171, 247, 0.9);
color: white;
font-size: 11px;
padding: 4px 8px;
border-radius: 4px;
white-space: nowrap;
pointer-events: none;
opacity: 0;
transition: opacity 0.3s ease;
z-index: 12;
}

.sd-editor-resizable-wrapper:hover::after {
opacity: 1;
}
18 changes: 9 additions & 9 deletions packages/super-editor/src/extensions/image/image.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Node, Attribute } from '@core/index.js';
import { Attribute, Node } from '@core/index.js';
import { ImagePlaceholderPlugin } from './imageHelpers/imagePlaceholderPlugin.js';
import { ImagePositionPlugin } from './imageHelpers/imagePositionPlugin.js';

Expand Down Expand Up @@ -41,7 +41,7 @@ export const Image = Node.create({
alt: {
default: null,
},

id: { rendered: false },

title: {
Expand All @@ -64,7 +64,7 @@ export const Image = Node.create({
default: null,
rendered: false,
},

isAnchor: { rendered: false },
simplePos: { rendered: false },
wrapText: { rendered: false },
Expand All @@ -73,17 +73,17 @@ export const Image = Node.create({
default: {},
renderDOM: ({ size }) => {
let style = '';
let { width, height } = size ?? {};
const { width, height } = size ?? {};
if (width) style += `width: ${width}px;`;
if (height) style += `height: auto;`;
if (height) style += 'height: auto;';
return { style };
},
},

padding: {
default: {},
renderDOM: ({ padding, marginOffset }) => {
let { left = 0, top = 0, bottom = 0, right = 0 } = padding ?? {};
const { left = 0, top = 0, bottom = 0, right = 0 } = padding ?? {};
let style = '';
if (left && !marginOffset?.left) style += `margin-left: ${left}px;`;
if (top && !marginOffset?.top) style += `margin-top: ${top}px;`;
Expand All @@ -96,7 +96,7 @@ export const Image = Node.create({
marginOffset: {
default: {},
renderDOM: ({ marginOffset }) => {
let { left = 0, top = 0 } = marginOffset ?? {};
const { left = 0, top = 0 } = marginOffset ?? {};
let style = '';
if (left) style += `margin-left: ${left}px;`;
if (top) style += `margin-top: ${top}px;`;
Expand Down Expand Up @@ -141,6 +141,6 @@ export const Image = Node.create({
},

addPmPlugins() {
return [ImagePlaceholderPlugin(), ImagePositionPlugin({editor: this.editor })];
return [ImagePlaceholderPlugin(), ImagePositionPlugin({ editor: this.editor })];
},
});
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ export const ImagePositionPlugin = ({ editor }) => {
if (shouldUpdate) {
shouldUpdate = false;
const decorations = getImagePositionDecorations(lastState, view);
const updateTransaction = view.state.tr.setMeta(
ImagePositionPluginKey,
{ decorations }
);
const updateTransaction = view.state.tr.setMeta(ImagePositionPluginKey, { decorations });
view.dispatch(updateTransaction);
}
if (pagination?.isReadyToInit) {
Expand All @@ -57,7 +54,7 @@ const getImagePositionDecorations = (state, view) => {
let className = '';
const { vRelativeFrom, alignH } = node.attrs.anchorData;
const { size, padding } = node.attrs;

const pageBreak = findPreviousDomNodeWithClass(view, pos, 'pagination-break-wrapper');
if (pageBreak) {
switch (alignH) {
Expand All @@ -71,8 +68,11 @@ const getImagePositionDecorations = (state, view) => {
style += 'display: block; margin-left: auto; margin-right: auto; ';
break;
}
style += vRelativeFrom === 'margin' ? `position: absolute; top: ${pageBreak?.offsetTop + pageBreak?.offsetHeight}px; ` : '';

style +=
vRelativeFrom === 'margin'
? `position: absolute; top: ${pageBreak?.offsetTop + pageBreak?.offsetHeight}px; `
: '';

if (vRelativeFrom === 'margin') {
const nextPos = view.posAtDOM(pageBreak, 1);
const imageBlock = document.createElement('div');
Expand All @@ -94,7 +94,7 @@ const getImagePositionDecorations = (state, view) => {

const findPreviousDomNodeWithClass = (view, pos, className) => {
let { node } = view.domAtPos(pos);

// If you get a text node, go to its parent
if (node.nodeType === 3) {
node = node.parentNode;
Expand All @@ -117,4 +117,4 @@ const findPreviousDomNodeWithClass = (view, pos, className) => {
}

return null; // Not found
}
};
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ export * from './startImageUpload.js';
export * from './handleImageUpload.js';
export * from './imagePlaceholderPlugin.js';
export * from './processUploadedImage.js';
export * from './imagePositionPlugin.js';
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,14 @@ export const processUploadedImage = (fileData, editor) => {

img.onload = () => {
const canvas = document.createElement('canvas');
const { width, height } = getAllowedImageDimensions(
img.width,
img.height,
editor,
);
const { width, height } = getAllowedImageDimensions(img.width, img.height, editor);
canvas.width = width;
canvas.height = height;

const ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0, width, height);

if (typeof fileData === 'string' ) {
if (typeof fileData === 'string') {
const resizedBase64 = canvas.toDataURL();
resolve(resizedBase64);
} else {
Expand All @@ -47,13 +43,13 @@ export const getAllowedImageDimensions = (width, height, editor) => {
const aspectRatio = width / height;

if (height > maxHeight) {
adjustedHeight = maxHeight;
adjustedWidth = Math.round(maxHeight * aspectRatio);
adjustedHeight = maxHeight;
adjustedWidth = Math.round(maxHeight * aspectRatio);
}

if (adjustedWidth > maxWidth) {
adjustedWidth = maxWidth;
adjustedHeight = Math.round(maxWidth / aspectRatio);
adjustedWidth = maxWidth;
adjustedHeight = Math.round(maxWidth / aspectRatio);
}

return { width: adjustedWidth, height: adjustedHeight };
Expand Down
1 change: 1 addition & 0 deletions packages/super-editor/src/extensions/image/index.js
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export * from './image';
export * from './imageHelpers';
4 changes: 4 additions & 0 deletions packages/super-editor/src/extensions/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { TrackChanges } from './track-changes/index.js';
import { Pagination } from './pagination/index.js';
import { LinkedStyles } from './linked-styles/linked-styles.js';
import { Search } from './search/index.js';
import { NodeResizer } from './noderesizer/index.js';

// Helpers
import { trackChangesHelpers } from './track-changes/index.js';
Expand Down Expand Up @@ -100,6 +101,7 @@ const getRichTextExtensions = () => {
TrackFormat,
AiPlugin,
Image,
NodeResizer,
];
};

Expand Down Expand Up @@ -165,6 +167,7 @@ const getStarterExtensions = () => {
ContentBlock,
Search,
StructuredContent,
NodeResizer,
];
};

Expand Down Expand Up @@ -227,4 +230,5 @@ export {
AiPlugin,
Search,
StructuredContent,
NodeResizer,
};
1 change: 1 addition & 0 deletions packages/super-editor/src/extensions/noderesizer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export * from './noderesizer.js';
Loading