diff --git a/exporters/variables-scss/src/generators/__tests__/stylesObjectGenerator.test.ts b/exporters/variables-scss/src/generators/__tests__/stylesObjectGenerator.test.ts index 2f227aab64..e066abe33b 100644 --- a/exporters/variables-scss/src/generators/__tests__/stylesObjectGenerator.test.ts +++ b/exporters/variables-scss/src/generators/__tests__/stylesObjectGenerator.test.ts @@ -69,11 +69,13 @@ describe('stylesObjectGenerator', () => { expectedStyles: { '$heading-xlarge-bold': { desktop: - '(\nfont-family: "\'Inter\', sans-serif",\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)', + // eslint-disable-next-line quotes -- we are handling special characters + "(\nfont-family: 'Inter', sans-serif,\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)", }, '$heading-xlarge-bold-underline': { desktop: - '(\nfont-family: "\'Inter\', sans-serif",\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)', + // eslint-disable-next-line quotes -- we are handling special characters + "(\nfont-family: 'Inter', sans-serif,\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)", }, $styles: { 'heading-xlarge-bold': '$heading-xlarge-bold', @@ -154,16 +156,19 @@ describe('stylesObjectGenerator', () => { expectedObject: { '$heading-xlarge-bold': { desktop: - '(\nfont-family: "\'Inter\', sans-serif",\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)', + // eslint-disable-next-line quotes -- we are handling special characters + "(\nfont-family: 'Inter', sans-serif,\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)", tablet: - '(\nfont-family: "\'Inter\', sans-serif",\nfont-size: 32px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)', + // eslint-disable-next-line quotes -- we are handling special characters + "(\nfont-family: 'Inter', sans-serif,\nfont-size: 32px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)", }, }, description: 'should create object structure from typography token', stylesObjectRef: { '$heading-xlarge-bold': { tablet: - '(\nfont-family: "\'Inter\', sans-serif",\nfont-size: 32px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)', + // eslint-disable-next-line quotes -- we are handling special characters + "(\nfont-family: 'Inter', sans-serif,\nfont-size: 32px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)", }, } as StylesObjectType, hasJsOutput: false, @@ -210,7 +215,8 @@ describe('stylesObjectGenerator', () => { expectedStyles: { '$heading-xlarge-bold': { desktop: - '(\nfont-family: "\'Inter\', sans-serif",\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)', + // eslint-disable-next-line quotes -- we are handling special characters + "(\nfont-family: 'Inter', sans-serif,\nfont-size: 64px,\nfont-style: normal,\nfont-weight: 700,\nline-height: 1.2,\n)", }, exampleRef: 'exampleRef', }, diff --git a/exporters/variables-scss/src/helpers/tokenHelper.ts b/exporters/variables-scss/src/helpers/tokenHelper.ts index 3efa569ac0..95a505b8dc 100644 --- a/exporters/variables-scss/src/helpers/tokenHelper.ts +++ b/exporters/variables-scss/src/helpers/tokenHelper.ts @@ -1,3 +1,4 @@ +import { NamingHelper, StringCase } from '@supernovaio/export-helpers'; import { ColorToken, DimensionToken, @@ -9,7 +10,6 @@ import { TokenType, TypographyTokenValue, } from '@supernovaio/sdk-exporters'; -import { NamingHelper, StringCase } from '@supernovaio/export-helpers'; import { toCamelCase } from './stringHelper'; export const tokenVariableName = (token: Token, tokenGroups: Array, hasParentPrefix: boolean): string => { @@ -120,38 +120,68 @@ export const addAngleVarToGradient = (inputString: string): string => { return inputString; }; +const toKebabCase = (value: string) => value.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase(); + +const removePairQuotes = (input: string): string => { + const regex = /^'([^']*)'$/; + + return input.replace(regex, '$1'); +}; + +const isNumber = (value: unknown): boolean => typeof value === 'number'; + +const jsObjectTemplate = (strings: string[]) => `{ +${strings.join(',\n')}, +}`; + +const scssObjectTemplate = (strings: string[]) => `( +${strings.join(',\n')}, +)`; + +type KeyValueTemplateCallback = (key: string, value: string | number) => string; + +type TypographyShape = { + fontFamily: string; + fontSize: string; + fontStyle: string; + fontWeight: string; + lineHeight?: number; +}; + +const jsKeyValueTemplate: KeyValueTemplateCallback = (key, value) => { + return `${key}: ${/\s/.test(value as string) ? `"${value}"` : value}`; +}; + +const scssKeyValueTemplate: KeyValueTemplateCallback = (key, value) => { + return `${toKebabCase(key)}: ${isNumber(value) ? value : removePairQuotes(value as string)}`; +}; + +const passObjectKeyValueToCallback = (object: Shape, callback: KeyValueTemplateCallback) => { + return Object.entries(object).map((record) => { + const [key, value] = record; + + return callback(key, value); + }); +}; + export const typographyValue = ( { fontFamily, fontSize, fontWeight, lineHeight }: TypographyTokenValue, isItalic: boolean, hasJsOutput: boolean, ): string => { - const baseStyles = [ - `font-family: "'${fontFamily.text}', sans-serif"`, - `font-size: ${fontSize.measure}${fontSize.unit === 'Pixels' ? 'px' : fontSize.unit}`, - `font-style: ${isItalic ? 'italic' : 'normal'}`, - `font-weight: ${fontWeight.text}`, - ]; - - const baseJsStyles = [ - `fontFamily: "'${fontFamily.text}', sans-serif"`, - `fontSize: '${fontSize.measure}${fontSize.unit === 'Pixels' ? 'px' : fontSize.unit}'`, - `fontStyle: '${isItalic ? 'italic' : 'normal'}'`, - `fontWeight: ${fontWeight.text}`, - ]; + const typographyObject: TypographyShape = { + fontFamily: `'${fontFamily.text}', sans-serif`, + fontSize: `'${fontSize.measure}${fontSize.unit === 'Pixels' ? 'px' : fontSize.unit}'`, + fontStyle: `'${isItalic ? 'italic' : 'normal'}'`, + fontWeight: fontWeight.text, + }; if (lineHeight && lineHeight.measure) { - hasJsOutput - ? baseJsStyles.push(`lineHeight: ${lineHeight.measure / 100},`) - : baseStyles.push(`line-height: ${lineHeight.measure / 100},`); + typographyObject.lineHeight = lineHeight.measure / 100; } - if (hasJsOutput) { - return `{ -${baseJsStyles.join(',\n')} -}`; - } + const baseStyles = passObjectKeyValueToCallback(typographyObject, scssKeyValueTemplate); + const baseJsStyles = passObjectKeyValueToCallback(typographyObject, jsKeyValueTemplate); - return `( -${baseStyles.join(',\n')} -)`; + return hasJsOutput ? jsObjectTemplate(baseJsStyles) : scssObjectTemplate(baseStyles); }; diff --git a/exporters/variables-scss/tests/fixtures/exampleTypographyTokens.ts b/exporters/variables-scss/tests/fixtures/exampleTypographyTokens.ts index 4fc7f81fe1..96f4e94040 100644 --- a/exporters/variables-scss/tests/fixtures/exampleTypographyTokens.ts +++ b/exporters/variables-scss/tests/fixtures/exampleTypographyTokens.ts @@ -33,7 +33,7 @@ exampleTypographyTokens.set('typographyRef2', { } as TypographyToken); export const expectedTypographyValue = `( -font-family: "'Inter', sans-serif", +font-family: 'Inter', sans-serif, font-size: 64px, font-style: italic, font-weight: 700,