fix(mask): the live preview reaches its styles through the scope barrier #14
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "fix/mask-live-preview-scope"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
The MaskCanvas gesture preview is injected by
mask.jsviainnerHTML, so its shapes never receive the CSS-isolation scope attribute — the scoped.kg-mask__live-rect/.kg-mask__live-strokerules silently missed them:stroke: none) never rendered at all.The fix routes the three live rules through
::deepon the scoped live layer (.kg-mask__live ::deep …), the same pattern FileUpload already uses for its cross-boundary input.Verified in the browser against the compiled bundle: an injected rect without the descendant rule computes
fill rgb(0,0,0)/ opacity 1 (the reported black box); with it, all three tools compute the translucent accent preview (rect fill accent @ 0.25, stroke accent @ 0.35).🤖 Generated with Claude Code
Summary
Summary
Coverage
Kagaku.UI - 95%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh! A CSS isolation scope-barrier bug~ how deliciously subtle! fufu~ The live preview shapes injected by
mask.jsviainnerHTMLnever receive theb-<scope>attribute Blazor stamps on its own render-tree elements, so the scoped rules silently missed them — a solid black rect and invisible strokes. What a sneaky little bug~ ♡Verdict: ✅ Looks good to me~
The diagnosis is precise, and the fix is the textbook-correct Blazor pattern. Let me show my work~
Root cause confirmed by tracing the full path:
MaskCanvas.razorrenders<svg class="kg-mask__live" data-mask-live>— Blazor owns this element, so it does carry the scope attribute. ✓mask.js:124grabs that exact svg viaquerySelector('[data-mask-live]'), thenmask.js:132/:140write the preview shapes aslive.innerHTML = .... innerHTML-injected nodes are outside Blazor's render tree → no scope attribute. ✓.kg-mask__live-rect { … }compiled to.kg-mask__live-rect[b-scope]— the injected rect has no[b-scope], so the rule never matched → default SVGfill: black,opacity: 1. Exactly the reported symptom. ✓.kg-mask__live ::deep .kg-mask__live-rect { … }compiles to.kg-mask__live[b-scope] .kg-mask__live-rect— scope attribute rides the parent (which Blazor rendered), descendant selector matches the un-scoped child. Barrier pierced~ ♪Sibling consistency — fufu, this is the same pattern FileUpload already uses!
FileUpload.razor.css:41→.kg-fileupload ::deep .kg-fileupload__inputwith the comment "InputFile renders it as a child component, so its element sits outside this component's CSS scope — ::deep reaches across that boundary." This PR even mirrors that explanatory comment style. Consistency makes Jibril very happy~ ♡No specificity regression: the compiled selector goes from
(0,1,0)to(0,2,0), but there are no competing rules for.kg-mask__live-*classes anywhere in the bundle, so nothing to shadow. The--surfaceCSS custom property on the erase variant inherits through the DOM as before. All three rules (rect / stroke / stroke--erase) migrated uniformly — and--erasecorrectly stays a modifier layered on top oflive-stroke(mask.js:139 emits both classes), so both rules apply as designed. ✓✅ What I liked~
mask.jsdoesn't touch it) and its.kg-mask__fillrule are correctly left alone.::deepresolution (computedfill/opacitybefore vs. after). No fabricated test.💡 Little idea (non-blocking)~
::deepscope resolution is inherently unverifiable in bUnit (bUnit renders the Blazor tree, not JS-injectedinnerHTMLchildren, and doesn't apply CSS isolation attributes against real stylesheets). FileUpload's::deepinput has no CSS-scope test either — same characteristic. The browser verification in the PR body is the right tool. Mentioning this only so nobody reads "no new test" as a gap; it's a property of the layer. ♡Automated review by Jibril · 2026-08-06
CI/CD: absent for head
2904e37(no coverage bot comment) · Local checks: not run — CSS-only change, browser-verified per PR body, no executable code path added