Skip to content

Slides text box: insert-to-edit, drag sizing, content-fit auto-grow#298

Merged
hackerwins merged 9 commits into
mainfrom
slides-textbox-autogrow
May 25, 2026
Merged

Slides text box: insert-to-edit, drag sizing, content-fit auto-grow#298
hackerwins merged 9 commits into
mainfrom
slides-textbox-autogrow

Conversation

@hackerwins

@hackerwins hackerwins commented May 25, 2026

Copy link
Copy Markdown
Collaborator

Summary

Brings the Slides text-box authoring flow in line with Google Slides:

  • Insert-to-edit — inserting a text box drops the caret straight inside it (edit mode + focus), instead of leaving an empty selected box that needed a double-click. Shapes are unchanged (still select-only).
  • Drag sizing — a text box can be drawn by dragging (width + position from the drag rect); a sub-threshold drag uses the default width. A near-vertical drag is clamped to a usable minimum width.
  • Auto-grow — the box height fits its content (grow + shrink, min one line), live while typing. The drawn height is intentionally not retained (height tracks content). The fitted height is persisted into the element frame at commit, in the same batch as the text write — one undo entry, no per-keystroke CRDT churn.

Mechanism

  • @wafflebase/docs text engine: new onContentHeightChange option (fired from renderNow after layout, de-duped) + setContentHeight() setter. computeLayout already produced layout.totalHeight; it was only used internally.
  • Slides text-box wrapper resizes its editing container/canvas to the fitted height, delegates setContentHeight, and reports the logical height to the editor.
  • Slides editor enters edit mode on text insert and writes frame.h at commit.

Design: docs/design/slides/slides-textbox-autogrow.md · Plan: docs/tasks/active/20260525-slides-textbox-autogrow-todo.md

Non-goals

Width autofit, a per-element autofit-mode selector, and auto-grow for text inside non-text shapes.

Test Plan

  • pnpm verify:fast (lint + unit) — green
  • pnpm verify:self (+ all builds + entropy/knip/doc-staleness) — green
  • docs unit (API surface) + slides end-to-end auto-grow tests under test-canvas-env; insert-to-edit + one-undo height-fit tests
  • Self code review (reviewer subagent); Important finding (sliver-width drag) fixed
  • Manual smoke in pnpm dev: insert via click and via drag → caret inside, one-line tall; type to grow, delete to shrink; reopen → height preserved; shapes still select-only; double-click still edits

Known limitations

  • No live ghost preview while dragging a text box (an empty box paints nothing); the box appears on release.
  • enterEditMode resolves the element top-level, so auto-grow applies to top-level text boxes; text inside groups is out of scope (pre-existing).

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Text boxes now auto-grow height as you type, expanding and shrinking dynamically with your content
    • Insert text boxes using drag-to-size; releases to immediately enter edit mode
  • Documentation

    • Added comprehensive design and implementation documentation for text box auto-grow feature
  • Tests

    • Added test coverage for auto-grow behavior and insert-to-edit workflow

Review Change Stack

hackerwins and others added 8 commits May 25, 2026 20:24
Three coordinated improvements to the slides text-box authoring flow to
match Google Slides: insert drops the caret straight into edit mode,
text boxes can be drawn by dragging (width + position), and box height
fits its content live (grow + shrink, min one line). Auto-grow needs a
new onContentHeightChange callback + setContentHeight() seam in the docs
text-box engine, which currently computes layout.totalHeight only for
internal use.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Plan covers four TDD tasks: docs content-height callback + setter,
slides wrapper live resize, text drag sizing, and editor insert-to-edit
with commit-time height fit. Refines the design doc to persist frame
height at commit (one undo batch) rather than per-keystroke.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
computeLayout already produces layout.totalHeight but only used it
internally. Expose it via an onContentHeightChange option (fired from
renderNow, de-duped on change) and a setContentHeight() setter so a host
can grow/shrink the editing surface to fit content.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
The wrapper forwards docs onContentHeightChange: it resizes its
container + canvas to the new logical height (times slide scale and
browser dpr), delegates setContentHeight so the docs editor's pointer
math stays consistent, then reports the height to the host.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Text insert now uses the same click-vs-drag rect logic as shapes: a
drag sets width + top-left, a sub-threshold drag keeps TEXT_DEFAULT_W.
Height stays TEXT_DEFAULT_H at insert; the editor fits it to content on
the first layout, so the drawn height is intentionally not retained.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Inserting a text box now drag-sizes and drops the caret straight inside
(enterEditMode on pointerup) instead of leaving an empty selected box.
The latest content height reported during editing is written into
frame.h at commit, in the same batch as the text — one undo entry,
content-fit height matching Google Slides.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Code-review follow-ups: a near-vertical text drag cleared the click
threshold but yielded a sliver-width box that auto-grew into a 1-char
column — clamp drag width to MIN_TEXT_BOX_W. Also document why the
wrapper's onContentHeightChange may reference api before assignment
(it only fires via rAF, after the const binds).

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@coderabbitai

coderabbitai Bot commented May 25, 2026

Copy link
Copy Markdown

Caution

Review failed

Pull request was closed or merged during review

📝 Walkthrough

Walkthrough

This PR implements Google Slides–like text-box auto-grow behavior by extending the docs text engine with height-change callbacks and a height-setter API, wiring those callbacks through the slides wrapper to resize containers and canvases, updating the text insertion flow to use click-vs-drag sizing, and integrating height tracking and commit-time persistence in the slides editor.

Changes

Slides Text Box Auto-Grow Implementation

Layer / File(s) Summary
Design, planning, and implementation guide
docs/design/slides/slides-textbox-autogrow.md, docs/tasks/README.md, docs/tasks/active/20260525-slides-textbox-autogrow-*.md, docs/design/README.md
Comprehensive design specification, four-task implementation roadmap, and lessons-learned document coordinate the auto-grow feature across docs and slides packages and record engineering constraints (build order, canvas shim for tests, batch undo writes, reusing shape interaction patterns).
Docs text engine height callback and setter API
packages/docs/src/view/text-box-editor.ts, packages/docs/test/view/text-box-editor.test.ts
TextBoxEditorOptions gains optional onContentHeightChange callback (fired after layout when layout.totalHeight changes, deduped via lastReportedHeight tracker). TextBoxEditorAPI exposes setContentHeight() to update logical height, rebuild paginated layout, and trigger re-render. Smoke tests in jsdom verify the new API surface before live integration.
Slides text-box wrapper height callback forwarding
packages/slides/src/view/editor/text-box-editor.ts, packages/slides/test/view/editor/text-box-autogrow.test.ts
MountSlidesTextBoxOptions gains optional onContentHeightChange callback. Wrapper intercepts docs editor callback to resize DOM container and canvas bitmap (accounting for device-pixel ratio and scale), calls api.setContentHeight(), then forwards logical height to user callback. Integration tests verify reported heights increase with content and container resizes match reported heights.
Text insertion click-vs-drag sizing
packages/slides/src/view/editor/interactions/insert.ts, packages/slides/test/view/editor/interactions/insert.test.ts
buildInsertElement text branch now applies click-vs-drag threshold (like shapes): sub-threshold creates default-width box at start; drag-sized derives width from horizontal delta and clamps to MIN_TEXT_BOX_W to prevent slivers. Height stays TEXT_DEFAULT_H. Tests cover click, drag, backwards-drag normalization, sub-threshold-as-click, and near-vertical clamping.
Slides editor auto-grow integration and insert-to-edit flow
packages/slides/src/view/editor/editor.ts, packages/slides/test/view/editor/text-box-editor.test.ts
Adds MIN_TEXT_BOX_H constant and lastEditingContentHeight tracker. On entering edit mode, tracker resets; text editor fires height changes to tracker via onContentHeightChange. On commit, fitted height (clamped to minimum) persists into element frame in same store batch as text write (single undo entry). Text insert now drags-to-size then enters edit mode immediately; Escape cancels in-flight insert via document-level key capture. Mock extended with fireContentHeight() hook; tests verify insert-to-edit transitions and height persistence through undo.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • wafflebase/wafflebase#239: Both PRs modify the Slides editor's insert-mode interaction layer—especially packages/slides/src/view/editor/editor.ts and packages/slides/src/view/editor/interactions/insert.ts via buildInsertElement click-vs-drag sizing and Escape/ghost insert-preview behavior—though this PR focuses on text-box auto-grow.

Poem

🐰 Text boxes grow with every word we type,
No fixed heights here—they stretch just right!
From docs to slides, the callbacks dance,
Insert to edit, a graceful prance. ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title directly summarizes the main changes: insert-to-edit mode, drag sizing, and auto-grow height behavior for text boxes.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch slides-textbox-autogrow

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented May 25, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 219.2s

Lane Status Duration
tokens:build ✅ pass 2.0s
sheets:build ✅ pass 12.9s
docs:build ✅ pass 11.0s
slides:build ✅ pass 12.6s
verify:fast ✅ pass 141.3s
frontend:build ✅ pass 16.9s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.7s
cli:build ✅ pass 2.0s
verify:entropy ✅ pass 15.5s

Verification: verify:integration

Result: ✅ PASS

@codecov

codecov Bot commented May 25, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 66.66667% with 4 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/docs/src/view/text-box-editor.ts 66.66% 4 Missing ⚠️

📢 Thoughts on this report? Let us know!

@hackerwins

Copy link
Copy Markdown
Collaborator Author

Code review

No issues found. Checked for bugs and CLAUDE.md compliance.

🤖 Generated with Claude Code

- If this code review was useful, please react with 👍. Otherwise, react with 👎.

buildInsertElement JSDoc and the hoverPreview / onInsertHoverMove notes
still described text as a single-click fixed-size insert; update them to
the drag-to-size + content-fit-height behavior this branch introduced.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
@hackerwins
hackerwins merged commit cf83a49 into main May 25, 2026
1 check passed
@hackerwins
hackerwins deleted the slides-textbox-autogrow branch May 25, 2026 12:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant