|
| 1 | +## Context |
| 2 | + |
| 3 | +The Rich Text widget's image insert dialog (`ImageDialog.tsx`) currently collects only `src`, `alt`, and `title`, then calls `editor.chain().focus().setImage(imageAttrs).run()`. The underlying `ImageResize` TipTap extension already defines `width` and `height` node attributes (both defaulting to `null`), but they are only ever populated by the drag-resize node view (`ImageResize.tsx`) after the image is on the canvas. This change surfaces those attributes at insert time. |
| 4 | + |
| 5 | +Constraints: |
| 6 | + |
| 7 | +- No node schema changes are required — `width`/`height` attributes already flow through `setImage`. |
| 8 | +- Dialog UI must match existing patterns (`dialog-field`, i18n via `useT`). |
| 9 | +- Values must be consistent with the drag-resize output, which writes pixel strings like `"300px"`. |
| 10 | + |
| 11 | +## Goals / Non-Goals |
| 12 | + |
| 13 | +**Goals:** |
| 14 | + |
| 15 | +- Let users set initial width and (optionally) height when inserting an image. |
| 16 | +- Provide a "maintain aspect ratio" toggle that, when on, applies width only and lets the browser derive height. |
| 17 | +- Keep the change contained to the dialog + i18n + tests; no extension or widget-prop changes. |
| 18 | + |
| 19 | +**Non-Goals:** |
| 20 | + |
| 21 | +- Changing how drag-resize behaves (it continues to always preserve ratio). |
| 22 | +- Persisting "maintain aspect ratio" as a property of the image node — it is an insert-time decision only. |
| 23 | +- Supporting non-pixel units (`%`, `em`) or a unit picker. |
| 24 | +- Preloading images to read natural dimensions. |
| 25 | + |
| 26 | +## Decisions |
| 27 | + |
| 28 | +**Decision: "Maintain aspect ratio" leaves height auto (Interpretation A).** |
| 29 | +When checked, only `width` is applied and `height` is left `null`, so the browser renders height proportionally via `height: auto`. Chosen over computing a locked height because it requires no natural-dimension lookup (no image preloading, no async resolution differences between URL/base64/entity sources) and always stays proportional. |
| 30 | + |
| 31 | +- Alternative considered: read natural width/height and write both attributes. Rejected — adds async complexity and source-specific handling for little benefit at insert time. |
| 32 | + |
| 33 | +**Decision: Pixel-only number inputs.** |
| 34 | +Inputs are numeric and interpreted as pixels, applied as `"<n>px"` strings to match the drag-resize output. A unit picker was considered but rejected as scope creep. |
| 35 | + |
| 36 | +**Decision: Checkbox defaults to ON.** |
| 37 | +Matches common editor behavior and avoids accidental distortion. Height input is disabled (greyed) while ON. |
| 38 | + |
| 39 | +**Decision: Non-destructive toggle.** |
| 40 | +Toggling the checkbox ON keeps any previously typed height value in component state; it is simply not sent on submit. Un-ticking restores the value. Avoids surprising data loss. |
| 41 | + |
| 42 | +**Decision: Apply only filled, positive-numeric values.** |
| 43 | +Empty or invalid (non-numeric, zero, negative) width/height are omitted from `imageAttrs`, falling back to today's natural-size behavior. Any combination of filled/empty is allowed (e.g., height only → width auto). |
| 44 | + |
| 45 | +## Risks / Trade-offs |
| 46 | + |
| 47 | +- [Ratio checkbox is insert-time only, but drag-resize always keeps ratio] → Acceptable; an image inserted with ratio unchecked (distorted) will re-derive ratio from its current box on next drag. Documented as a non-goal. |
| 48 | +- [Users may expect `%` or other units] → Out of scope for this change; pixel-only keeps behavior consistent with existing resize. Can be revisited later. |
| 49 | +- [Disabled height field showing a stale typed value could confuse] → Field is visually greyed while checkbox is ON, signalling it is inactive; value is preserved intentionally. |
0 commit comments