Skip to content

Commit

Permalink
Merge pull request #4 from front-of-house/dev
Browse files Browse the repository at this point in the history
feat: further improve type safety
  • Loading branch information
estrattonbailey committed Apr 11, 2023
2 parents 8629d14 + 69f7a5a commit 08f1359
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 85 deletions.
6 changes: 6 additions & 0 deletions .changeset/yellow-deers-listen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"@svbstrate/react-native": patch
"@svbstrate/core": patch
---

Further improve type safety in both `core` and `react-native`
5 changes: 4 additions & 1 deletion packages/core/lib/__tests__/index.test.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { test, expect } from "vitest";

import { createTheme, explode, style, pick } from "../";
import * as types from "../types";
import { properties as defaultCssProps } from "../properties";
import * as defaults from "../presets";

Expand Down Expand Up @@ -85,7 +86,9 @@ for (const key of Object.keys(defaultCssProps)) {
}

for (const key of Object.keys(shorthands)) {
const properties = ([] as string[]).concat(shorthands[key]);
const properties = ([] as string[]).concat(
shorthands[key as keyof types.Shorthands]
);

for (const prop of properties) {
// @ts-expect-error
Expand Down
43 changes: 15 additions & 28 deletions packages/core/lib/__tests__/test
Original file line number Diff line number Diff line change
@@ -1,17 +1,22 @@
import * as s from "../";
import * as presets from "../presets";

declare module "../" {
interface Tokens {
interface Tokens extends s.PresetTokens {
color: {
primary: "#ff4567";
secondary: "#ff4567";
};
other: [0, 1, 2];
}

interface Shorthands extends s.PresetShorthands {}
interface Shorthands extends s.PresetShorthands {
pl: s.MapShorthandToToken<"paddingLeft", "space">;
}

interface Macros {}
interface Macros extends s.PresetMacros {
row: boolean
}

interface Variants {
btn: "primary" | "secondary";
Expand All @@ -20,6 +25,7 @@ declare module "../" {

const theme = s.createTheme({
tokens: {
...presets.tokens,
other: [0, 1, 2],
color: {
primary: "#ff4567",
Expand All @@ -29,38 +35,18 @@ const theme = s.createTheme({
fontFamily: {
mono: "monospace",
},
fontSize: [
"3rem",
"3rem",
"2.2rem",
"1.8rem",
"1.4rem",
"1rem",
"0.875rem",
],
fontWeight: [
"0",
"100",
"200",
"300",
"400",
"500",
"600",
"700",
"800",
"900",
"1000",
],
lineHeight: [1.1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6],
width: [1],
},
shorthands: {
pl: ["paddingLeft"],
...presets.shorthands,
},
macros: {
f: {
...presets.macros,
row: {
display: "flex",
},
flexDirection: "row",
}
},
variants: {
btn: {
Expand Down Expand Up @@ -92,6 +78,7 @@ s.style(
},
w: 5,
other: 0,
row: false
},
theme
);
30 changes: 20 additions & 10 deletions packages/core/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,27 @@ export function explode(
let styles: types.SvbstrateStyleObject = {};

for (const [prop, value] of Object.entries(props)) {
if (theme.macros[prop] && typeof value === "boolean") {
if (
theme.macros[prop as keyof types.Macros] &&
typeof value === "boolean"
) {
/*
* Macro exists and is true, merge it in. If false, just drop it, hence
* the typeof check above.
*/
if (value)
Object.assign(styles, theme.macros[prop] as types.SvbstrateStyleObject);
} else if (theme.variants[prop]) {
Object.assign(
styles,
theme.macros[prop as keyof types.Macros] as types.SvbstrateStyleObject
);
} else if (theme.variants[prop as keyof types.Variants]) {
/*
* Variant exists, merge it in.
*/
Object.assign(styles, theme.variants[prop][value as string]);
Object.assign(
styles,
theme.variants[prop as keyof types.Variants][value as string]
);
} else if (typeof value === "object" && !Array.isArray(value)) {
/*
* If we have some other object here, we need to recurse.
Expand All @@ -43,7 +52,9 @@ export function explode(
* values
*/
for (const [prop, value] of Object.entries(styles)) {
const cssProperties = theme.shorthands[prop];
const cssProperties = theme.shorthands[prop as keyof types.Shorthands] as
| string[]
| undefined;

if (cssProperties && cssProperties.length) {
for (const property of cssProperties) {
Expand Down Expand Up @@ -190,11 +201,10 @@ export function pick<T = types.UnknownKeyValue>(

for (const prop of Object.keys(props)) {
if (
theme.macros[prop] ||
theme.variants[prop] ||
theme.shorthands[prop] ||
// @ts-ignore
theme.properties[prop]
theme.macros[prop as keyof types.Macros] ||
theme.variants[prop as keyof types.Variants] ||
theme.shorthands[prop as keyof types.Shorthands] ||
theme.properties[prop as keyof types.CSSProperties]
) {
styles[prop] = props[prop] as types.SvbstrateStyleObject;
} else {
Expand Down
88 changes: 44 additions & 44 deletions packages/core/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,31 +27,31 @@ export interface PresetTokens {
export interface Tokens {}

export interface PresetShorthands {
d: PropertyToTokenMapping<"display", "display">;
w: PropertyToTokenMapping<"width", "width">;
h: PropertyToTokenMapping<"height", "height">;
c: PropertyToTokenMapping<"color", "color">;
bg: PropertyToTokenMapping<"backgroundColor", "color">;
m: PropertyToTokenMapping<"margin", "space">;
mt: PropertyToTokenMapping<"marginTop", "space">;
mb: PropertyToTokenMapping<"marginBottom", "space">;
ml: PropertyToTokenMapping<"marginLeft", "space">;
mr: PropertyToTokenMapping<"marginRight", "space">;
my: PropertyToTokenMapping<"marginTop", "space">;
mx: PropertyToTokenMapping<"marginLeft", "space">;
pa: PropertyToTokenMapping<"padding", "space">;
pt: PropertyToTokenMapping<"paddingTop", "space">;
pb: PropertyToTokenMapping<"paddingBottom", "space">;
pl: PropertyToTokenMapping<"paddingLeft", "space">;
pr: PropertyToTokenMapping<"paddingRight", "space">;
py: PropertyToTokenMapping<"paddingTop", "space">;
px: PropertyToTokenMapping<"paddingLeft", "space">;
z: PropertyToTokenMapping<"zIndex", "zIndex">;
fs: PropertyToTokenMapping<"fontSize", "fontSize">;
ff: PropertyToTokenMapping<"fontFamily", "fontFamily">;
fw: PropertyToTokenMapping<"fontWeight", "fontWeight">;
lh: PropertyToTokenMapping<"lineHeight", "lineHeight">;
ta: PropertyToTokenMapping<"textAlign", "textAlign">;
d: MapShorthandToToken<"display", "display">;
w: MapShorthandToToken<"width", "width">;
h: MapShorthandToToken<"height", "height">;
c: MapShorthandToToken<"color", "color">;
bg: MapShorthandToToken<"backgroundColor", "color">;
m: MapShorthandToToken<"margin", "space">;
mt: MapShorthandToToken<"marginTop", "space">;
mb: MapShorthandToToken<"marginBottom", "space">;
ml: MapShorthandToToken<"marginLeft", "space">;
mr: MapShorthandToToken<"marginRight", "space">;
my: MapShorthandToToken<"marginTop", "space">;
mx: MapShorthandToToken<"marginLeft", "space">;
pa: MapShorthandToToken<"padding", "space">;
pt: MapShorthandToToken<"paddingTop", "space">;
pb: MapShorthandToToken<"paddingBottom", "space">;
pl: MapShorthandToToken<"paddingLeft", "space">;
pr: MapShorthandToToken<"paddingRight", "space">;
py: MapShorthandToToken<"paddingTop", "space">;
px: MapShorthandToToken<"paddingLeft", "space">;
z: MapShorthandToToken<"zIndex", "zIndex">;
fs: MapShorthandToToken<"fontSize", "fontSize">;
ff: MapShorthandToToken<"fontFamily", "fontFamily">;
fw: MapShorthandToToken<"fontWeight", "fontWeight">;
lh: MapShorthandToToken<"lineHeight", "lineHeight">;
ta: MapShorthandToToken<"textAlign", "textAlign">;
}
export interface Shorthands {}

Expand Down Expand Up @@ -89,7 +89,7 @@ export interface Macros {}
export interface PresetVariants {} // unused
export interface Variants {}

export type PropertyToTokenMapping<
export type MapShorthandToToken<
Prop extends keyof CSSProperties,
Token extends keyof BaseTokens
> = ResponsiveValue<keyof BaseTokens[Token] | CSSProperties[Prop]>;
Expand All @@ -99,20 +99,20 @@ export type SvbstrateCSSStyleObject = {
BaseTokens[Property] | CSSProperties[Property]
>;
} & {
top?: PropertyToTokenMapping<"top", "space">;
bottom?: PropertyToTokenMapping<"bottom", "space">;
left?: PropertyToTokenMapping<"left", "space">;
right?: PropertyToTokenMapping<"right", "space">;
margin?: PropertyToTokenMapping<"margin", "space">;
marginTop?: PropertyToTokenMapping<"marginTop", "space">;
marginBottom?: PropertyToTokenMapping<"marginBottom", "space">;
marginLeft?: PropertyToTokenMapping<"marginLeft", "space">;
marginRight?: PropertyToTokenMapping<"marginRight", "space">;
padding?: PropertyToTokenMapping<"padding", "space">;
paddingTop?: PropertyToTokenMapping<"paddingTop", "space">;
paddingBottom?: PropertyToTokenMapping<"paddingBottom", "space">;
paddingLeft?: PropertyToTokenMapping<"paddingLeft", "space">;
paddingRight?: PropertyToTokenMapping<"paddingRight", "space">;
top?: MapShorthandToToken<"top", "space">;
bottom?: MapShorthandToToken<"bottom", "space">;
left?: MapShorthandToToken<"left", "space">;
right?: MapShorthandToToken<"right", "space">;
margin?: MapShorthandToToken<"margin", "space">;
marginTop?: MapShorthandToToken<"marginTop", "space">;
marginBottom?: MapShorthandToToken<"marginBottom", "space">;
marginLeft?: MapShorthandToToken<"marginLeft", "space">;
marginRight?: MapShorthandToToken<"marginRight", "space">;
padding?: MapShorthandToToken<"padding", "space">;
paddingTop?: MapShorthandToToken<"paddingTop", "space">;
paddingBottom?: MapShorthandToToken<"paddingBottom", "space">;
paddingLeft?: MapShorthandToToken<"paddingLeft", "space">;
paddingRight?: MapShorthandToToken<"paddingRight", "space">;
} & Partial<Shorthands>;

export type SvbstratePsuedoStyleObject = {
Expand Down Expand Up @@ -146,14 +146,14 @@ export interface ThemeConfig {
[Property in keyof Tokens]: Tokens[Property][] | Tokens[Property];
};
shorthands: {
[shorthand: string]: (keyof CSSProperties)[];
[Shorthand in keyof Shorthands]: (keyof CSSProperties)[];
};
macros: {
[macro: string]: SvbstrateCSSStyleObject;
[Macro in keyof Macros]: SvbstrateCSSStyleObject;
};
variants: {
[variation: string]: {
[name: string]: SvbstrateStyleObject;
[Variant in keyof Variants]: {
[Value in Variants[Variant]]: SvbstrateStyleObject;
};
};
properties: {
Expand Down
5 changes: 3 additions & 2 deletions packages/react-native/lib/index.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import * as svbstrate from "@svbstrate/core";
import React from "react";
import { View, Text, ViewProps } from "react-native";
import { View, ViewProps } from "react-native";
import * as Polymorphic from "@radix-ui/react-polymorphic";

export type Theme = Partial<svbstrate.ThemeConfig>;
Expand Down Expand Up @@ -68,7 +68,7 @@ export const Box = React.forwardRef(({ children, as, ...rest }, ref) => {
);
}

const Component = as || (typeof children === "string" ? Text : View);
const Component = as || View;

return (
// @ts-ignore
Expand All @@ -77,6 +77,7 @@ export const Box = React.forwardRef(({ children, as, ...rest }, ref) => {
{...props}
style={{
...mergedStyles,
// override with user-defined styles
...(typeof props.style === "object" ? props.style : {}),
}}
>
Expand Down

0 comments on commit 08f1359

Please sign in to comment.