feat(editor): float image with text wrap (#145, port from Forkmost)
Adds floatLeft / floatRight image alignment so text wraps beside the image, beyond the existing block left/center/right. Ported from Forkmost PR #7 / upstream Docmost PR #1132 (fuscodev), adapted to gitmost's imperative image node-view (the upstream uses a React styled component; ours styles the node-view container directly via applyAlignment). - editor-ext image.ts: `setImageAlign` accepts `floatLeft`/`floatRight`; `applyAlignment` resets float/padding then, for a float mode, sets `float:left|right` + side padding on the (shrink-to-fit) container so text flows beside it (the inner <img> already has max-width:100%). The resolved align is mirrored onto the container as `data-image-align` for the responsive rule. `data-align` already round-trips the value through parse/renderHTML, so float survives serialization / collab / history with no schema change. - image-menu.tsx: Float-left / Float-right bubble-menu buttons (IconFloatLeft/ Right) with active state. - image-resize.module.css: on narrow screens (<=600px) a floated image collapses to full width and drops the float (`!important`, keyed on data-image-align) — the upstream "100% width on small screen" follow-up. - i18n: en-US + ru-RU strings. editor-ext build + client tsc --noEmit clean. Visual wrap behavior is best confirmed in-browser (logic/serialization verified by build + types). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -51,7 +51,9 @@ declare module "@tiptap/core" {
|
||||
setImageAt: (
|
||||
attributes: ImageAttributes & { pos: number | Range },
|
||||
) => ReturnType;
|
||||
setImageAlign: (align: "left" | "center" | "right") => ReturnType;
|
||||
setImageAlign: (
|
||||
align: "left" | "center" | "right" | "floatLeft" | "floatRight",
|
||||
) => ReturnType;
|
||||
setImageWidth: (width: number) => ReturnType;
|
||||
setImageSize: (width: number, height: number) => ReturnType;
|
||||
};
|
||||
@@ -375,7 +377,26 @@ export const TiptapImage = Image.extend<ImageOptions>({
|
||||
});
|
||||
|
||||
function applyAlignment(container: HTMLElement, align: string) {
|
||||
if (align === "left") {
|
||||
// Reset the float-mode styles first so toggling between any two modes is clean
|
||||
// (a previous float must not leak into a later left/center/right).
|
||||
container.style.float = "";
|
||||
container.style.padding = "";
|
||||
// Mirror the resolved alignment onto the CONTAINER as a data attribute so the
|
||||
// responsive stylesheet can neutralize the float on small screens (an inline
|
||||
// `float` can only be overridden by `!important`, which keys off this attr).
|
||||
container.dataset.imageAlign = align;
|
||||
|
||||
if (align === "floatLeft") {
|
||||
// Real text wrap: the (shrink-to-fit) container floats left, text flows on
|
||||
// its right. The inner <img> already carries max-width:100%.
|
||||
container.style.float = "left";
|
||||
container.style.padding = "0 10px 0 0";
|
||||
container.style.justifyContent = "flex-start";
|
||||
} else if (align === "floatRight") {
|
||||
container.style.float = "right";
|
||||
container.style.padding = "0 0 0 10px";
|
||||
container.style.justifyContent = "flex-end";
|
||||
} else if (align === "left") {
|
||||
container.style.justifyContent = "flex-start";
|
||||
} else if (align === "right") {
|
||||
container.style.justifyContent = "flex-end";
|
||||
|
||||
Reference in New Issue
Block a user