diff --git a/packages/core/src/lib/adapters/inbound/colorsToCssVariables.ts b/packages/core/src/lib/adapters/inbound/colorsToCssVariables.ts index f017666..e876d79 100644 --- a/packages/core/src/lib/adapters/inbound/colorsToCssVariables.ts +++ b/packages/core/src/lib/adapters/inbound/colorsToCssVariables.ts @@ -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), } }) diff --git a/packages/core/src/lib/adapters/inbound/pageComponentsToCssClasses.ts b/packages/core/src/lib/adapters/inbound/pageComponentsToCssClasses.ts index 68de03b..1b4f8d9 100644 --- a/packages/core/src/lib/adapters/inbound/pageComponentsToCssClasses.ts +++ b/packages/core/src/lib/adapters/inbound/pageComponentsToCssClasses.ts @@ -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, + }) } } } diff --git a/packages/core/src/lib/adapters/inbound/typographyToCssClasses.ts b/packages/core/src/lib/adapters/inbound/typographiesToCssClasses.ts similarity index 84% rename from packages/core/src/lib/adapters/inbound/typographyToCssClasses.ts rename to packages/core/src/lib/adapters/inbound/typographiesToCssClasses.ts index 7a01111..599aa4e 100644 --- a/packages/core/src/lib/adapters/inbound/typographyToCssClasses.ts +++ b/packages/core/src/lib/adapters/inbound/typographiesToCssClasses.ts @@ -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 diff --git a/packages/core/src/lib/index.ts b/packages/core/src/lib/index.ts index 3f4b8a2..6e9d9c4 100644 --- a/packages/core/src/lib/index.ts +++ b/packages/core/src/lib/index.ts @@ -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' diff --git a/packages/core/src/lib/outputters/css.ts b/packages/core/src/lib/outputters/css/index.ts similarity index 80% rename from packages/core/src/lib/outputters/css.ts rename to packages/core/src/lib/outputters/css/index.ts index 0c8d563..972deed 100644 --- a/packages/core/src/lib/outputters/css.ts +++ b/packages/core/src/lib/outputters/css/index.ts @@ -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, @@ -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 = ( diff --git a/packages/core/src/lib/css/helpers.test.ts b/packages/core/src/lib/outputters/css/syntax.test.ts similarity index 94% rename from packages/core/src/lib/css/helpers.test.ts rename to packages/core/src/lib/outputters/css/syntax.test.ts index 5b4f739..81dcdee 100644 --- a/packages/core/src/lib/css/helpers.test.ts +++ b/packages/core/src/lib/outputters/css/syntax.test.ts @@ -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)', () => { diff --git a/packages/core/src/lib/css/helpers.ts b/packages/core/src/lib/outputters/css/syntax.ts similarity index 95% rename from packages/core/src/lib/css/helpers.ts rename to packages/core/src/lib/outputters/css/syntax.ts index 9435adf..bdd3bf4 100644 --- a/packages/core/src/lib/css/helpers.ts +++ b/packages/core/src/lib/outputters/css/syntax.ts @@ -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) } diff --git a/packages/core/src/lib/string.ts b/packages/core/src/lib/string.ts deleted file mode 100644 index 1186463..0000000 --- a/packages/core/src/lib/string.ts +++ /dev/null @@ -1,3 +0,0 @@ -export function camelToKebab(str: string) { - return str.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase() -} diff --git a/packages/core/src/lib/types.ts b/packages/core/src/lib/types.ts index e546b4a..a532ddf 100644 --- a/packages/core/src/lib/types.ts +++ b/packages/core/src/lib/types.ts @@ -1,15 +1,17 @@ export interface CSSClassDefinition { - selector: string + scope: string + name: string cssProps: Record } 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 }