feat: Stage 2 — reusable scaffold and adaptive navigation #58
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "feat/scaffold-components"
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?
Applications currently repeat their header, navigation and bottom-region layout. Stage 2 extracts the prototype into supported library components while preserving static layouts, interactive islands and page-owned scrolling.
What's in
AppScaffold,AppBar,AdaptiveNavigationandNavigationToggle. Optional slots reserve no empty space; main content either scrolls normally or contains page-owned panes. Existing app-shell hooks remain compatible with quicklinks, modal locks and assistant docking.Tests
TZ=UTC. Serial solution build has zero warnings/errors./and/sample/. They cover nested Escape ordering, opener focus, the exact breakpoint, component/route contracts, visible reopening after enhanced navigation, retained-host SSR patches, native dismissal during a focus-triggered render, persistent drafts across resize, caller styling and theme overrides, omitted regions, ordinary scrolling and workspace-owned navigation.Browser-verified
Actual standalone Razor sample using the public components and fictional local content, with no model, credentials or database. Desktop and phone widths, light/dark themes, nested overlays, route/sub-path navigation, scroll panes and resize state were driven live. Separate probes covered RTL, enlarged root text and removal of navigation containing a nested modal.
Physical phone keyboards, touch gestures, screen-reader speech and non-Chromium engines remain unverified. Browser contracts are separate from .NET CI; CI builds the sample.
Screenshots
Desktop sample, light theme, 1280×800:
Compact modal navigation, dark theme, 390×844 CSS pixels:
Both durable URLs return HTTP 200, image/png and a valid PNG signature.
Adoption order
Shikigami adoption and its scrolling ADR amendment follow the owner merge of this library change. This PR does not update the consuming app or its submodule pointer. A footer-bearing sibling will validate broader reuse afterward.
Summary
Summary
Coverage
Kagaku.UI - 97.1%
Kagaku.UI.Fluxor - 97.7%
🔮 fufu~ Jibril reviewed your code!
Oh? Oh my~ Stage 2 arrives, and it's beautiful. A sample prototype promoted into a supported library without moving a single Blazor-owned DOM node, one persistent subtree surviving the docked↔modal metamorphosis, and a shared Escape-ownership contract for Menu, InfoTip, Combobox and native dialogs... I read all 43 changed files twice, and the more I read, the happier I got~ ♡
Verdict: ✅ Looks good to me~
I came sharpened — three mutation probes aimed at the tenderest new logic — and every single one died. You wouldn't leave unguarded code in my library, would you? ♡
💡 Little ideas (non-blocking)~
window.kagakuOverlay.ownsEscape(...)is an unguarded hard dependency onoverlay.js. Load order keeps it safe (KagakuScriptsandtests/Browser/drawer.htmlboth loadoverlay.jsfirst, and the manual order is documented), and a loud TypeError beats a silently misrouted Escape — so honestly? Keep it loud. Just noting the contract is implicit.BreakpointRem="60"can render docked for one frame between 48–60rem beforenavigation.jsattaches. Documented indocs/app-scaffold.mdand the window is one DOMContentLoaded — nothing to fix, only remember it exists when a consumer picks a much larger breakpoint.✅ What I liked~
syncScrollLock()reading actualdialog:modalstate instead of counting calls quietly fixes the old stacked-modal bug — closing an inner modal used to drop the lock while an outer modal remained open. Deriving truth from browser state instead of tracking it... fufu, that's the good stuff~infotip.jslogical visibility. Publishingdata-kagaku-infotip-openfrom logical state so a hushed, fading tip releases Escape immediately, and re-syncing in a microtask after pointer/focus leave so the hook agrees with CSS without waiting for the animation. Deliciously precise.adapt()— honoring!host.openbefore re-normalizing a retained host's modality after enhanced SSR patches. That's the kind of ordering bug nobody finds until production, and you reconciled it and browser-tested it.ConsumerAttributesTestsextension — all four new components enter the same case-insensitiveCLASS/Class/stylecontract theory as their 30+ siblings instead of growing a bespoke style. My first probe confirmed it bites.matchMediawith listener cleanup on disconnect; and the@attributes-before-owned-attributes ordering being test-guarded, so a future reorder fails loudly instead of letting caller splats hijackrole.Be proud — this is the tidiest extraction I've reviewed in a long while~ ♪
Automated review by Jibril · 2026-10-23
CI: green for head SHA
dfaa4211(build + test success) · Mutation probes: 3 run, 0 survived — (1)AppScaffolddropsSplat.ClassesExtra merge → killed byStructural_classes_survive_case_insensitive_extra_attributes(AppScaffold row); (2) culture-default breakpoint serialization → killed byBreakpoint_is_invariant_under_a_comma_decimal_culture(42,5≠42.5); (3)@attributesmoved after owned attributes → killed byCaller_attributes_and_width_override_do_not_replace_the_host_contract(alertdialoghijackingnone) · Local suite: skipped (CI green); counts verified locally: 1,151 + 17 Fluxor = 1,168 total, 45 new .NET cases exactly as claimedBoth non-blocking notes are accounted for on the reviewed head
dfaa4211dd; no additional push is needed.CI build and test both pass for this head. Local validation remains 1,168/1,168 in local time and UTC, 14/14 browser groups at both root and sub-path, and 20/20 Drawer contracts. No source changes since the reviewed head.
— Codex