@tamagui/core 1.0.1-rc.9 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/createComponent.js +25 -27
- package/dist/cjs/createComponent.js.map +2 -2
- package/dist/cjs/createTamagui.js +2 -1
- package/dist/cjs/createTamagui.js.map +2 -2
- package/dist/cjs/helpers/ThemeManager.js +4 -2
- package/dist/cjs/helpers/ThemeManager.js.map +2 -2
- package/dist/cjs/helpers/Unwrap.js +29 -0
- package/dist/cjs/helpers/Unwrap.js.map +7 -0
- package/dist/cjs/helpers/cache.js +7 -11
- package/dist/cjs/helpers/cache.js.map +2 -2
- package/dist/cjs/helpers/expandStyle.js +29 -41
- package/dist/cjs/helpers/expandStyle.js.map +2 -2
- package/dist/cjs/helpers/getSplitStyles.js +8 -14
- package/dist/cjs/helpers/getSplitStyles.js.map +2 -2
- package/dist/cjs/helpers/getStylesAtomic.js +10 -11
- package/dist/cjs/helpers/getStylesAtomic.js.map +2 -2
- package/dist/cjs/helpers/insertStyleRule.js +0 -2
- package/dist/cjs/helpers/insertStyleRule.js.map +2 -2
- package/dist/cjs/hooks/useTheme.js +45 -50
- package/dist/cjs/hooks/useTheme.js.map +3 -3
- package/dist/cjs/views/TamaguiProvider.js +3 -0
- package/dist/cjs/views/TamaguiProvider.js.map +2 -2
- package/dist/cjs/views/Theme.js +15 -21
- package/dist/cjs/views/Theme.js.map +3 -3
- package/dist/esm/createComponent.js +26 -28
- package/dist/esm/createComponent.js.map +2 -2
- package/dist/esm/createTamagui.js +2 -1
- package/dist/esm/createTamagui.js.map +2 -2
- package/dist/esm/helpers/ThemeManager.js +4 -2
- package/dist/esm/helpers/ThemeManager.js.map +2 -2
- package/dist/esm/helpers/Unwrap.js +5 -0
- package/dist/esm/helpers/Unwrap.js.map +7 -0
- package/dist/esm/helpers/cache.js +7 -10
- package/dist/esm/helpers/cache.js.map +2 -2
- package/dist/esm/helpers/expandStyle.js +26 -38
- package/dist/esm/helpers/expandStyle.js.map +2 -2
- package/dist/esm/helpers/getSplitStyles.js +8 -14
- package/dist/esm/helpers/getSplitStyles.js.map +2 -2
- package/dist/esm/helpers/getStylesAtomic.js +10 -11
- package/dist/esm/helpers/getStylesAtomic.js.map +2 -2
- package/dist/esm/helpers/insertStyleRule.js +0 -2
- package/dist/esm/helpers/insertStyleRule.js.map +2 -2
- package/dist/esm/hooks/useTheme.js +45 -50
- package/dist/esm/hooks/useTheme.js.map +3 -3
- package/dist/esm/views/TamaguiProvider.js +3 -0
- package/dist/esm/views/TamaguiProvider.js.map +2 -2
- package/dist/esm/views/Theme.js +14 -14
- package/dist/esm/views/Theme.js.map +2 -2
- package/package.json +13 -13
- package/src/createComponent.tsx +47 -43
- package/src/createTamagui.ts +2 -1
- package/src/helpers/ThemeManager.tsx +7 -2
- package/src/helpers/cache.ts +7 -9
- package/src/helpers/expandStyle.ts +27 -41
- package/src/helpers/getSplitStyles.tsx +23 -14
- package/src/helpers/getStylesAtomic.ts +15 -15
- package/src/helpers/insertStyleRule.tsx +0 -2
- package/src/hooks/useTheme.tsx +67 -48
- package/src/views/TamaguiProvider.tsx +6 -0
- package/src/views/Theme.tsx +15 -22
- package/types/createComponent.d.ts +1 -1
- package/types/helpers/ThemeManager.d.ts +1 -1
- package/types/helpers/cache.d.ts +2 -4
- package/types/hooks/useTheme.d.ts +1 -1
- package/types/views/Theme.d.ts +1 -1
package/src/helpers/cache.ts
CHANGED
|
@@ -2,17 +2,15 @@ type Value = Object | Array<any> | string | number
|
|
|
2
2
|
|
|
3
3
|
export type Style = { [key: string]: Value }
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
v: Record<string, any> = {}
|
|
5
|
+
const v: Record<string, any> = {}
|
|
7
6
|
|
|
7
|
+
export const cache = {
|
|
8
8
|
get(key: string, valStr: string) {
|
|
9
|
-
return
|
|
10
|
-
}
|
|
9
|
+
return v[key]?.[valStr]
|
|
10
|
+
},
|
|
11
11
|
|
|
12
12
|
set(key: string, valStr: string, object: any) {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
}
|
|
13
|
+
v[key] ??= {}
|
|
14
|
+
v[key][valStr] = object
|
|
15
|
+
},
|
|
16
16
|
}
|
|
17
|
-
|
|
18
|
-
export const cache = new Cache()
|
|
@@ -30,25 +30,16 @@ export function expandStyle(key: string, value: any) {
|
|
|
30
30
|
|
|
31
31
|
// web only
|
|
32
32
|
switch (key) {
|
|
33
|
-
case 'aspectRatio': {
|
|
34
|
-
return [[key, value.toString()]]
|
|
35
|
-
}
|
|
36
|
-
|
|
37
33
|
case 'textAlignVertical': {
|
|
38
34
|
return [['verticalAlign', value === 'center' ? 'middle' : value]]
|
|
39
35
|
}
|
|
40
|
-
|
|
41
|
-
case 'textDecorationLine': {
|
|
42
|
-
return [['textDecorationLine', value]]
|
|
43
|
-
}
|
|
44
|
-
|
|
45
36
|
case 'writingDirection': {
|
|
46
37
|
return [['direction', value]]
|
|
47
38
|
}
|
|
48
39
|
}
|
|
49
40
|
}
|
|
50
41
|
|
|
51
|
-
const longKey =
|
|
42
|
+
const longKey = EXPANSIONS[key]
|
|
52
43
|
if (longKey) {
|
|
53
44
|
return longKey.map((key) => {
|
|
54
45
|
return [key, value]
|
|
@@ -56,41 +47,36 @@ export function expandStyle(key: string, value: any) {
|
|
|
56
47
|
}
|
|
57
48
|
}
|
|
58
49
|
|
|
59
|
-
const
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
],
|
|
50
|
+
const all = ['Top', 'Right', 'Bottom', 'Left']
|
|
51
|
+
const horiz = ['Right', 'Left']
|
|
52
|
+
const vert = ['Top', 'Bottom']
|
|
53
|
+
const xy = ['X', 'Y']
|
|
54
|
+
|
|
55
|
+
const EXPANSIONS: Record<string, string[]> = {
|
|
56
|
+
borderColor: ['TopColor', 'RightColor', 'BottomColor', 'LeftColor'],
|
|
66
57
|
borderRadius: [
|
|
67
|
-
'
|
|
68
|
-
'
|
|
69
|
-
'
|
|
70
|
-
'
|
|
71
|
-
],
|
|
72
|
-
borderWidth: [
|
|
73
|
-
'borderTopWidth',
|
|
74
|
-
'borderRightWidth',
|
|
75
|
-
'borderBottomWidth',
|
|
76
|
-
'borderLeftWidth',
|
|
58
|
+
'TopLeftRadius',
|
|
59
|
+
'TopRightRadius',
|
|
60
|
+
'BottomRightRadius',
|
|
61
|
+
'BottomLeftRadius',
|
|
77
62
|
],
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
63
|
+
borderWidth: ['TopWidth', 'RightWidth', 'BottomWidth', 'LeftWidth'],
|
|
64
|
+
margin: all,
|
|
65
|
+
marginHorizontal: horiz,
|
|
66
|
+
marginVertical: vert,
|
|
67
|
+
overscrollBehavior: xy,
|
|
68
|
+
padding: all,
|
|
69
|
+
paddingHorizontal: horiz,
|
|
70
|
+
paddingVertical: vert,
|
|
85
71
|
...(isWeb && {
|
|
86
72
|
// react-native only supports borderStyle
|
|
87
|
-
borderStyle: [
|
|
88
|
-
'borderTopStyle',
|
|
89
|
-
'borderRightStyle',
|
|
90
|
-
'borderBottomStyle',
|
|
91
|
-
'borderLeftStyle',
|
|
92
|
-
],
|
|
73
|
+
borderStyle: ['TopStyle', 'RightStyle', 'BottomStyle', 'LeftStyle'],
|
|
93
74
|
// react-native doesn't support X / Y
|
|
94
|
-
overflow:
|
|
75
|
+
overflow: xy,
|
|
95
76
|
}),
|
|
96
77
|
}
|
|
78
|
+
|
|
79
|
+
for (const parent in EXPANSIONS) {
|
|
80
|
+
const prefix = parent.slice(0, /[A-Z]/.exec(parent)?.index ?? parent.length)
|
|
81
|
+
EXPANSIONS[parent] = EXPANSIONS[parent].map((k) => `${prefix}${k}`)
|
|
82
|
+
}
|
|
@@ -429,20 +429,12 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
429
429
|
}
|
|
430
430
|
break
|
|
431
431
|
}
|
|
432
|
-
case '
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
}
|
|
432
|
+
case 'accessibilityLabelledBy':
|
|
433
|
+
case 'accessibilityFlowTo':
|
|
434
|
+
case 'accessibilityControls':
|
|
436
435
|
case 'accessibilityDescribedBy': {
|
|
437
|
-
viewProps[
|
|
438
|
-
|
|
439
|
-
}
|
|
440
|
-
case 'accessibilityFlowTo': {
|
|
441
|
-
viewProps['aria-flowto'] = processIDRefList(valInit)
|
|
442
|
-
break
|
|
443
|
-
}
|
|
444
|
-
case 'accessibilityLabelledBy': {
|
|
445
|
-
viewProps['aria-labelledby'] = processIDRefList(valInit)
|
|
436
|
+
viewProps[`aria-${keyInit.replace('accessibility', '').toLowerCase()}`] =
|
|
437
|
+
processIDRefList(valInit)
|
|
446
438
|
break
|
|
447
439
|
}
|
|
448
440
|
case 'accessibilityKeyShortcuts': {
|
|
@@ -646,7 +638,24 @@ export const getSplitStyles: StyleSplitter = (
|
|
|
646
638
|
}
|
|
647
639
|
}
|
|
648
640
|
} else {
|
|
649
|
-
|
|
641
|
+
let isDisabled = !state[descriptor.stateKey || descriptor.name]
|
|
642
|
+
|
|
643
|
+
// we never animate in on server side just show the full thing
|
|
644
|
+
// on client side we use CSS to hide the fully in SSR items, then
|
|
645
|
+
// un-hide and replay with original animation.
|
|
646
|
+
if (!isClient && isEnter) {
|
|
647
|
+
isDisabled = false
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
// console.log(
|
|
651
|
+
// 'isDisabled',
|
|
652
|
+
// state,
|
|
653
|
+
// descriptor.stateKey,
|
|
654
|
+
// state[descriptor.stateKey || descriptor.name],
|
|
655
|
+
// isDisabled,
|
|
656
|
+
// descriptor
|
|
657
|
+
// )
|
|
658
|
+
|
|
650
659
|
if (!isDisabled) {
|
|
651
660
|
usedKeys[key] ||= 1
|
|
652
661
|
}
|
|
@@ -82,7 +82,21 @@ const generateAtomicStyles = (
|
|
|
82
82
|
|
|
83
83
|
// transform
|
|
84
84
|
if (style.transform && Array.isArray(style.transform)) {
|
|
85
|
-
style.transform = style.transform
|
|
85
|
+
style.transform = style.transform
|
|
86
|
+
.map(
|
|
87
|
+
// { scale: 2 } => 'scale(2)'
|
|
88
|
+
// { translateX: 20 } => 'translateX(20px)'
|
|
89
|
+
// { matrix: [1,2,3,4,5,6] } => 'matrix(1,2,3,4,5,6)'
|
|
90
|
+
(transform) => {
|
|
91
|
+
const type = Object.keys(transform)[0]
|
|
92
|
+
const value = transform[type]
|
|
93
|
+
if (type === 'matrix' || type === 'matrix3d') {
|
|
94
|
+
return `${type}(${value.join(',')})`
|
|
95
|
+
}
|
|
96
|
+
return `${type}(${normalizeValueWithProperty(value, type)})`
|
|
97
|
+
}
|
|
98
|
+
)
|
|
99
|
+
.join(' ')
|
|
86
100
|
}
|
|
87
101
|
|
|
88
102
|
styleToCSS(style)
|
|
@@ -160,20 +174,6 @@ export function styleToCSS(style: Record<string, any>) {
|
|
|
160
174
|
}
|
|
161
175
|
}
|
|
162
176
|
|
|
163
|
-
// { scale: 2 } => 'scale(2)'
|
|
164
|
-
// { translateX: 20 } => 'translateX(20px)'
|
|
165
|
-
// { matrix: [1,2,3,4,5,6] } => 'matrix(1,2,3,4,5,6)'
|
|
166
|
-
const mapTransform = (transform) => {
|
|
167
|
-
const type = Object.keys(transform)[0]
|
|
168
|
-
const value = transform[type]
|
|
169
|
-
if (type === 'matrix' || type === 'matrix3d') {
|
|
170
|
-
return `${type}(${value.join(',')})`
|
|
171
|
-
} else {
|
|
172
|
-
const normalizedValue = normalizeValueWithProperty(value, type)
|
|
173
|
-
return `${type}(${normalizedValue})`
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
|
|
177
177
|
function createDeclarationBlock(style: Style, important = false) {
|
|
178
178
|
let next = ''
|
|
179
179
|
for (const key in style) {
|
|
@@ -40,13 +40,11 @@ const isClient = typeof document !== 'undefined'
|
|
|
40
40
|
|
|
41
41
|
const scannedNum = new WeakMap<CSSStyleSheet, number>()
|
|
42
42
|
const totalSheetSelectors = new Map<string, number>()
|
|
43
|
-
const referencesInSheet = new WeakMap<CSSStyleSheet>()
|
|
44
43
|
|
|
45
44
|
export function listenForSheetChanges() {
|
|
46
45
|
if (!isClient) return
|
|
47
46
|
function handleNode(node: Node, remove = false) {
|
|
48
47
|
if (node instanceof HTMLStyleElement && node.sheet) {
|
|
49
|
-
console.warn('update', node.sheet)
|
|
50
48
|
updateSheetStyles(node.sheet, remove)
|
|
51
49
|
}
|
|
52
50
|
}
|
package/src/hooks/useTheme.tsx
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { isClient, isRSC, isServer, isWeb } from '@tamagui/constants'
|
|
3
|
-
import { useContext, useEffect,
|
|
3
|
+
import { useContext, useEffect, useMemo, useState } from 'react'
|
|
4
4
|
|
|
5
5
|
import { getConfig } from '../config'
|
|
6
6
|
import { isDevTools } from '../constants/isDevTools'
|
|
@@ -13,6 +13,7 @@ import {
|
|
|
13
13
|
import { ThemeManagerContext } from '../helpers/ThemeManagerContext'
|
|
14
14
|
import { ThemeParsed, ThemeProps } from '../types'
|
|
15
15
|
import { GetThemeUnwrapped } from './getThemeUnwrapped'
|
|
16
|
+
import { useServerRef } from './useServerHooks'
|
|
16
17
|
|
|
17
18
|
export type ChangedThemeResponse = {
|
|
18
19
|
themeManager: ThemeManager | null
|
|
@@ -33,12 +34,28 @@ function getDefaultThemeProxied() {
|
|
|
33
34
|
})
|
|
34
35
|
}
|
|
35
36
|
|
|
37
|
+
interface UseThemeState {
|
|
38
|
+
keys: Set<string>
|
|
39
|
+
}
|
|
40
|
+
|
|
36
41
|
export const useTheme = (props: ThemeProps = emptyProps): ThemeParsed => {
|
|
37
42
|
if (isRSC) {
|
|
38
43
|
return getDefaultThemeProxied()
|
|
39
44
|
}
|
|
40
45
|
|
|
41
|
-
const
|
|
46
|
+
const state = useServerRef() as React.MutableRefObject<UseThemeState>
|
|
47
|
+
if (isClient && !state.current) {
|
|
48
|
+
state.current = {
|
|
49
|
+
keys: new Set(),
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
state.current?.keys.clear()
|
|
53
|
+
|
|
54
|
+
const { name, theme, themeManager, className, isNewTheme } = useChangeThemeEffect(
|
|
55
|
+
props,
|
|
56
|
+
false,
|
|
57
|
+
isClient ? () => state.current.keys.size === 0 : undefined
|
|
58
|
+
)
|
|
42
59
|
|
|
43
60
|
if (process.env.NODE_ENV === 'development') {
|
|
44
61
|
// ensure we aren't creating too many ThemeManagers
|
|
@@ -73,6 +90,7 @@ export const useTheme = (props: ThemeProps = emptyProps): ThemeParsed => {
|
|
|
73
90
|
name,
|
|
74
91
|
className,
|
|
75
92
|
themeManager,
|
|
93
|
+
state,
|
|
76
94
|
})
|
|
77
95
|
}, [theme, isNewTheme, name, className, themeManager])
|
|
78
96
|
}
|
|
@@ -83,12 +101,14 @@ function getThemeProxied({
|
|
|
83
101
|
className,
|
|
84
102
|
themeManager,
|
|
85
103
|
isNewTheme,
|
|
104
|
+
state,
|
|
86
105
|
}: {
|
|
87
106
|
theme: any
|
|
88
107
|
name: string
|
|
89
108
|
className?: string
|
|
90
109
|
themeManager?: ThemeManager | null
|
|
91
110
|
isNewTheme?: boolean
|
|
111
|
+
state?: React.RefObject<UseThemeState>
|
|
92
112
|
}) {
|
|
93
113
|
return createProxy(theme, {
|
|
94
114
|
has(_, key) {
|
|
@@ -122,7 +142,20 @@ function getThemeProxied({
|
|
|
122
142
|
if (!themeManager) {
|
|
123
143
|
return theme[key]
|
|
124
144
|
}
|
|
125
|
-
|
|
145
|
+
const val = themeManager.getValue(key)
|
|
146
|
+
if (val && state) {
|
|
147
|
+
if (isClient) {
|
|
148
|
+
return new Proxy(val as any, {
|
|
149
|
+
get(_, subkey) {
|
|
150
|
+
if (subkey === 'val') {
|
|
151
|
+
state.current!.keys.add(key as any)
|
|
152
|
+
}
|
|
153
|
+
return Reflect.get(val, subkey)
|
|
154
|
+
},
|
|
155
|
+
})
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return val
|
|
126
159
|
},
|
|
127
160
|
})
|
|
128
161
|
}
|
|
@@ -139,7 +172,8 @@ export const activeThemeManagers = new Set<ThemeManager>()
|
|
|
139
172
|
|
|
140
173
|
export const useChangeThemeEffect = (
|
|
141
174
|
props: ThemeProps,
|
|
142
|
-
root = false
|
|
175
|
+
root = false,
|
|
176
|
+
disableUpdate?: () => boolean
|
|
143
177
|
): ChangedThemeResponse => {
|
|
144
178
|
if (isRSC) {
|
|
145
179
|
// we need context working for this to work well
|
|
@@ -186,20 +220,16 @@ export const useChangeThemeEffect = (
|
|
|
186
220
|
return
|
|
187
221
|
}
|
|
188
222
|
activeThemeManagers.add(themeManager)
|
|
189
|
-
const disposeChangeListener = parentManager?.onChangeTheme(() => {
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
} else {
|
|
197
|
-
updateState()
|
|
198
|
-
}
|
|
199
|
-
})
|
|
223
|
+
// const disposeChangeListener = parentManager?.onChangeTheme((name, manager) => {
|
|
224
|
+
// // console.log('hi', props, state, name, manager)
|
|
225
|
+
// if (state.theme !== manager.state.theme) {
|
|
226
|
+
// console.warn('now update to', manager.state.name)
|
|
227
|
+
// updateState(manager)
|
|
228
|
+
// }
|
|
229
|
+
// })
|
|
200
230
|
return () => {
|
|
201
231
|
activeThemeManagers.delete(themeManager)
|
|
202
|
-
disposeChangeListener?.()
|
|
232
|
+
// disposeChangeListener?.()
|
|
203
233
|
}
|
|
204
234
|
}, [disable, state, isNewTheme, debug])
|
|
205
235
|
}
|
|
@@ -209,13 +239,8 @@ export const useChangeThemeEffect = (
|
|
|
209
239
|
|
|
210
240
|
if (shouldReturnParentState) {
|
|
211
241
|
if (!parentManager) throw 'impossible'
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
'useTheme hasNoThemeUpdatingProps',
|
|
215
|
-
parentManager.state.name,
|
|
216
|
-
'isInversingOnMount',
|
|
217
|
-
isInversingOnMount
|
|
218
|
-
)
|
|
242
|
+
// prettier-ignore
|
|
243
|
+
if (process.env.NODE_ENV === 'development' && props.debug === 'verbose') console.log('useTheme hasNoThemeUpdatingProps', parentManager.state.name, 'isInversingOnMount', isInversingOnMount)
|
|
219
244
|
return {
|
|
220
245
|
...parentManager.state,
|
|
221
246
|
className: isInversingOnMount ? '' : parentManager.state.className,
|
|
@@ -234,27 +259,19 @@ export const useChangeThemeEffect = (
|
|
|
234
259
|
}
|
|
235
260
|
|
|
236
261
|
function createState(prev?: State) {
|
|
262
|
+
if (prev && disableUpdate?.()) {
|
|
263
|
+
return prev
|
|
264
|
+
}
|
|
265
|
+
// returns previous theme manager if no change
|
|
237
266
|
const _ = new ThemeManager(props, root ? 'root' : parentManager)
|
|
238
267
|
const isNewTheme = _ !== parentManager
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
'props',
|
|
247
|
-
props,
|
|
248
|
-
'\n',
|
|
249
|
-
isClient ? parentManager : '',
|
|
250
|
-
'getState',
|
|
251
|
-
isNewTheme && isClient ? _.getState(props) : '',
|
|
252
|
-
'\n',
|
|
253
|
-
'state',
|
|
254
|
-
isClient ? { ..._.state } : ''
|
|
255
|
-
),
|
|
256
|
-
console.groupEnd(),
|
|
257
|
-
]
|
|
268
|
+
// prettier-ignore
|
|
269
|
+
|
|
270
|
+
// if (prev?.isNewTheme && _.state.theme !== parentManager?.state.theme) {
|
|
271
|
+
// console.warn('notify')
|
|
272
|
+
// _.notify()
|
|
273
|
+
// }
|
|
274
|
+
|
|
258
275
|
// only inverse relies on this for ssr
|
|
259
276
|
const mounted = !props.inverse ? true : root || prev?.mounted
|
|
260
277
|
return {
|
|
@@ -266,12 +283,14 @@ export const useChangeThemeEffect = (
|
|
|
266
283
|
}
|
|
267
284
|
}
|
|
268
285
|
|
|
269
|
-
function updateState() {
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
)
|
|
286
|
+
function updateState(updatingManager?: ThemeManager) {
|
|
287
|
+
if (disableUpdate?.()) {
|
|
288
|
+
return
|
|
289
|
+
}
|
|
290
|
+
const manager = updatingManager ?? themeManager
|
|
291
|
+
const next = manager.getState(props, parentManager)
|
|
292
|
+
const shouldChange = manager.getStateShouldChange(next, isNewTheme ? state : null)
|
|
293
|
+
// console.log(`got it`, next, isNewTheme, shouldChange, { ...updatingManager?.state })
|
|
275
294
|
if (shouldChange) {
|
|
276
295
|
setThemeState(createState)
|
|
277
296
|
} else {
|
|
@@ -32,6 +32,12 @@ export function TamaguiProvider({
|
|
|
32
32
|
// inject CSS if asked to (not SSR compliant)
|
|
33
33
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
34
34
|
React.useLayoutEffect(() => {
|
|
35
|
+
// for easier support of hidden-until-js mount animations
|
|
36
|
+
// user must set t_unmounted on documentElement from SSR
|
|
37
|
+
if (document.documentElement.classList.contains('t_unmounted')) {
|
|
38
|
+
document.documentElement.classList.remove('t_unmounted')
|
|
39
|
+
}
|
|
40
|
+
|
|
35
41
|
if (disableInjectCSS) return
|
|
36
42
|
const style = document.createElement('style')
|
|
37
43
|
style.appendChild(document.createTextNode(config.getCSS()))
|
package/src/views/Theme.tsx
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { isWeb } from '@tamagui/constants'
|
|
2
|
-
import React, { useMemo } from 'react'
|
|
2
|
+
import React, { Children, cloneElement, useMemo } from 'react'
|
|
3
3
|
|
|
4
4
|
import { variableToString } from '../createVariable'
|
|
5
5
|
import { ThemeManager } from '../helpers/ThemeManager'
|
|
@@ -14,23 +14,20 @@ export function Theme(props: ThemeProps) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
const isRoot = !!props['_isRoot']
|
|
17
|
-
const { name, theme, themeManager,
|
|
18
|
-
props,
|
|
19
|
-
isRoot
|
|
20
|
-
)
|
|
21
|
-
|
|
17
|
+
const { name, theme, themeManager, className } = useChangeThemeEffect(props, isRoot)
|
|
22
18
|
const disableThemeClass = props.disableThemeClass
|
|
23
19
|
const missingTheme = !(name && theme)
|
|
24
20
|
|
|
25
21
|
// memo here, changing theme without re-rendering all children is a critical optimization
|
|
26
22
|
// may require some effort of end user to memoize but without this memo they'd have no option
|
|
27
|
-
let contents =
|
|
28
|
-
|
|
29
|
-
?
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
23
|
+
let contents = useThemeManagerContext(
|
|
24
|
+
props['data-themeable']
|
|
25
|
+
? Children.map(props.children, (child) =>
|
|
26
|
+
cloneElement(child, { ['data-themeable']: true })
|
|
27
|
+
)
|
|
28
|
+
: props.children,
|
|
29
|
+
themeManager
|
|
30
|
+
)
|
|
34
31
|
|
|
35
32
|
if (process.env.NODE_ENV === 'development' && missingTheme) {
|
|
36
33
|
// eslint-disable-next-line no-console
|
|
@@ -60,15 +57,15 @@ export function Theme(props: ThemeProps) {
|
|
|
60
57
|
return contents
|
|
61
58
|
}
|
|
62
59
|
|
|
63
|
-
export function
|
|
60
|
+
export function useThemeManagerContext(
|
|
64
61
|
children: any,
|
|
65
62
|
themeManager?: ThemeManager | null,
|
|
66
63
|
shouldReset?: boolean
|
|
67
64
|
) {
|
|
65
|
+
// disabled super memoize it - listener first strategy
|
|
66
|
+
const value = themeManager // useMemo(() => themeManager, [!!themeManager])
|
|
68
67
|
// be sure to memoize themeManager to avoid reparenting
|
|
69
|
-
if (!
|
|
70
|
-
return children
|
|
71
|
-
}
|
|
68
|
+
if (!value) return children
|
|
72
69
|
// be sure to memoize shouldReset to avoid reparenting
|
|
73
70
|
let next = children
|
|
74
71
|
// TODO likely not necessary if we do reset logic now in useTheme?
|
|
@@ -76,9 +73,5 @@ export function wrapThemeManagerContext(
|
|
|
76
73
|
if (shouldReset && themeManager) {
|
|
77
74
|
next = <Theme name={themeManager.state.parentName}>{next}</Theme>
|
|
78
75
|
}
|
|
79
|
-
return
|
|
80
|
-
<ThemeManagerContext.Provider value={themeManager}>
|
|
81
|
-
{next}
|
|
82
|
-
</ThemeManagerContext.Provider>
|
|
83
|
-
)
|
|
76
|
+
return <ThemeManagerContext.Provider value={value}>{next}</ThemeManagerContext.Provider>
|
|
84
77
|
}
|
|
@@ -17,5 +17,5 @@ export type SpacedChildrenProps = {
|
|
|
17
17
|
direction?: SpaceDirection;
|
|
18
18
|
separator?: React.ReactNode;
|
|
19
19
|
};
|
|
20
|
-
export declare function spacedChildren(
|
|
20
|
+
export declare function spacedChildren(props: SpacedChildrenProps): React.ReactNode;
|
|
21
21
|
//# sourceMappingURL=createComponent.d.ts.map
|
|
@@ -25,7 +25,7 @@ export declare class ThemeManager {
|
|
|
25
25
|
forceTheme?: ThemeParsed;
|
|
26
26
|
}, notify?: boolean): ThemeManagerState | undefined;
|
|
27
27
|
getStateIfChanged(props?: ThemeProps, state?: ThemeManagerState | null, parentManager?: ThemeManager | null): ThemeManagerState | null | undefined;
|
|
28
|
-
getStateShouldChange(nextState: ThemeManagerState | null, state?: ThemeManagerState | null):
|
|
28
|
+
getStateShouldChange(nextState: ThemeManagerState | null, state?: ThemeManagerState | null): boolean;
|
|
29
29
|
getState(props?: ThemeProps, parentManager?: ThemeManager | null): ThemeManagerState | null;
|
|
30
30
|
get allKeys(): Set<string>;
|
|
31
31
|
getValue(key: string, state?: ThemeManagerState): import("..").Variable<any> | undefined;
|
package/types/helpers/cache.d.ts
CHANGED
|
@@ -2,11 +2,9 @@ type Value = Object | Array<any> | string | number;
|
|
|
2
2
|
export type Style = {
|
|
3
3
|
[key: string]: Value;
|
|
4
4
|
};
|
|
5
|
-
declare
|
|
6
|
-
v: Record<string, any>;
|
|
5
|
+
export declare const cache: {
|
|
7
6
|
get(key: string, valStr: string): any;
|
|
8
7
|
set(key: string, valStr: string, object: any): void;
|
|
9
|
-
}
|
|
10
|
-
export declare const cache: Cache;
|
|
8
|
+
};
|
|
11
9
|
export {};
|
|
12
10
|
//# sourceMappingURL=cache.d.ts.map
|
|
@@ -11,5 +11,5 @@ export declare const useTheme: (props?: ThemeProps) => ThemeParsed;
|
|
|
11
11
|
export declare const getThemeManager: (theme: any) => ThemeManager | undefined;
|
|
12
12
|
export declare const getThemeIsNewTheme: (theme: any) => ThemeManager | undefined;
|
|
13
13
|
export declare const activeThemeManagers: Set<ThemeManager>;
|
|
14
|
-
export declare const useChangeThemeEffect: (props: ThemeProps, root?: boolean) => ChangedThemeResponse;
|
|
14
|
+
export declare const useChangeThemeEffect: (props: ThemeProps, root?: boolean, disableUpdate?: () => boolean) => ChangedThemeResponse;
|
|
15
15
|
//# sourceMappingURL=useTheme.d.ts.map
|
package/types/views/Theme.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ThemeManager } from '../helpers/ThemeManager';
|
|
2
2
|
import { ThemeProps } from '../types';
|
|
3
3
|
export declare function Theme(props: ThemeProps): any;
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function useThemeManagerContext(children: any, themeManager?: ThemeManager | null, shouldReset?: boolean): any;
|
|
5
5
|
//# sourceMappingURL=Theme.d.ts.map
|