feat(editor): float image with text wrap (#145) #157
Reference in New Issue
Block a user
Delete Branch "feat/float-image"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Закрывает #145.
Что
Обтекание картинки текстом:
floatLeft/floatRight— текст обтекает изображение сбоку, в дополнение к блочным left/center/right. Порт из Forkmost PR #7 / апстрим Docmost PR #1132 (fuscodev), адаптирован под нашу императивную ноду-вью картинки (у апстрима — React styled-компонент, у нас стилизуется контейнер node-view черезapplyAlignment).Изменения
editor-ext/image.ts:setImageAlignпринимаетfloatLeft/floatRight;applyAlignmentсначала сбрасывает float/padding, затем для float-режима ставитfloat:left|right+ боковой padding на shrink-to-fit контейнер (внутренний<img>уже сmax-width:100%). Резолвнутый align зеркалится вdata-image-alignна контейнере для адаптивного правила.data-alignуже round-trip'ится через parse/renderHTML → float переживает сериализацию/коллаборацию/историю без смены схемы.image-menu.tsx: кнопки Float-left / Float-right в bubble-меню (IconFloatLeft/Right) с active-состоянием.image-resize.module.css: на узких экранах (≤600px) плавающая картинка схлопывается в 100% ширины и сбрасывает float (!important, поdata-image-align) — это follow-up-коммит «100% width on small screen» из Forkmost.Проверка
pnpm --filter @docmost/editor-ext build+ clienttsc --noEmit— чисто. Логика и сериализация подтверждены типами/сборкой; визуальное обтекание лучше глянуть в браузере.🤖 Generated with Claude Code
Code review — float image with text wrap
Вердикт: Approve with comments. Прогнаны все 8 аспектов (Full‑tier, >100 строк). Критичных проблем и регрессий нет, ядро новой логики (
applyAlignment) покрыто проходящими тестами (6/6, jsdom). Замечания ниже — только улучшения, мердж не блокируют.Critical
Нет.
Warnings
Нет. Security, documentation/a11y/i18n, simplification — LGTM. Инъекций нет:
alignиспользуется только в сравнениях===, значения стилей — литералы,data-image-alignпишется через DOMdataset(экранируется браузером). i18n‑политика (только en‑US + ru‑RU,fallbackLng:"en-US") задокументирована вi18n.ts. У обеих кнопок естьaria-label={t(...)}.Suggestions
[conventions] Незаскоупленный
:global([data-image-align=…])—node-resize.module.css:84-90Единственный другой
:globalв файле локально заскоуплен (.container:global(.ProseMirror-selectednode), стр. 47), а новое правило полностью глобально в*.module.css. Работает только потому, чтоdata-image-alignесть лишь на image‑контейнере.Fix:
.container:global([data-image-align="floatLeft"]), .container:global([data-image-align="floatRight"])— это тот же элемент, на которыйapplyAlignmentпишетdataset.imageAlign.[stability/regressions] Фолбэк
ImageViewне знает про float —image-view.tsx:13-18alignClassмапит только left/right/center;floatLeft/floatRightмолча уходят вalignCenter. Не живая регрессия:ImageViewобслуживает только плейсхолдер/загрузку (нетsrc) или конфиг с выключенным resize; картинка сsrcрендерится через float‑awareResizableNodeView. Fix (по желанию): добавить в memoif (align === "floatLeft") return "alignLeft"; if (align === "floatRight") return "alignRight";.[stability] У плавающей картинки нет clearing —
node-resize.module.css:76-90Классика CSS‑float: картинка выше следующего короткого абзаца может перекрыть последующие блоки (картинку, код, таблицу). Присуще самой фиче, не дефект кода — стоит глазами проверить кейс «высокая картинка → короткий абзац → блок» и решить, нужен ли
clear.Test coverage
Ядро покрыто осмысленно:
image.spec.tsгоняет все 5 ветокapplyAlignment(cssFloat/padding/dataset.imageAlign/justifyContent) и пинит reset‑guard на floatLeft→left. Тест проходит (6/6, jsdom). Один пробел:else/default тестируется только валидным"center"—image.spec.ts:49-56applyAlignmentтипизирована какalign: stringи зовётся сnode.attrs.alignизparseHTML(getAttribute("data-align"))— устаревшее/неизвестное значение реально попадёт вelse. Контракт «любой неизвестный align безопасно деградирует в center» не запинен. Fix: добавить кейсapplyAlignment(el, "justify")с проверкойjustifyContent==="center",cssFloat==="",padding==="",dataset.imageAlign==="justify".Node‑view (вызовы на init/onUpdate) и кнопки меню тестами не покрыты — но это соответствует планке проекта (у существующих кнопок left/center/right тестов тоже нет), не отмечаю.
Architecture & design (forward-looking, non-blocking)
1. Дублирование
applyAlignmentпо image/video/drawio/excalidraw. Ветка left/center/right побайтово идентична в четырёх расширениях; PR расширяет до 5 веток толькоimage.ts, увеличивая расхождение. Дублирование было до PR.applyMediaAlignment(container, align)(medium). + единый источник, новые режимы один раз. − правка четырёх расширений в PR про image‑float, второго потребителя float пока нет.2. Раздвоение источника истины:
data-align(renderHTML) vsdata-image-align+ inline‑стили (node‑view). Подтверждено: ни в клиентском CSS, ни в серверномgenerateHTMLнет правилаdata-align → выравнивание. Выравнивание (и существующее left/center/right, и float) применяется только JS‑нодвью. Следствие: в серверно‑сериализованном HTML (экспорт HTML/DOCX/PDF, статика публичного шаринга) float не рендерится — как и текущее выравнивание. В read‑only редакторе внутри приложения (те же расширения, resize включён) float работает. Это не регрессия — то же ограничение у left/center/right.data-alignкак единственным источником истины, убратьdata-image-align(large). + консистентность везде, уходит смелл. − масштаб больше фичи, риск регрессии выравнивания.Итог: чистая, протестированная фича; логика выравнивания корректна на всех прослеженных путях, сериализация
floatLeft/floatRightчерезdata-alignбезопасна (потребители трактуют значение как непрозрачную строку), старый клиент деградирует в центрированный блок без потери данных. К мерджу после (опционального) учёта замечаний — в первую очередь тест‑кейс на неизвестныйalignи скоуп CSS‑правила.🤖 Multi-aspect review (security · stability · conventions · documentation · regressions · test-coverage · simplification · architecture)
после исправления можно мержить