@oxyhq/bloom 0.25.0 → 0.25.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/lib/commonjs/theme/color-scope/index.js +21 -10
- package/lib/commonjs/theme/color-scope/index.js.map +1 -1
- package/lib/commonjs/theme/color-scope/index.web.js +21 -10
- package/lib/commonjs/theme/color-scope/index.web.js.map +1 -1
- package/lib/module/theme/color-scope/index.js +21 -10
- package/lib/module/theme/color-scope/index.js.map +1 -1
- package/lib/module/theme/color-scope/index.web.js +21 -10
- package/lib/module/theme/color-scope/index.web.js.map +1 -1
- package/lib/typescript/commonjs/theme/color-scope/index.d.ts.map +1 -1
- package/lib/typescript/commonjs/theme/color-scope/index.web.d.ts.map +1 -1
- package/lib/typescript/module/theme/color-scope/index.d.ts.map +1 -1
- package/lib/typescript/module/theme/color-scope/index.web.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/__tests__/BloomColorScope.test.tsx +66 -0
- package/src/theme/color-scope/index.tsx +26 -15
- package/src/theme/color-scope/index.web.tsx +25 -15
|
@@ -18,15 +18,15 @@ function BloomColorScope({
|
|
|
18
18
|
style,
|
|
19
19
|
children
|
|
20
20
|
}) {
|
|
21
|
+
// All hooks are called UNCONDITIONALLY, in the same order on every render —
|
|
22
|
+
// never gate a hook behind an early return (rules of hooks). The conditional
|
|
23
|
+
// no-op/throw behavior is applied AFTER every hook has run, using the values
|
|
24
|
+
// the hooks produced. `resolvedMode` falls back harmlessly when the provider
|
|
25
|
+
// is absent (that render path throws below anyway).
|
|
21
26
|
const parent = (0, _react.useContext)(_BloomThemeProvider.BloomThemeContext);
|
|
22
|
-
|
|
23
|
-
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
24
|
-
}
|
|
25
|
-
if (!colorPreset) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
26
|
-
children: children
|
|
27
|
-
});
|
|
28
|
-
const resolvedMode = parent.theme.mode;
|
|
27
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
29
28
|
const contextValue = (0, _react.useMemo)(() => {
|
|
29
|
+
if (!parent || !colorPreset) return null;
|
|
30
30
|
const theme = (0, _buildTheme.buildTheme)(colorPreset, resolvedMode);
|
|
31
31
|
return {
|
|
32
32
|
...parent,
|
|
@@ -39,7 +39,16 @@ function BloomColorScope({
|
|
|
39
39
|
// VariableContext (`VariableContextProvider`), NOT via an inline `vars()`
|
|
40
40
|
// style — under react-native-css@3 inline vars applied to a plain `<View>`
|
|
41
41
|
// (no matched className rules) are dropped silently. See `style-builder.ts`.
|
|
42
|
-
const nativeVars = (0, _react.useMemo)(() => (0, _styleBuilder.buildScopeVars)(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
42
|
+
const nativeVars = (0, _react.useMemo)(() => colorPreset ? (0, _styleBuilder.buildScopeVars)(colorPreset, resolvedMode) : null, [colorPreset, resolvedMode]);
|
|
43
|
+
if (!parent) {
|
|
44
|
+
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
45
|
+
}
|
|
46
|
+
// `colorPreset` undefined => the scope is a no-op; children inherit the
|
|
47
|
+
// parent scope. With `parent` present, `contextValue`/`nativeVars` are null
|
|
48
|
+
// iff `colorPreset` is absent, so this guard also narrows them to non-null.
|
|
49
|
+
if (!contextValue || !nativeVars) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
50
|
+
children: children
|
|
51
|
+
});
|
|
43
52
|
const VariableProvider = (0, _styleBuilder.getVariableContextProvider)();
|
|
44
53
|
let content;
|
|
45
54
|
if (asChild) {
|
|
@@ -88,11 +97,13 @@ function BloomColorScope({
|
|
|
88
97
|
* `<BloomColorScope>`, which wraps children in `VariableContextProvider`.
|
|
89
98
|
*/
|
|
90
99
|
function useColorScopeStyle(colorPreset) {
|
|
100
|
+
// Hooks first, unconditionally; throw only after they have all run.
|
|
91
101
|
const parent = (0, _react.useContext)(_BloomThemeProvider.BloomThemeContext);
|
|
102
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
103
|
+
const scopeStyle = (0, _react.useMemo)(() => (0, _styleBuilder.buildNativePresetStyle)(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
92
104
|
if (!parent) {
|
|
93
105
|
throw new Error('useColorScopeStyle must be used within a <BloomThemeProvider>');
|
|
94
106
|
}
|
|
95
|
-
|
|
96
|
-
return (0, _react.useMemo)(() => (0, _styleBuilder.buildNativePresetStyle)(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
107
|
+
return scopeStyle;
|
|
97
108
|
}
|
|
98
109
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_BloomThemeProvider","_buildTheme","_styleBuilder","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","BloomColorScope","colorPreset","asChild","style","children","parent","useContext","BloomThemeContext","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_reactNative","_BloomThemeProvider","_buildTheme","_styleBuilder","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","BloomColorScope","colorPreset","asChild","style","children","parent","useContext","BloomThemeContext","resolvedMode","theme","mode","contextValue","useMemo","buildTheme","nativeVars","buildScopeVars","Error","jsx","Fragment","VariableProvider","getVariableContextProvider","content","child","Children","only","isValidElement","childStyle","props","mergedStyle","cloneElement","View","flex","scoped","value","Provider","useColorScopeStyle","scopeStyle","buildNativePresetStyle"],"sourceRoot":"../../../../src","sources":["theme/color-scope/index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -36,15 +36,15 @@ function BloomColorScope({
|
|
|
36
36
|
style,
|
|
37
37
|
children
|
|
38
38
|
}) {
|
|
39
|
+
// All hooks are called UNCONDITIONALLY, in the same order on every render —
|
|
40
|
+
// never gate a hook behind an early return (rules of hooks). The conditional
|
|
41
|
+
// no-op/throw behavior is applied AFTER every hook has run, using the values
|
|
42
|
+
// the hooks produced. `resolvedMode` falls back harmlessly when the provider
|
|
43
|
+
// is absent (that render path throws below anyway).
|
|
39
44
|
const parent = (0, _react.useContext)(_BloomThemeProvider.BloomThemeContext);
|
|
40
|
-
|
|
41
|
-
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
42
|
-
}
|
|
43
|
-
if (!colorPreset) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
44
|
-
children: children
|
|
45
|
-
});
|
|
46
|
-
const resolvedMode = parent.theme.mode;
|
|
45
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
47
46
|
const contextValue = (0, _react.useMemo)(() => {
|
|
47
|
+
if (!parent || !colorPreset) return null;
|
|
48
48
|
const theme = (0, _buildTheme.buildTheme)(colorPreset, resolvedMode);
|
|
49
49
|
return {
|
|
50
50
|
...parent,
|
|
@@ -52,7 +52,16 @@ function BloomColorScope({
|
|
|
52
52
|
colorPreset
|
|
53
53
|
};
|
|
54
54
|
}, [colorPreset, resolvedMode, parent]);
|
|
55
|
-
const varsStyle = (0, _react.useMemo)(() => buildWebScopeVars(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
55
|
+
const varsStyle = (0, _react.useMemo)(() => colorPreset ? buildWebScopeVars(colorPreset, resolvedMode) : null, [colorPreset, resolvedMode]);
|
|
56
|
+
if (!parent) {
|
|
57
|
+
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
58
|
+
}
|
|
59
|
+
// `colorPreset` undefined => the scope is a no-op; children inherit the
|
|
60
|
+
// parent scope. With `parent` present, `contextValue`/`varsStyle` are null
|
|
61
|
+
// iff `colorPreset` is absent, so this guard also narrows them to non-null.
|
|
62
|
+
if (!contextValue || !varsStyle) return /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
63
|
+
children: children
|
|
64
|
+
});
|
|
56
65
|
let content;
|
|
57
66
|
if (asChild) {
|
|
58
67
|
const child = _react.Children.only(children);
|
|
@@ -92,11 +101,13 @@ function BloomColorScope({
|
|
|
92
101
|
* caller. Returns a stable React style object carrying the preset's CSS vars.
|
|
93
102
|
*/
|
|
94
103
|
function useColorScopeStyle(colorPreset) {
|
|
104
|
+
// Hooks first, unconditionally; throw only after they have all run.
|
|
95
105
|
const parent = (0, _react.useContext)(_BloomThemeProvider.BloomThemeContext);
|
|
106
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
107
|
+
const scopeStyle = (0, _react.useMemo)(() => buildWebScopeVars(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
96
108
|
if (!parent) {
|
|
97
109
|
throw new Error('useColorScopeStyle must be used within a <BloomThemeProvider>');
|
|
98
110
|
}
|
|
99
|
-
|
|
100
|
-
return (0, _react.useMemo)(() => buildWebScopeVars(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
111
|
+
return scopeStyle;
|
|
101
112
|
}
|
|
102
113
|
//# sourceMappingURL=index.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["_react","_interopRequireWildcard","require","_BloomThemeProvider","_buildTheme","_styleBuilder","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","buildWebScopeVars","colorPreset","mode","buildScopeVars","BloomColorScope","asChild","style","children","parent","useContext","BloomThemeContext","
|
|
1
|
+
{"version":3,"names":["_react","_interopRequireWildcard","require","_BloomThemeProvider","_buildTheme","_styleBuilder","_jsxRuntime","e","t","WeakMap","r","n","__esModule","o","i","f","__proto__","default","has","get","set","hasOwnProperty","call","Object","defineProperty","getOwnPropertyDescriptor","buildWebScopeVars","colorPreset","mode","buildScopeVars","BloomColorScope","asChild","style","children","parent","useContext","BloomThemeContext","resolvedMode","theme","contextValue","useMemo","buildTheme","varsStyle","Error","jsx","Fragment","content","child","Children","only","isValidElement","childStyle","props","mergedStyle","cloneElement","Provider","value","useColorScopeStyle","scopeStyle"],"sourceRoot":"../../../../src","sources":["theme/color-scope/index.web.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -12,15 +12,15 @@ export function BloomColorScope({
|
|
|
12
12
|
style,
|
|
13
13
|
children
|
|
14
14
|
}) {
|
|
15
|
+
// All hooks are called UNCONDITIONALLY, in the same order on every render —
|
|
16
|
+
// never gate a hook behind an early return (rules of hooks). The conditional
|
|
17
|
+
// no-op/throw behavior is applied AFTER every hook has run, using the values
|
|
18
|
+
// the hooks produced. `resolvedMode` falls back harmlessly when the provider
|
|
19
|
+
// is absent (that render path throws below anyway).
|
|
15
20
|
const parent = useContext(BloomThemeContext);
|
|
16
|
-
|
|
17
|
-
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
18
|
-
}
|
|
19
|
-
if (!colorPreset) return /*#__PURE__*/_jsx(_Fragment, {
|
|
20
|
-
children: children
|
|
21
|
-
});
|
|
22
|
-
const resolvedMode = parent.theme.mode;
|
|
21
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
23
22
|
const contextValue = useMemo(() => {
|
|
23
|
+
if (!parent || !colorPreset) return null;
|
|
24
24
|
const theme = buildTheme(colorPreset, resolvedMode);
|
|
25
25
|
return {
|
|
26
26
|
...parent,
|
|
@@ -33,7 +33,16 @@ export function BloomColorScope({
|
|
|
33
33
|
// VariableContext (`VariableContextProvider`), NOT via an inline `vars()`
|
|
34
34
|
// style — under react-native-css@3 inline vars applied to a plain `<View>`
|
|
35
35
|
// (no matched className rules) are dropped silently. See `style-builder.ts`.
|
|
36
|
-
const nativeVars = useMemo(() => buildScopeVars(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
36
|
+
const nativeVars = useMemo(() => colorPreset ? buildScopeVars(colorPreset, resolvedMode) : null, [colorPreset, resolvedMode]);
|
|
37
|
+
if (!parent) {
|
|
38
|
+
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
39
|
+
}
|
|
40
|
+
// `colorPreset` undefined => the scope is a no-op; children inherit the
|
|
41
|
+
// parent scope. With `parent` present, `contextValue`/`nativeVars` are null
|
|
42
|
+
// iff `colorPreset` is absent, so this guard also narrows them to non-null.
|
|
43
|
+
if (!contextValue || !nativeVars) return /*#__PURE__*/_jsx(_Fragment, {
|
|
44
|
+
children: children
|
|
45
|
+
});
|
|
37
46
|
const VariableProvider = getVariableContextProvider();
|
|
38
47
|
let content;
|
|
39
48
|
if (asChild) {
|
|
@@ -82,11 +91,13 @@ export function BloomColorScope({
|
|
|
82
91
|
* `<BloomColorScope>`, which wraps children in `VariableContextProvider`.
|
|
83
92
|
*/
|
|
84
93
|
export function useColorScopeStyle(colorPreset) {
|
|
94
|
+
// Hooks first, unconditionally; throw only after they have all run.
|
|
85
95
|
const parent = useContext(BloomThemeContext);
|
|
96
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
97
|
+
const scopeStyle = useMemo(() => buildNativePresetStyle(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
86
98
|
if (!parent) {
|
|
87
99
|
throw new Error('useColorScopeStyle must be used within a <BloomThemeProvider>');
|
|
88
100
|
}
|
|
89
|
-
|
|
90
|
-
return useMemo(() => buildNativePresetStyle(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
101
|
+
return scopeStyle;
|
|
91
102
|
}
|
|
92
103
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Children","cloneElement","isValidElement","useContext","useMemo","View","BloomThemeContext","buildTheme","buildNativePresetStyle","buildScopeVars","getVariableContextProvider","Fragment","_Fragment","jsx","_jsx","BloomColorScope","colorPreset","asChild","style","children","parent","
|
|
1
|
+
{"version":3,"names":["React","Children","cloneElement","isValidElement","useContext","useMemo","View","BloomThemeContext","buildTheme","buildNativePresetStyle","buildScopeVars","getVariableContextProvider","Fragment","_Fragment","jsx","_jsx","BloomColorScope","colorPreset","asChild","style","children","parent","resolvedMode","theme","mode","contextValue","nativeVars","Error","VariableProvider","content","child","only","childStyle","props","mergedStyle","flex","scoped","value","Provider","useColorScopeStyle","scopeStyle"],"sourceRoot":"../../../../src","sources":["theme/color-scope/index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -32,15 +32,15 @@ export function BloomColorScope({
|
|
|
32
32
|
style,
|
|
33
33
|
children
|
|
34
34
|
}) {
|
|
35
|
+
// All hooks are called UNCONDITIONALLY, in the same order on every render —
|
|
36
|
+
// never gate a hook behind an early return (rules of hooks). The conditional
|
|
37
|
+
// no-op/throw behavior is applied AFTER every hook has run, using the values
|
|
38
|
+
// the hooks produced. `resolvedMode` falls back harmlessly when the provider
|
|
39
|
+
// is absent (that render path throws below anyway).
|
|
35
40
|
const parent = useContext(BloomThemeContext);
|
|
36
|
-
|
|
37
|
-
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
38
|
-
}
|
|
39
|
-
if (!colorPreset) return /*#__PURE__*/_jsx(_Fragment, {
|
|
40
|
-
children: children
|
|
41
|
-
});
|
|
42
|
-
const resolvedMode = parent.theme.mode;
|
|
41
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
43
42
|
const contextValue = useMemo(() => {
|
|
43
|
+
if (!parent || !colorPreset) return null;
|
|
44
44
|
const theme = buildTheme(colorPreset, resolvedMode);
|
|
45
45
|
return {
|
|
46
46
|
...parent,
|
|
@@ -48,7 +48,16 @@ export function BloomColorScope({
|
|
|
48
48
|
colorPreset
|
|
49
49
|
};
|
|
50
50
|
}, [colorPreset, resolvedMode, parent]);
|
|
51
|
-
const varsStyle = useMemo(() => buildWebScopeVars(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
51
|
+
const varsStyle = useMemo(() => colorPreset ? buildWebScopeVars(colorPreset, resolvedMode) : null, [colorPreset, resolvedMode]);
|
|
52
|
+
if (!parent) {
|
|
53
|
+
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
54
|
+
}
|
|
55
|
+
// `colorPreset` undefined => the scope is a no-op; children inherit the
|
|
56
|
+
// parent scope. With `parent` present, `contextValue`/`varsStyle` are null
|
|
57
|
+
// iff `colorPreset` is absent, so this guard also narrows them to non-null.
|
|
58
|
+
if (!contextValue || !varsStyle) return /*#__PURE__*/_jsx(_Fragment, {
|
|
59
|
+
children: children
|
|
60
|
+
});
|
|
52
61
|
let content;
|
|
53
62
|
if (asChild) {
|
|
54
63
|
const child = Children.only(children);
|
|
@@ -88,11 +97,13 @@ export function BloomColorScope({
|
|
|
88
97
|
* caller. Returns a stable React style object carrying the preset's CSS vars.
|
|
89
98
|
*/
|
|
90
99
|
export function useColorScopeStyle(colorPreset) {
|
|
100
|
+
// Hooks first, unconditionally; throw only after they have all run.
|
|
91
101
|
const parent = useContext(BloomThemeContext);
|
|
102
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
103
|
+
const scopeStyle = useMemo(() => buildWebScopeVars(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
92
104
|
if (!parent) {
|
|
93
105
|
throw new Error('useColorScopeStyle must be used within a <BloomThemeProvider>');
|
|
94
106
|
}
|
|
95
|
-
|
|
96
|
-
return useMemo(() => buildWebScopeVars(colorPreset, resolvedMode), [colorPreset, resolvedMode]);
|
|
107
|
+
return scopeStyle;
|
|
97
108
|
}
|
|
98
109
|
//# sourceMappingURL=index.web.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["React","Children","cloneElement","isValidElement","useContext","useMemo","BloomThemeContext","buildTheme","buildScopeVars","Fragment","_Fragment","jsx","_jsx","buildWebScopeVars","colorPreset","mode","BloomColorScope","asChild","style","children","parent","
|
|
1
|
+
{"version":3,"names":["React","Children","cloneElement","isValidElement","useContext","useMemo","BloomThemeContext","buildTheme","buildScopeVars","Fragment","_Fragment","jsx","_jsx","buildWebScopeVars","colorPreset","mode","BloomColorScope","asChild","style","children","parent","resolvedMode","theme","contextValue","varsStyle","Error","content","child","only","childStyle","props","mergedStyle","Provider","value","useColorScopeStyle","scopeStyle"],"sourceRoot":"../../../../src","sources":["theme/color-scope/index.web.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAC3F,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAIpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0GAA0G;IAC1G,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAMD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAC3F,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAIpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0GAA0G;IAC1G,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAMD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,2CA4DtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,CAYlF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAI3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yGAAyG;IACzG,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAI3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yGAAyG;IACzG,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,2CAoDtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,YAAY,GAAG,KAAK,CAAC,aAAa,CAYjF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAC3F,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAIpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0GAA0G;IAC1G,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAMD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAC3F,OAAO,EAAQ,KAAK,SAAS,EAAE,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAIpE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,0GAA0G;IAC1G,KAAK,CAAC,EAAE,SAAS,CAAC,SAAS,CAAC,CAAC;IAC7B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAMD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,2CA4DtB;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC,SAAS,CAAC,CAYlF"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAI3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yGAAyG;IACzG,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,
|
|
1
|
+
{"version":3,"file":"index.web.d.ts","sourceRoot":"","sources":["../../../../../src/theme/color-scope/index.web.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAsE,MAAM,OAAO,CAAC;AAI3F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAgBrD,MAAM,WAAW,oBAAoB;IACnC;;;OAGG;IACH,WAAW,EAAE,YAAY,GAAG,SAAS,CAAC;IACtC;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,yGAAyG;IACzG,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;IAC5B,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAuBD,wBAAgB,eAAe,CAAC,EAC9B,WAAW,EACX,OAAe,EACf,KAAK,EACL,QAAQ,GACT,EAAE,oBAAoB,2CAoDtB;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,YAAY,GAAG,KAAK,CAAC,aAAa,CAYjF"}
|
package/package.json
CHANGED
|
@@ -76,6 +76,72 @@ describe('BloomColorScope', () => {
|
|
|
76
76
|
consoleError.mockRestore();
|
|
77
77
|
});
|
|
78
78
|
|
|
79
|
+
// Regression: a Rules-of-Hooks violation (caught at runtime on a real Android
|
|
80
|
+
// device) where an early return between `useContext` and the `useMemo` calls
|
|
81
|
+
// changed the hook count/order when `colorPreset` toggled undefined <-> set:
|
|
82
|
+
// "React has detected a change in the order of Hooks called by
|
|
83
|
+
// BloomColorScope. Previous render: 1. useContext 2. undefined.
|
|
84
|
+
// Next render: 1. useContext 2. useMemo".
|
|
85
|
+
// All hooks must now run unconditionally on every render, so toggling the
|
|
86
|
+
// preset must neither warn about hook order nor throw.
|
|
87
|
+
it.each([
|
|
88
|
+
['native variant (index)', BloomColorScope] as const,
|
|
89
|
+
['web variant (index.web)', BloomColorScopeWeb] as const,
|
|
90
|
+
])(
|
|
91
|
+
'does not change hook order when colorPreset toggles undefined <-> set (%s)',
|
|
92
|
+
(_label, Scope) => {
|
|
93
|
+
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
94
|
+
|
|
95
|
+
// First render: no preset -> the bug ran only `useContext` (1 hook).
|
|
96
|
+
const { rerender, getByTestId } = render(
|
|
97
|
+
<BloomThemeProvider defaultColorPreset="blue" fonts={false}>
|
|
98
|
+
<Scope colorPreset={undefined}>
|
|
99
|
+
<CurrentPreset />
|
|
100
|
+
</Scope>
|
|
101
|
+
</BloomThemeProvider>,
|
|
102
|
+
);
|
|
103
|
+
expect(getByTestId('preset').props.children).toBe('blue');
|
|
104
|
+
|
|
105
|
+
// Re-render with a preset -> the bug now ran `useContext` + 2x `useMemo`,
|
|
106
|
+
// changing the hook order between renders. Must not throw or warn.
|
|
107
|
+
expect(() =>
|
|
108
|
+
rerender(
|
|
109
|
+
<BloomThemeProvider defaultColorPreset="blue" fonts={false}>
|
|
110
|
+
<Scope colorPreset="green">
|
|
111
|
+
<CurrentPreset />
|
|
112
|
+
</Scope>
|
|
113
|
+
</BloomThemeProvider>,
|
|
114
|
+
),
|
|
115
|
+
).not.toThrow();
|
|
116
|
+
expect(getByTestId('preset').props.children).toBe('green');
|
|
117
|
+
|
|
118
|
+
// Toggle back to undefined to exercise the reverse transition.
|
|
119
|
+
expect(() =>
|
|
120
|
+
rerender(
|
|
121
|
+
<BloomThemeProvider defaultColorPreset="blue" fonts={false}>
|
|
122
|
+
<Scope colorPreset={undefined}>
|
|
123
|
+
<CurrentPreset />
|
|
124
|
+
</Scope>
|
|
125
|
+
</BloomThemeProvider>,
|
|
126
|
+
),
|
|
127
|
+
).not.toThrow();
|
|
128
|
+
expect(getByTestId('preset').props.children).toBe('blue');
|
|
129
|
+
|
|
130
|
+
const hookOrderWarning = consoleError.mock.calls.some((args) =>
|
|
131
|
+
args.some(
|
|
132
|
+
(arg) =>
|
|
133
|
+
typeof arg === 'string' &&
|
|
134
|
+
(arg.includes('order of Hooks') ||
|
|
135
|
+
arg.includes('Rendered more hooks') ||
|
|
136
|
+
arg.includes('Rendered fewer hooks')),
|
|
137
|
+
),
|
|
138
|
+
);
|
|
139
|
+
expect(hookOrderWarning).toBe(false);
|
|
140
|
+
|
|
141
|
+
consoleError.mockRestore();
|
|
142
|
+
},
|
|
143
|
+
);
|
|
144
|
+
|
|
79
145
|
it('throws when used outside BloomThemeProvider', () => {
|
|
80
146
|
const consoleError = jest.spyOn(console, 'error').mockImplementation(() => {});
|
|
81
147
|
expect(() =>
|
|
@@ -32,16 +32,16 @@ export function BloomColorScope({
|
|
|
32
32
|
style,
|
|
33
33
|
children,
|
|
34
34
|
}: BloomColorScopeProps) {
|
|
35
|
+
// All hooks are called UNCONDITIONALLY, in the same order on every render —
|
|
36
|
+
// never gate a hook behind an early return (rules of hooks). The conditional
|
|
37
|
+
// no-op/throw behavior is applied AFTER every hook has run, using the values
|
|
38
|
+
// the hooks produced. `resolvedMode` falls back harmlessly when the provider
|
|
39
|
+
// is absent (that render path throws below anyway).
|
|
35
40
|
const parent = useContext(BloomThemeContext);
|
|
36
|
-
|
|
37
|
-
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (!colorPreset) return <>{children}</>;
|
|
41
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
41
42
|
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
const contextValue = useMemo<BloomThemeContextValue>(() => {
|
|
43
|
+
const contextValue = useMemo<BloomThemeContextValue | null>(() => {
|
|
44
|
+
if (!parent || !colorPreset) return null;
|
|
45
45
|
const theme = buildTheme(colorPreset, resolvedMode);
|
|
46
46
|
return { ...parent, theme, colorPreset };
|
|
47
47
|
}, [colorPreset, resolvedMode, parent]);
|
|
@@ -50,10 +50,19 @@ export function BloomColorScope({
|
|
|
50
50
|
// VariableContext (`VariableContextProvider`), NOT via an inline `vars()`
|
|
51
51
|
// style — under react-native-css@3 inline vars applied to a plain `<View>`
|
|
52
52
|
// (no matched className rules) are dropped silently. See `style-builder.ts`.
|
|
53
|
-
const nativeVars = useMemo(
|
|
54
|
-
() => buildScopeVars(colorPreset, resolvedMode),
|
|
53
|
+
const nativeVars = useMemo<Record<string, string> | null>(
|
|
54
|
+
() => (colorPreset ? buildScopeVars(colorPreset, resolvedMode) : null),
|
|
55
55
|
[colorPreset, resolvedMode],
|
|
56
56
|
);
|
|
57
|
+
|
|
58
|
+
if (!parent) {
|
|
59
|
+
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
60
|
+
}
|
|
61
|
+
// `colorPreset` undefined => the scope is a no-op; children inherit the
|
|
62
|
+
// parent scope. With `parent` present, `contextValue`/`nativeVars` are null
|
|
63
|
+
// iff `colorPreset` is absent, so this guard also narrows them to non-null.
|
|
64
|
+
if (!contextValue || !nativeVars) return <>{children}</>;
|
|
65
|
+
|
|
57
66
|
const VariableProvider = getVariableContextProvider();
|
|
58
67
|
|
|
59
68
|
let content: React.ReactNode;
|
|
@@ -97,13 +106,15 @@ export function BloomColorScope({
|
|
|
97
106
|
* `<BloomColorScope>`, which wraps children in `VariableContextProvider`.
|
|
98
107
|
*/
|
|
99
108
|
export function useColorScopeStyle(colorPreset: AppColorName): StyleProp<ViewStyle> {
|
|
109
|
+
// Hooks first, unconditionally; throw only after they have all run.
|
|
100
110
|
const parent = useContext(BloomThemeContext);
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
const resolvedMode = parent.theme.mode;
|
|
105
|
-
return useMemo(
|
|
111
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
112
|
+
const scopeStyle = useMemo(
|
|
106
113
|
() => buildNativePresetStyle(colorPreset, resolvedMode),
|
|
107
114
|
[colorPreset, resolvedMode],
|
|
108
115
|
);
|
|
116
|
+
if (!parent) {
|
|
117
|
+
throw new Error('useColorScopeStyle must be used within a <BloomThemeProvider>');
|
|
118
|
+
}
|
|
119
|
+
return scopeStyle;
|
|
109
120
|
}
|
|
@@ -61,25 +61,33 @@ export function BloomColorScope({
|
|
|
61
61
|
style,
|
|
62
62
|
children,
|
|
63
63
|
}: BloomColorScopeProps) {
|
|
64
|
+
// All hooks are called UNCONDITIONALLY, in the same order on every render —
|
|
65
|
+
// never gate a hook behind an early return (rules of hooks). The conditional
|
|
66
|
+
// no-op/throw behavior is applied AFTER every hook has run, using the values
|
|
67
|
+
// the hooks produced. `resolvedMode` falls back harmlessly when the provider
|
|
68
|
+
// is absent (that render path throws below anyway).
|
|
64
69
|
const parent = useContext(BloomThemeContext);
|
|
65
|
-
|
|
66
|
-
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
if (!colorPreset) return <>{children}</>;
|
|
70
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
70
71
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
const contextValue = useMemo<BloomThemeContextValue>(() => {
|
|
72
|
+
const contextValue = useMemo<BloomThemeContextValue | null>(() => {
|
|
73
|
+
if (!parent || !colorPreset) return null;
|
|
74
74
|
const theme = buildTheme(colorPreset, resolvedMode);
|
|
75
75
|
return { ...parent, theme, colorPreset };
|
|
76
76
|
}, [colorPreset, resolvedMode, parent]);
|
|
77
77
|
|
|
78
|
-
const varsStyle = useMemo(
|
|
79
|
-
() => buildWebScopeVars(colorPreset, resolvedMode),
|
|
78
|
+
const varsStyle = useMemo<React.CSSProperties | null>(
|
|
79
|
+
() => (colorPreset ? buildWebScopeVars(colorPreset, resolvedMode) : null),
|
|
80
80
|
[colorPreset, resolvedMode],
|
|
81
81
|
);
|
|
82
82
|
|
|
83
|
+
if (!parent) {
|
|
84
|
+
throw new Error('BloomColorScope must be used within a <BloomThemeProvider>');
|
|
85
|
+
}
|
|
86
|
+
// `colorPreset` undefined => the scope is a no-op; children inherit the
|
|
87
|
+
// parent scope. With `parent` present, `contextValue`/`varsStyle` are null
|
|
88
|
+
// iff `colorPreset` is absent, so this guard also narrows them to non-null.
|
|
89
|
+
if (!contextValue || !varsStyle) return <>{children}</>;
|
|
90
|
+
|
|
83
91
|
let content: React.ReactNode;
|
|
84
92
|
if (asChild) {
|
|
85
93
|
const child = Children.only(children);
|
|
@@ -111,13 +119,15 @@ export function BloomColorScope({
|
|
|
111
119
|
* caller. Returns a stable React style object carrying the preset's CSS vars.
|
|
112
120
|
*/
|
|
113
121
|
export function useColorScopeStyle(colorPreset: AppColorName): React.CSSProperties {
|
|
122
|
+
// Hooks first, unconditionally; throw only after they have all run.
|
|
114
123
|
const parent = useContext(BloomThemeContext);
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
118
|
-
const resolvedMode = parent.theme.mode;
|
|
119
|
-
return useMemo(
|
|
124
|
+
const resolvedMode = parent?.theme.mode ?? 'light';
|
|
125
|
+
const scopeStyle = useMemo(
|
|
120
126
|
() => buildWebScopeVars(colorPreset, resolvedMode),
|
|
121
127
|
[colorPreset, resolvedMode],
|
|
122
128
|
);
|
|
129
|
+
if (!parent) {
|
|
130
|
+
throw new Error('useColorScopeStyle must be used within a <BloomThemeProvider>');
|
|
131
|
+
}
|
|
132
|
+
return scopeStyle;
|
|
123
133
|
}
|