-
Notifications
You must be signed in to change notification settings - Fork 3
/
useBoxStyles.ts
95 lines (80 loc) · 2.56 KB
/
useBoxStyles.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
import clsx from 'clsx'
import { Theme } from 'treat/theme'
import { useStyles } from 'react-treat'
import { resolveResponsiveProp } from './utils'
import { ResponsiveProp } from './types'
import * as styleRefs from './useBoxStyles.treat'
type NotUndefOrNever<T extends {}> = Pick<
T,
{ [K in keyof T]: T[K] extends undefined | never ? never : K }[keyof T]
>
export type BoxStylesProps = {
[K in keyof Theme['rules']]?: ResponsiveProp<keyof Theme['rules'][K]>
}
export type BoxHoverProps = NotUndefOrNever<
{
[K in keyof Theme['variants']]?: NonNullable<
Theme['variants'][K]
>['hover'] extends true
? ResponsiveProp<keyof Theme['rules'][K]>
: never
}
>
export type BoxFocusProps = NotUndefOrNever<
{
[K in keyof Theme['variants']]?: NonNullable<
Theme['variants'][K]
>['focus'] extends true
? ResponsiveProp<keyof Theme['rules'][K]>
: never
}
>
const resolveClassNames = (props: BoxStylesProps | undefined, styles: any) => {
if (props === undefined) return
let resolvedClassNames: (string | undefined)[] = []
for (const key in props) {
const value = props[key as keyof Theme['rules']]
if (value === null || value === undefined) continue
resolvedClassNames.push(
resolveResponsiveProp(value, styles[key as keyof Theme['rules']]),
)
}
return resolvedClassNames
}
/**
* A React hook for mapping atomic styles to `className`s. This is the low
* level hook that `<Box />` is built on.
*
* @param styles - The object of styles to map to `className`s
* @returns A string containing the resolved `className`s.
*/
export function useBoxStyles(styles: BoxStylesProps | undefined): string {
const boxStyles = useStyles(styleRefs)
return clsx(resolveClassNames(styles, boxStyles.styles))
}
/**
* A React hook for mapping pseudo atomic styles to `className`s. This is the low
* level hook that `<Box />` is built on.
*
* @remarks
* Psuedo refers to pseudo-modifiers such as `:hover` and `:focus`.
*
* @param styles The object of styles to map to `className`s
* @param psuedo The pseudo modifier to use.
* @returns A string containing the resolved `className`s.
*/
export function usePseudoBoxStyles(
styles: BoxFocusProps | undefined,
pseudo: 'focus',
): string
export function usePseudoBoxStyles(
styles: BoxHoverProps | undefined,
pseudo: 'hover',
): string
export function usePseudoBoxStyles(
styles: BoxHoverProps | BoxFocusProps | undefined,
pseudo: 'focus' | 'hover',
): string {
const boxStyles = useStyles(styleRefs)
return clsx(resolveClassNames(styles, boxStyles[pseudo]))
}