mirror of
https://github.com/penpot/penpot-export.git
synced 2025-01-19 21:22:28 -05:00
refactor(core): delegate CSS tokenization and serialization to the outputter
This commit is contained in:
parent
b76d4d57ef
commit
9a39da7a65
9 changed files with 37 additions and 26 deletions
|
@ -1,5 +1,3 @@
|
|||
import { textToCssIdentToken } from '../../css/helpers'
|
||||
|
||||
import { PenpotApiFile } from '../../api'
|
||||
import { CSSCustomPropertyDefinition } from '../../types'
|
||||
|
||||
|
@ -17,13 +15,13 @@ const toRgbaCssValue = (hex: string, alpha: number = 1) => {
|
|||
export const adaptColorsToCssVariables = (
|
||||
penpotFile: PenpotApiFile,
|
||||
): CSSCustomPropertyDefinition[] => {
|
||||
const fileName = penpotFile.name
|
||||
const colors = Object.values(penpotFile.data.colors ?? {})
|
||||
|
||||
const cssPropsEntries = colors.map((color) => {
|
||||
const objectClassName = textToCssIdentToken(color.name)
|
||||
|
||||
return {
|
||||
name: objectClassName,
|
||||
scope: fileName,
|
||||
name: color.name,
|
||||
value: toRgbaCssValue(color.color, color.opacity),
|
||||
}
|
||||
})
|
||||
|
|
|
@ -3,7 +3,6 @@ import {
|
|||
isComponent,
|
||||
pickObjectProps,
|
||||
} from '../../api/helpers'
|
||||
import { textToCssClassSelector } from '../../css/helpers'
|
||||
|
||||
import { PenpotApiFile, PenpotApiObject } from '../../api'
|
||||
import { CSSClassDefinition } from '../../types'
|
||||
|
@ -51,8 +50,11 @@ export const adaptPageComponentsToCssClassDefinitions = (
|
|||
const object = component.objects[objectId]
|
||||
if (object.type === 'text') {
|
||||
const cssProps = getTextObjectCssProps(object)
|
||||
const selector = textToCssClassSelector(`${page.name}--${object.name}`)
|
||||
cssClassDefinitions.push({ selector, cssProps })
|
||||
cssClassDefinitions.push({
|
||||
scope: page.name,
|
||||
name: object.name,
|
||||
cssProps,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
import { textToCssClassSelector } from '../../css/helpers'
|
||||
|
||||
import { PenpotApiTypography, CssTextProperty, PenpotApiFile } from '../../api'
|
||||
import { CSSClassDefinition } from '../../types'
|
||||
|
||||
|
@ -25,9 +23,12 @@ export const adaptTypographiesToCssClassDefinitions = (
|
|||
|
||||
const cssClassDefinitions = typographies.map((typography) => {
|
||||
const cssProps = getTypographyAssetCssProps(typography)
|
||||
const selector = textToCssClassSelector(`${fileName}--${typography.name}`)
|
||||
|
||||
return { selector, cssProps }
|
||||
return {
|
||||
scope: fileName,
|
||||
name: typography.name,
|
||||
cssProps,
|
||||
}
|
||||
})
|
||||
|
||||
return cssClassDefinitions
|
|
@ -1,6 +1,6 @@
|
|||
import path from 'node:path'
|
||||
|
||||
import { adaptTypographiesToCssClassDefinitions } from './adapters/inbound/typographyToCssClasses'
|
||||
import { adaptTypographiesToCssClassDefinitions } from './adapters/inbound/typographiesToCssClasses'
|
||||
import { adaptColorsToCssVariables } from './adapters/inbound/colorsToCssVariables'
|
||||
import { adaptPageComponentsToCssClassDefinitions } from './adapters/inbound/pageComponentsToCssClasses'
|
||||
|
||||
|
|
|
@ -1,14 +1,17 @@
|
|||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import { textToCssCustomProperyName } from '../css/helpers'
|
||||
import {
|
||||
camelToKebab,
|
||||
textToCssClassSelector,
|
||||
textToCssCustomPropertyName,
|
||||
} from './syntax'
|
||||
|
||||
import { camelToKebab } from '../string'
|
||||
import {
|
||||
CSSClassDefinition,
|
||||
CSSCustomPropertyDefinition,
|
||||
isCssClassDefinition,
|
||||
} from '../types'
|
||||
} from '../../types'
|
||||
|
||||
const areCssCustomPropertiesDefinitions = (
|
||||
objects: Array<object>,
|
||||
|
@ -17,11 +20,14 @@ const areCssCustomPropertiesDefinitions = (
|
|||
}
|
||||
|
||||
const serializeCssClass = (cssClassDefinition: CSSClassDefinition): string => {
|
||||
const selector = textToCssClassSelector(
|
||||
`${cssClassDefinition.scope}--${cssClassDefinition.name}`,
|
||||
)
|
||||
const cssValidProps = Object.keys(cssClassDefinition.cssProps).map(
|
||||
(key) => ` ${camelToKebab(key)}: ${cssClassDefinition.cssProps[key]};`,
|
||||
)
|
||||
|
||||
return [`${cssClassDefinition.selector} {`, ...cssValidProps, '}'].join('\n')
|
||||
return [`${selector} {`, ...cssValidProps, '}'].join('\n')
|
||||
}
|
||||
|
||||
const serializeCssCustomProperty = (
|
||||
|
@ -29,9 +35,10 @@ const serializeCssCustomProperty = (
|
|||
pad: number,
|
||||
): string => {
|
||||
const { name, value } = cssCustomProperty
|
||||
const key = textToCssCustomPropertyName(name)
|
||||
const padding = ' '.repeat(pad)
|
||||
|
||||
return `${padding}${textToCssCustomProperyName(name)}: ${value};`
|
||||
return `${padding}${key}: ${value};`
|
||||
}
|
||||
|
||||
const serializeCss = (
|
|
@ -1,9 +1,9 @@
|
|||
import assert from 'node:assert'
|
||||
import { describe, it } from 'node:test'
|
||||
|
||||
import { textToCssIdentToken } from './helpers'
|
||||
import { textToCssIdentToken } from './syntax'
|
||||
|
||||
describe('CSS helpers', () => {
|
||||
describe('CSS syntax helpers', () => {
|
||||
describe('Transforming text to CSS ident tokens', () => {
|
||||
describe('when input text includes ASCII printable characters', () => {
|
||||
it('escapes all ASCII printable characters except ident code points (-, 0-9, A-Z, _, a-z)', () => {
|
|
@ -1,3 +1,7 @@
|
|||
export function camelToKebab(str: string) {
|
||||
return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
|
||||
}
|
||||
|
||||
/** From: https://www.w3.org/TR/css-syntax-3/#escaping
|
||||
* Any Unicode code point can be included in an ident sequence or quoted string by escaping it. CSS escape sequences
|
||||
* start with a backslash (\), and continue with:
|
||||
|
@ -70,7 +74,7 @@ export function textToCssClassSelector(str: string) {
|
|||
* case-sensitive (meaning they’re compared using the "identical to" operation), even in the ASCII range (e.g. example
|
||||
* and EXAMPLE are two different, unrelated user-defined identifiers).
|
||||
*/
|
||||
export function textToCssCustomProperyName(str: string) {
|
||||
export function textToCssCustomPropertyName(str: string) {
|
||||
const unescapedDashedIdentifier = '--' + str.trimStart()
|
||||
return textToCssIdentToken(unescapedDashedIdentifier)
|
||||
}
|
|
@ -1,3 +0,0 @@
|
|||
export function camelToKebab(str: string) {
|
||||
return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()
|
||||
}
|
|
@ -1,15 +1,17 @@
|
|||
export interface CSSClassDefinition {
|
||||
selector: string
|
||||
scope: string
|
||||
name: string
|
||||
cssProps: Record<string, string>
|
||||
}
|
||||
|
||||
export const isCssClassDefinition = (
|
||||
object: object,
|
||||
): object is CSSClassDefinition => {
|
||||
return 'selector' in object
|
||||
return 'cssProps' in object
|
||||
}
|
||||
|
||||
export interface CSSCustomPropertyDefinition {
|
||||
scope: string
|
||||
name: string
|
||||
value: string
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue