Skip to content

AI Assistant: stop the Form block prompt from covering the form - #51050

Draft
taipeicoder wants to merge 18 commits into
trunkfrom
dsgcom-549-editor-ai-assistant-prompt-covers-the-appointment-forms
Draft

AI Assistant: stop the Form block prompt from covering the form#51050
taipeicoder wants to merge 18 commits into
trunkfrom
dsgcom-549-editor-ai-assistant-prompt-covers-the-appointment-forms

Conversation

@taipeicoder

@taipeicoder taipeicoder commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Proposed changes

  • The AI Assistant prompt sticks to the bottom of the viewport so it stays reachable while a block grows during generation. That only keeps it clear of the block because the block pads its bottom to make room for it. The Form block opted out of that adjustment a while back, to stop its negative margin dragging the prompt over the top of the block, but kept the sticky prompt — so as soon as the form is taller than the viewport, as it is on a phone, the prompt pins itself over the form's last fields and submit button. This happens on insertion, when opening the prompt from the toolbar, and while the AI is generating.
  • The sticky positioning is now tied to the same flag that reserves the space, so the Form block gets the prompt in normal flow below the form. Blocks that do reserve the space are unchanged.
  • A prompt in normal flow does not re-pin itself the way a sticky one does, so the scrolling that follows a request has to do it. Each generated chunk now targets the prompt itself, and a chunk that arrives while a scroll is already in flight is kept rather than dropped, so its Stop button cannot be stranded by content that outran it. When a request ends, the cursor returns to the input without scrolling, and the editor is moved after it only if the scrolling was still following the content — the same takeover the per-chunk scrolling already honours, so scrolling away is not undone at the end. A failed request scrolls instead of focusing, since the error renders below the input and a quota error leaves that input disabled.

Related product discussion/links

  • DSGCOM-549

Does this pull request change what data or activity we track or use?

No.

Testing instructions

Requires a site with Jetpack AI available.

On a phone-sized viewport (375px wide — a real device, or your browser's device emulation):

  • Open the post editor and insert an Appointment Form block, or any Form block variation tall enough to exceed the viewport.
  • Confirm nothing is covered: the editor settles with the end of the form visible and the prompt docked below it, ready to type. Before this change the AI prompt ("Example: make email optional… You have N requests remaining") sat pinned over the bottom of the form, hiding the Notes field and the "Book appointment" button.
  • Ask it for a change ("add a phone number field"), and confirm it and its Stop button stay on screen for the whole generation, with the fields appearing above it visible as they arrive. Confirm the undo/close controls are reachable when it finishes.
  • Close the prompt and reopen it from the block toolbar. It should be brought into view and focused, as before.

On a desktop viewport:

  • Insert a Form block, confirm the prompt still opens automatically and sits below the form, and run a request through it.
  • Repeat with a form long enough to exceed the window height — the prompt should stay below the form instead of hovering over it, during generation as well.
  • Run a request from a paragraph, heading, and list block and confirm the prompt still follows the viewport as it does today, including while generating a long response, and that scrolling by hand during generation still stops it from scrolling on its own. This is the path most likely to regress, since those blocks keep the old positioning and scroll target.

The AI input is sticky to the bottom of the viewport. On the Form block
it renders in normal flow after the block with no reserved space, so on a
narrow screen where the form is taller than the viewport the input hovers
over the tail of the form — hiding the last fields and the submit button
the moment the block is inserted.

Skip the auto-open below the editor's mobile breakpoint. The prompt is
still reachable from the block toolbar.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@taipeicoder taipeicoder added Bug When a feature is broken and / or not performing as intended [Status] In Progress labels Aug 5, 2026
@taipeicoder taipeicoder self-assigned this Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Are you an Automattician? Please test your changes on all WordPress.com environments to help mitigate accidental explosions.

  • To test on WoA, go to the Plugins menu on a WoA dev site. Click on the "Upload" button and follow the upgrade flow to be able to upload, install, and activate the Jetpack Beta plugin. Once the plugin is active, go to Jetpack > Jetpack Beta, select your plugin (Jetpack), and enable the dsgcom-549-editor-ai-assistant-prompt-covers-the-appointment-forms branch.
  • To test on Simple, run the following command on your sandbox:
bin/jetpack-downloader test jetpack dsgcom-549-editor-ai-assistant-prompt-covers-the-appointment-forms

Interested in more tips and information?

  • In your local development environment, use the jetpack rsync command to sync your changes to a WoA dev blog.
  • Read more about our development workflow here: PCYsg-eg0-p2
  • Figure out when your changes will be shipped to customers here: PCYsg-eg5-p2

@github-actions github-actions Bot added [Block] AI Assistant [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ labels Aug 5, 2026
@github-actions

github-actions Bot commented Aug 5, 2026

Copy link
Copy Markdown
Contributor

Thank you for your PR!

When contributing to Jetpack, we have a few suggestions that can help us test and review your patch:

  • ✅ Include a description of your PR changes.
  • ✅ Add a "[Status]" label (In Progress, Needs Review, ...).
  • ✅ Add testing instructions.
  • ✅ Specify whether this PR includes any changes to data or privacy.
  • ✅ Add changelog entries to affected projects

This comment will be updated as you work on your PR and make changes. If you think that some of those checks are not needed for your PR, please explain why you think so. Thanks for cooperation 🤖


Follow this PR Review Process:

  1. Ensure all required checks appearing at the bottom of this PR are passing.
  2. Make sure to test your changes on all platforms that it applies to. You're responsible for the quality of the code you ship.
  3. You can use GitHub's Reviewers functionality to request a review.
  4. When it's reviewed and merged, you will be pinged in Slack to deploy the changes to WordPress.com simple once the build is done.

If you have questions about anything, reach out in #jetpack-developers for guidance!


Jetpack plugin:

No scheduled milestone found for this plugin.

If you have any questions about the release process, please ask in the #jetpack-releases channel on Slack.

…or it

The sticky positioning assumes the block pads its bottom to make room for
the input. The Form block opted out of that adjustment but kept the sticky
input, so once the form is taller than the viewport the prompt pins itself
over the form's last fields and submit button — on insertion, from the
toolbar, and while generating.

Tie the sticky positioning to the same flag that reserves the space. Blocks
that adjust their position are unchanged; the Form block gets the input in
normal flow, below the form.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@taipeicoder taipeicoder changed the title AI Assistant: don't auto-open the Form block prompt on small screens AI Assistant: stop the Form block prompt from covering the form Aug 5, 2026
@jp-launch-control

jp-launch-control Bot commented Aug 5, 2026

Copy link
Copy Markdown

Code Coverage Summary

Coverage changed in 2 files.

File Coverage Δ% Δ Uncovered
projects/plugins/jetpack/extensions/blocks/ai-assistant/hooks/use-auto-scroll/index.ts 0/81 (0.00%) 0.00% 13 💔
projects/plugins/jetpack/extensions/blocks/ai-assistant/extensions/text-blocks/with-ai-text-extension.tsx 0/191 (0.00%) 0.00% 9 💔

Full summary · PHP report · JS report

If appropriate, add one of these labels to override the failing coverage check: Covered by non-unit tests Use to ignore the Code coverage requirement check when E2Es or other non-unit tests cover the code Coverage tests to be added later Use to ignore the Code coverage requirement check when tests will be added in a follow-up PR I don't care about code coverage for this PR Use this label to ignore the check for insufficient code coveage.

taipeicoder and others added 16 commits August 5, 2026 15:56
A prompt in normal flow scrolls away with the block, so the auto-scroll
that runs on every generated chunk was pushing it — and its Stop button —
below the viewport. Point that scroll at the prompt itself when it is not
sticky; it sits directly below the block, so the arriving content stays
visible above it. Sticky prompts keep targeting the block, whose reserved
padding already holds the prompt clear.

Also drop the mobile carve-out for the automatic opening. It relied on the
block toolbar as the fallback entry point, but that toolbar is replaced by
the AI sidebar button on surfaces where that feature is on, which would
have left the form prompt unreachable there. The positioning fix already
keeps the prompt off the form on its own.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
It stopped meaning "the last paragraph" when the block became a possible
target, and it can now be the prompt wrapper too.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two consequences of taking the Form prompt out of sticky positioning, both
of which a sticky prompt was absorbing on its own.

The prompt opens with the block, and showing it focuses it, which scrolls
it into view. Below a form taller than the viewport that drags the editor
past the form that was just inserted. Skip the focus for an appearance the
user did not ask for; every later opening still focuses.

The scroll that follows each generated chunk also ran before the dispatched
content had rendered, so it measured the prompt's old position and left it
below the viewport once the taller content committed. Wait a frame. Sticky
prompts re-pin themselves after a layout change and are left alone.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Suppressing focus for every automatically opened prompt was broader than
the problem: where the prompt is already on screen, as it is for a short
form or a desktop window, focusing costs nothing and losing it means an
extra click before typing.

Gate on what actually causes the trouble — whether focusing would scroll.
An automatic opening focuses only when the prompt is already in view, and
so does the focus on completion, which otherwise pulls the editor back to
a prompt the user had deliberately scrolled away from. Openings the user
asked for, and the focus after Stop, still focus unconditionally.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A sticky prompt reaches completion where it has always been, so gating its
focus on visibility would change behaviour this branch has no business
changing. Only the prompt that now scrolls with its block needs the check.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Completion adds a missing submit button and swaps the prompt over to its
completed buttons, both after auto-scroll has stopped. A sticky prompt
absorbed that; one in normal flow can be left past the bottom of the
viewport, with the visibility check declining to recover it.

Have disableAutoScroll report whether the user had taken the scrolling
over, which it already tracks, and use that rather than visibility as the
test at completion: focus unconditionally when the prompt was still being
followed, and leave a user who scrolled away where they are.

Also name the prompt's positioning prop after the class it sets, so the
two no longer disagree.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The scroll flag answers the question on its own, so completion no longer
needs the visibility check: focus unless the user scrolled off, and skip it
entirely if they did rather than focusing an input they cannot see.

Measure the input, not the whole control, when deciding whether focusing
would move the editor — the input is what focus scrolls to, so a clipped
disclaimer below it was wrongly suppressing focus for a prompt already in
view.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Suppressing the focus that follows the prompt opening was a mistake. That
focus scrolls the minimum needed, which lands the prompt at the bottom of
the viewport with the end of the form above it — nothing covered, which is
the outcome asked for. Withholding it bought nothing and cost the ability
to insert a form and start typing.

Removes the auto-open tracking and the visibility test with it. Completion
still declines to pull back a user who scrolled away mid-request.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The error panel grows the control, which on a tall form can leave a prompt
in normal flow past the bottom of the viewport with Try again out of reach.
Scroll it back rather than focus it, since a quota error disables the input
and focus would do nothing, and leave a user who scrolled off where they are.

Drop the positioning prop while here. It carried one class name to a single
call site, which can set that class through the className it already passes,
keeping the decision beside the other branches on the same flag.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The scroll-takeover flag is not set until the first automatic snap has run,
so a request that fails before producing any content reports that the user
never scrolled, even when they did — and the recovery scroll then pulled
them back.

Measure the prompt against the viewport instead, just before the error panel
renders. That answers the question the flag was standing in for, and does it
for every failure rather than only those that got far enough to scroll once.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Aligning to the bottom moved a prompt that was already fully visible, so an
error that did not push anything out of view still jumped the editor. The
nearest edge scrolls only as far as it has to, and does nothing when the
panel fits — and when the control is taller than the viewport it settles on
the top, which is the end the error and its Try again sit at.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Skipping the focus when the user had scrolled asked more of the flag than
it can answer. It records any scroll at all, so nudging the page while the
prompt stayed in view was enough to lose the focus that lets you type a
follow-up, and scrolls during the hook's own listener gap go unrecorded
either way.

Completion goes back to focusing unconditionally, as it always has. That
removes the regression, and with it the only reason for the shared hook to
report anything, so it returns to what it was.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Completion focusing unconditionally pulls the editor back to a prompt in
normal flow that the user had scrolled away from. Guarding it on the
scroll-takeover flag was the wrong instrument — that flag trips on any
scroll at all, including one that left the prompt in plain view — so ask
where the prompt was instead, measured before the closing update moves it.

The error path already asked that question inline; both now share it, which
also stops a prompt with one pixel showing counting as visible there.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
… prompt

Geometry alone cannot tell a prompt the user left from one the stream
outran: a throttled or dropped snap leaves it off screen with nobody having
scrolled anywhere. Ask the scroller too — if it was still following when it
stopped, the prompt is worth bringing back.

Either signal restores it, which also keeps the case each one misses
covered: a harmless nudge trips the follow flag but leaves the prompt in
view, and a failure before the first snap has no follow state to read.

Skip the measurement entirely for sticky blocks, whose paths are unchanged
and which should not pay for a layout read they never consult.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The hand-rolled visibility check was reinventing behaviour that focus() and
scrollIntoView already have. Focus scrolls an element into view only when it
is not already there, and only as far as needed, so completion needs no test
and no guard — it goes back to the unconditional focus it always did. The
nearest block alignment does the same for the error path.

The editor takes the same line: block selection observes once and scrolls
only when the block is out of view, without asking whether the user meant to
be elsewhere. Inferring that intent was a policy of this branch's own making,
and every attempt at it had a hole.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Focus does both at once, which is why deciding whether to move the editor
at a terminal state kept turning into a question about focus. Ask it not to
scroll, and the two become separate decisions: the cursor always returns to
the input, and the editor moves only when the scrolling was still following
the content — the same takeover the per-chunk scrolling already honours,
now read from the hook rather than inferred.

Also stop dropping the newest explicit target while a scroll is in flight.
Chunks arrive faster than that window closes, and a dropped one used to
leave a prompt in normal flow wherever the content it was following had
pushed it, with its Stop button out of reach until the next chunk. Keep the
latest and catch up when the window closes, before the scroll listener is
restored so the catch-up is not mistaken for the user's own. Targetless
callers are untouched.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

[Block] AI Assistant Bug When a feature is broken and / or not performing as intended [Plugin] Jetpack Issues about the Jetpack plugin. https://wordpress.org/plugins/jetpack/ [Status] In Progress

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant