Skip to content

fix: let plugin activities control their own modal height#956

Open
nd0ut wants to merge 2 commits intomainfrom
fix/plugin-activity-height
Open

fix: let plugin activities control their own modal height#956
nd0ut wants to merge 2 commits intomainfrom
fix/plugin-activity-height

Conversation

@nd0ut
Copy link
Copy Markdown
Member

@nd0ut nd0ut commented Apr 21, 2026

Summary

  • Plugin activity host used height: 100% which resolved to 0 in Safari when the dialog only had max-height (no explicit height). Short activities like URL source collapsed to header-only with content clipped by overflow: hidden.
  • Host (uc-plugin-activity-host) and its inner wrapper are now display: contents, so the plugin's activity element is effectively a direct layout child of the <dialog>. Percentage heights, flex sizing, and containing blocks chain through transparently, and :has() / [activity][active] selectors keep matching through the host.
  • Plugin authors now control modal sizing purely via CSS on their own element — no registration flag, no framework attribute. Built-in activities (Camera, ExternalSource, CloudImageEditor) continue to use their existing :has()-based height: 100% rules, unchanged.

Test plan

  • Safari: URL activity modal opens with input + Import button visible (not collapsed to header)
  • Safari: Camera activity fills the modal (video preview sizes correctly)
  • Safari: External source activity fills the modal (iframe sizes correctly)
  • Safari: Cloud image editor fills the modal
  • Chrome: no regression in any of the above
  • Verify start-from and upload-list modals (non-plugin) still size correctly

🤖 Generated with Claude Code

Summary by CodeRabbit

  • Style

    • Adjusted the plugin activity renderer’s layout to improve positioning and visual spacing of child elements.
  • Refactor

    • Simplified the container wrapper to reduce unnecessary layout constraints while preserving functionality.
  • Tests

    • Improved end-to-end test flow for the image editor to make validations more reliable and reduce flaky timing issues.

Plugin activity host used `height: 100%` which resolved to 0 in Safari
when the dialog only had `max-height` (no explicit `height`), collapsing
short activities such as URL source to header-only visibility with
overflow clipped.

Make the host and its inner wrapper `display: contents` so the plugin
activity element is effectively a direct layout child of the dialog.
Plugin authors now control sizing purely via CSS on their own element
(e.g. `:has()` for full-height, or viewport units for self-sizing), with
no framework API or attribute coupling.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings April 21, 2026 07:14
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Apr 21, 2026

📝 Walkthrough

Walkthrough

Replaces the PluginActivityRenderer wrapper layout from a flex/positioned element to display: contents, removing its layout box; updates end-to-end tests to use event-driven waits (waitForEditorChange) instead of fixed delays for editor interactions.

Changes

Cohort / File(s) Summary
Renderer layout
src/blocks/PluginActivityRenderer/PluginActivityRenderer.ts, src/blocks/PluginActivityRenderer/uc-plugin-activity-host.css
Changed wrapper from a flex/positioned container with explicit sizing/overflow to display: contents, removing the element's own box and transferring layout behavior to children.
E2E test timing / validation
tests/validation.e2e.test.tsx
Replaced fixed delay(1000) sleeps with waitForEditorChange() event-driven waits; added explicit waits for controls visibility and button enablement, and ensured change listeners are registered before triggering editor actions.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 I nudged a wrapper, soft and light,

Now children dance in open flight.
Tests listen close, no waits to fear,
A tidier layout — hop, cheer! 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main change: allowing plugin activities to control their own modal height via CSS, which aligns with the core fix in the changeset.
Description check ✅ Passed The description comprehensively covers the problem, solution, and testing strategy with relevant details about Safari height resolution and the display: contents approach.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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 fix/plugin-activity-height

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

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adjusts the plugin activity host layout so plugin activities can determine their own modal sizing via their own CSS, fixing Safari cases where the host’s height: 100% effectively collapsed when the <dialog> only had max-height.

Changes:

  • Switch uc-plugin-activity-host from a flex/100%-height wrapper to display: contents.
  • Switch the host’s internal container <div> to display: contents while keeping it as the render mount point for plugin activities.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
src/blocks/PluginActivityRenderer/uc-plugin-activity-host.css Makes the host element transparent to layout with display: contents to avoid Safari percentage-height collapse.
src/blocks/PluginActivityRenderer/PluginActivityRenderer.ts Updates the render mount wrapper <div> to display: contents so the plugin activity element participates directly in dialog flex sizing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Replace arbitrary delay(1000) calls with editor `change` event waits so
the mirror operation is guaranteed to commit before Apply is clicked.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@nd0ut nd0ut requested a review from egordidenko April 21, 2026 11:37
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@tests/validation.e2e.test.tsx`:
- Around line 451-454: The helper waitForEditorChange currently can hang because
document.querySelector('uc-cloud-image-editor') may be null or the change event
might never fire; update waitForEditorChange to attach the event listener only
if the element exists and add a timeout fallback (e.g., setTimeout) that rejects
or resolves with an error after a configurable delay, and ensure any created
listener and timeout are cleaned up when either the event fires or the timeout
triggers; reference the waitForEditorChange function and the
'uc-cloud-image-editor' element and make the timeout clear with a descriptive
Error message so awaiting callers fail fast instead of hanging.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: a9b8c80f-b7b5-4bfb-b464-948941d60a63

📥 Commits

Reviewing files that changed from the base of the PR and between b854136 and 28e224f.

📒 Files selected for processing (1)
  • tests/validation.e2e.test.tsx

Comment on lines +451 to +454
const waitForEditorChange = () =>
new Promise<void>((resolve) => {
document.querySelector('uc-cloud-image-editor')?.addEventListener('change', () => resolve(), { once: true });
});
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Add a timeout/failure path to waitForEditorChange to prevent hanging awaits.

At Line 453, optional chaining can leave the Promise pending forever if the editor is missing (or the awaited event is missed), which makes this test flaky and slow-failing.

Proposed hardening
-      const waitForEditorChange = () =>
-        new Promise<void>((resolve) => {
-          document.querySelector('uc-cloud-image-editor')?.addEventListener('change', () => resolve(), { once: true });
-        });
+      const waitForEditorChange = (timeoutMs = 5000) =>
+        new Promise<void>((resolve, reject) => {
+          const editor = document.querySelector('uc-cloud-image-editor');
+          if (!editor) {
+            reject(new Error('uc-cloud-image-editor not found'));
+            return;
+          }
+
+          const timeoutId = window.setTimeout(() => {
+            reject(new Error('Timed out waiting for uc-cloud-image-editor change event'));
+          }, timeoutMs);
+
+          editor.addEventListener(
+            'change',
+            () => {
+              window.clearTimeout(timeoutId);
+              resolve();
+            },
+            { once: true },
+          );
+        });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const waitForEditorChange = () =>
new Promise<void>((resolve) => {
document.querySelector('uc-cloud-image-editor')?.addEventListener('change', () => resolve(), { once: true });
});
const waitForEditorChange = (timeoutMs = 5000) =>
new Promise<void>((resolve, reject) => {
const editor = document.querySelector('uc-cloud-image-editor');
if (!editor) {
reject(new Error('uc-cloud-image-editor not found'));
return;
}
const timeoutId = window.setTimeout(() => {
reject(new Error('Timed out waiting for uc-cloud-image-editor change event'));
}, timeoutMs);
editor.addEventListener(
'change',
() => {
window.clearTimeout(timeoutId);
resolve();
},
{ once: true },
);
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tests/validation.e2e.test.tsx` around lines 451 - 454, The helper
waitForEditorChange currently can hang because
document.querySelector('uc-cloud-image-editor') may be null or the change event
might never fire; update waitForEditorChange to attach the event listener only
if the element exists and add a timeout fallback (e.g., setTimeout) that rejects
or resolves with an error after a configurable delay, and ensure any created
listener and timeout are cleaned up when either the event fires or the timeout
triggers; reference the waitForEditorChange function and the
'uc-cloud-image-editor' element and make the timeout clear with a descriptive
Error message so awaiting callers fail fast instead of hanging.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

3 participants