feat: Shadow DOM isolation for WP plugin with deferred CSS loading - #664
feat: Shadow DOM isolation for WP plugin with deferred CSS loading#664jackgranatowski wants to merge 2 commits into
Conversation
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
|
Warning Review limit reached
Next review available in: 50 minutes You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Plus Run ID: 📒 Files selected for processing (1)
📝 WalkthroughWalkthroughThe PR adds optional explanatory notes to semantic color overrides. It also updates embedded WordPress mounting to use an open Shadow DOM with stylesheet loading, timeout handling, and light-DOM fallback. ChangesConfigurator mounting
Semantic override notes
Estimated code review effort: 3 (Moderate) | ~20 minutes Sequence Diagram(s)sequenceDiagram
participant main.ts
participant window.slashedApp
participant ShadowRoot
participant Stylesheet
participant App
main.ts->>window.slashedApp: Read and validate cssUrl
main.ts->>ShadowRoot: Create open shadow root
ShadowRoot->>Stylesheet: Load internal stylesheet
Stylesheet-->>main.ts: Load, error, or timeout
main.ts->>App: Apply theme root and mount app
Possibly related PRs
Suggested labels: Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches 💡 1🛠️ Fix failing CI checks 💡
📝 Generate docstrings
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@configurator/src/main.ts`:
- Around line 64-78: Update the Shadow DOM mounting logic around wpHost and
attachShadow so it no longer claims or implies JavaScript isolation; describe
the protection as CSS and DOM encapsulation only. Keep the existing Shadow DOM
behavior and light-DOM fallback unchanged unless the implementation explicitly
requires isolation from host scripts, in which case replace the mount with an
isolated iframe document.
- Around line 31-34: Update embeddedCssUrl() to reject stylesheet URLs that
contain only whitespace, while continuing to return valid non-empty URLs
unchanged. Apply the validation before the URL is consumed by the Shadow DOM
mounting flow.
🪄 Autofix
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: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a8f61809-e09b-4ac0-a92b-5a722e5869a6
📒 Files selected for processing (2)
configurator/src/components/panels/ColorsPanel.svelteconfigurator/src/main.ts
Browsers restrict :visited styling for privacy, so the preview's links (never visited) can't repaint with a --sf-color-link--visited override — it only takes effect on genuinely-visited links on the published site. The control was correct but read as broken; add a short inline note on the row so the behaviour is expected rather than surprising. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01PtvNAKsrEE1mynifQbjSun
When mounted into a host page's #slashed-admin-app (the WordPress plugin),
the panel shared one document with every other admin plugin's CSS and JS. A
competing reset or a broad rule like `* { pointer-events: none }` could
leave it fully rendered but non-interactive, while the frontend overlay
(already in a Shadow DOM) stayed fine on the same site.
Mount the embedded panel inside a Shadow DOM too. This is CSS/DOM
encapsulation, not a JS sandbox (an open shadow root shares the host realm),
but it is what the failure needs: host styles no longer cross in, and
Svelte's delegated listeners bind to the shadow-internal root so host
document-level handlers can't preempt them. The panel stylesheet is
preloaded, then linked inside the shadow once it loads (head styles don't
cross the boundary); on stylesheet error or a stalled load we fall back to
the previous light-DOM mount, which the plugin's head-enqueued app.css
still styles. attachShadow is deferred until load success so a failed
stylesheet can never trap the panel unstyled. Standalone (#app) is
unchanged. embeddedCssUrl() trims its input so a whitespace-only value
can't pass the same-origin check and mount without a stylesheet.
Verified headlessly: under a hostile `* { pointer-events: none !important }`
rule plus a clobbered window.wp, the shadow-isolated panel renders fully and
responds to clicks; a 404 stylesheet falls back to a styled light-DOM mount.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PtvNAKsrEE1mynifQbjSun
5d61cc8 to
74e86b7
Compare
CI status — green except a pre-existing checkAll functional and lint checks pass on The one red check is Dependency vulnerability audit, which is pre-existing on Both CodeRabbit review threads (whitespace-only Generated by Claude Code |
Summary
Adds Shadow DOM isolation for the configurator when embedded in WordPress admin, protecting it from interference by other admin plugins' CSS and JavaScript. The panel now mounts inside a shadow root with its stylesheet linked inside the shadow boundary (preventing style leakage), and mounting is deferred until the stylesheet loads to avoid unstyled flashes.
Standalone mode (light DOM mount into
#app) is unchanged. WordPress plugin mode now:cssUrlprovided viawindow.slashedApp.cssUrl#slashed-admin-appif Shadow DOM is supportedcssUrlis missing/cross-originAlso adds a note to the "Link visited" color override in ColorsPanel explaining the browser privacy restriction that prevents live preview of
:visitedstyling.Type
Checklist
feat:,fix:,docs:, …) — enforced by commitlintnpm run lint:csspasses (stylelint)npm run buildrebuildsdist/(bundles are git-ignored; CI rebuilds and stamps headers)npm testpasses (unit + Playwright e2e)npm run check:version)core/*.css,optional/*.css, ortoken-registry.jsonchanged (npm run check:llm-guide)npm run check:macros,check:registry,audit:check)CHANGELOG.mdupdated under## [Unreleased](for user-facing changes)Notes
Manual testing:
#appwith light DOMcssUrl: verify the app mounts into a shadow root, styles load inside the shadow, and no unstyled flash occurscssUrl: verify fallback to light DOM mount worksImplementation details:
embeddedCssUrl()safely readswindow.slashedApp.cssUrlwith type guardsisSameOrigin()validates the CSS URL before loading it into the shadowmountedflag prevents double-mounting if bothloadanderrorevents firehttps://claude.ai/code/session_01PtvNAKsrEE1mynifQbjSun
Summary by CodeRabbit
New Features
Bug Fixes