style(storybook): refine manager sidebar, LNB inset and shared story frame
- Manager sidebar labels and sort order for the grouped pages; LNB 1-depth text start 12px (token, baseline and LNB doc updated) - Shared story frame: drop the divider under section titles, side margin max 60px -> 30px; Foundation color/typography spacing - Pseudo-state mirroring also pins :focus-visible via data-sb-focus while keeping the previous clones for compound rules (Slider Focus + Drag)
This commit is contained in:
1 parent
7ff852952a
commit
fe9c115cf9
22 files changed
+100
-83
No files matched your search
@@ -1,19 +1,28 @@
|
||||
// Pins :hover and :active visuals for state Stories (Storybook only, never loaded by the app).
|
||||
// Every rule that uses :hover or :active is cloned right after itself with the pseudo-class swapped for a
|
||||
// Pins :hover, :active and :focus-visible visuals for state Stories (Storybook only, never loaded by the app).
|
||||
// Every rule that uses :hover, :active or :focus-visible is cloned right after itself with the pseudo-class swapped for a
|
||||
// data attribute, so cascade order and specificity stay the same. No declaration or value is authored here.
|
||||
// 2026-11-13: :focus-visible → data-sb-focus, so a Focus specimen can show its ring without holding the page focus (only one
|
||||
// element can be focused; e.g. Selection Controls focuses the Checkbox and pins the Radio Group / Switch rings).
|
||||
const HOVER = "data-sb-hover"
|
||||
const ACTIVE = "data-sb-active"
|
||||
const FOCUS = "data-sb-focus"
|
||||
const PSEUDO = /:hover\b|:active\b|:focus-visible\b/
|
||||
// A negated :focus-visible (:not(:focus-visible)) would match every element without the attribute, so such a rule keeps its
|
||||
// :focus-visible and only its :hover / :active (if any) are swapped.
|
||||
const NEGATED_FOCUS = /:not\([^)]*:focus-visible/
|
||||
const mirrored = new WeakSet<CSSStyleSheet>()
|
||||
|
||||
function mirror(list: CSSStyleSheet | CSSGroupingRule) {
|
||||
for (let i = list.cssRules.length - 1; i >= 0; i--) {
|
||||
const rule = list.cssRules[i]
|
||||
if (rule instanceof CSSStyleRule) {
|
||||
if (/:hover\b|:active\b/.test(rule.selectorText)) {
|
||||
list.insertRule(
|
||||
rule.cssText.replace(/:hover\b/g, `[${HOVER}]`).replace(/:active\b/g, `[${ACTIVE}]`),
|
||||
i + 1,
|
||||
)
|
||||
if (PSEUDO.test(rule.selectorText)) {
|
||||
// `base` keeps :focus-visible (the pre-2026-11-13 clone), so real focus + data-sb-hover / data-sb-active still matches
|
||||
// a compound rule such as :focus-visible:active (Slider Focus + Drag). `full` also swaps :focus-visible.
|
||||
const base = rule.cssText.replace(/:hover\b/g, `[${HOVER}]`).replace(/:active\b/g, `[${ACTIVE}]`)
|
||||
const full = NEGATED_FOCUS.test(rule.selectorText) ? base : base.replace(/:focus-visible\b/g, `[${FOCUS}]`)
|
||||
if (full !== base) list.insertRule(full, i + 1)
|
||||
if (base !== rule.cssText) list.insertRule(base, i + 1)
|
||||
}
|
||||
} else if ("cssRules" in rule) {
|
||||
mirror(rule as CSSGroupingRule)
|
||||
|
||||
Reference in new issue
Block a user