@cobalt-ui/plugin-css
Advanced tools
Comparing version 0.4.3 to 0.5.1
# @cobalt-ui/plugin-css | ||
## 0.5.1 | ||
### Patch Changes | ||
- Update core | ||
## 0.5.0 | ||
### Minor Changes | ||
- 8845084: Add typography class support | ||
## 0.4.3 | ||
@@ -4,0 +16,0 @@ |
@@ -26,6 +26,6 @@ import type { ParsedColorToken, ParsedCubicBezierToken, ParsedDimensionToken, ParsedDurationToken, ParsedFileToken, ParsedFontToken, ParsedGradientToken, ParsedShadowToken, ParsedTransitionToken, ParsedTypographyToken, ParsedURLToken, Plugin } from '@cobalt-ui/core'; | ||
transform?: Partial<TokenTransformer>; | ||
/** don’t like CSS variable names? Change it! */ | ||
transformVariableNames?(id: string): string; | ||
/** prefix variable names */ | ||
prefix?: string; | ||
} | ||
export default function css(options?: Options): Plugin; | ||
export {}; |
@@ -11,3 +11,3 @@ import color from 'better-color-tools'; | ||
let filename = options?.filename || './tokens.css'; | ||
let format = options?.transformVariableNames || defaultFormatter; | ||
let prefix = options?.prefix || ''; | ||
let transform = { | ||
@@ -34,19 +34,28 @@ ...(options?.transform || {}), | ||
transform.gradient = transformGradient; | ||
if (!transform.typography) | ||
transform.typography = transformTypography; | ||
if (!transform.transition) | ||
transform.transition = transformTransition; | ||
const i = new Indenter(); | ||
function defaultFormatter(id) { | ||
return id.replace(DOT_UNDER_GLOB_RE, '-'); | ||
} | ||
function makeVars(tokens, wrapper = ':root', indentLv = 0) { | ||
function makeVars(tokens, indentLv = 0, generateRoot = false) { | ||
const output = []; | ||
output.push(i.indent(`${wrapper} {`, indentLv)); | ||
if (generateRoot) | ||
output.push(i.indent(':root {', indentLv)); | ||
for (const [id, value] of Object.entries(tokens)) { | ||
output.push(i.indent(`${format(id).replace(DASH_PREFIX_RE, '--')}: ${value};`, indentLv + 1)); | ||
output.push(i.indent(`${id.replace(DASH_PREFIX_RE, `--${prefix}`).replace(DOT_UNDER_GLOB_RE, '-')}: ${value};`, indentLv + (generateRoot ? 1 : 0))); | ||
} | ||
output.push(i.indent('}', indentLv)); | ||
if (generateRoot) | ||
output.push(i.indent('}', indentLv)); | ||
return output; | ||
} | ||
function makeTypography(tokens, indentLv = 0) { | ||
const output = []; | ||
for (const [id, properties] of Object.entries(tokens)) { | ||
output.push(''); | ||
output.push(i.indent(`.${id.replace(DOT_UNDER_GLOB_RE, '-')} {`, indentLv)); | ||
for (const [property, value] of Object.entries(properties)) { | ||
output.push(i.indent(`${property}: ${Array.isArray(value) ? formatFontNames(value) : value};`, indentLv + 1)); | ||
} | ||
output.push(i.indent('}', indentLv)); | ||
} | ||
return output; | ||
} | ||
function makeP3(input) { | ||
@@ -77,6 +86,29 @@ const output = []; | ||
const tokenVals = {}; | ||
const typographyVals = {}; | ||
const modeVals = {}; | ||
const typographyModeVals = {}; | ||
const selectors = []; | ||
// transformation (1 pass through all tokens + modes) | ||
for (const token of tokens) { | ||
// exception: typography tokens require CSS classes | ||
if (token.type === 'typography') { | ||
typographyVals[token.id] = token.value; | ||
if (token.mode && options?.modeSelectors) { | ||
for (let [modeID, modeSelectors] of Object.entries(options.modeSelectors)) { | ||
const [groupRoot, modeName] = parseModeSelector(modeID); | ||
if ((groupRoot && !token.id.startsWith(groupRoot)) || !token.mode[modeName]) | ||
continue; | ||
if (!Array.isArray(selectors)) | ||
modeSelectors = [selectors]; | ||
for (const selector of modeSelectors) { | ||
if (!selectors.includes(selector)) | ||
selectors.push(selector); | ||
if (!modeVals[selector]) | ||
modeVals[selector] = {}; | ||
typographyModeVals[selector][token.id] = token.mode[modeName]; | ||
} | ||
} | ||
} | ||
continue; | ||
} | ||
const transformer = transform[token.type]; | ||
@@ -119,7 +151,8 @@ if (!transformer) | ||
code.push(''); | ||
code.push(...makeVars(tokenVals)); | ||
code.push(''); | ||
code.push(...makeVars(tokenVals, 0, true)); | ||
code.push(...makeTypography(typographyVals)); | ||
// modes | ||
for (const selector of selectors) { | ||
if (!Object.keys(modeVals[selector]).length) { | ||
code.push(''); | ||
if (!Object.keys(modeVals[selector]).length && !Object.keys(typographyModeVals[selector]).length) { | ||
// eslint-disable-next-line no-console | ||
@@ -130,31 +163,24 @@ console.warn(`${FG_YELLOW}@cobalt-ui/plugin-css${RESET} can’t find any tokens for "${selector}"`); | ||
const wrapper = selector.trim().replace(SELECTOR_BRACKET_RE, ''); | ||
if (selector.startsWith('@')) { | ||
code.push(i.indent(`${wrapper} {`, 0)); | ||
code.push(...makeVars(modeVals[selector], ':root', 1)); | ||
code.push(i.indent('}', 0)); | ||
} | ||
else { | ||
code.push(...makeVars(modeVals[selector], wrapper)); | ||
} | ||
code.push(`${wrapper} {`); | ||
if (modeVals[selector]) | ||
code.push(...makeVars(modeVals[selector], 1, wrapper.startsWith('@'))); | ||
if (typographyModeVals[selector]) | ||
code.push(...makeTypography(typographyModeVals[selector], 1)); | ||
code.push('}'); | ||
} | ||
code.push(''); | ||
// P3 | ||
if (tokens.some((t) => t.type === 'color' || t.type === 'gradient' || t.type === 'shadow')) { | ||
code.push(''); | ||
code.push(i.indent(`@media (color-gamut: p3) {`, 0)); | ||
code.push(...makeP3(makeVars(tokenVals, ':root', 1))); | ||
code.push(''); | ||
code.push(...makeP3(makeVars(tokenVals, 1, true))); | ||
for (const selector of selectors) { | ||
code.push(''); | ||
const wrapper = selector.trim().replace(SELECTOR_BRACKET_RE, ''); | ||
if (selector.startsWith('@')) { | ||
code.push(i.indent(`${wrapper} {`, 1)); | ||
code.push(...makeP3(makeVars(modeVals[selector], ':root', 2))); | ||
code.push(i.indent('}', 1)); | ||
} | ||
else { | ||
code.push(...makeP3(makeVars(modeVals[selector], wrapper, 1))); | ||
} | ||
code.push(i.indent(`${wrapper} {`, 1)); | ||
code.push(...makeP3(makeVars(modeVals[selector], 2, wrapper.startsWith('@')))); | ||
code.push(i.indent('}', 1)); | ||
} | ||
code.push(i.indent('}', 0)); | ||
code.push(''); | ||
} | ||
code.push(''); | ||
return [ | ||
@@ -205,8 +231,2 @@ { | ||
} | ||
/** transform typography */ | ||
function transformTypography(value) { | ||
const hasLineHeight = typeof value.lineHeight === 'number' || typeof value.lineHeight === 'string'; | ||
let size = value.fontSize || hasLineHeight ? `${value.fontSize}${hasLineHeight ? `/${value.lineHeight}` : ''}` : ''; | ||
return [value.fontStyle, value.fontWeight, size, formatFontNames(value.fontName || [])].filter((v) => !!v).join(' '); | ||
} | ||
/** transform transition */ | ||
@@ -213,0 +233,0 @@ function transformTransition(value) { |
{ | ||
"name": "@cobalt-ui/plugin-css", | ||
"description": "Generate CSS from your design tokens schema (requires @cobalt-ui/cli)", | ||
"version": "0.4.3", | ||
"version": "0.5.1", | ||
"author": { | ||
@@ -26,4 +26,4 @@ "name": "Drew Powers", | ||
"devDependencies": { | ||
"@cobalt-ui/cli": "^0.3.7", | ||
"@cobalt-ui/core": "^0.3.4", | ||
"@cobalt-ui/cli": "^0.3.8", | ||
"@cobalt-ui/core": "^0.4.0", | ||
"@types/mime": "^2.0.3", | ||
@@ -30,0 +30,0 @@ "@types/svgo": "^2.6.1", |
@@ -14,2 +14,3 @@ import type { | ||
ParsedTypographyToken, | ||
ParsedTypographyValue, | ||
ParsedURLToken, | ||
@@ -51,4 +52,4 @@ Plugin, | ||
transform?: Partial<TokenTransformer>; | ||
/** don’t like CSS variable names? Change it! */ | ||
transformVariableNames?(id: string): string; | ||
/** prefix variable names */ | ||
prefix?: string; | ||
} | ||
@@ -59,3 +60,3 @@ | ||
let filename = options?.filename || './tokens.css'; | ||
let format = options?.transformVariableNames || defaultFormatter; | ||
let prefix = options?.prefix || ''; | ||
let transform = { | ||
@@ -73,3 +74,2 @@ ...(options?.transform || {}), | ||
if (!transform.gradient) transform.gradient = transformGradient; | ||
if (!transform.typography) transform.typography = transformTypography; | ||
if (!transform.transition) transform.transition = transformTransition; | ||
@@ -79,13 +79,22 @@ | ||
function defaultFormatter(id: string): string { | ||
return id.replace(DOT_UNDER_GLOB_RE, '-'); | ||
function makeVars(tokens: Record<string, any>, indentLv = 0, generateRoot = false): string[] { | ||
const output: string[] = []; | ||
if (generateRoot) output.push(i.indent(':root {', indentLv)); | ||
for (const [id, value] of Object.entries(tokens)) { | ||
output.push(i.indent(`${id.replace(DASH_PREFIX_RE, `--${prefix}`).replace(DOT_UNDER_GLOB_RE, '-')}: ${value};`, indentLv + (generateRoot ? 1 : 0))); | ||
} | ||
if (generateRoot) output.push(i.indent('}', indentLv)); | ||
return output; | ||
} | ||
function makeVars(tokens: Record<string, any>, wrapper = ':root', indentLv = 0): string[] { | ||
function makeTypography(tokens: Record<string, ParsedTypographyValue>, indentLv = 0): string[] { | ||
const output: string[] = []; | ||
output.push(i.indent(`${wrapper} {`, indentLv)); | ||
for (const [id, value] of Object.entries(tokens)) { | ||
output.push(i.indent(`${format(id).replace(DASH_PREFIX_RE, '--')}: ${value};`, indentLv + 1)); | ||
for (const [id, properties] of Object.entries(tokens)) { | ||
output.push(''); | ||
output.push(i.indent(`.${id.replace(DOT_UNDER_GLOB_RE, '-')} {`, indentLv)); | ||
for (const [property, value] of Object.entries(properties)) { | ||
output.push(i.indent(`${property}: ${Array.isArray(value) ? formatFontNames(value) : value};`, indentLv + 1)); | ||
} | ||
output.push(i.indent('}', indentLv)); | ||
} | ||
output.push(i.indent('}', indentLv)); | ||
return output; | ||
@@ -119,3 +128,5 @@ } | ||
const tokenVals: { [id: string]: any } = {}; | ||
const typographyVals: { [id: string]: ParsedTypographyValue } = {}; | ||
const modeVals: { [selector: string]: { [id: string]: any } } = {}; | ||
const typographyModeVals: { [selector: string]: { [id: string]: ParsedTypographyValue } } = {}; | ||
const selectors: string[] = []; | ||
@@ -125,2 +136,21 @@ | ||
for (const token of tokens) { | ||
// exception: typography tokens require CSS classes | ||
if (token.type === 'typography') { | ||
typographyVals[token.id] = token.value as ParsedTypographyValue; | ||
if (token.mode && options?.modeSelectors) { | ||
for (let [modeID, modeSelectors] of Object.entries(options.modeSelectors)) { | ||
const [groupRoot, modeName] = parseModeSelector(modeID); | ||
if ((groupRoot && !token.id.startsWith(groupRoot)) || !token.mode[modeName]) continue; | ||
if (!Array.isArray(selectors)) modeSelectors = [selectors]; | ||
for (const selector of modeSelectors) { | ||
if (!selectors.includes(selector)) selectors.push(selector); | ||
if (!modeVals[selector]) modeVals[selector] = {}; | ||
typographyModeVals[selector][token.id] = token.mode[modeName] as ParsedTypographyValue; | ||
} | ||
} | ||
} | ||
continue; | ||
} | ||
const transformer = transform[token.type]; | ||
@@ -159,8 +189,9 @@ if (!transformer) throw new Error(`No transformer found for token type "${token.type}"`); | ||
code.push(''); | ||
code.push(...makeVars(tokenVals)); | ||
code.push(''); | ||
code.push(...makeVars(tokenVals, 0, true)); | ||
code.push(...makeTypography(typographyVals)); | ||
// modes | ||
for (const selector of selectors) { | ||
if (!Object.keys(modeVals[selector]).length) { | ||
code.push(''); | ||
if (!Object.keys(modeVals[selector]).length && !Object.keys(typographyModeVals[selector]).length) { | ||
// eslint-disable-next-line no-console | ||
@@ -171,31 +202,25 @@ console.warn(`${FG_YELLOW}@cobalt-ui/plugin-css${RESET} can’t find any tokens for "${selector}"`); | ||
const wrapper = selector.trim().replace(SELECTOR_BRACKET_RE, ''); | ||
if (selector.startsWith('@')) { | ||
code.push(i.indent(`${wrapper} {`, 0)); | ||
code.push(...makeVars(modeVals[selector], ':root', 1)); | ||
code.push(i.indent('}', 0)); | ||
} else { | ||
code.push(...makeVars(modeVals[selector], wrapper)); | ||
} | ||
code.push(`${wrapper} {`); | ||
if (modeVals[selector]) code.push(...makeVars(modeVals[selector], 1, wrapper.startsWith('@'))); | ||
if (typographyModeVals[selector]) code.push(...makeTypography(typographyModeVals[selector], 1)); | ||
code.push('}'); | ||
} | ||
code.push(''); | ||
// P3 | ||
if (tokens.some((t) => t.type === 'color' || t.type === 'gradient' || t.type === 'shadow')) { | ||
code.push(''); | ||
code.push(i.indent(`@media (color-gamut: p3) {`, 0)); | ||
code.push(...makeP3(makeVars(tokenVals, ':root', 1))); | ||
code.push(''); | ||
code.push(...makeP3(makeVars(tokenVals, 1, true))); | ||
for (const selector of selectors) { | ||
code.push(''); | ||
const wrapper = selector.trim().replace(SELECTOR_BRACKET_RE, ''); | ||
if (selector.startsWith('@')) { | ||
code.push(i.indent(`${wrapper} {`, 1)); | ||
code.push(...makeP3(makeVars(modeVals[selector], ':root', 2))); | ||
code.push(i.indent('}', 1)); | ||
} else { | ||
code.push(...makeP3(makeVars(modeVals[selector], wrapper, 1))); | ||
} | ||
code.push(i.indent(`${wrapper} {`, 1)); | ||
code.push(...makeP3(makeVars(modeVals[selector], 2, wrapper.startsWith('@')))); | ||
code.push(i.indent('}', 1)); | ||
} | ||
code.push(i.indent('}', 0)); | ||
code.push(''); | ||
} | ||
code.push(''); | ||
return [ | ||
@@ -247,8 +272,2 @@ { | ||
} | ||
/** transform typography */ | ||
function transformTypography(value: ParsedTypographyToken['value']): string { | ||
const hasLineHeight = typeof value.lineHeight === 'number' || typeof value.lineHeight === 'string'; | ||
let size = value.fontSize || hasLineHeight ? `${value.fontSize}${hasLineHeight ? `/${value.lineHeight}` : ''}` : ''; | ||
return [value.fontStyle, value.fontWeight, size, formatFontNames((value.fontName as any) || [])].filter((v) => !!v).join(' '); | ||
} | ||
/** transform transition */ | ||
@@ -255,0 +274,0 @@ function transformTransition(value: ParsedTransitionToken['value']): string { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
61327
19
905