The chat composer reused .miu-textarea, which the INBOX MAIL composer already
owned further down the stylesheet with `resize: vertical; min-height: 90px`.
Equal specificity, later rule wins — so the mail styling applied to the chat box:
90px tall with a resize grabber, and every height fix in 0.1.10–0.1.12 was
silently overridden. That is why the box never changed.
The composer now uses its own .miu-composer-box; the inbox rule is untouched.
Adds a regression test asserting the composer does not carry .miu-textarea.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
The textarea swap made the composer row tall and dragged the controls with it.
Three causes, all fixed:
- No box-sizing anywhere in the stylesheet, so `min-height: 38px` on a padded,
bordered textarea rendered ~58px (content-box adds 18px padding + 2px border
on top). The textarea is now border-box with a 40px min-height — the same
height the old single-line input had.
- .miu-composer-row is display:flex with no align-items, so it defaulted to
`stretch` and the buttons — neither of which declared a height — grew to the
row. Now align-items: flex-end, so controls stay pinned to the bottom while
the box grows upward (WhatsApp behaviour), with an explicit 40px on both.
The send height is scoped to .miu-composer so modal/settings buttons keep
their own sizing.
- The auto-grow effect set height = scrollHeight, which under content-box
double-counted padding on every keystroke. It now compensates for the border
explicitly, correct under border-box.
Bumped to 0.1.11. SDK suite: 17 files / 98 tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Composer becomes a <textarea> so the PLATFORM supplies text services: red
spellcheck squiggles, right-click suggestions / add-to-dictionary, and mobile
autocorrect (spellCheck + autoCorrect + autoCapitalize). Nothing shipped for it.
Previously a single-line <input>, which Firefox does not spellcheck by default
(layout.spellcheckDefault=1 checks multi-line only) and which could not hold a
multi-line message at all. Enter sends, Shift+Enter (and IME composition) makes a
newline, and the box grows with content.
WhatsApp-style markup: *bold*, _italic_, ~strike~, `code`, ```fenced blocks```,
plus bare URLs. Cmd/Ctrl+B/I/E and a small toolbar wrap the selection in markers.
Messages stay PLAIN TEXT on the wire, so stored history and older clients are
unaffected — formatting is purely a render concern.
renderRichText() returns a ReactNode tree and never uses dangerouslySetInnerHTML,
so message text cannot inject markup; links are restricted to http/https/mailto
(safeHref) to close the javascript: vector. Code is tokenized first and its
contents stay literal; markers require word boundaries so snake_case_name and
"5 * 3" are not mangled.
Bumped to 0.1.9. SDK suite: 17 files / 95 tests green.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Picking a file now shows an immediate chip with the filename + a spinner while
the bytes upload (mail compose, mail reply, and the messenger composer), instead
of only appearing once upload finishes. Respects prefers-reduced-motion.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Replies (messages with parentInteractionId) now open in a right-hand ThreadPane
instead of inline quoting:
- extracted a shared Composer (draft + @mention autocomplete + attach) and
MessageItem (bubble + mentions + attachment + reactions + reply affordance)
- Thread shows top-level messages only; a message with replies gets a
'💬 N replies' link, and hovering shows 💬 'Reply in thread'
- ThreadPane renders the root + its replies + a composer that posts back with
parentInteractionId; Messenger becomes 3-column (list | thread | pane),
pane closes on conversation switch
- no contract/adapter/backend change (parentInteractionId was already wired)
- thread-pane render test (open → reply → parent shows the count); 58 green
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>