-
-
Notifications
You must be signed in to change notification settings - Fork 389
Expand file tree
/
Copy pathcreateUseStyles.js
More file actions
117 lines (96 loc) · 2.92 KB
/
createUseStyles.js
File metadata and controls
117 lines (96 loc) · 2.92 KB
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import React, {useEffect, useLayoutEffect, useContext, useRef, useMemo, useDebugValue} from 'react'
import {ThemeContext as DefaultThemeContext} from 'theming'
import JssContext from './JssContext'
import {
createStyleSheet,
addDynamicRules,
updateDynamicRules,
removeDynamicRules
} from './utils/sheets'
import getSheetIndex from './utils/getSheetIndex'
import {manageSheet, unmanageSheet} from './utils/managers'
import getSheetClasses from './utils/getSheetClasses'
function getUseInsertionEffect(isSSR) {
return isSSR
? useEffect
: React.useInsertionEffect || // React 18+ (https://github.com/reactwg/react-18/discussions/110)
useLayoutEffect
}
const noTheme = {}
const createUseStyles = (styles, options = {}) => {
const {index = getSheetIndex(), theming, name, ...sheetOptions} = options
const ThemeContext = (theming && theming.context) || DefaultThemeContext
const useTheme = (theme) => {
if (typeof styles === 'function') {
return theme || useContext(ThemeContext) || noTheme
}
return noTheme
}
const emptyObject = {}
return function useStyles(data) {
const isFirstMount = useRef(true)
const context = useContext(JssContext)
const theme = useTheme(data && data.theme)
const [sheet, dynamicRules] = useMemo(() => {
const newSheet = createStyleSheet({
context,
styles,
name,
theme,
index,
sheetOptions
})
if (newSheet && context.isSSR) {
// manage immediately during SSRs. browsers will manage the sheet through useInsertionEffect below
manageSheet({
index,
context,
sheet: newSheet,
theme
})
}
return [newSheet, newSheet ? addDynamicRules(newSheet, data) : null]
}, [context, theme])
getUseInsertionEffect(context.isSSR)(() => {
// We only need to update the rules on a subsequent update and not in the first mount
if (sheet && dynamicRules && !isFirstMount.current) {
updateDynamicRules(data, sheet, dynamicRules)
}
}, [data])
getUseInsertionEffect(context.isSSR)(() => {
if (sheet) {
manageSheet({
index,
context,
sheet,
theme
})
}
return () => {
if (sheet) {
unmanageSheet({
index,
context,
sheet,
theme
})
// when sheet changes, remove related dynamic rules
if (dynamicRules) {
removeDynamicRules(sheet, dynamicRules)
}
}
}
}, [sheet])
const classes = useMemo(
() => (sheet && dynamicRules ? getSheetClasses(sheet, dynamicRules) : emptyObject),
[sheet, dynamicRules]
)
useDebugValue(classes)
useDebugValue(theme === noTheme ? 'No theme' : theme)
useEffect(() => {
isFirstMount.current = false
})
return classes
}
}
export default createUseStyles