CI / Build & Quality Checks (push) Successful in 1m53s
CI / Docker image build & smoke test (push) Skipped
CI / Secret scan (gitleaks) (push) Successful in 6s
CI / Trigger Desktop Build (push) Successful in 6s
CI / Playwright smoke (e2e) (push) Successful in 1m38s
The composer looked off in two ways, both confirmed by rendering CustomEditor
with RoomInput's exact props and measuring the buttons headlessly:
Desktop: the Lotus additions (location, poll, voice, schedule) used
`Icon size="100"` (18px) inside the same `IconButton size="300"` as the
upstream Aa/sticker/emoji/send buttons (24px icons), so one row mixed
32×32, 26×26 and a 28×19 "GIF" text stub. Every button is now 32×32: the
four small icons use the default icon size and the GIF label sits in a
1.5rem box, the same footprint as an icon. The mic's idle button in
VoiceMessageRecorder gets the same treatment since it lives in this row.
Phones: d6159997 let the before|editable|after row flex-wrap at <=750px, but
folds' Scroll (the editable's wrapper) is `width: 100%`, so the row ALWAYS
broke into three stacked lines — "+" alone on top, the input flush against
the left edge on its own line (the :first-child padding selectors no longer
matched), and emoji/draft/send left-aligned underneath. e1bb8301's "+"
overflow menu was meant to produce [ + | input | emoji | send ] but never
could while the row wrapped. The row no longer wraps (upstream behaviour);
instead the collapse into the "+" overflow is keyed on the viewport
(ScreenSize.Mobile) as well as the touch UA, so a phone-width window on a
desktop UA — iPad desktop mode, split-screen PWA, docked window — also
collapses instead of rendering ten controls inline and clipping Send behind
the editor's overflow:hidden. The "Draft saved" label moves into the overflow
row in compact mode so the inline row stays [ + | input | emoji | count |
send ]. The editable's vertical padding grows to 19px at phone width (only
when the row actually has buttons) so the text sits level with the 44px
touch targets instead of hugging the top of the row. Those touch targets now
also apply the shared MobileTouchTarget class, matching the recorder button.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PPmy3tPq869XDW4njjVaKA
103 lines
2.6 KiB
TypeScript
103 lines
2.6 KiB
TypeScript
import { style } from '@vanilla-extract/css';
|
|
import { color, config, DefaultReset, toRem } from 'folds';
|
|
|
|
export const Editor = style([
|
|
DefaultReset,
|
|
{
|
|
backgroundColor: color.SurfaceVariant.Container,
|
|
color: color.SurfaceVariant.OnContainer,
|
|
boxShadow: `inset 0 0 0 ${config.borderWidth.B300} ${color.SurfaceVariant.ContainerLine}`,
|
|
borderRadius: config.radii.R400,
|
|
overflow: 'hidden',
|
|
},
|
|
]);
|
|
|
|
export const EditorOptions = style([
|
|
DefaultReset,
|
|
{
|
|
padding: config.space.S200,
|
|
},
|
|
]);
|
|
|
|
// The composer's before | editable | after row. It must NOT wrap: folds'
|
|
// Scroll (the editable's wrapper) is `width: 100%`, so a wrapping row always
|
|
// breaks into three stacked lines (before / editable / after) — the "wonky"
|
|
// phone composer. Narrow viewports keep one row by collapsing the secondary
|
|
// buttons behind the "+" overflow instead (RoomInput `compact`).
|
|
export const EditorInputRow = style({
|
|
minWidth: 0,
|
|
});
|
|
|
|
export const EditorTextareaScroll = style({});
|
|
|
|
export const EditorTextarea = style([
|
|
DefaultReset,
|
|
{
|
|
flexGrow: 1,
|
|
height: '100%',
|
|
padding: `${toRem(13)} ${toRem(1)}`,
|
|
'@media': {
|
|
// Phone-width composer rows carry 44px touch targets (MobileTouchTarget),
|
|
// so the row is 60px instead of 48px; pad the text to keep it level with
|
|
// the buttons instead of hugging the top of the row. Only when the row
|
|
// actually has before/after buttons (not the edit-message editor).
|
|
'(max-width: 750px)': {
|
|
selectors: {
|
|
[`${EditorTextareaScroll}:not(:only-child) &`]: {
|
|
paddingTop: toRem(19),
|
|
paddingBottom: toRem(19),
|
|
},
|
|
},
|
|
},
|
|
},
|
|
selectors: {
|
|
[`${EditorTextareaScroll}:first-child &`]: {
|
|
paddingLeft: toRem(13),
|
|
},
|
|
[`${EditorTextareaScroll}:last-child &`]: {
|
|
paddingRight: toRem(13),
|
|
},
|
|
'&:focus': {
|
|
outline: 'none',
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
|
|
export const EditorPlaceholderContainer = style([
|
|
DefaultReset,
|
|
{
|
|
opacity: config.opacity.Placeholder,
|
|
pointerEvents: 'none',
|
|
userSelect: 'none',
|
|
},
|
|
]);
|
|
|
|
export const EditorPlaceholderTextVisual = style([
|
|
DefaultReset,
|
|
{
|
|
display: 'block',
|
|
paddingTop: toRem(13),
|
|
paddingLeft: toRem(1),
|
|
'@media': {
|
|
'(max-width: 750px)': {
|
|
selectors: {
|
|
[`${EditorTextareaScroll}:not(:only-child) &`]: { paddingTop: toRem(19) },
|
|
},
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
|
|
export const EditorToolbarBase = style({
|
|
padding: `0 ${config.borderWidth.B300}`,
|
|
});
|
|
|
|
export const EditorToolbar = style({
|
|
padding: config.space.S100,
|
|
});
|
|
|
|
export const MarkdownBtnBox = style({
|
|
paddingRight: config.space.S100,
|
|
});
|