From e5ec68b837889c2d03bfbc8f64f0975e41132582 Mon Sep 17 00:00:00 2001 From: Devin Abbott Date: Thu, 11 Jan 2024 16:32:27 -0800 Subject: [PATCH] Improve css output --- .../__snapshots__/compile.test.ts.snap | 288 +++++++----------- packages/noya-compiler/src/project.ts | 66 +++- 2 files changed, 173 insertions(+), 181 deletions(-) diff --git a/packages/noya-compiler/src/__tests__/__snapshots__/compile.test.ts.snap b/packages/noya-compiler/src/__tests__/__snapshots__/compile.test.ts.snap index 1f20bcdf9..8ffcd1e72 100644 --- a/packages/noya-compiler/src/__tests__/__snapshots__/compile.test.ts.snap +++ b/packages/noya-compiler/src/__tests__/__snapshots__/compile.test.ts.snap @@ -56,22 +56,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #3b82f633; color: #2563ebcc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #fff; font-size: 3.75rem; line-height: 1; @@ -80,7 +77,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #fff; font-size: 1.875rem; line-height: 1; @@ -89,29 +86,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #3b82f6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -119,14 +113,12 @@ Object { } ", "public/vanilla/blue/dark/components/hero/html-css/hero.html": "
- - Create, iterate, inspire. - - Turn great ideas into new possibilities. - -
- - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. +
@@ -160,22 +152,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #3b82f633; color: #2563ebcc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #fff; font-size: 3.75rem; line-height: 1; @@ -184,7 +173,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #fff; font-size: 1.875rem; line-height: 1; @@ -193,29 +182,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #3b82f6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -225,16 +211,14 @@ Object { "public/vanilla/blue/dark/components/hero/react-css/hero.tsx": "export default function Hero() { return (
-
New
- Create, iterate, inspire. - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. -
- - + @@ -277,22 +261,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #bfdbfe33; color: #2563ebcc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #000; font-size: 3.75rem; line-height: 1; @@ -301,7 +282,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #000; font-size: 1.875rem; line-height: 1; @@ -310,29 +291,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #3b82f6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -340,14 +318,12 @@ Object { } ", "public/vanilla/blue/light/components/hero/html-css/hero.html": "
- - Create, iterate, inspire. - - Turn great ideas into new possibilities. - -
- - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. +
@@ -381,22 +357,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #bfdbfe33; color: #2563ebcc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #000; font-size: 3.75rem; line-height: 1; @@ -405,7 +378,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #000; font-size: 1.875rem; line-height: 1; @@ -414,29 +387,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #3b82f6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -446,16 +416,14 @@ Object { "public/vanilla/blue/light/components/hero/react-css/hero.tsx": "export default function Hero() { return (
-
New
- Create, iterate, inspire. - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. -
- - + @@ -498,22 +466,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #14b8a633; color: #0d9488cc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #fff; font-size: 3.75rem; line-height: 1; @@ -522,7 +487,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #fff; font-size: 1.875rem; line-height: 1; @@ -531,29 +496,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #14b8a6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -561,14 +523,12 @@ Object { } ", "public/vanilla/teal/dark/components/hero/html-css/hero.html": "
- - Create, iterate, inspire. - - Turn great ideas into new possibilities. - -
- - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. +
@@ -602,22 +562,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #14b8a633; color: #0d9488cc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #fff; font-size: 3.75rem; line-height: 1; @@ -626,7 +583,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #fff; font-size: 1.875rem; line-height: 1; @@ -635,29 +592,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #14b8a6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -667,16 +621,14 @@ Object { "public/vanilla/teal/dark/components/hero/react-css/hero.tsx": "export default function Hero() { return (
-
New
- Create, iterate, inspire. - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. -
- - + @@ -719,22 +671,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #99f6e433; color: #0d9488cc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #000; font-size: 3.75rem; line-height: 1; @@ -743,7 +692,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #000; font-size: 1.875rem; line-height: 1; @@ -752,29 +701,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #14b8a6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -782,14 +728,12 @@ Object { } ", "public/vanilla/teal/light/components/hero/html-css/hero.html": "
- - Create, iterate, inspire. - - Turn great ideas into new possibilities. - -
- - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. +
@@ -823,22 +767,19 @@ Object { gap: 1rem; } -.hero__content__tag { +.hero__tag { display: inline-flex; align-items: center; - padding-left: 0.625rem; - padding-right: 0.625rem; - padding-top: 0.125rem; - padding-bottom: 0.125rem; border-radius: 9999px; font-size: 0.875rem; line-height: 1.25rem; font-weight: 500; background-color: #99f6e433; color: #0d9488cc; + padding: 0.125rem 0.625rem; } -.hero__content__title { +.hero__title { color: #000; font-size: 3.75rem; line-height: 1; @@ -847,7 +788,7 @@ Object { text-align: center; } -.hero__content__subtitle { +.hero__subtitle { color: #000; font-size: 1.875rem; line-height: 1; @@ -856,29 +797,26 @@ Object { text-align: center; } -.hero__content__actions-row { +.hero__actions-row { display: flex; align-items: center; gap: 1rem; margin-top: 0.5rem; } -.hero__content__actions-row__button { +.hero__button { appearance: none; font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; border-radius: 0.375rem; - padding-left: 0.875rem; - padding-right: 0.875rem; - padding-top: 0.625rem; - padding-bottom: 0.625rem; background-color: #14b8a6; color: #fff; box-shadow: 0 1px 2px 0 rgb(0 0 0 / 0.05); + padding: 0.625rem 0.875rem; } -.hero__content__actions-row__link { +.hero__link { font-size: 0.875rem; line-height: 1.25rem; font-weight: 700; @@ -888,16 +826,14 @@ Object { "public/vanilla/teal/light/components/hero/react-css/hero.tsx": "export default function Hero() { return (
-
New
- Create, iterate, inspire. - +
New
+ Create, iterate, inspire. + Turn great ideas into new possibilities. -
- - + diff --git a/packages/noya-compiler/src/project.ts b/packages/noya-compiler/src/project.ts index 1778e0963..35ef73ce1 100644 --- a/packages/noya-compiler/src/project.ts +++ b/packages/noya-compiler/src/project.ts @@ -873,6 +873,7 @@ function compileCSS({ }) { let styleRules: StyleRule[] = []; const simpleElementToClassName = new Map(); + const existingNames = new Set(); SimpleElementTree.visit(simpleElement, (simple) => { if (typeof simple === 'string') return; @@ -887,8 +888,13 @@ function compileCSS({ const pathOfNodes = ResolvedHierarchy.accessPath(resolvedNode, indexPath); const namePath = pathOfNodes.map((n) => getNodeName(n, findComponent)); + const elementName = namePath[namePath.length - 1]; - const className = [component.name, ...namePath] + const className = ( + !existingNames.has(elementName) + ? [component.name, elementName] + : [component.name, ...namePath] + ) .map((name) => getComponentNameIdentifier(name, 'kebab')) .join('__'); @@ -898,14 +904,19 @@ function compileCSS({ (simple.props.className as string | undefined)?.split(' '), ); - const allDeclarations = Object.entries({ + const allDeclarationsObject = mergeShorthand({ ...(simple.props.style ?? {}), ...convertedFromTailwind, - }).map(([key, value]) => { - const styleName = styleNameToString(key); - return [styleName, value.toString()] as [string, string]; }); + const allDeclarations = Object.entries(allDeclarationsObject) + // Filter undefined values + .filter(([, value]) => value !== undefined) + .map(([key, value]) => { + const styleName = styleNameToString(key); + return [styleName, value.toString()] as [string, string]; + }); + styleRules.push({ selector: `.${className}`, declarations: allDeclarations, @@ -925,3 +936,48 @@ function buildStyleSheet(styleRules: StyleRule[]) { }) .join('\n\n'); } + +const shorthandProperties = { + padding: [ + 'paddingTop' as const, + 'paddingRight' as const, + 'paddingBottom' as const, + 'paddingLeft' as const, + ], + margin: [ + 'marginTop' as const, + 'marginRight' as const, + 'marginBottom' as const, + 'marginLeft' as const, + ], +}; + +type ShorthandProperty = keyof typeof shorthandProperties; + +function mergeShorthand(style: CSSProperties): CSSProperties { + for (const shorthand in shorthandProperties) { + const properties = shorthandProperties[shorthand as ShorthandProperty]; + const usedProps = (properties as any[]).filter((prop) => prop in style); + + // Only create shorthand if 2 or more properties are used + if (usedProps.length >= 2) { + const values = properties.map((prop) => style[prop] || '0'); + + // Determine the shortest possible shorthand + let shorthandValue: string | number = ''; + if (values[0] === values[2] && values[1] === values[3]) { + shorthandValue = + values[0] === values[1] ? values[0] : `${values[0]} ${values[1]}`; + } else if (values[1] === values[3]) { + shorthandValue = `${values[0]} ${values[1]} ${values[2]}`; + } else { + shorthandValue = values.join(' '); + } + + style[shorthand as ShorthandProperty] = shorthandValue; + properties.forEach((prop) => delete style[prop]); + } + } + + return style; +}