diff --git a/src/__tests__/KeyPaths.types.test.ts b/src/__tests__/KeyPaths.types.test.ts new file mode 100644 index 00000000000..d4755f2e800 --- /dev/null +++ b/src/__tests__/KeyPaths.types.test.ts @@ -0,0 +1,13 @@ +import {KeyPaths} from '../utils/types/KeyPaths' + +type NestedObject = { + a: string + b: { + b1: string + b2: string + } +} + +export function generatesKeyPathsFromObject(x: KeyPaths): 'a' | 'b.b1' | 'b.b2' { + return x +} diff --git a/src/sx.ts b/src/sx.ts index fdd88509dff..f97d5f342aa 100644 --- a/src/sx.ts +++ b/src/sx.ts @@ -1,7 +1,19 @@ -import css, {SystemStyleObject} from '@styled-system/css' +import css, {SystemCssProperties, SystemStyleObject} from '@styled-system/css' +import {ThemeColorPaths, ThemeShadowPaths} from './theme' +import {ColorProps, ShadowProps} from 'styled-system' + +export type BetterCssProperties = { + [K in keyof SystemCssProperties]: K extends keyof ColorProps + ? ThemeColorPaths | SystemCssProperties[K] + : K extends keyof ShadowProps + ? ThemeShadowPaths | SystemCssProperties[K] + : SystemCssProperties[K] +} + +export type BetterSystemStyleObject = BetterCssProperties | SystemStyleObject export interface SxProp { - sx?: SystemStyleObject + sx?: BetterSystemStyleObject } const sx = (props: SxProp) => css(props.sx) diff --git a/src/theme.ts b/src/theme.ts index c83d7143693..cca8a16273d 100644 --- a/src/theme.ts +++ b/src/theme.ts @@ -1,3 +1,89 @@ import {theme} from './theme-preval' +import {KeyPaths} from './utils/types/KeyPaths' export default theme + +// NOTE: for now, ThemeColors and ThemeShadows are handcrafted types. It would be nice if these +// were exports from primitives (or a different shape but derived from those exports). + +type ThemeColors = { + fg: { + default: string + muted: string + subtle: string + onEmphasis: string + } + canvas: { + default: string + overlay: string + inset: string + subtle: string + } + border: { + default: string + muted: string + subtle: string + } + + // Roles + neutral: { + emphasisPlus: string + emphasis: string + muted: string + subtle: string + } + accent: { + fg: string + emphasis: string + muted: string + subtle: string + } + success: { + fg: string + emphasis: string + muted: string + subtle: string + } + attention: { + fg: string + emphasis: string + muted: string + subtle: string + } + severe: { + fg: string + emphasis: string + muted: string + subtle: string + } + danger: { + fg: string + emphasis: string + muted: string + subtle: string + } + done: { + fg: string + emphasis: string + muted: string + subtle: string + } + sponsors: { + fg: string + emphasis: string + muted: string + subtle: string + } +} + +type ThemeShadows = { + shadow: { + small: string + medium: string + large: string + extraLarge: string + } +} + +export type ThemeColorPaths = KeyPaths +export type ThemeShadowPaths = KeyPaths diff --git a/src/utils/types/KeyPaths.ts b/src/utils/types/KeyPaths.ts new file mode 100644 index 00000000000..a5970e303db --- /dev/null +++ b/src/utils/types/KeyPaths.ts @@ -0,0 +1,4 @@ +// Produces a union of dot-delimited keypaths to the string values in a nested object: +export type KeyPaths = { + [K in keyof O]: K extends string ? (O[K] extends string ? `${K}` : `${K}.${KeyPaths}`) : never +}[keyof O]