1 | import React, {useEffect, useLayoutEffect, useContext, useRef, useMemo, useDebugValue} from 'react'
|
2 | import {ThemeContext as DefaultThemeContext} from 'theming'
|
3 |
|
4 | import JssContext from './JssContext'
|
5 | import {
|
6 | createStyleSheet,
|
7 | addDynamicRules,
|
8 | updateDynamicRules,
|
9 | removeDynamicRules
|
10 | } from './utils/sheets'
|
11 | import getSheetIndex from './utils/getSheetIndex'
|
12 | import {manageSheet, unmanageSheet} from './utils/managers'
|
13 | import getSheetClasses from './utils/getSheetClasses'
|
14 |
|
15 | function getUseInsertionEffect(isSSR) {
|
16 | return isSSR
|
17 | ? useEffect
|
18 | : React.useInsertionEffect ||
|
19 | useLayoutEffect
|
20 | }
|
21 |
|
22 | const noTheme = {}
|
23 |
|
24 | const createUseStyles = (styles, options = {}) => {
|
25 | const {index = getSheetIndex(), theming, name, ...sheetOptions} = options
|
26 | const ThemeContext = (theming && theming.context) || DefaultThemeContext
|
27 |
|
28 | const useTheme = (theme) => {
|
29 | if (typeof styles === 'function') {
|
30 | return theme || useContext(ThemeContext) || noTheme
|
31 | }
|
32 |
|
33 | return noTheme
|
34 | }
|
35 |
|
36 | const emptyObject = {}
|
37 |
|
38 | return function useStyles(data) {
|
39 | const isFirstMount = useRef(true)
|
40 | const context = useContext(JssContext)
|
41 | const theme = useTheme(data && data.theme)
|
42 |
|
43 | const [sheet, dynamicRules] = useMemo(() => {
|
44 | const newSheet = createStyleSheet({
|
45 | context,
|
46 | styles,
|
47 | name,
|
48 | theme,
|
49 | index,
|
50 | sheetOptions
|
51 | })
|
52 |
|
53 | if (newSheet && context.isSSR) {
|
54 |
|
55 | manageSheet({
|
56 | index,
|
57 | context,
|
58 | sheet: newSheet,
|
59 | theme
|
60 | })
|
61 | }
|
62 |
|
63 | return [newSheet, newSheet ? addDynamicRules(newSheet, data) : null]
|
64 | }, [context, theme])
|
65 |
|
66 | getUseInsertionEffect(context.isSSR)(() => {
|
67 |
|
68 | if (sheet && dynamicRules && !isFirstMount.current) {
|
69 | updateDynamicRules(data, sheet, dynamicRules)
|
70 | }
|
71 | }, [data])
|
72 |
|
73 | getUseInsertionEffect(context.isSSR)(() => {
|
74 | if (sheet) {
|
75 | manageSheet({
|
76 | index,
|
77 | context,
|
78 | sheet,
|
79 | theme
|
80 | })
|
81 | }
|
82 |
|
83 | return () => {
|
84 | if (sheet) {
|
85 | unmanageSheet({
|
86 | index,
|
87 | context,
|
88 | sheet,
|
89 | theme
|
90 | })
|
91 |
|
92 |
|
93 | if (dynamicRules) {
|
94 | removeDynamicRules(sheet, dynamicRules)
|
95 | }
|
96 | }
|
97 | }
|
98 | }, [sheet])
|
99 |
|
100 | const classes = useMemo(
|
101 | () => (sheet && dynamicRules ? getSheetClasses(sheet, dynamicRules) : emptyObject),
|
102 | [sheet, dynamicRules]
|
103 | )
|
104 |
|
105 | useDebugValue(classes)
|
106 |
|
107 | useDebugValue(theme === noTheme ? 'No theme' : theme)
|
108 |
|
109 | useEffect(() => {
|
110 | isFirstMount.current = false
|
111 | })
|
112 |
|
113 | return classes
|
114 | }
|
115 | }
|
116 |
|
117 | export default createUseStyles
|