Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 6 additions & 2 deletions .fork/customizations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -938,8 +938,12 @@
inflate scrollHeight on the editor, so upstream's max-h + overflow-y:auto
there painted a phantom thumb on a single line. The wrapper owns the
12.5rem cap (upstream max-h-50); the editor stays unclamped and clips its
ink. Scoped to the same >=40rem media as the line box — below that the
prompt stays on leading-relaxed and upstream's editor scroll is left alone.
ink. The editor's siblings — Lexical's placeholder and spacer — clip the
same way, because the placeholder's overhanging line box otherwise reaches
the wrapper's scrollable overflow through its abspos box and paints the
thumb on an empty prompt only. Scoped to the same >=40rem media as the
line box — below that the prompt stays on leading-relaxed and upstream's
editor scroll is left alone.
The prompt and its placeholder are set by one rule and must stay that way:
they are two elements stacked exactly on top of each other, and any
disagreement about size or leading puts the caret beside the text it
Expand Down
13 changes: 13 additions & 0 deletions apps/web/src/__fork_guards__/forkComposerShell.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,19 @@ describe("fork guard: fork-composer-shell", () => {
expect(editor!.body).toMatch(/max-height:\s*none/u);
expect(editor!.body).toMatch(/overflow-y:\s*hidden/u);

// The editor's clip does not cover its siblings: the placeholder's line
// box overhangs its inset-0 box by a pixel at 14/16, and abspos overflow
// propagates to the wrapper's scrollable overflow — a thumb that appears
// only while the prompt is empty. The siblings clip like the editor does.
const siblings = rules.find(
(rule) =>
inDesktopLineBoxMedia(rule) &&
rule.selector.includes("[data-fork-composer-prompt]") &&
/\[data-testid="composer-editor"\]\s*~\s*div/u.test(rule.selector),
);
expect(siblings, "desktop placeholder clip rule missing or unscoped").toBeDefined();
expect(siblings!.body).toMatch(/overflow-y:\s*hidden/u);

// An imperative attribute toggle is the failure mode this replaces — see
// .fork/notes/FORK-CUSTOMIZATION-DECISIONS.md#fork-composer-shell.
expect(theme).not.toContain("data-composer-prompt-scrollable");
Expand Down
14 changes: 14 additions & 0 deletions apps/web/src/theme.custom.css
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,20 @@
max-height: none;
overflow-y: hidden;
}

/* The placeholder (and Lexical's zero-height spacer) are the editor's
siblings, outside its clip. At 14/16 the placeholder's line box is a pixel
taller than its inset-0 box, and that pixel propagates through the
absolutely-positioned box into the wrapper's scrollable overflow — a
phantom thumb that shows only while the prompt is empty, because typing
unmounts the placeholder. Clip them the way the editor clips its own ink;
typed text already paints without that pixel. */
:root[data-fork="noahhendrickson-t3code"]
[data-fork-composer-prompt]
[data-testid="composer-editor"]
~ div {
overflow-y: hidden;
}
Comment on lines +419 to +424

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fourth selector is unnecessary. The media block already uses :is([data-testid="composer-editor"], [data-testid="composer-editor"] ~ div) for the type ramp — reuse that shape for the clip.

Fold the editor unclamp and this sibling-only rule into one prompt-scoped :is(...):

:root[data-fork="noahhendrickson-t3code"]
  [data-fork-composer-prompt]
  :is([data-testid="composer-editor"], [data-testid="composer-editor"] ~ div) {
  max-height: none;
  overflow-y: hidden;
}

max-height: none on the abspos spacer/placeholder is harmless (initial value; they are sized by inset). Delete this sibling-only rule and most of the comment; keep a short note that siblings must share the clip because abspos overflow bypasses the editor. Update the fork guard to assert the unified :is(...) rule instead of locking in a fourth near-duplicate.

Net: −1 rule, reuse the existing selector shape, and stop growing an already >1k theme.custom.css for a duplicate.

}

/* The in-box pills and the control row below it share one 24px ghost treatment:
Expand Down
Loading