1
1
import hash from '@emotion/hash' ;
2
- import { ATTR_TOKEN , CSS_IN_JS_INSTANCE , CSS_IN_JS_INSTANCE_ID } from '../StyleContext' ;
2
+ import { ATTR_TOKEN , CSS_IN_JS_INSTANCE , useStyleInject } from '../StyleContext' ;
3
3
import type Theme from '../theme/Theme' ;
4
4
import useGlobalCache from './useGlobalCache' ;
5
5
import { flattenToken , token2key } from '../util' ;
@@ -12,7 +12,7 @@ const EMPTY_OVERRIDE = {};
12
12
// This helps developer not to do style override directly on the hash id.
13
13
const hashPrefix = process . env . NODE_ENV !== 'production' ? 'css-dev-only-do-not-override' : 'css' ;
14
14
15
- export interface Option < DerivativeToken > {
15
+ export interface Option < DerivativeToken , DesignToken > {
16
16
/**
17
17
* Generate token with salt.
18
18
* This is used to generate different hashId even same derivative token for different version.
@@ -30,27 +30,41 @@ export interface Option<DerivativeToken> {
30
30
* It's ok to useMemo outside but this has better cache strategy.
31
31
*/
32
32
formatToken ?: ( mergedToken : any ) => DerivativeToken ;
33
+ /**
34
+ * Get final token with origin token, override token and theme.
35
+ * The parameters do not contain formatToken since it's passed by user.
36
+ * @param origin The original token.
37
+ * @param override Extra tokens to override.
38
+ * @param theme Theme instance. Could get derivative token by `theme.getDerivativeToken`
39
+ */
40
+ getComputedToken ?: (
41
+ origin : DesignToken ,
42
+ override : object ,
43
+ theme : Theme < any , any > ,
44
+ ) => DerivativeToken ;
33
45
}
34
46
35
47
const tokenKeys = new Map < string , number > ( ) ;
36
48
function recordCleanToken ( tokenKey : string ) {
37
49
tokenKeys . set ( tokenKey , ( tokenKeys . get ( tokenKey ) || 0 ) + 1 ) ;
38
50
}
39
51
40
- function removeStyleTags ( key : string ) {
52
+ function removeStyleTags ( key : string , instanceId : string ) {
41
53
if ( typeof document !== 'undefined' ) {
42
54
const styles = document . querySelectorAll ( `style[${ ATTR_TOKEN } ="${ key } "]` ) ;
43
55
44
56
styles . forEach ( style => {
45
- if ( ( style as any ) [ CSS_IN_JS_INSTANCE ] === CSS_IN_JS_INSTANCE_ID ) {
57
+ if ( ( style as any ) [ CSS_IN_JS_INSTANCE ] === instanceId ) {
46
58
style . parentNode ?. removeChild ( style ) ;
47
59
}
48
60
} ) ;
49
61
}
50
62
}
51
63
64
+ const TOKEN_THRESHOLD = 0 ;
65
+
52
66
// Remove will check current keys first
53
- function cleanTokenStyle ( tokenKey : string ) {
67
+ function cleanTokenStyle ( tokenKey : string , instanceId : string ) {
54
68
tokenKeys . set ( tokenKey , ( tokenKeys . get ( tokenKey ) || 0 ) - 1 ) ;
55
69
56
70
const tokenKeyList = Array . from ( tokenKeys . keys ( ) ) ;
@@ -60,14 +74,37 @@ function cleanTokenStyle(tokenKey: string) {
60
74
return count <= 0 ;
61
75
} ) ;
62
76
63
- if ( cleanableKeyList . length < tokenKeyList . length ) {
77
+ // Should keep tokens under threshold for not to insert style too often
78
+ if ( tokenKeyList . length - cleanableKeyList . length > TOKEN_THRESHOLD ) {
64
79
cleanableKeyList . forEach ( key => {
65
- removeStyleTags ( key ) ;
80
+ removeStyleTags ( key , instanceId ) ;
66
81
tokenKeys . delete ( key ) ;
67
82
} ) ;
68
83
}
69
84
}
70
85
86
+ export const getComputedToken = < DerivativeToken = object , DesignToken = DerivativeToken > (
87
+ originToken : DesignToken ,
88
+ overrideToken : object ,
89
+ theme : Theme < any , any > ,
90
+ format ?: ( token : DesignToken ) => DerivativeToken ,
91
+ ) => {
92
+ const derivativeToken = theme . getDerivativeToken ( originToken ) ;
93
+
94
+ // Merge with override
95
+ let mergedDerivativeToken = {
96
+ ...derivativeToken ,
97
+ ...overrideToken ,
98
+ } ;
99
+
100
+ // Format if needed
101
+ if ( format ) {
102
+ mergedDerivativeToken = format ( mergedDerivativeToken ) ;
103
+ }
104
+
105
+ return mergedDerivativeToken ;
106
+ } ;
107
+
71
108
/**
72
109
* Cache theme derivative token as global shared one
73
110
* @param theme Theme entity
@@ -78,8 +115,10 @@ function cleanTokenStyle(tokenKey: string) {
78
115
export default function useCacheToken < DerivativeToken = object , DesignToken = DerivativeToken > (
79
116
theme : Ref < Theme < any , any > > ,
80
117
tokens : Ref < Partial < DesignToken > [ ] > ,
81
- option : Ref < Option < DerivativeToken > > = ref ( { } ) ,
118
+ option : Ref < Option < DerivativeToken , DesignToken > > = ref ( { } ) ,
82
119
) {
120
+ const style = useStyleInject ( ) ;
121
+
83
122
// Basic - We do basic cache here
84
123
const mergedToken = computed ( ( ) => Object . assign ( { } , ...tokens . value ) ) ;
85
124
const tokenStr = computed ( ( ) => flattenToken ( mergedToken . value ) ) ;
@@ -94,19 +133,15 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
94
133
overrideTokenStr . value ,
95
134
] ) ,
96
135
( ) => {
97
- const { salt = '' , override = EMPTY_OVERRIDE , formatToken } = option . value ;
98
- const derivativeToken = theme . value . getDerivativeToken ( mergedToken . value ) ;
99
-
100
- // Merge with override
101
- let mergedDerivativeToken = {
102
- ...derivativeToken ,
103
- ...override ,
104
- } ;
105
-
106
- // Format if needed
107
- if ( formatToken ) {
108
- mergedDerivativeToken = formatToken ( mergedDerivativeToken ) ;
109
- }
136
+ const {
137
+ salt = '' ,
138
+ override = EMPTY_OVERRIDE ,
139
+ formatToken,
140
+ getComputedToken : compute ,
141
+ } = option . value ;
142
+ const mergedDerivativeToken = compute
143
+ ? compute ( mergedToken . value , override , theme . value )
144
+ : getComputedToken ( mergedToken . value , override , theme . value , formatToken ) ;
110
145
111
146
// Optimize for `useStyleRegister` performance
112
147
const tokenKey = token2key ( mergedDerivativeToken , salt ) ;
@@ -120,7 +155,7 @@ export default function useCacheToken<DerivativeToken = object, DesignToken = De
120
155
} ,
121
156
cache => {
122
157
// Remove token will remove all related style
123
- cleanTokenStyle ( cache [ 0 ] . _tokenKey ) ;
158
+ cleanTokenStyle ( cache [ 0 ] . _tokenKey , style . value ?. cache . instanceId ) ;
124
159
} ,
125
160
) ;
126
161
0 commit comments