Skip to content

Commit

Permalink
Refactor CSS generation
Browse files Browse the repository at this point in the history
  • Loading branch information
seanchas116 committed Apr 28, 2023
1 parent 4108781 commit 81a817c
Show file tree
Hide file tree
Showing 10 changed files with 71 additions and 280 deletions.
1 change: 1 addition & 0 deletions packages/cli/package.json
Expand Up @@ -56,6 +56,7 @@
"@types/shelljs": "^0.8.12",
"@types/tmp": "^0.2.3",
"@uimix/adapter-types": "workspace:*",
"@uimix/elements-react": "workspace:*",
"@uimix/foundation": "workspace:*",
"@uimix/model": "workspace:*",
"csstype": "^3.1.2",
Expand Down
12 changes: 3 additions & 9 deletions packages/cli/src/compiler/CSSGenerator.ts
Expand Up @@ -2,13 +2,9 @@ import { kebabCase } from "lodash-es";
import * as CSS from "csstype";
import { Page } from "@uimix/model/src/models/Page";
import * as CodeAsset from "@uimix/adapter-types";
import {
buildNodeCSS,
Selectable,
SelfAndChildrenCSS,
Variant,
} from "@uimix/model/src/models";
import { Selectable, Variant } from "@uimix/model/src/models";
import { ClassNameGenerator } from "./ClassNameGenerator";
import { SelfAndChildrenCSS } from "@uimix/elements-react/src/buildNodeCSS";

function isDesignToken(
value: CodeAsset.DesignToken | CodeAsset.DesignTokens
Expand Down Expand Up @@ -70,9 +66,7 @@ export class CSSGenerator {
return css;
}

css = buildNodeCSS(
selectable.node.type,
selectable.style,
css = selectable.buildCSS(
(tokenID) =>
getColorToken(this.designTokens, tokenID.split("/"))?.$value ??
selectable.project.colorTokens.resolve(tokenID)
Expand Down
6 changes: 2 additions & 4 deletions packages/editor/src/views/viewport/TextEditor.tsx
@@ -1,7 +1,7 @@
import { action, reaction } from "mobx";
import { observer } from "mobx-react-lite";
import React, { useEffect, useRef } from "react";
import { Selectable, buildNodeCSS } from "@uimix/model/src/models";
import { Selectable } from "@uimix/model/src/models";
import { viewportState } from "../../state/ViewportState";
import { projectState } from "../../state/ProjectState";

Expand All @@ -10,9 +10,7 @@ export const TextEditorBody: React.FC<{
}> = observer(({ selectable }) => {
const style = selectable.style;

const cssStyle = buildNodeCSS("text", style, (tokenID) =>
selectable.project.colorTokens.resolve(tokenID)
).self;
const cssStyle = selectable.buildCSS().self;
delete cssStyle.marginTop;
delete cssStyle.marginRight;
delete cssStyle.marginBottom;
Expand Down
6 changes: 2 additions & 4 deletions packages/editor/src/views/viewport/renderer/NodeRenderer.tsx
@@ -1,6 +1,6 @@
import React, { createRef, useEffect, useRef } from "react";
import { observer } from "mobx-react-lite";
import { Selectable, buildNodeCSS } from "@uimix/model/src/models";
import { Selectable } from "@uimix/model/src/models";
import { viewportState } from "../../../state/ViewportState";
import { ComputedRectProvider } from "./ComputedRectProvider";
import { projectState } from "../../../state/ProjectState";
Expand Down Expand Up @@ -59,9 +59,7 @@ export const NodeRenderer: React.FC<{
const style = selectable.style;
const type = selectable.node.type;

const builtStyle = buildNodeCSS(type, style, (tokenID) =>
selectable.project.colorTokens.resolve(tokenID)
);
const builtStyle = selectable.buildCSS();

const cssStyle: React.CSSProperties = {
all: "revert",
Expand Down
10 changes: 8 additions & 2 deletions packages/elements-react/src/buildNodeCSS.ts
Expand Up @@ -210,10 +210,16 @@ export function buildNodeCSS(
cssStyle.fontWeight = style.fontWeight;
const lineHeight = style.lineHeight;
cssStyle.lineHeight =
typeof lineHeight === "number" ? `${lineHeight}px` : lineHeight ?? "auto";
lineHeight === null
? "normal"
: typeof lineHeight === "number"
? `${lineHeight}px`
: lineHeight;
const letterSpacing = style.letterSpacing;
cssStyle.letterSpacing =
typeof letterSpacing === "number" ? `${letterSpacing}px` : letterSpacing;
typeof letterSpacing === "number"
? `${letterSpacing}px`
: `${Number.parseFloat(letterSpacing) / 100}em`;
cssStyle.textAlign = style.textHorizontalAlign;
cssStyle.justifyContent = (() => {
switch (style.textVerticalAlign) {
Expand Down
1 change: 1 addition & 0 deletions packages/model/package.json
Expand Up @@ -11,6 +11,7 @@
"dependencies": {
"@babel/standalone": "^7.21.4",
"@uimix/adapter-types": "workspace:*",
"@uimix/elements-react": "workspace:*",
"@uimix/foundation": "workspace:*",
"crypto-js": "^4.1.1",
"lodash-es": "^4.17.21",
Expand Down
48 changes: 48 additions & 0 deletions packages/model/src/models/Selectable.ts
Expand Up @@ -11,6 +11,11 @@ import { Project } from "./Project";
import { Component, Variant } from "./Component";
import { ObjectData } from "./ObjectData";
import { Page } from "./Page";
import {
buildNodeCSS,
SelfAndChildrenCSS,
} from "@uimix/elements-react/src/buildNodeCSS";
import { StyleProps } from "@uimix/elements-react/src/StyleProps";

export interface IComputedRectProvider {
readonly value: Rect | undefined;
Expand Down Expand Up @@ -654,6 +659,49 @@ export class Selectable {
);
return selectable;
}

buildCSS(
getColorToken: (id: string) => string = (tokenID) =>
this.project.colorTokens.resolve(tokenID)
): SelfAndChildrenCSS {
const style = { ...defaultStyle, ...this.style.toJSON() };

const nodeType = this.node.type;
const resolveColor = (color: Data.Color): string => {
if (typeof color === "string") {
return color;
}
return getColorToken(color.token);
};
const resolveFill = (fill: Data.Fill): StyleProps["fills"][number] => {
return {
solid: resolveColor(fill.solid),
};
};

if (nodeType === "component") {
return {
self: {},
children: {},
};
}

const resolvedStyle: StyleProps = {
...style,
fills: style.fills.map(resolveFill),
border: style.border && resolveFill(style.border),
shadows: style.shadows.map((shadow) => ({
...shadow,
color: resolveColor(shadow.color),
})),
image: null,
};

return buildNodeCSS(
nodeType as "frame" | "text" | "image" | "svg",
resolvedStyle
);
}
}

export class SelectableMap {
Expand Down

0 comments on commit 81a817c

Please sign in to comment.