Skip to content

Commit

Permalink
refactor: component theming system (#6221)
Browse files Browse the repository at this point in the history
* refactor: theming system and helpers

* chore: update pkgs

* docs: update changesets

* chore: update changesets

* chore: fix typo

* chore: updates

* chore: fix error

* chore: update changeset

* chore: update lockfile

* refactor: batch 1

* refactor: anatomy

* refactor: anatomy

* refactor: anatomy

* fix: errors

* fix: errors

* fix: patch default props for now

* chore: update mdx extension

* chore: update

* chore: update package json
  • Loading branch information
segunadebayo committed Aug 24, 2022
1 parent a00afda commit 872c0cc
Show file tree
Hide file tree
Showing 67 changed files with 1,286 additions and 1,132 deletions.
5 changes: 5 additions & 0 deletions .changeset/plenty-kangaroos-divide.md
@@ -0,0 +1,5 @@
---
"@chakra-ui/anatomy": patch
---

Update package to use styled-system as dependency
5 changes: 5 additions & 0 deletions .changeset/silver-pillows-jump.md
@@ -0,0 +1,5 @@
---
"@chakra-ui/theme-tools": patch
---

Refactored code to use from `styled-system` package
6 changes: 6 additions & 0 deletions .changeset/thin-radios-wink.md
@@ -0,0 +1,6 @@
---
"@chakra-ui/skeleton": patch
"@chakra-ui/theme": patch
---

Refactor to use the new helpers from `styled-system` package
50 changes: 50 additions & 0 deletions .changeset/tricky-lies-act.md
@@ -0,0 +1,50 @@
---
"@chakra-ui/styled-system": minor
---

Add `defineStyle` and `defineStyleConfig` to improve the TypeScript authoring
experience of style objects and single part component themes.

```jsx live=false
import { defineStyleConfig, defineStyle } from "@chakra-ui/styled-system"

// authoring style objects
const style = defineStyle({
marginTop: "20px",
})

// authoring style configs for single part component
const button = defineStyleConfig({
baseStyle: {},
variants: {},
defaultProps: {},
})
```

Add `createMultiStyleConfigHelpers` factory that provides functions that help
improve the TypeScript authoring experience of multipart component themes.

```jsx live=false
import { createMultiStyleConfigHelpers } from "@chakra-ui/styled-sytem"

// create scoped helpers for that defined parts
const helpers = createMultiStyleConfigHelpers(["button", "label"])
const { definePartsStyle, defineMultiStyleConfig } = helpers

// authoring styles for each part
const outlineVariant = definePartsStyle({
button: {},
label: {},
})

// authoring styles for multipart component
const accordion = defineMultiStyleConfig({
baseStyle: {
button: {},
label: {},
},
variants: {
outline: outlineVariant,
},
})
```
2 changes: 1 addition & 1 deletion .vscode/extensions.json
Expand Up @@ -6,6 +6,6 @@
"eamodio.gitlens",
"pflannery.vscode-versionlens",
"esbenp.prettier-vscode",
"silvenon.mdx"
"unifiedjs.vscode-mdx"
]
}
2 changes: 1 addition & 1 deletion packages/react/tests/extend-theme.test.tsx
Expand Up @@ -264,7 +264,7 @@ describe("extendTheme", () => {
}

const customTheme = extendTheme(override)
// @ts-expect-error
// @ts-ignore
delete Array.prototype["customFunction"]

expect((customTheme.breakpoints as any).customFunction).toBeUndefined()
Expand Down
77 changes: 0 additions & 77 deletions packages/styled-system/src/component.types.ts

This file was deleted.

118 changes: 118 additions & 0 deletions packages/styled-system/src/define-styles.ts
@@ -0,0 +1,118 @@
import { SystemStyleObject } from "./system.types"

type Dict<T = any> = { [key: string]: T }

// ------------------------------------------------------------------ //

export type StyleFunctionProps = {
colorScheme: string
colorMode: "light" | "dark"
orientation?: "horizontal" | "vertical"
theme: Dict
[key: string]: any
}

export type SystemStyleFunction = (
props: StyleFunctionProps,
) => SystemStyleObject

export type SystemStyleInterpolation = SystemStyleObject | SystemStyleFunction

// ------------------------------------------------------------------ //

export function defineStyle<T extends SystemStyleInterpolation>(styles: T) {
return styles
}

// ------------------------------------------------------------------ //

type DefaultProps = {
size?: string
variant?: string
colorScheme?: string
}

export type StyleConfig = {
baseStyle?: SystemStyleInterpolation
sizes?: { [size: string]: SystemStyleInterpolation }
variants?: { [variant: string]: SystemStyleInterpolation }
defaultProps?: DefaultProps
}

/**
* Defines the style config for a single-part component.
*/
export function defineStyleConfig<
BaseStyle extends SystemStyleInterpolation,
Sizes extends Dict<SystemStyleInterpolation>,
Variants extends Dict<SystemStyleInterpolation>,
>(config: {
baseStyle?: BaseStyle
sizes?: Sizes
variants?: Variants
defaultProps?: {
size?: keyof Sizes
variant?: keyof Variants
colorScheme?: string
}
}) {
return config
}

// ------------------------------------------------------------------ //

type Anatomy = { keys: string[] }

export type PartsStyleObject<Parts extends Anatomy = Anatomy> = Partial<
Record<Parts["keys"][number], SystemStyleObject>
>

export type PartsStyleFunction<Parts extends Anatomy = Anatomy> = (
props: StyleFunctionProps,
) => PartsStyleObject<Parts>

export type PartsStyleInterpolation<Parts extends Anatomy = Anatomy> =
| PartsStyleObject<Parts>
| PartsStyleFunction<Parts>

export interface MultiStyleConfig<Parts extends Anatomy = Anatomy> {
parts: Parts["keys"]
baseStyle?: PartsStyleInterpolation<Parts>
sizes?: { [size: string]: PartsStyleInterpolation<Parts> }
variants?: { [variant: string]: PartsStyleInterpolation<Parts> }
defaultProps?: DefaultProps
}

// ------------------------------------------------------------------ //

/**
* Returns an object of helpers that can be used to define
* the style configuration for a multi-part component.
*/
export function createMultiStyleConfigHelpers<Part extends string>(
parts: Part[] | Readonly<Part[]>,
) {
return {
definePartsStyle<
PartStyles extends PartsStyleInterpolation<{ keys: Part[] }>,
>(config: PartStyles) {
return config
},
defineMultiStyleConfig<
BaseStyle extends PartsStyleInterpolation<{ keys: Part[] }>,
Sizes extends Dict<PartsStyleInterpolation<{ keys: Part[] }>>,
Variants extends Dict<PartsStyleInterpolation<{ keys: Part[] }>>,
>(config: {
baseStyle?: BaseStyle
sizes?: Sizes
variants?: Variants
defaultProps?: {
size?: keyof Sizes
variant?: keyof Variants
colorScheme?: string
}
}) {
return { parts: parts as Part[], ...config }
},
}
}
3 changes: 2 additions & 1 deletion packages/styled-system/src/index.ts
@@ -1,6 +1,7 @@
export * from "./config"
export * from "./create-theme-vars"
export * from "./css"
export * from "./define-styles"
export * from "./pseudos"
export * from "./style-config"
export * from "./system"
Expand All @@ -15,5 +16,5 @@ export type {
} from "./utils"
export { tokenToCSSVar } from "./utils/create-transform"
export type OmitSpaceXY<T> = Omit<T, "spaceX" | "spaceY">
export * from "./component.types"
export { getCSSVar } from "./get-css-var"
export * from "./theming-props"
23 changes: 23 additions & 0 deletions packages/styled-system/src/theming-props.ts
@@ -0,0 +1,23 @@
import { omit } from "@chakra-ui/object-utils"
import { ThemeTypings } from "./theme.types"
import { ResponsiveValue } from "./utils"

export interface ThemingProps<ThemeComponent extends string = any> {
variant?: ResponsiveValue<
ThemeComponent extends keyof ThemeTypings["components"]
? ThemeTypings["components"][ThemeComponent]["variants"]
: string
>
size?: ResponsiveValue<
ThemeComponent extends keyof ThemeTypings["components"]
? ThemeTypings["components"][ThemeComponent]["sizes"]
: string
>
colorScheme?: ThemeTypings["colorSchemes"]
orientation?: "vertical" | "horizontal"
styleConfig?: Record<string, any>
}

export function omitThemingProps<T extends ThemingProps>(props: T) {
return omit(props, ["styleConfig", "size", "variant", "colorScheme"])
}
4 changes: 3 additions & 1 deletion packages/theme-tools/package.json
Expand Up @@ -31,13 +31,15 @@
},
"dependencies": {
"@chakra-ui/anatomy": "workspace:*",
"@chakra-ui/utils": "workspace:*",
"@ctrl/tinycolor": "^3.4.0"
},
"peerDependencies": {
"@chakra-ui/styled-system": ">=2.0.0"
},
"devDependencies": {
"dlv": "^1.1.3",
"@types/dlv": "^1.1.2",
"@chakra-ui/shared-utils": "workspace:*",
"@chakra-ui/styled-system": "workspace:*"
},
"scripts": {
Expand Down
5 changes: 4 additions & 1 deletion packages/theme-tools/src/color.ts
Expand Up @@ -5,7 +5,10 @@ import {
random,
WCAG2Parms,
} from "@ctrl/tinycolor"
import { memoizedGet as get, Dict, isEmptyObject } from "@chakra-ui/utils"
import get from "dlv"

type Dict = { [key: string]: any }
const isEmptyObject = (obj: any) => Object.keys(obj).length === 0

/**
* Get the color raw value from theme
Expand Down
23 changes: 17 additions & 6 deletions packages/theme-tools/src/component.ts
@@ -1,9 +1,20 @@
import {
import type {
SystemStyleObject,
StyleFunctionProps,
SystemStyleInterpolation,
} from "@chakra-ui/styled-system"

export type {
StyleConfig,
MultiStyleConfig,
SystemStyleObject,
// StyleFunctionProps,
SystemStyleFunction,
SystemStyleInterpolation,
PartsStyleObject,
PartsStyleFunction,
PartsStyleInterpolation,
} from "@chakra-ui/styled-system"
import { Dict } from "@chakra-ui/utils"

/* -----------------------------------------------------------------------------
* Global Style object definitions
Expand All @@ -22,14 +33,14 @@ export type JSXElementStyles = {
export type Styles = GlobalStyles & JSXElementStyles

export function mode<T>(light: T, dark: T) {
return (props: Dict | StyleFunctionProps) =>
return (props: Record<string, any> | StyleFunctionProps) =>
props.colorMode === "dark" ? dark : light
}

export function orient(options: {
export function orient<T>(options: {
orientation?: "vertical" | "horizontal"
vertical: SystemStyleObject
horizontal: SystemStyleObject
vertical: T
horizontal: T
}) {
const { orientation, vertical, horizontal } = options
if (!orientation) return {}
Expand Down
2 changes: 1 addition & 1 deletion packages/theme-tools/src/create-breakpoints.ts
@@ -1,4 +1,4 @@
import { warn } from "@chakra-ui/utils"
import { warn } from "@chakra-ui/shared-utils"

export interface BaseBreakpointConfig {
sm: string
Expand Down

1 comment on commit 872c0cc

@vercel
Copy link

@vercel vercel bot commented on 872c0cc Aug 24, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.