@thewhileloop/whileui 4.2.1 → 4.2.3
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.
|
@@ -79,7 +79,7 @@ export function Sheet({ open, onOpenChange, children, maxHeight = 'full', maxWid
|
|
|
79
79
|
widthStyle,
|
|
80
80
|
frostedSurface.surfaceStyle,
|
|
81
81
|
];
|
|
82
|
-
return (_jsx(OverlayHost, { open: mounted, animationType: "none", onRequestClose: onClose, children: _jsxs(View, { className: "flex-1 justify-end", children: [_jsx(Animated.View, { style: [
|
|
82
|
+
return (_jsx(OverlayHost, { open: mounted, animationType: "none", onRequestClose: open ? onClose : undefined, children: _jsxs(View, { className: "flex-1 justify-end", children: [_jsx(Animated.View, { style: [
|
|
83
83
|
StyleSheet.absoluteFill,
|
|
84
84
|
{ backgroundColor: frosted ? 'transparent' : colors.overlay },
|
|
85
85
|
backdropStyle,
|
|
@@ -125,5 +125,5 @@ export function DrawerMenu({ visible, onClose, sections, activeKey, onSelect, he
|
|
|
125
125
|
frostedSurface.surfaceStyle,
|
|
126
126
|
style,
|
|
127
127
|
], className: drawerPanelClassName(frosted, className), children: [frostedSurface.overlay, _jsxs(View, { className: "flex-1 pb-8", style: { paddingTop: contentTopPadding }, children: [header && _jsx(View, { className: "px-5 pb-4 mb-2 border-b border-border", children: header }), _jsx(DrawerSectionList, { sections: sections, activeKey: activeKey, onSelect: handleItemPress, interaction: interaction, visual: visual }), footer && _jsx(View, { className: "px-5 py-4 mt-auto border-t border-border", children: footer })] })] })] }));
|
|
128
|
-
return (_jsx(OverlayHost, { open: mounted, animationType: "none", onRequestClose: onClose, children: drawerTree }));
|
|
128
|
+
return (_jsx(OverlayHost, { open: mounted, animationType: "none", onRequestClose: visible ? onClose : undefined, children: drawerTree }));
|
|
129
129
|
}
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { type ThemeColors } from './theme-contract';
|
|
2
2
|
export type { ThemeColors } from './theme-contract';
|
|
3
3
|
export declare function useThemeColors(): ThemeColors;
|
|
4
|
-
|
|
5
|
-
export declare function useIconColors(): {
|
|
4
|
+
export interface IconColors {
|
|
6
5
|
foreground: string;
|
|
7
6
|
muted: string;
|
|
8
7
|
primary: string;
|
|
@@ -12,6 +11,8 @@ export declare function useIconColors(): {
|
|
|
12
11
|
success: string;
|
|
13
12
|
info: string;
|
|
14
13
|
destructive: string;
|
|
15
|
-
}
|
|
14
|
+
}
|
|
15
|
+
/** Icon colors derived from theme. For @expo/vector-icons which need hex values. */
|
|
16
|
+
export declare function useIconColors(): IconColors;
|
|
16
17
|
/** Alias for useThemeColors. Returns RN-safe color strings (hex/rgb/rgba) for RefreshControl, LinearGradient, charts. */
|
|
17
18
|
export declare const useThemeTokens: typeof useThemeColors;
|
package/dist/lib/theme-colors.js
CHANGED
|
@@ -41,10 +41,29 @@ function resolveThemeToken(cssValue, appValue) {
|
|
|
41
41
|
}
|
|
42
42
|
return parseThemeColor(cssValue) ?? parseThemeColor(appValue);
|
|
43
43
|
}
|
|
44
|
+
// Every themed component calls this hook on every render, and parsing 104 colour
|
|
45
|
+
// strings plus deriving the palette cost about 0.16 ms per call in Node, several times
|
|
46
|
+
// that under Hermes. The inputs only change with the theme, so the result is derived
|
|
47
|
+
// once per distinct snapshot and shared: the same object comes back until the CSS
|
|
48
|
+
// variables change, which also keeps it stable for downstream memoisation.
|
|
49
|
+
const resolvedThemeColors = new Map();
|
|
50
|
+
const RESOLVED_THEME_LIMIT = 8;
|
|
44
51
|
export function useThemeColors() {
|
|
45
52
|
const { theme } = useUniwind();
|
|
46
53
|
const values = useCSSVariable(THEME_TOKEN_VARIABLES);
|
|
47
54
|
const scheme = theme === 'dark' ? 'dark' : 'light';
|
|
55
|
+
const key = `${scheme}\u0001${values.join('\u0001')}`;
|
|
56
|
+
const cached = resolvedThemeColors.get(key);
|
|
57
|
+
if (cached)
|
|
58
|
+
return cached;
|
|
59
|
+
const resolved = resolveThemeColors(values, scheme);
|
|
60
|
+
if (resolvedThemeColors.size >= RESOLVED_THEME_LIMIT) {
|
|
61
|
+
resolvedThemeColors.delete(resolvedThemeColors.keys().next().value);
|
|
62
|
+
}
|
|
63
|
+
resolvedThemeColors.set(key, resolved);
|
|
64
|
+
return resolved;
|
|
65
|
+
}
|
|
66
|
+
function resolveThemeColors(values, scheme) {
|
|
48
67
|
const fallbackPalette = scheme === 'dark' ? WHILEUI_DARK_THEME_COLORS : WHILEUI_LIGHT_THEME_COLORS;
|
|
49
68
|
const defined = {};
|
|
50
69
|
let index = 0;
|
|
@@ -61,10 +80,14 @@ export function useThemeColors() {
|
|
|
61
80
|
const derived = deriveThemeColors(base, scheme);
|
|
62
81
|
return { ...derived, ...defined, placeholder: derived.placeholder };
|
|
63
82
|
}
|
|
83
|
+
const iconColorsByTheme = new WeakMap();
|
|
64
84
|
/** Icon colors derived from theme. For @expo/vector-icons which need hex values. */
|
|
65
85
|
export function useIconColors() {
|
|
66
86
|
const c = useThemeColors();
|
|
67
|
-
|
|
87
|
+
const cached = iconColorsByTheme.get(c);
|
|
88
|
+
if (cached)
|
|
89
|
+
return cached;
|
|
90
|
+
const icons = {
|
|
68
91
|
foreground: c.foreground,
|
|
69
92
|
muted: c.mutedForeground,
|
|
70
93
|
primary: c.primary,
|
|
@@ -75,6 +98,8 @@ export function useIconColors() {
|
|
|
75
98
|
info: c.info,
|
|
76
99
|
destructive: c.destructive,
|
|
77
100
|
};
|
|
101
|
+
iconColorsByTheme.set(c, icons);
|
|
102
|
+
return icons;
|
|
78
103
|
}
|
|
79
104
|
/** Alias for useThemeColors. Returns RN-safe color strings (hex/rgb/rgba) for RefreshControl, LinearGradient, charts. */
|
|
80
105
|
export const useThemeTokens = useThemeColors;
|
|
@@ -28,11 +28,24 @@ function resolveVisualToken(spec, value) {
|
|
|
28
28
|
}
|
|
29
29
|
return parseRatio(value, spec.fallback, spec.min ?? 0, spec.max ?? 1);
|
|
30
30
|
}
|
|
31
|
+
// Resolved once per distinct CSS snapshot and shared, for the same reason as
|
|
32
|
+
// `useThemeColors`: 83 parses per component per render add up on a list screen, and a
|
|
33
|
+
// stable object lets callers memoise on it.
|
|
34
|
+
const resolvedVisualTokens = new Map();
|
|
35
|
+
const RESOLVED_VISUAL_LIMIT = 8;
|
|
31
36
|
export function useVisualTokens() {
|
|
32
37
|
const values = useCSSVariable(VISUAL_TOKEN_VARIABLES);
|
|
38
|
+
const key = values.join('\u0001');
|
|
39
|
+
const cached = resolvedVisualTokens.get(key);
|
|
40
|
+
if (cached)
|
|
41
|
+
return cached;
|
|
33
42
|
const resolved = {};
|
|
34
43
|
VISUAL_TOKEN_SPECS.forEach((spec, index) => {
|
|
35
44
|
resolved[spec.key] = resolveVisualToken(spec, values[index]);
|
|
36
45
|
});
|
|
46
|
+
if (resolvedVisualTokens.size >= RESOLVED_VISUAL_LIMIT) {
|
|
47
|
+
resolvedVisualTokens.delete(resolvedVisualTokens.keys().next().value);
|
|
48
|
+
}
|
|
49
|
+
resolvedVisualTokens.set(key, resolved);
|
|
37
50
|
return resolved;
|
|
38
51
|
}
|
package/dist/metro.cjs
CHANGED
|
@@ -12,6 +12,11 @@ const { withUniwindConfig } = require('uniwind/metro');
|
|
|
12
12
|
const NEEDS_REAL_REACT_NATIVE = ['expo-asset', 'expo-font', '@expo/vector-icons'];
|
|
13
13
|
|
|
14
14
|
function withWhileUIMetro(config, options) {
|
|
15
|
+
if (!options || typeof options.cssEntryFile !== 'string') {
|
|
16
|
+
throw new Error(
|
|
17
|
+
"withWhileUIMetro(config, options): pass Uniwind's options, at least { cssEntryFile: './global.css' }"
|
|
18
|
+
);
|
|
19
|
+
}
|
|
15
20
|
const { exemptFromUniwindRewrite = [], ...uniwindOptions } = options;
|
|
16
21
|
const wrapped = withUniwindConfig(config, uniwindOptions);
|
|
17
22
|
const exempt = [...NEEDS_REAL_REACT_NATIVE, ...exemptFromUniwindRewrite];
|
|
@@ -19,7 +24,8 @@ function withWhileUIMetro(config, options) {
|
|
|
19
24
|
|
|
20
25
|
wrapped.resolver.resolveRequest = (context, moduleName, platform) => {
|
|
21
26
|
if (moduleName === 'react-native') {
|
|
22
|
-
|
|
27
|
+
// Metro reports Windows paths with backslashes; match either separator.
|
|
28
|
+
const origin = (context.originModulePath ?? '').replace(/\\/g, '/');
|
|
23
29
|
if (exempt.some((pkg) => origin.includes(`node_modules/${pkg}/`))) {
|
|
24
30
|
return context.resolveRequest(context, moduleName, platform);
|
|
25
31
|
}
|