From 6e63f5be7450fb0198bf4315eca13ca2e0346771 Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Wed, 19 Aug 2020 16:18:44 +0200 Subject: [PATCH 1/3] require tokens to be used when defined With this change the compiler will yield an error when tokens are defined but raw values are used instead. In order to use non-token values developers must add `as any` or `@ts-ignore`. https://twitter.com/fgnass/status/1296034855562743808 --- packages/css/src/types.ts | 4 ++-- packages/css/tests/index.test.ts | 17 ++++++++++++++++- 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/packages/css/src/types.ts b/packages/css/src/types.ts index b20c7c03..b3bab0c9 100644 --- a/packages/css/src/types.ts +++ b/packages/css/src/types.ts @@ -49,7 +49,7 @@ export type TRecursiveCss< T extends TConfig, D = { [K in keyof Properties]?: K extends keyof ICssPropToToken - ? ICssPropToToken[K] | Properties[K] + ? ICssPropToToken[K] : Properties[K]; } > = ( @@ -68,7 +68,7 @@ export type TFlatCSS< T extends TConfig, D = { [K in keyof Properties]?: K extends keyof ICssPropToToken - ? ICssPropToToken[K] | Properties[K] + ? ICssPropToToken[K] : Properties[K]; } > = D; diff --git a/packages/css/tests/index.test.ts b/packages/css/tests/index.test.ts index f6315e30..2b76effe 100644 --- a/packages/css/tests/index.test.ts +++ b/packages/css/tests/index.test.ts @@ -608,7 +608,7 @@ describe("createCss", () => { ); }); - test("should inject styles for animations into sheet", () => { + test("should inject styles for animations into sheet", () => { const css = createCss({}, null); const keyFrame = css.keyframes({ "0%": { background: "red" }, @@ -624,4 +624,19 @@ describe("createCss", () => { "/* STITCHES */\n\n@keyframes kNUAiX {0% {background: red;}100% {background: green;}\n._hVCFgX{animation-name:kNUAiX;}" ); }); + + test("should yield type errors when tokens are defined", () => { + const css = createCss({ + tokens: { + colors: { + primary: "red", + }, + }, + }); + css({ + color: "primary", + // @ts-expect-error + backgroundColor: "red", + }); + }); }); From f89a01ab137921f4d00cebff75b2b58c33a9534a Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Wed, 19 Aug 2020 16:35:10 +0200 Subject: [PATCH 2/3] allow non-token values if no tokens are defined This change allows the use of non-token values if no tokens are defined for the corresponding category. --- packages/css/src/types.ts | 148 ++++++++++++++++++++----------- packages/css/tests/index.test.ts | 14 +++ 2 files changed, 112 insertions(+), 50 deletions(-) diff --git a/packages/css/src/types.ts b/packages/css/src/types.ts index b3bab0c9..addd548d 100644 --- a/packages/css/src/types.ts +++ b/packages/css/src/types.ts @@ -4,6 +4,54 @@ import { LineStyle, LineWidth, Properties, + MarginProperty, + MarginTopProperty, + MarginLeftProperty, + MarginRightProperty, + MarginBottomProperty, + PaddingProperty, + PaddingTopProperty, + PaddingLeftProperty, + PaddingRightProperty, + PaddingBottomProperty, + GridGapProperty, + GridColumnProperty, + GridRowGapProperty, + FontSizeProperty, + BorderColorProperty, + BorderTopColorProperty, + BorderLeftColorProperty, + BorderRightColorProperty, + BorderBottomColorProperty, + FontFamilyProperty, + FontWeightProperty, + LineHeightProperty, + LetterSpacingProperty, + FlexBasisProperty, + WidthProperty, + HeightProperty, + MinWidthProperty, + MaxWidthProperty, + MinHeightProperty, + MaxHeightProperty, + BorderWidthProperty, + BorderTopWidthProperty, + BorderLeftWidthProperty, + BorderRightWidthProperty, + BorderBottomWidthProperty, + BorderStyleProperty, + BorderTopStyleProperty, + BorderLeftStyleProperty, + BorderRightStyleProperty, + BorderBottomStyleProperty, + BorderRadiusProperty, + BorderTopLeftRadiusProperty, + BorderTopRightRadiusProperty, + BorderBottomRightRadiusProperty, + BorderBottomLeftRadiusProperty, + TextShadowProperty, + ZIndexProperty, + TransitionProperty, } from "./css-types"; import { StrictMode } from "react"; @@ -122,10 +170,10 @@ export type ICssPropToToken = T["tokens"] extends object ]; color: T["tokens"]["colors"] extends object ? keyof T["tokens"]["colors"] - : never; + : Color; backgroundColor: T["tokens"]["colors"] extends object ? keyof T["tokens"]["colors"] - : never; + : Color; margin: T["tokens"]["space"] extends object ? | keyof T["tokens"]["space"] @@ -141,19 +189,19 @@ export type ICssPropToToken = T["tokens"] extends object keyof T["tokens"]["space"], keyof T["tokens"]["space"] ] - : never; + : MarginProperty; marginTop: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : MarginTopProperty; marginLeft: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : MarginLeftProperty; marginRight: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : MarginRightProperty; marginBottom: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : MarginBottomProperty; padding: T["tokens"]["space"] extends object ? | keyof T["tokens"]["space"] @@ -169,61 +217,61 @@ export type ICssPropToToken = T["tokens"] extends object keyof T["tokens"]["space"], keyof T["tokens"]["space"] ] - : never; + : PaddingProperty; paddingTop: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : PaddingTopProperty; paddingLeft: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : PaddingLeftProperty; paddingRight: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : PaddingRightProperty; paddingBottom: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : PaddingBottomProperty; gridGap: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : GridGapProperty; gridColumnGap: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : GridColumnProperty; gridRowGap: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : GridRowGapProperty; fontSize: T["tokens"]["fontSizes"] extends object ? keyof T["tokens"]["fontSizes"] - : never; + : FontSizeProperty; borderColor: T["tokens"]["colors"] extends object ? keyof T["tokens"]["colors"] - : never; + : BorderColorProperty; borderTopColor: T["tokens"]["colors"] extends object ? keyof T["tokens"]["colors"] - : never; + : BorderTopColorProperty; borderLeftColor: T["tokens"]["colors"] extends object ? keyof T["tokens"]["colors"] - : never; + : BorderLeftColorProperty; borderRightColor: T["tokens"]["colors"] extends object ? keyof T["tokens"]["colors"] - : never; + : BorderRightColorProperty; borderBottomColor: T["tokens"]["colors"] extends object ? keyof T["tokens"]["colors"] - : never; + : BorderBottomColorProperty; fontFamily: T["tokens"]["fonts"] extends object ? keyof T["tokens"]["fonts"] - : never; + : FontFamilyProperty; fontWeight: T["tokens"]["fontWeights"] extends object ? keyof T["tokens"]["fontWeights"] - : never; + : FontWeightProperty; lineHeight: T["tokens"]["lineHeights"] extends object ? keyof T["tokens"]["lineHeights"] - : never; + : LineHeightProperty; letterSpacing: T["tokens"]["letterSpacings"] extends object ? keyof T["tokens"]["letterSpacings"] - : never; + : LetterSpacingProperty; flexBasis: T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] - : never; + : FlexBasisProperty; flex: | (T["tokens"]["space"] extends object ? keyof T["tokens"]["space"] @@ -243,67 +291,67 @@ export type ICssPropToToken = T["tokens"] extends object ]; width: T["tokens"]["sizes"] extends object ? keyof T["tokens"]["sizes"] - : never; + : WidthProperty; height: T["tokens"]["sizes"] extends object ? keyof T["tokens"]["sizes"] - : never; + : HeightProperty; minWidth: T["tokens"]["sizes"] extends object ? keyof T["tokens"]["sizes"] - : never; + : MinWidthProperty; maxWidth: T["tokens"]["sizes"] extends object ? keyof T["tokens"]["sizes"] - : never; + : MaxWidthProperty; minHeight: T["tokens"]["sizes"] extends object ? keyof T["tokens"]["sizes"] - : never; + : MinHeightProperty; maxHeight: T["tokens"]["sizes"] extends object ? keyof T["tokens"]["sizes"] - : never; + : MaxHeightProperty; borderWidth: T["tokens"]["borderWidths"] extends object ? keyof T["tokens"]["borderWidths"] - : never; + : BorderWidthProperty; borderTopWidth: T["tokens"]["borderWidths"] extends object ? keyof T["tokens"]["borderWidths"] - : never; + : BorderTopWidthProperty; borderLeftWidth: T["tokens"]["borderWidths"] extends object ? keyof T["tokens"]["borderWidths"] - : never; + : BorderLeftWidthProperty; borderRightWidth: T["tokens"]["borderWidths"] extends object ? keyof T["tokens"]["borderWidths"] - : never; + : BorderRightWidthProperty; borderBottomWidth: T["tokens"]["borderWidths"] extends object ? keyof T["tokens"]["borderWidths"] - : never; + : BorderBottomWidthProperty; borderStyle: T["tokens"]["borderStyles"] extends object ? keyof T["tokens"]["borderStyles"] - : never; + : BorderStyleProperty; borderTopStyle: T["tokens"]["borderStyles"] extends object ? keyof T["tokens"]["borderStyles"] - : never; + : BorderTopStyleProperty; borderLeftStyle: T["tokens"]["borderStyles"] extends object ? keyof T["tokens"]["borderStyles"] - : never; + : BorderLeftStyleProperty; borderRightStyle: T["tokens"]["borderStyles"] extends object ? keyof T["tokens"]["borderStyles"] - : never; + : BorderRightStyleProperty; borderBottomStyle: T["tokens"]["borderStyles"] extends object ? keyof T["tokens"]["borderStyles"] - : never; + : BorderBottomStyleProperty; borderRadius: T["tokens"]["radii"] extends object ? keyof T["tokens"]["radii"] - : never; + : BorderRadiusProperty; borderTopLeftRadius: T["tokens"]["radii"] extends object ? keyof T["tokens"]["radii"] - : never; + : BorderTopLeftRadiusProperty; borderTopRightRadius: T["tokens"]["radii"] extends object ? keyof T["tokens"]["radii"] - : never; + : BorderTopRightRadiusProperty; borderBottomRightRadius: T["tokens"]["radii"] extends object ? keyof T["tokens"]["radii"] - : never; + : BorderBottomRightRadiusProperty; borderBottomLeftRadius: T["tokens"]["radii"] extends object ? keyof T["tokens"]["radii"] - : never; + : BorderBottomLeftRadiusProperty; boxShadow: T["tokens"]["shadows"] extends object ? keyof T["tokens"]["shadows"] : [ @@ -316,13 +364,13 @@ export type ICssPropToToken = T["tokens"] extends object ]; textShadow: T["tokens"]["shadows"] extends object ? keyof T["tokens"]["shadows"] - : never; + : TextShadowProperty; zIndex: T["tokens"]["zIndices"] extends object ? keyof T["tokens"]["zIndices"] - : never; + : ZIndexProperty; transition: T["tokens"]["transitions"] extends object ? keyof T["tokens"]["transitions"] - : never; + : TransitionProperty; } : {}; diff --git a/packages/css/tests/index.test.ts b/packages/css/tests/index.test.ts index 2b76effe..8bfa057c 100644 --- a/packages/css/tests/index.test.ts +++ b/packages/css/tests/index.test.ts @@ -639,4 +639,18 @@ describe("createCss", () => { backgroundColor: "red", }); }); + + test("should not yield type errors when a token category is missing", () => { + const css = createCss({ + tokens: { + radii: { + tiny: "3px", + }, + }, + }); + css({ + borderRadius: "tiny", + color: "lime", // allowed since no color tokens are defined + }); + }); }); From 8cbaa2929f173af28e475d3d8f687900acb60144 Mon Sep 17 00:00:00 2001 From: Felix Gnass Date: Thu, 20 Aug 2020 19:47:38 +0200 Subject: [PATCH 3/3] add stict mode Adds a strict flag as discussed in #108 --- packages/css/src/types.ts | 23 ++++++++--------------- packages/css/tests/index.test.ts | 19 +++++++++++++++++-- 2 files changed, 25 insertions(+), 17 deletions(-) diff --git a/packages/css/src/types.ts b/packages/css/src/types.ts index addd548d..072da1da 100644 --- a/packages/css/src/types.ts +++ b/packages/css/src/types.ts @@ -93,14 +93,7 @@ export interface IKeyframesAtom { [ATOM]: true; } -export type TRecursiveCss< - T extends TConfig, - D = { - [K in keyof Properties]?: K extends keyof ICssPropToToken - ? ICssPropToToken[K] - : Properties[K]; - } -> = ( +export type TRecursiveCss> = ( | D | { [pseudo: string]: ( @@ -112,14 +105,13 @@ export type TRecursiveCss< ) & D; -export type TFlatCSS< - T extends TConfig, - D = { - [K in keyof Properties]?: K extends keyof ICssPropToToken +export type TFlatCSS = { + [K in keyof Properties]?: K extends keyof ICssPropToToken + ? T extends { strict: true } ? ICssPropToToken[K] - : Properties[K]; - } -> = D; + : ICssPropToToken[K] | Properties[K] + : Properties[K]; +}; export type TFlatUtils< T extends TConfig, @@ -403,6 +395,7 @@ export type TConfig = { showFriendlyClassnames?: boolean; prefix?: string; utilityFirst?: boolean; + strict?: boolean; } & (STRICT_MODE extends true ? { screens: IScreens; tokens: ITokensDefinition; utils: IUtils } : { diff --git a/packages/css/tests/index.test.ts b/packages/css/tests/index.test.ts index 8bfa057c..a7444fbf 100644 --- a/packages/css/tests/index.test.ts +++ b/packages/css/tests/index.test.ts @@ -625,7 +625,7 @@ describe("createCss", () => { ); }); - test("should yield type errors when tokens are defined", () => { + test("should not yield type errors when raw values are used even though tokens are defined", () => { const css = createCss({ tokens: { colors: { @@ -633,15 +633,30 @@ describe("createCss", () => { }, }, }); + css({ + color: "lime", + }); + }); + + test("should yield type errors in strict mode when tokens are defined but raw values are used", () => { + const css = createCss({ + strict: true, + tokens: { + colors: { + primary: "red", + }, + }, + }); css({ color: "primary", - // @ts-expect-error + // @ts-ignore backgroundColor: "red", }); }); test("should not yield type errors when a token category is missing", () => { const css = createCss({ + strict: true, tokens: { radii: { tiny: "3px",