Skip to content

fix(editor): prevent styling loss flash on custom page tabs when splitting/closing panes#2449

Merged
bajrangCoder merged 2 commits into
mainfrom
fix/page-tab-style-flash
Jul 5, 2026
Merged

fix(editor): prevent styling loss flash on custom page tabs when splitting/closing panes#2449
bajrangCoder merged 2 commits into
mainfrom
fix/page-tab-style-flash

Conversation

@bajrangCoder

@bajrangCoder bajrangCoder commented Jul 5, 2026

Copy link
Copy Markdown
Member
  • Implement DOM reconciliation in renderPaneLayout to keep pane element detachment to a minimum.
  • Retrieve the document's main.css stylesheet and adopt it directly into the Shadow DOM.
  • Catch adoption failures and fall back safely to a constructed CSSStyleSheet (caching only upon successful replaceSync compilation) or a link stylesheet.

…tting/closing panes

- Implement DOM reconciliation in renderPaneLayout to keep pane element detachment to a minimum.
- Use adoptedStyleSheets inside Shadow DOM for type: "page" files to synchronously apply and retain main.css styles, avoiding FOUC when re-parenting.
@greptile-apps

greptile-apps Bot commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Greptile Summary

This PR fixes a flash of unstyled content (FOUC) on custom "page" type tabs when panes are split or closed by addressing two root causes: unnecessary DOM detachment during pane layout re-renders, and style loss on Shadow DOM re-parenting.

  • DOM reconciliation in renderPaneLayout (editorManager.js): instead of calling replaceChildren() which detaches all pane elements and causes style re-application, the new implementation diffs current vs. target children, removes only obsolete split handles, and moves/inserts elements in-place — preserving Shadow DOM attachment continuity.
  • adoptedStyleSheets for shadow DOM styling (editorFile.js): for type \"page\" files, styles are now applied synchronously via adoptedStyleSheets using the live document.styleSheets entry for main.css, with a fallback to a constructed CSSStyleSheet copy and then a <link> element if neither approach is available.

Confidence Score: 5/5

Safe to merge — both code paths have correct fallback handling and the reconciliation logic is well-bounded.

The DOM reconciliation in renderPaneLayout correctly handles element removal, reordering, and insertion via a two-pass algorithm with no missed edge cases. The adoptedStyleSheets path in editorFile.js has a well-structured three-tier fallback and the try/catch wrapping prevents any unhandled exceptions. No unaddressed correctness issues were found.

No files require special attention.

Important Files Changed

Filename Overview
src/lib/editorFile.js Adds adoptedStyleSheets-based styling for shadow DOM with a three-tier fallback; the module-level cache only activates for the constructed-sheet fallback, meaning the happy path re-scans document.styleSheets on every EditorFile creation.
src/lib/editorManager.js Replaces full replaceChildren() with a minimal DOM reconciliation pass; logic is correct — orphan removal and insertion ordering both handle split handle turnover and pane element preservation properly.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A[renderPaneLayout called] --> B[Build targetElements array\nnew split handles + child.element refs]
    B --> C[cleanupPaneSplitHandles\nremove event listeners from old handles]
    C --> D[Snapshot currentChildren]
    D --> E{Each current child\nin targetSet?}
    E -- No --> F[Remove from DOM]
    E -- Yes --> G[Keep in DOM]
    F --> H[Insertion pass:\nwalk targetElements in order]
    G --> H
    H --> I{currentEl === targetEl?}
    I -- Yes --> J[Advance currentEl pointer]
    I -- No --> K[insertBefore targetEl, currentEl\nmoves or inserts element]
    J --> L[Next targetEl]
    K --> L
    L --> M[Recurse: renderPaneLayout for each child]

    N[new EditorFile type=page] --> O[getMainCSSStyleSheet]
    O --> P{mainCSSStyleSheet cached?}
    P -- Yes --> Q[Return constructed sheet]
    P -- No --> R[Scan document.styleSheets\nfor main.css]
    R --> S{Found?}
    S -- No --> T[Fall back to link element]
    S -- Yes --> U[Try: shadow.adoptedStyleSheets = liveSheet]
    Q --> U
    U -- Success --> V[Styles applied synchronously\nno FOUC on re-parent]
    U -- Throws --> W[Try: new CSSStyleSheet + replaceSync\ncache in mainCSSStyleSheet]
    W -- Success --> V
    W -- Throws --> T
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
    A[renderPaneLayout called] --> B[Build targetElements array\nnew split handles + child.element refs]
    B --> C[cleanupPaneSplitHandles\nremove event listeners from old handles]
    C --> D[Snapshot currentChildren]
    D --> E{Each current child\nin targetSet?}
    E -- No --> F[Remove from DOM]
    E -- Yes --> G[Keep in DOM]
    F --> H[Insertion pass:\nwalk targetElements in order]
    G --> H
    H --> I{currentEl === targetEl?}
    I -- Yes --> J[Advance currentEl pointer]
    I -- No --> K[insertBefore targetEl, currentEl\nmoves or inserts element]
    J --> L[Next targetEl]
    K --> L
    L --> M[Recurse: renderPaneLayout for each child]

    N[new EditorFile type=page] --> O[getMainCSSStyleSheet]
    O --> P{mainCSSStyleSheet cached?}
    P -- Yes --> Q[Return constructed sheet]
    P -- No --> R[Scan document.styleSheets\nfor main.css]
    R --> S{Found?}
    S -- No --> T[Fall back to link element]
    S -- Yes --> U[Try: shadow.adoptedStyleSheets = liveSheet]
    Q --> U
    U -- Success --> V[Styles applied synchronously\nno FOUC on re-parent]
    U -- Throws --> W[Try: new CSSStyleSheet + replaceSync\ncache in mainCSSStyleSheet]
    W -- Success --> V
    W -- Throws --> T
Loading

Reviews (2): Last reviewed commit: "fix issue" | Re-trigger Greptile

Comment thread src/lib/editorFile.js Outdated
Comment thread src/lib/editorFile.js
@bajrangCoder

Copy link
Copy Markdown
Member Author

@greptile

@bajrangCoder bajrangCoder merged commit 5ff7964 into main Jul 5, 2026
13 checks passed
@bajrangCoder bajrangCoder deleted the fix/page-tab-style-flash branch July 5, 2026 05:29
@github-project-automation github-project-automation Bot moved this from Backlog to Done in The Code Board - Acode Jul 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

1 participant