64 lines
2.9 KiB
JavaScript
64 lines
2.9 KiB
JavaScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
|
|
const root = process.cwd()
|
|
const sourcePath = path.join(root, 'packages/kbx-ui/src/tokens/source/kbx.tokens.json')
|
|
const cssPath = path.join(root, 'packages/kbx-ui/src/tokens/kbx.css')
|
|
const manifestPath = path.join(root, 'generated/token-manifest.json')
|
|
const figmaPath = path.join(root, 'design/figma/variables.contract.json')
|
|
const source = JSON.parse(fs.readFileSync(sourcePath, 'utf8'))
|
|
const byPath = new Map(source.tokens.map(t => [t.path, t]))
|
|
|
|
function cssValue(value) {
|
|
const ref = /^\{(.+)\}$/.exec(value)
|
|
if (!ref) return value
|
|
const token = byPath.get(ref[1])
|
|
if (!token) throw new Error(`Unknown token reference: ${value}`)
|
|
return `var(${token.css})`
|
|
}
|
|
|
|
const roles = ['primitive', 'semantic', 'component']
|
|
const lines = [':root {']
|
|
for (const role of roles) {
|
|
lines.push(` /* ${role[0].toUpperCase()}${role.slice(1)} tokens */`)
|
|
for (const token of source.tokens.filter(t => t.role === role)) {
|
|
lines.push(` ${token.css}: ${cssValue(token.value)};`)
|
|
}
|
|
lines.push('')
|
|
}
|
|
lines.push('}')
|
|
lines.push('')
|
|
lines.push('html, body, button, input, select, textarea {')
|
|
lines.push(' font-family: var(--kbx-font-family);')
|
|
lines.push('}')
|
|
lines.push('')
|
|
for (const [mode, overrides] of Object.entries(source.modes ?? {})) {
|
|
if (mode === 'compact') continue
|
|
lines.push(`[data-kbx-density="${mode}"] {`)
|
|
for (const [tokenPath, value] of Object.entries(overrides)) {
|
|
const token = byPath.get(tokenPath)
|
|
if (!token) throw new Error(`Unknown mode token: ${tokenPath}`)
|
|
lines.push(` ${token.css}: ${value};`)
|
|
}
|
|
lines.push('}')
|
|
lines.push('')
|
|
}
|
|
lines.push(':focus-visible {')
|
|
lines.push(' outline: 2px solid var(--kbx-color-focus);')
|
|
lines.push(' outline-offset: 2px;')
|
|
lines.push('}')
|
|
lines.push('')
|
|
|
|
fs.mkdirSync(path.dirname(manifestPath), { recursive: true })
|
|
fs.mkdirSync(path.dirname(figmaPath), { recursive: true })
|
|
fs.writeFileSync(cssPath, lines.join('\n'))
|
|
fs.writeFileSync(manifestPath, JSON.stringify({version: source.version, tokens: source.tokens, modes: source.modes}, null, 2) + '\n')
|
|
|
|
const collections = {
|
|
'KBX Primitive': source.tokens.filter(t => t.role === 'primitive').map(t => ({name:t.path, type:t.type, value:t.value, description:t.description ?? ''})),
|
|
'KBX Semantic': source.tokens.filter(t => t.role === 'semantic').map(t => ({name:t.path, type:t.type, value:t.value, description:t.description ?? ''})),
|
|
'KBX Component': source.tokens.filter(t => t.role === 'component').map(t => ({name:t.path, type:t.type, value:t.value, description:t.description ?? '', modes:Object.fromEntries(Object.entries(source.modes ?? {}).filter(([,o]) => t.path in o).map(([mode,o]) => [mode,o[t.path]]))}))
|
|
}
|
|
fs.writeFileSync(figmaPath, JSON.stringify({schemaVersion:'1.0', tokenVersion:source.version, collections}, null, 2) + '\n')
|
|
console.log(`Generated ${source.tokens.length} design tokens -> CSS / token manifest / Figma variable contract`)
|