import { RawValueSignature, ResolvableModeLevelAlias, ResolvableTopLevelAlias, SpecifyTextStyleValue, TokenState, UnresolvableModeLevelAlias, } from '@specifyapp/specify-design-token-format'; import { colorValueToCss, rawColorToCss } from './color.js'; import { dimensionValueToCss, rawDimensionToCss } from './dimension.js'; import { fontValueToCss, rawFontToCss } from './font.js'; import { makeCSSAlias } from '../utils/makeCSSAlias.js'; import { unwrapInnerValue } from '../../_utils/unwrapInnerValue.js'; import { DEFAULT_UNRESOLVABLE_STRATEGY } from '../aliasStrategies/throwOnUnresolvable.js'; import { CssResolvableAliasStrategy, CssUnresolvableAliasStrategy, } from '../aliasStrategies/CssAliasStrategy.js'; import { TemplateRenderer, dataOfToken, dataOfUnresolvedAlias, } from '../../../builtInParsers/utils/template.js'; /** * Converts a `TokenState<'textStyle'>` to a css value. * **Warning**: this token is composite, so the output will be an object. * E.g: * ``` * { * 'font-style': 'normal', * 'font-family': 'My Font', * 'font-weight': 'light', * 'font-size': '24px', * color: 'rgba(12, 80, 244, 1)', * 'text-indent': '24px', * 'line-height': '24px', * 'letter-spacing': '24px', * 'text-align': 'center', * 'text-transform': 'uppercase', * 'text-decoration': 'underline' * } ``` */ export function textStyleToCss( aliasStrategy: CssResolvableAliasStrategy, unresolvableAliasStrategy: CssUnresolvableAliasStrategy = DEFAULT_UNRESOLVABLE_STRATEGY, ) { return (tokenState: TokenState<'textStyle'>) => tokenState .getStatefulValueResult() .mapResolvableTopLevelAlias(aliasStrategy) .mapUnresolvableTopLevelAlias(alias => unresolvableAliasStrategy(tokenState, alias)) .mapTopLevelValue(value => value .mapRawValue(rawValue => rawTextStyleToCss(rawValue, aliasStrategy, unresolvableAliasStrategy), ) .mapResolvableModeLevelAlias(aliasStrategy) .mapUnresolvableModeLevelAlias(alias => unresolvableAliasStrategy(tokenState, alias)) .unwrap(), ) .unwrap() as { [mode: string]: ReturnType }; } export function modeLevelAliasTextStyleToVariables( alias: ResolvableModeLevelAlias | ResolvableTopLevelAlias, renderAlias: TemplateRenderer, textStyle: RawValueSignature<'textStyle'>, withCssAlias = true, ) { const targetAlias = renderAlias( dataOfToken( alias.tokenState, alias instanceof ResolvableModeLevelAlias ? alias.targetMode : undefined, ), ); const fontStyle = `${targetAlias}-font-style`; const fontWeight = `${targetAlias}-font-weight`; const fontFamily = `${targetAlias}-font-family`; const fontSize = `${targetAlias}-font-size`; const variables: { 'font-style': string; 'font-family': string; 'font-weight': string; 'font-size': string; color?: string; 'text-indent'?: string; 'line-height'?: string; 'letter-spacing'?: string; 'text-align'?: string; 'text-transform'?: string; 'text-decoration'?: string; } = { 'font-style': withCssAlias ? makeCSSAlias(fontStyle) : fontStyle, 'font-weight': withCssAlias ? makeCSSAlias(fontWeight) : fontWeight, 'font-family': withCssAlias ? makeCSSAlias(fontFamily) : fontFamily, 'font-size': withCssAlias ? makeCSSAlias(fontSize) : fontSize, }; if (!!textStyle.color.unwrap()) { const color = `${targetAlias}-color`; variables['color'] = withCssAlias ? makeCSSAlias(color) : color; } if (!!textStyle.textIndent.unwrap()) { const textIndent = `${targetAlias}-text-indent`; variables['text-indent'] = withCssAlias ? makeCSSAlias(textIndent) : textIndent; } if (!!textStyle.lineHeight.unwrap()) { const lineHeight = `${targetAlias}-line-height`; variables['line-height'] = withCssAlias ? makeCSSAlias(lineHeight) : lineHeight; } if (!!textStyle.letterSpacing.unwrap()) { const letterSpacing = `${targetAlias}-letter-spacing`; variables['letter-spacing'] = withCssAlias ? makeCSSAlias(letterSpacing) : letterSpacing; } if (!!textStyle.textAlignHorizontal.unwrap()) { const textAlign = `${targetAlias}-text-align`; variables['text-align'] = withCssAlias ? makeCSSAlias(textAlign) : textAlign; } if (!!textStyle.textTransform.unwrap()) { const textTransform = `${targetAlias}-text-transform`; variables['text-transform'] = withCssAlias ? makeCSSAlias(textTransform) : textTransform; } if (!!textStyle.textDecoration.unwrap()) { const textDecoration = `${targetAlias}-text-decoration`; variables['text-decoration'] = withCssAlias ? makeCSSAlias(textDecoration) : textDecoration; } return variables; } export function modeLevelUnresolvableAliasTextStyleToVariables( alias: UnresolvableModeLevelAlias, renderAlias: TemplateRenderer, withCssAlias = true, ) { const targetAlias = renderAlias(dataOfUnresolvedAlias(alias)); const fontStyle = `${targetAlias}-font-style`; const fontWeight = `${targetAlias}-font-weight`; const fontFamily = `${targetAlias}-font-family`; const fontSize = `${targetAlias}-font-size`; const variables: { 'font-style': string; 'font-family': string; 'font-weight': string; 'font-size': string; color?: string; 'text-indent'?: string; 'line-height'?: string; 'letter-spacing'?: string; 'text-align'?: string; 'text-transform'?: string; 'text-decoration'?: string; } = { 'font-style': withCssAlias ? makeCSSAlias(fontStyle) : fontStyle, 'font-weight': withCssAlias ? makeCSSAlias(fontWeight) : fontWeight, 'font-family': withCssAlias ? makeCSSAlias(fontFamily) : fontFamily, 'font-size': withCssAlias ? makeCSSAlias(fontSize) : fontSize, }; const color = `${targetAlias}-color`; const textIndent = `${targetAlias}-text-indent`; const lineHeight = `${targetAlias}-line-height`; const letterSpacing = `${targetAlias}-letter-spacing`; const textAlign = `${targetAlias}-text-align`; const textTransform = `${targetAlias}-text-transform`; const textDecoration = `${targetAlias}-text-decoration`; // For now we generate those variables, but they might point to nothing if the value is null variables['color'] = withCssAlias ? makeCSSAlias(color) : color; variables['text-indent'] = withCssAlias ? makeCSSAlias(textIndent) : textIndent; variables['line-height'] = withCssAlias ? makeCSSAlias(lineHeight) : lineHeight; variables['letter-spacing'] = withCssAlias ? makeCSSAlias(letterSpacing) : letterSpacing; variables['text-align'] = withCssAlias ? makeCSSAlias(textAlign) : textAlign; variables['text-transform'] = withCssAlias ? makeCSSAlias(textTransform) : textTransform; variables['text-decoration'] = withCssAlias ? makeCSSAlias(textDecoration) : textDecoration; return variables; } /** * Converts a `RawValueSignature<'textStyle'>` to css. */ export function rawTextStyleToCss( textStyle: RawValueSignature<'textStyle'>, aliasStrategy: CssResolvableAliasStrategy, unresolvableAliasStrategy: CssUnresolvableAliasStrategy = DEFAULT_UNRESOLVABLE_STRATEGY, ) { const variables = textStyle.font .mapPrimitiveValue(v => rawFontToCss(v, aliasStrategy)) .mapResolvableValueLevelAlias(aliasStrategy) .mapUnresolvableValueLevelAlias(alias => unresolvableAliasStrategy(textStyle.font.tokenState, alias), ) .unwrap() as { 'font-style': string; 'font-family': string; 'font-weight': string; 'font-size': string; color?: string; 'text-indent'?: string; 'line-height'?: string; 'letter-spacing'?: string; 'text-align'?: string; 'text-transform'?: string; 'text-decoration'?: string; }; variables['font-size'] = unwrapInnerValue( textStyle.fontSize.mapPrimitiveValue(rawDimensionToCss), aliasStrategy, unresolvableAliasStrategy, ); const color = unwrapInnerValue( textStyle.color.mapPrimitiveValue(v => { if (!v) return ''; return rawColorToCss(v, aliasStrategy); }), aliasStrategy, unresolvableAliasStrategy, ); if (color && color !== '') variables['color'] = color; const textIndent = unwrapInnerValue( textStyle.textIndent.mapPrimitiveValue(v => { if (!v) return ''; return rawDimensionToCss(v); }), aliasStrategy, unresolvableAliasStrategy, ); if (textIndent && textIndent !== '') variables['text-indent'] = textIndent; const lineHeight = unwrapInnerValue( textStyle.lineHeight.mapPrimitiveValue(v => { if (!v) return ''; return rawDimensionToCss(v); }), aliasStrategy, unresolvableAliasStrategy, ); if (lineHeight && lineHeight !== '') variables['line-height'] = lineHeight; const letterSpacing = unwrapInnerValue( textStyle.letterSpacing.mapPrimitiveValue(v => { if (!v) return ''; return rawDimensionToCss(v); }), aliasStrategy, unresolvableAliasStrategy, ); if (letterSpacing && letterSpacing !== '') variables['letter-spacing'] = letterSpacing; const textAlign = unwrapInnerValue( textStyle.textAlignHorizontal, aliasStrategy, unresolvableAliasStrategy, ); if (textAlign) variables['text-align'] = textAlign; const textDecoration = unwrapInnerValue( textStyle.textDecoration, aliasStrategy, unresolvableAliasStrategy, ); if (textDecoration) variables['text-decoration'] = textDecoration; return variables; } /** * Converts a textStyle to css. */ export function textStyleValueToCss(textStyle: SpecifyTextStyleValue) { const variables = fontValueToCss(textStyle.font) as { 'font-style': string; 'font-family': string; 'font-weight': number; 'font-size': string; color?: string; 'text-indent'?: string; 'line-height'?: string; 'letter-spacing'?: string; 'text-align'?: string; 'text-transform'?: string; 'text-decoration'?: string; }; variables['font-size'] = dimensionValueToCss(textStyle.fontSize); if (!!textStyle.color) variables['color'] = colorValueToCss(textStyle.color); if (!!textStyle.textIndent) variables['text-indent'] = dimensionValueToCss(textStyle.textIndent); if (!!textStyle.lineHeight) variables['line-height'] = dimensionValueToCss(textStyle.lineHeight); if (!!textStyle.letterSpacing) variables['letter-spacing'] = dimensionValueToCss(textStyle.letterSpacing); if (!!textStyle.textAlignHorizontal) variables['text-align'] = textStyle.textAlignHorizontal; if (!!textStyle.textTransform) variables['text-transform'] = textStyle.textTransform; if (!!textStyle.textDecoration) variables['text-decoration'] = textStyle.textDecoration; return variables; }