fix: scope Tailwind Preflight to prevent style conflicts in embedded …#138
Open
sashathor wants to merge 16 commits into
Open
fix: scope Tailwind Preflight to prevent style conflicts in embedded …#138sashathor wants to merge 16 commits into
sashathor wants to merge 16 commits into
Conversation
…o-prevent-host-app-style Resolve snapshot conflicts by keeping branch versions (reflect CSS scoping changes). Made-with: Cursor
…ProseMirror formatting
…th Backspace at start
…ailwind-preflight-css-to-prevent-host-app-style Co-authored-by: Cursor <cursoragent@cursor.com> # Conflicts: # packages/react-designer/e2e/full-cycle/blockquote-visual.spec.ts-snapshots/email-text-style-h3-chromium-darwin-actual.png # packages/react-designer/e2e/full-cycle/heading-visual.spec.ts-snapshots/email-h3-default-chromium-darwin-actual.png # packages/react-designer/src/components/extensions/List/ListForm.tsx
Replace global preflight with scoped rules, add unlayered hover/focus resets for tabs, menus, and ghost buttons, harden portaled components and icons, expand the css-scoping dev harness, and refresh full-cycle snapshots. Co-authored-by: Cursor <cursoragent@cursor.com>
…o-prevent-host-app-style Resolve editor-dev routing conflicts by keeping both CSS Scoping and Translation Editor pages. Co-authored-by: Cursor <cursoragent@cursor.com>
…t in CI pnpm/action-setup@v4 fails when both workflow version: 10 and package.json packageManager are set. Co-authored-by: Cursor <cursoragent@cursor.com>
Scoped .tiptap heading rules remove 24px of document-flow margin inside .node-element blocks, so heading/blockquote/column designer baselines need refreshing. Co-authored-by: Cursor <cursoragent@cursor.com>
Restore pnpm packageManager in package.json and update column full-cycle email actual screenshots from the latest local run. Co-authored-by: Cursor <cursoragent@cursor.com>
pnpm/action-setup@v4 errors when both workflow version: 10 and package.json packageManager are set. Co-authored-by: Cursor <cursoragent@cursor.com>
…o-prevent-host-app-style Resolve package.json conflict by keeping main's packageManager field, which aligns with updated workflows that read pnpm version from Corepack. Co-authored-by: Cursor <cursoragent@cursor.com>
…o-prevent-host-app-style
…o-prevent-host-app-style
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Fixes global CSS conflicts when
@trycourier/react-designeris embedded in a host application. The editor's stylesheet previously shipped unscoped Tailwind Preflight resets (*,h1–h6,a,button,ol,ul,img, etc.) that could override the host app's styles outbound, while hostile host-app element selectors could leak into the editor inbound.This PR introduces scoped Preflight, inbound isolation rules, and defensive UI hardening so the editor renders correctly even when the host page injects aggressive global CSS.
Linear: C-17056
Canary:
@trycourier/react-designer@canaryfrom this branchProblem
When embedded, the designer imports
styles.css, which included Tailwind Preflight as global, unscoped element resets. That caused two classes of bugs:.theme-container.button { … },h1 { … },svg { display: none }, etc.) overrode editor chrome and content because:@layer utilitiesregardless of specificitySolution
1. Outbound isolation — scoped Preflight
tailwind.config.js(corePlugins: { preflight: false })scoped-preflight.css(~1,300 lines) with Preflight rules scoped via:where(.theme-container):where()contributes zero specificity, socourier-*utilities still override resets naturallyscoped-preflight.css→editor.css→ Tailwind layers2. Inbound isolation — block host styles from editor content
:where(.theme-container) .ProseMirrorexplicitly reset text/font/box properties that host apps commonly overrideall: revert(breaks Tailwind utility specificity inside the editor)html :where(.theme-container)protect editor chrome (buttons, tabs, inputs, menus)3. Unlayered defensive rules (Layer 3b)
Host CSS is unlayered, so fixes that must win over hostile globals use unlayered rules in
scoped-preflight.cssat higher specificity, including:borderColoronHandle; unlayeredborder-coloron button hover[role="menuitem"]hover withvar(--accent)andcolor: inherit[role="tablist"].courier-justify-stretchvs.courier-border-nonebutton.hover\:courier-bg-accent:where(:hover)instead of blanketbutton:hover { background: transparent }courier-shrink-0+ inline width/height; ghost buttons getborder-width: 04. Component hardening (~30 files)
Portaled and chrome UI components received defensive inline styles and
courier-prefix fixes so they survive hostile host CSS:Surface,AlertDialog,DropdownMenu,Popover,Tooltip,VariableAutocompleteTextMenu,ContentTypePicker,ContentItemMenu,SlashMenu/MenuListIcon.tsxpath attrs promoted inline; LucidestrokeWidthinline across toolbars.tiptapheading margin overrides on.node-element; block wrapper hardeningPreviewPaneltoggle styles,Tabs.tsx,Status,Handle, SMScourier-text-*fix,DividerFormjustify class fix5.
styles.cssscoping@layer baserules use:where(.theme-container)instead of bare*/body.dark inputspin buttons scoped to.theme-container.tiptapand.courier-email-editor .tiptapselectors scoped under.theme-containerDev tooling
New
/css-scopingpage ineditor-dev(CssScopingPage.tsx):TemplateEditorwith all channels (email,sms,push,inbox,slack,msteams)Tests
Unit (
css-scoping.test.ts)Expanded static analysis suite (~2,600+ assertions) covering:
*/bodyin@layer base:where(.theme-container)scoping inscoped-preflight.cssE2E
text-block.spec.ts— Backspace at paragraph start no longer deletes the block.tiptapheading margins removed 24px of document-flow spacing inside.node-elementblocksFiles changed
91 files — core CSS architecture + UI hardening + dev page + snapshot updates
scoped-preflight.css,styles.css,tailwind.config.jscss-scoping.test.ts, full-cycle snapshot PNGsCssScopingPage.tsx,App.tsx,Layout.tsxui-kit/(Tabs, DropdownMenu, AlertDialog, …),ui/(TextMenu, Handle, Surface, …), channel sidebarsTest plan
pnpm --filter @trycourier/react-designer test(css-scoping + unit)editor-dev→/css-scopingwith hostile stylesunit-test,e2e-test,full-cycle-e2e-testManual QA checklist
button,h1,a,svgstyles — host page unaffected outside editorPublishing
Changeset included (
@trycourier/react-designerpatch):Checklist
/css-scopingdev page)mainresolved (packageManager+ Corepack-aligned workflows)