feat(sw): add step header process tokens and align docs

This commit is contained in:
shkim4 committed 2026-11-10 17:25:00 +09:00
1 parent 2690a160e9
commit 8a09386b11
8 files changed
+112 -36

No files matched your search

@@ -196,10 +196,45 @@ async function dropdownColors(page, def, themed) {
await page.close()
}
// ---------- 1b. Step Header (2026-11-10): --hm-sw-process-* copies of the SWHeader tokens it paints with ----------
// Without a Step Header value an SWHeader theme on the outermost SW scope still reaches the Step Header; a
// --hm-sw-process-* value there changes the Step Header alone (it wins over the SWHeader token) and leaves SWHeader as is.
{
const page = await newPage()
await open(page, 'sw-step-header--process-header')
const outerOf = selector => page.locator(selector).first().evaluateHandle(element => { let outer = element; for (let e = element; e; e = e.parentElement) if (e.matches?.('.hm-sw-header, .hm-sw-theme')) outer = e; return outer })
const scope = await outerOf('.hm-sw-process-header')
const set = async (values) => scope.evaluate((outer, values) => Object.entries(values).forEach(([token, value]) => value === null ? outer.style.removeProperty(token) : outer.style.setProperty(token, value)), values)
const read = () => page.evaluate(() => {
const header = getComputedStyle(document.querySelector('.hm-sw-process-header'))
const step = document.querySelector('.hm-sw-process-bar__step[aria-checked="true"]')
return { background: `${header.backgroundColor} ${header.backgroundImage}`, selected: step ? getComputedStyle(step).color : null }
})
const base = await read()
await set({ '--hm-sw-header-background': 'rgb(44, 55, 66)', '--hm-sw-header-selected-color': 'rgb(11, 22, 33)' })
const inherited = await read()
check('Step Header: 바깥 범위의 SWHeader 토큰(배경·선택 색)이 그대로 전달', base.selected !== null && inherited.background.includes('rgb(44, 55, 66)') && inherited.selected === 'rgb(11, 22, 33)', JSON.stringify({ base, inherited }))
await set({ '--hm-sw-process-background': 'rgb(1, 2, 3)', '--hm-sw-process-selected-color': 'rgb(77, 88, 99)' })
const own = await read()
check('Step Header: --hm-sw-process-* 지정이 SWHeader 토큰보다 우선', own.background.includes('rgb(1, 2, 3)') && own.selected === 'rgb(77, 88, 99)', JSON.stringify(own))
await set({ '--hm-sw-header-background': null, '--hm-sw-header-selected-color': null, '--hm-sw-process-background': null, '--hm-sw-process-selected-color': null })
check('Step Header: 지정을 지우면 기본값으로 복귀', JSON.stringify(await read()) === JSON.stringify(base), JSON.stringify(base))
await page.close()
// The same Step Header tokens on an SWHeader page change nothing there.
const header = await newPage()
await open(header, 'sw-header--overview')
const paint = () => header.evaluate(() => [...document.querySelectorAll('.hm-sw-header, .hm-sw-header *')].map(element => { const s = getComputedStyle(element); return `${s.color}|${s.backgroundColor}|${s.backgroundImage}|${s.boxShadow}|${s.borderTopColor}` }).join('\n'))
const before = await paint()
await header.locator('.hm-sw-header').first().evaluate(element => { let outer = element; for (let e = element; e; e = e.parentElement) if (e.matches?.('.hm-sw-header, .hm-sw-theme')) outer = e; ['background', 'height', 'text-color', 'selected-color', 'hover-border-gradient', 'document-background', 'object-background', 'property-background', 'window-icon-color'].forEach(name => outer.style.setProperty(`--hm-sw-process-${name}`, 'rgb(1, 2, 3)')) })
check('Step Header 토큰은 SWHeader 화면에 영향 없음', before === await paint(), `${before.split('\n').length} elements`)
await header.close()
}
// ---------- 2. Regression: new cascade vs legacy cascade on every existing SW Story ----------
const here = path.dirname(fileURLToPath(import.meta.url))
const outermost = ':is(.hm-sw-header, .hm-sw-theme):not(:where(.hm-sw-header, .hm-sw-theme) *)'
const tokenBlocks = (await Promise.all(['sw.css', 'sw-viewer.css', 'sw-footer.css'].map(file => readFile(path.join(here, '../src/theme', file), 'utf8'))))
// 2026-11-10: sw-process-header.css (Step Header aliases) and the Step Header Stories joined the comparison.
const tokenBlocks = (await Promise.all(['sw.css', 'sw-viewer.css', 'sw-footer.css', 'sw-process-header.css'].map(file => readFile(path.join(here, '../src/theme', file), 'utf8'))))
.map(text => {
const start = text.indexOf(`${outermost} {`)
const end = text.indexOf('\n}', start)
@@ -212,7 +247,7 @@ const legacy = tokenBlocks.map(block => `.hm-sw-header,\n.hm-sw-theme ${block}`)
// command row) even though no value changes, so the legacy shot is also compared with this control shot.
const control = tokenBlocks.map(block => `${outermost} ${block}`).join('\n')
const index = await (await fetch(`${storybook}/index.json`)).json()
const ids = Object.values(index.entries).filter(entry => entry.type === 'story' && /^sw-(header|popup|viewer|footer|home-menu)/.test(entry.id)).map(entry => entry.id)
const ids = Object.values(index.entries).filter(entry => entry.type === 'story' && /^sw-(header|popup|viewer|footer|home-menu|step-header)/.test(entry.id)).map(entry => entry.id)
const snapshot = page => page.evaluate(() => [...document.querySelectorAll('.hm-sw-header, .hm-sw-theme')].flatMap(root => [root, ...root.querySelectorAll('*')]).map(element => {
const style = getComputedStyle(element), rect = element.getBoundingClientRect()
return `${style.fontFamily}|${style.fontSize}|${style.color}|${style.backgroundImage.slice(0, 80)}|${Math.round(rect.x * 10)},${Math.round(rect.y * 10)},${Math.round(rect.width * 10)},${Math.round(rect.height * 10)}`