mirror of
https://github.com/getpaseo/paseo.git
synced 2026-11-01 06:02:56 +00:00
A style update racing a window resize could recommit old root constraints. Rebuild the style update from the current root on each commit attempt.
764 lines
35 KiB
Diff
764 lines
35 KiB
Diff
diff --git a/node_modules/react-native-unistyles/lib/commonjs/web/registry.js b/node_modules/react-native-unistyles/lib/commonjs/web/registry.js
|
|
index 120ff60..d1ff102 100644
|
|
--- a/node_modules/react-native-unistyles/lib/commonjs/web/registry.js
|
|
+++ b/node_modules/react-native-unistyles/lib/commonjs/web/registry.js
|
|
@@ -10,6 +10,17 @@ class UnistylesRegistry {
|
|
stylesheets = new Map();
|
|
stylesCache = new Set();
|
|
stylesCounter = new Map();
|
|
+ cleanupGeneration = 0;
|
|
+ finalizerTokens = new WeakMap();
|
|
+ finalizationRegistry = typeof FinalizationRegistry === 'undefined' ? undefined : new FinalizationRegistry(({
|
|
+ hash,
|
|
+ generation
|
|
+ }) => {
|
|
+ if (generation !== this.cleanupGeneration) {
|
|
+ return;
|
|
+ }
|
|
+ this.decrementAndMaybeCleanup(hash);
|
|
+ });
|
|
disposeListenersMap = new Map();
|
|
dependenciesMap = new Map();
|
|
constructor(services) {
|
|
@@ -50,26 +61,48 @@ class UnistylesRegistry {
|
|
this.disposeListenersMap.set(stylesheet, dispose);
|
|
};
|
|
connect = (ref, hash) => {
|
|
- const stylesCounter = this.stylesCounter.get(hash) ?? new Set();
|
|
- stylesCounter.add(ref);
|
|
- this.stylesCounter.set(hash, stylesCounter);
|
|
+ this.stylesCounter.set(hash, (this.stylesCounter.get(hash) ?? 0) + 1);
|
|
+ if (!this.finalizationRegistry) {
|
|
+ return;
|
|
+ }
|
|
+ const token = {};
|
|
+ const tokensByHash = this.finalizerTokens.get(ref) ?? new Map();
|
|
+ const tokens = tokensByHash.get(hash) ?? [];
|
|
+ tokens.push(token);
|
|
+ tokensByHash.set(hash, tokens);
|
|
+ this.finalizerTokens.set(ref, tokensByHash);
|
|
+ this.finalizationRegistry.register(ref, {
|
|
+ hash,
|
|
+ generation: this.cleanupGeneration
|
|
+ }, token);
|
|
};
|
|
remove = (ref, hash) => {
|
|
- const stylesCounter = this.stylesCounter.get(hash) ?? new Set();
|
|
- stylesCounter.delete(ref);
|
|
- if (stylesCounter.size === 0) {
|
|
- // Move this to the end of the event loop so the element is removed from the DOM
|
|
- return Promise.resolve().then(() => {
|
|
- // Check if element is still in the DOM
|
|
- if (document.querySelector(`.${hash}`)) {
|
|
- return false;
|
|
- }
|
|
- this.css.remove(hash);
|
|
- this.stylesCache.delete(hash);
|
|
- return true;
|
|
- });
|
|
+ const token = this.finalizerTokens.get(ref)?.get(hash)?.pop();
|
|
+ if (token) {
|
|
+ this.finalizationRegistry?.unregister(token);
|
|
+ }
|
|
+ return this.decrementAndMaybeCleanup(hash);
|
|
+ };
|
|
+ decrementAndMaybeCleanup = hash => {
|
|
+ const next = (this.stylesCounter.get(hash) ?? 0) - 1;
|
|
+ if (next > 0) {
|
|
+ this.stylesCounter.set(hash, next);
|
|
+ return Promise.resolve(false);
|
|
}
|
|
- return Promise.resolve(false);
|
|
+ this.stylesCounter.delete(hash);
|
|
+ // Move this to the end of the event loop so the element is removed from the DOM
|
|
+ return Promise.resolve().then(() => {
|
|
+ // Check if element is still in the DOM
|
|
+ if ((this.stylesCounter.get(hash) ?? 0) > 0) {
|
|
+ return false;
|
|
+ }
|
|
+ if (document.querySelector(`.${hash}`)) {
|
|
+ return false;
|
|
+ }
|
|
+ this.css.remove(hash);
|
|
+ this.stylesCache.delete(hash);
|
|
+ return true;
|
|
+ });
|
|
};
|
|
add = (value, forChild) => {
|
|
const generatedHash = (0, _utils.generateHash)(value);
|
|
@@ -91,7 +124,10 @@ class UnistylesRegistry {
|
|
this.css.add(hash, value);
|
|
};
|
|
reset = () => {
|
|
+ this.cleanupGeneration += 1;
|
|
+ this.disposeListenersMap.forEach(dispose => dispose());
|
|
this.css.reset();
|
|
+ this.stylesheets.clear();
|
|
this.stylesCache.clear();
|
|
this.dependenciesMap.clear();
|
|
this.disposeListenersMap.clear();
|
|
diff --git a/node_modules/react-native-unistyles/lib/module/web/registry.js b/node_modules/react-native-unistyles/lib/module/web/registry.js
|
|
index 6362f43..8e769f8 100644
|
|
--- a/node_modules/react-native-unistyles/lib/module/web/registry.js
|
|
+++ b/node_modules/react-native-unistyles/lib/module/web/registry.js
|
|
@@ -6,6 +6,17 @@ export class UnistylesRegistry {
|
|
stylesheets = new Map();
|
|
stylesCache = new Set();
|
|
stylesCounter = new Map();
|
|
+ cleanupGeneration = 0;
|
|
+ finalizerTokens = new WeakMap();
|
|
+ finalizationRegistry = typeof FinalizationRegistry === 'undefined' ? undefined : new FinalizationRegistry(({
|
|
+ hash,
|
|
+ generation
|
|
+ }) => {
|
|
+ if (generation !== this.cleanupGeneration) {
|
|
+ return;
|
|
+ }
|
|
+ this.decrementAndMaybeCleanup(hash);
|
|
+ });
|
|
disposeListenersMap = new Map();
|
|
dependenciesMap = new Map();
|
|
constructor(services) {
|
|
@@ -46,26 +57,48 @@ export class UnistylesRegistry {
|
|
this.disposeListenersMap.set(stylesheet, dispose);
|
|
};
|
|
connect = (ref, hash) => {
|
|
- const stylesCounter = this.stylesCounter.get(hash) ?? new Set();
|
|
- stylesCounter.add(ref);
|
|
- this.stylesCounter.set(hash, stylesCounter);
|
|
+ this.stylesCounter.set(hash, (this.stylesCounter.get(hash) ?? 0) + 1);
|
|
+ if (!this.finalizationRegistry) {
|
|
+ return;
|
|
+ }
|
|
+ const token = {};
|
|
+ const tokensByHash = this.finalizerTokens.get(ref) ?? new Map();
|
|
+ const tokens = tokensByHash.get(hash) ?? [];
|
|
+ tokens.push(token);
|
|
+ tokensByHash.set(hash, tokens);
|
|
+ this.finalizerTokens.set(ref, tokensByHash);
|
|
+ this.finalizationRegistry.register(ref, {
|
|
+ hash,
|
|
+ generation: this.cleanupGeneration
|
|
+ }, token);
|
|
};
|
|
remove = (ref, hash) => {
|
|
- const stylesCounter = this.stylesCounter.get(hash) ?? new Set();
|
|
- stylesCounter.delete(ref);
|
|
- if (stylesCounter.size === 0) {
|
|
- // Move this to the end of the event loop so the element is removed from the DOM
|
|
- return Promise.resolve().then(() => {
|
|
- // Check if element is still in the DOM
|
|
- if (document.querySelector(`.${hash}`)) {
|
|
- return false;
|
|
- }
|
|
- this.css.remove(hash);
|
|
- this.stylesCache.delete(hash);
|
|
- return true;
|
|
- });
|
|
+ const token = this.finalizerTokens.get(ref)?.get(hash)?.pop();
|
|
+ if (token) {
|
|
+ this.finalizationRegistry?.unregister(token);
|
|
+ }
|
|
+ return this.decrementAndMaybeCleanup(hash);
|
|
+ };
|
|
+ decrementAndMaybeCleanup = hash => {
|
|
+ const next = (this.stylesCounter.get(hash) ?? 0) - 1;
|
|
+ if (next > 0) {
|
|
+ this.stylesCounter.set(hash, next);
|
|
+ return Promise.resolve(false);
|
|
}
|
|
- return Promise.resolve(false);
|
|
+ this.stylesCounter.delete(hash);
|
|
+ // Move this to the end of the event loop so the element is removed from the DOM
|
|
+ return Promise.resolve().then(() => {
|
|
+ // Check if element is still in the DOM
|
|
+ if ((this.stylesCounter.get(hash) ?? 0) > 0) {
|
|
+ return false;
|
|
+ }
|
|
+ if (document.querySelector(`.${hash}`)) {
|
|
+ return false;
|
|
+ }
|
|
+ this.css.remove(hash);
|
|
+ this.stylesCache.delete(hash);
|
|
+ return true;
|
|
+ });
|
|
};
|
|
add = (value, forChild) => {
|
|
const generatedHash = generateHash(value);
|
|
@@ -87,7 +120,10 @@ export class UnistylesRegistry {
|
|
this.css.add(hash, value);
|
|
};
|
|
reset = () => {
|
|
+ this.cleanupGeneration += 1;
|
|
+ this.disposeListenersMap.forEach(dispose => dispose());
|
|
this.css.reset();
|
|
+ this.stylesheets.clear();
|
|
this.stylesCache.clear();
|
|
this.dependenciesMap.clear();
|
|
this.disposeListenersMap.clear();
|
|
diff --git a/node_modules/react-native-unistyles/src/web/registry.ts b/node_modules/react-native-unistyles/src/web/registry.ts
|
|
index 39e0d9d..a21ba95 100644
|
|
--- a/node_modules/react-native-unistyles/src/web/registry.ts
|
|
+++ b/node_modules/react-native-unistyles/src/web/registry.ts
|
|
@@ -9,7 +9,24 @@ import { error, extractUnistyleDependencies, generateHash } from './utils'
|
|
export class UnistylesRegistry {
|
|
private readonly stylesheets = new Map<StyleSheetWithSuperPowers<StyleSheet>, StyleSheet>()
|
|
private readonly stylesCache = new Set<string>()
|
|
- private readonly stylesCounter = new Map<string, Set<HTMLElement>>()
|
|
+ // Use counter instead of Set<HTMLElement> to avoid retaining detached DOM nodes
|
|
+ // FR is a fallback when remove() is missed
|
|
+ private readonly stylesCounter = new Map<string, number>()
|
|
+ // Bumped on reset() so stale FR callbacks are ignored
|
|
+ private cleanupGeneration = 0
|
|
+ // Per-registration unregister token, so remove() cancels only its own registration
|
|
+ private readonly finalizerTokens = new WeakMap<HTMLElement, Map<string, Array<object>>>()
|
|
+ // FR isn't available on every runtime - fall back to counter-only cleanup
|
|
+ private readonly finalizationRegistry =
|
|
+ typeof FinalizationRegistry === 'undefined'
|
|
+ ? undefined
|
|
+ : new FinalizationRegistry<{ hash: string; generation: number }>(({ hash, generation }) => {
|
|
+ if (generation !== this.cleanupGeneration) {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ this.decrementAndMaybeCleanup(hash)
|
|
+ })
|
|
private readonly disposeListenersMap = new Map<object, VoidFunction>()
|
|
private readonly dependenciesMap = new Map<StyleSheetWithSuperPowers<StyleSheet>, Set<UnistyleDependency>>()
|
|
readonly css: CSSState
|
|
@@ -78,33 +95,61 @@ export class UnistylesRegistry {
|
|
}
|
|
|
|
connect = (ref: HTMLElement, hash: string) => {
|
|
- const stylesCounter = this.stylesCounter.get(hash) ?? new Set()
|
|
+ this.stylesCounter.set(hash, (this.stylesCounter.get(hash) ?? 0) + 1)
|
|
|
|
- stylesCounter.add(ref)
|
|
- this.stylesCounter.set(hash, stylesCounter)
|
|
+ if (!this.finalizationRegistry) {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ const token = {}
|
|
+ const tokensByHash = this.finalizerTokens.get(ref) ?? new Map<string, Array<object>>()
|
|
+ const tokens = tokensByHash.get(hash) ?? []
|
|
+
|
|
+ tokens.push(token)
|
|
+ tokensByHash.set(hash, tokens)
|
|
+ this.finalizerTokens.set(ref, tokensByHash)
|
|
+ this.finalizationRegistry.register(ref, { hash, generation: this.cleanupGeneration }, token)
|
|
}
|
|
|
|
remove = (ref: HTMLElement, hash: string) => {
|
|
- const stylesCounter = this.stylesCounter.get(hash) ?? new Set()
|
|
+ const token = this.finalizerTokens.get(ref)?.get(hash)?.pop()
|
|
|
|
- stylesCounter.delete(ref)
|
|
+ if (token) {
|
|
+ this.finalizationRegistry?.unregister(token)
|
|
+ }
|
|
|
|
- if (stylesCounter.size === 0) {
|
|
- // Move this to the end of the event loop so the element is removed from the DOM
|
|
- return Promise.resolve().then(() => {
|
|
- // Check if element is still in the DOM
|
|
- if (document.querySelector(`.${hash}`)) {
|
|
- return false
|
|
- }
|
|
+ return this.decrementAndMaybeCleanup(hash)
|
|
+ }
|
|
+
|
|
+ private decrementAndMaybeCleanup = (hash: string): Promise<boolean> => {
|
|
+ const next = (this.stylesCounter.get(hash) ?? 0) - 1
|
|
|
|
- this.css.remove(hash)
|
|
- this.stylesCache.delete(hash)
|
|
+ if (next > 0) {
|
|
+ this.stylesCounter.set(hash, next)
|
|
|
|
- return true
|
|
- })
|
|
+ return Promise.resolve(false)
|
|
}
|
|
|
|
- return Promise.resolve(false)
|
|
+ // Drop the empty bucket from the Map
|
|
+ this.stylesCounter.delete(hash)
|
|
+
|
|
+ // Move this to the end of the event loop so the element is removed from the DOM
|
|
+ return Promise.resolve().then(() => {
|
|
+ // New connect raced in during the microtask
|
|
+ if ((this.stylesCounter.get(hash) ?? 0) > 0) {
|
|
+ return false
|
|
+ }
|
|
+
|
|
+ // Check if element is still in the DOM
|
|
+ if (document.querySelector(`.${hash}`)) {
|
|
+ return false
|
|
+ }
|
|
+
|
|
+ this.css.remove(hash)
|
|
+ this.stylesCache.delete(hash)
|
|
+
|
|
+ return true
|
|
+ })
|
|
}
|
|
|
|
add = (value: UnistylesValues, forChild?: boolean) => {
|
|
@@ -126,7 +171,11 @@ export class UnistylesRegistry {
|
|
}
|
|
|
|
reset = () => {
|
|
+ // Invalidate pending FR callbacks from this generation
|
|
+ this.cleanupGeneration += 1
|
|
+ this.disposeListenersMap.forEach((dispose) => dispose())
|
|
this.css.reset()
|
|
+ this.stylesheets.clear()
|
|
this.stylesCache.clear()
|
|
this.dependenciesMap.clear()
|
|
this.disposeListenersMap.clear()
|
|
diff --git a/node_modules/react-native-unistyles/android/build.gradle b/node_modules/react-native-unistyles/android/build.gradle
|
|
index 195954b..c4ac28c 100644
|
|
--- a/node_modules/react-native-unistyles/android/build.gradle
|
|
+++ b/node_modules/react-native-unistyles/android/build.gradle
|
|
@@ -38,6 +38,7 @@ if (isNewArchitectureEnabled()) {
|
|
|
|
android {
|
|
compileSdkVersion safeExtGet('compileSdkVersion', 35)
|
|
+ ndkVersion safeExtGet('ndkVersion', '27.1.12297006')
|
|
namespace "com.unistyles"
|
|
|
|
defaultConfig {
|
|
diff --git a/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.tsx b/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.tsx
|
|
--- a/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.tsx
|
|
+++ b/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.tsx
|
|
@@ -28,13 +28,14 @@
|
|
|
|
return forwardRef<GenericComponentRef<TComponent>, PropsWithUnistyles>((props, ref) => {
|
|
const narrowedProps = props as PropsWithUnistyles & UnistyleStyles
|
|
+ const { uniProps, ...componentProps } = narrowedProps
|
|
const styleClassNames = getClassName(narrowedProps.style, true)
|
|
const contentContainerStyleClassNames = getClassName(narrowedProps.contentContainerStyle)
|
|
const { proxifiedRuntime, proxifiedTheme } = useProxifiedUnistyles()
|
|
|
|
const { key: mappingsKey, ...mappingsProps } = mappings ? mappings(proxifiedTheme, proxifiedRuntime) : {}
|
|
- const { key: uniPropsKey, ...unistyleProps } = narrowedProps.uniProps
|
|
- ? narrowedProps.uniProps(proxifiedTheme, proxifiedRuntime)
|
|
+ const { key: uniPropsKey, ...unistyleProps } = uniProps
|
|
+ ? uniProps(proxifiedTheme, proxifiedRuntime)
|
|
: {}
|
|
|
|
const emptyStyles = narrowedProps.style
|
|
@@ -46,7 +47,7 @@
|
|
: undefined
|
|
|
|
const combinedProps = {
|
|
- ...deepMergeObjects(mappingsProps, unistyleProps, props),
|
|
+ ...deepMergeObjects(mappingsProps, unistyleProps, componentProps),
|
|
...(narrowedProps.style
|
|
? {
|
|
// Override default component styles with undefined values to reset them
|
|
diff --git a/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.native.tsx b/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.native.tsx
|
|
--- a/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.native.tsx
|
|
+++ b/node_modules/react-native-unistyles/src/core/withUnistyles/withUnistyles.native.tsx
|
|
@@ -63,6 +63,7 @@
|
|
|
|
return forwardRef<GenericComponentRef<TComponent>, PropsWithUnistyles>((props, ref) => {
|
|
const narrowedProps = props as PropsWithUnistyles & UnistyleStyles
|
|
+ const { uniProps, ...componentProps } = narrowedProps
|
|
const NativeComponent = Component as ComponentType
|
|
|
|
// @ts-ignore we don't know the type of the component
|
|
@@ -89,15 +90,15 @@
|
|
}, [narrowedProps.style, narrowedProps.contentContainerStyle])
|
|
|
|
const { key: mappingsKey, ...mappingsProps } = mappings ? mappings(proxifiedTheme, proxifiedRuntime) : {}
|
|
- const { key: uniPropsKey, ...unistyleProps } = narrowedProps.uniProps
|
|
- ? narrowedProps.uniProps(proxifiedTheme, proxifiedRuntime)
|
|
+ const { key: uniPropsKey, ...unistyleProps } = uniProps
|
|
+ ? uniProps(proxifiedTheme, proxifiedRuntime)
|
|
: {}
|
|
|
|
const styleSecrets = getSecrets(narrowedProps.style)
|
|
const contentContainerStyleSecrets = getSecrets(narrowedProps.contentContainerStyle)
|
|
|
|
const finalProps = {
|
|
- ...deepMergeObjects(mappingsProps, unistyleProps, props),
|
|
+ ...deepMergeObjects(mappingsProps, unistyleProps, componentProps),
|
|
...(narrowedProps.style
|
|
? {
|
|
style: styleSecrets.styles,
|
|
diff --git a/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.js b/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.js
|
|
--- a/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.js
|
|
+++ b/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.js
|
|
@@ -13,6 +13,7 @@
|
|
export const withUnistyles = (Component, mappings) => {
|
|
return /*#__PURE__*/forwardRef((props, ref) => {
|
|
const narrowedProps = props;
|
|
+ const { uniProps, ...componentProps } = narrowedProps;
|
|
const styleClassNames = getClassName(narrowedProps.style, true);
|
|
const contentContainerStyleClassNames = getClassName(narrowedProps.contentContainerStyle);
|
|
const {
|
|
@@ -26,10 +27,10 @@
|
|
const {
|
|
key: uniPropsKey,
|
|
...unistyleProps
|
|
- } = narrowedProps.uniProps ? narrowedProps.uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
+ } = uniProps ? uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
const emptyStyles = narrowedProps.style ? Object.fromEntries(Object.entries(Object.getOwnPropertyDescriptors(narrowedProps.style)).filter(([key]) => !key.startsWith('unistyles') && !key.startsWith('_')).map(([key]) => [key, undefined])) : undefined;
|
|
const combinedProps = {
|
|
- ...deepMergeObjects(mappingsProps, unistyleProps, props),
|
|
+ ...deepMergeObjects(mappingsProps, unistyleProps, componentProps),
|
|
...(narrowedProps.style ? {
|
|
// Override default component styles with undefined values to reset them
|
|
style: emptyStyles
|
|
diff --git a/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.native.js b/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.native.js
|
|
--- a/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.native.js
|
|
+++ b/node_modules/react-native-unistyles/lib/module/core/withUnistyles/withUnistyles.native.js
|
|
@@ -27,6 +27,7 @@
|
|
};
|
|
return /*#__PURE__*/forwardRef((props, ref) => {
|
|
const narrowedProps = props;
|
|
+ const { uniProps, ...componentProps } = narrowedProps;
|
|
const NativeComponent = Component;
|
|
|
|
// @ts-ignore we don't know the type of the component
|
|
@@ -57,11 +58,11 @@
|
|
const {
|
|
key: uniPropsKey,
|
|
...unistyleProps
|
|
- } = narrowedProps.uniProps ? narrowedProps.uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
+ } = uniProps ? uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
const styleSecrets = getSecrets(narrowedProps.style);
|
|
const contentContainerStyleSecrets = getSecrets(narrowedProps.contentContainerStyle);
|
|
const finalProps = {
|
|
- ...deepMergeObjects(mappingsProps, unistyleProps, props),
|
|
+ ...deepMergeObjects(mappingsProps, unistyleProps, componentProps),
|
|
...(narrowedProps.style ? {
|
|
style: styleSecrets.styles
|
|
} : {}),
|
|
diff --git a/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.js b/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.js
|
|
--- a/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.js
|
|
+++ b/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.js
|
|
@@ -18,6 +18,7 @@
|
|
const withUnistyles = (Component, mappings) => {
|
|
return /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
const narrowedProps = props;
|
|
+ const { uniProps, ...componentProps } = narrowedProps;
|
|
const styleClassNames = (0, _getClassname.getClassName)(narrowedProps.style, true);
|
|
const contentContainerStyleClassNames = (0, _getClassname.getClassName)(narrowedProps.contentContainerStyle);
|
|
const {
|
|
@@ -31,10 +32,10 @@
|
|
const {
|
|
key: uniPropsKey,
|
|
...unistyleProps
|
|
- } = narrowedProps.uniProps ? narrowedProps.uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
+ } = uniProps ? uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
const emptyStyles = narrowedProps.style ? Object.fromEntries(Object.entries(Object.getOwnPropertyDescriptors(narrowedProps.style)).filter(([key]) => !key.startsWith('unistyles') && !key.startsWith('_')).map(([key]) => [key, undefined])) : undefined;
|
|
const combinedProps = {
|
|
- ...(0, _utils.deepMergeObjects)(mappingsProps, unistyleProps, props),
|
|
+ ...(0, _utils.deepMergeObjects)(mappingsProps, unistyleProps, componentProps),
|
|
...(narrowedProps.style ? {
|
|
// Override default component styles with undefined values to reset them
|
|
style: emptyStyles
|
|
diff --git a/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.native.js b/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.native.js
|
|
--- a/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.native.js
|
|
+++ b/node_modules/react-native-unistyles/lib/commonjs/core/withUnistyles/withUnistyles.native.js
|
|
@@ -32,6 +32,7 @@
|
|
};
|
|
return /*#__PURE__*/(0, _react.forwardRef)((props, ref) => {
|
|
const narrowedProps = props;
|
|
+ const { uniProps, ...componentProps } = narrowedProps;
|
|
const NativeComponent = Component;
|
|
|
|
// @ts-ignore we don't know the type of the component
|
|
@@ -62,11 +63,11 @@
|
|
const {
|
|
key: uniPropsKey,
|
|
...unistyleProps
|
|
- } = narrowedProps.uniProps ? narrowedProps.uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
+ } = uniProps ? uniProps(proxifiedTheme, proxifiedRuntime) : {};
|
|
const styleSecrets = getSecrets(narrowedProps.style);
|
|
const contentContainerStyleSecrets = getSecrets(narrowedProps.contentContainerStyle);
|
|
const finalProps = {
|
|
- ...(0, _utils.deepMergeObjects)(mappingsProps, unistyleProps, props),
|
|
+ ...(0, _utils.deepMergeObjects)(mappingsProps, unistyleProps, componentProps),
|
|
...(narrowedProps.style ? {
|
|
style: styleSecrets.styles
|
|
} : {}),
|
|
diff --git a/node_modules/react-native-unistyles/lib/commonjs/web/runtime.js b/node_modules/react-native-unistyles/lib/commonjs/web/runtime.js
|
|
index 305fa49..5957aa5 100644
|
|
--- a/node_modules/react-native-unistyles/lib/commonjs/web/runtime.js
|
|
+++ b/node_modules/react-native-unistyles/lib/commonjs/web/runtime.js
|
|
@@ -35,10 +35,17 @@ class UnistylesRuntime {
|
|
return this.darkMedia;
|
|
}
|
|
get colorScheme() {
|
|
+ // Read the scheme through fresh lists, never through lightMedia/darkMedia. Chromium defers
|
|
+ // MediaQueryList change events while the document is hidden and drops the pending event
|
|
+ // of any list whose `matches` was read before the document became visible again, which
|
|
+ // would silence the adaptive-theme listeners registered on those two lists.
|
|
+ if ((0, _utils.isServer)()) {
|
|
+ return _types.ColorScheme.Unspecified;
|
|
+ }
|
|
switch (true) {
|
|
- case this.getLightMedia()?.matches:
|
|
+ case window.matchMedia('(prefers-color-scheme: light)').matches:
|
|
return _types.ColorScheme.Light;
|
|
- case this.getDarkMedia()?.matches:
|
|
+ case window.matchMedia('(prefers-color-scheme: dark)').matches:
|
|
return _types.ColorScheme.Dark;
|
|
default:
|
|
return _types.ColorScheme.Unspecified;
|
|
diff --git a/node_modules/react-native-unistyles/lib/module/web/runtime.js b/node_modules/react-native-unistyles/lib/module/web/runtime.js
|
|
index 7f13a06..c487bee 100644
|
|
--- a/node_modules/react-native-unistyles/lib/module/web/runtime.js
|
|
+++ b/node_modules/react-native-unistyles/lib/module/web/runtime.js
|
|
@@ -31,10 +31,17 @@ export class UnistylesRuntime {
|
|
return this.darkMedia;
|
|
}
|
|
get colorScheme() {
|
|
+ // Read the scheme through fresh lists, never through lightMedia/darkMedia. Chromium defers
|
|
+ // MediaQueryList change events while the document is hidden and drops the pending event
|
|
+ // of any list whose `matches` was read before the document became visible again, which
|
|
+ // would silence the adaptive-theme listeners registered on those two lists.
|
|
+ if (isServer()) {
|
|
+ return ColorScheme.Unspecified;
|
|
+ }
|
|
switch (true) {
|
|
- case this.getLightMedia()?.matches:
|
|
+ case window.matchMedia('(prefers-color-scheme: light)').matches:
|
|
return ColorScheme.Light;
|
|
- case this.getDarkMedia()?.matches:
|
|
+ case window.matchMedia('(prefers-color-scheme: dark)').matches:
|
|
return ColorScheme.Dark;
|
|
default:
|
|
return ColorScheme.Unspecified;
|
|
diff --git a/node_modules/react-native-unistyles/src/web/runtime.ts b/node_modules/react-native-unistyles/src/web/runtime.ts
|
|
index a16dac0..6519858 100644
|
|
--- a/node_modules/react-native-unistyles/src/web/runtime.ts
|
|
+++ b/node_modules/react-native-unistyles/src/web/runtime.ts
|
|
@@ -41,8 +41,16 @@ export class UnistylesRuntime {
|
|
get colorScheme() {
|
|
+ // Read the scheme through fresh lists, never through lightMedia/darkMedia. Chromium defers
|
|
+ // MediaQueryList change events while the document is hidden and drops the pending event
|
|
+ // of any list whose `matches` was read before the document became visible again, which
|
|
+ // would silence the adaptive-theme listeners registered on those two lists.
|
|
+ if (isServer()) {
|
|
+ return ColorScheme.Unspecified
|
|
+ }
|
|
+
|
|
switch (true) {
|
|
- case this.getLightMedia()?.matches:
|
|
+ case window.matchMedia('(prefers-color-scheme: light)').matches:
|
|
return ColorScheme.Light
|
|
- case this.getDarkMedia()?.matches:
|
|
+ case window.matchMedia('(prefers-color-scheme: dark)').matches:
|
|
return ColorScheme.Dark
|
|
default:
|
|
return ColorScheme.Unspecified
|
|
diff --git a/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+android.kt b/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+android.kt
|
|
index 0f8d1f0..154a12a 100644
|
|
--- a/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+android.kt
|
|
+++ b/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+android.kt
|
|
@@ -3,11 +3,16 @@ package com.unistyles
|
|
import android.os.Build
|
|
import android.content.Context
|
|
import android.content.res.Configuration
|
|
+import android.content.res.Resources
|
|
+import android.os.Handler
|
|
+import android.os.Looper
|
|
import android.util.DisplayMetrics
|
|
import android.view.View
|
|
import android.view.WindowManager
|
|
import androidx.annotation.Keep
|
|
+import androidx.core.content.OnConfigurationChangedProvider
|
|
import androidx.core.text.TextUtilsCompat
|
|
+import androidx.core.util.Consumer
|
|
import androidx.core.view.ViewCompat
|
|
import androidx.core.view.WindowCompat
|
|
import androidx.core.view.WindowInsetsCompat
|
|
@@ -22,6 +27,7 @@ import com.margelo.nitro.unistyles.Insets
|
|
import com.margelo.nitro.unistyles.Orientation
|
|
import com.margelo.nitro.unistyles.UnistyleDependency
|
|
import com.margelo.nitro.unistyles.UnistylesNativeMiniRuntime
|
|
+import java.lang.ref.WeakReference
|
|
import java.util.Locale
|
|
|
|
@Keep
|
|
@@ -30,6 +36,14 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
|
|
private val _insets = NativePlatformInsets(reactContext, this::getMiniRuntime) { this.onConfigChange() }
|
|
private var _miniRuntime: UnistylesNativeMiniRuntime = buildMiniRuntime()
|
|
private val _listener = NativePlatformListener(reactContext, this::getMiniRuntime) { this.diffMiniRuntime() }
|
|
+ private var _configurationProvider: WeakReference<OnConfigurationChangedProvider>? = null
|
|
+ private val _activityConfigurationListener = Consumer<Configuration> {
|
|
+ Handler(Looper.getMainLooper()).post { this.onConfigChange() }
|
|
+ }
|
|
+
|
|
+ // Application resources can lag behind configuration changes
|
|
+ private val configurationResources: Resources
|
|
+ get() = reactContext.currentActivity?.resources ?: reactContext.resources
|
|
|
|
init {
|
|
checkEdgeToEdge()
|
|
@@ -37,12 +51,16 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
|
|
}
|
|
|
|
fun onDestroy() {
|
|
+ stopObservingActivityConfiguration()
|
|
_listener.onDestroy()
|
|
_insets.onDestroy()
|
|
reactContext.removeLifecycleEventListener(this)
|
|
}
|
|
|
|
override fun onHostResume() {
|
|
+ observeActivityConfiguration()
|
|
+ // catch configuration changes missed while no Activity was attached
|
|
+ onConfigChange()
|
|
_insets.getInitialInsets(false)
|
|
_insets.startInsetsListener()
|
|
}
|
|
@@ -51,7 +69,26 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
|
|
_insets.stopInsetsListener()
|
|
}
|
|
|
|
- override fun onHostDestroy() {}
|
|
+ override fun onHostDestroy() {
|
|
+ stopObservingActivityConfiguration()
|
|
+ }
|
|
+
|
|
+ private fun observeActivityConfiguration() {
|
|
+ val provider = reactContext.currentActivity as? OnConfigurationChangedProvider
|
|
+
|
|
+ if (_configurationProvider?.get() === provider) {
|
|
+ return
|
|
+ }
|
|
+
|
|
+ stopObservingActivityConfiguration()
|
|
+ provider?.addOnConfigurationChangedListener(_activityConfigurationListener)
|
|
+ _configurationProvider = provider?.let { WeakReference(it) }
|
|
+ }
|
|
+
|
|
+ private fun stopObservingActivityConfiguration() {
|
|
+ _configurationProvider?.get()?.removeOnConfigurationChangedListener(_activityConfigurationListener)
|
|
+ _configurationProvider = null
|
|
+ }
|
|
|
|
override val memorySize: Long
|
|
get() = 0
|
|
@@ -61,7 +98,7 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
|
|
}
|
|
|
|
override fun getColorScheme(): ColorScheme {
|
|
- val uiMode = reactContext.resources.configuration.uiMode
|
|
+ val uiMode = configurationResources.configuration.uiMode
|
|
|
|
val colorScheme = when (uiMode.and(Configuration.UI_MODE_NIGHT_MASK)) {
|
|
Configuration.UI_MODE_NIGHT_YES -> ColorScheme.DARK
|
|
@@ -73,15 +110,15 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
|
|
}
|
|
|
|
override fun getFontScale(): Double {
|
|
- return reactContext.resources.configuration.fontScale.toDouble()
|
|
+ return configurationResources.configuration.fontScale.toDouble()
|
|
}
|
|
|
|
override fun getPixelRatio(): Double {
|
|
- return reactContext.resources.displayMetrics.density.toDouble()
|
|
+ return configurationResources.displayMetrics.density.toDouble()
|
|
}
|
|
|
|
override fun getOrientation(): Orientation {
|
|
- val orientation = when (reactContext.resources.configuration.orientation) {
|
|
+ val orientation = when (configurationResources.configuration.orientation) {
|
|
Configuration.ORIENTATION_PORTRAIT -> Orientation.PORTRAIT
|
|
Configuration.ORIENTATION_LANDSCAPE -> Orientation.LANDSCAPE
|
|
else -> Orientation.PORTRAIT
|
|
@@ -122,7 +159,7 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
|
|
return Dimensions(screenWidth, screenHeight)
|
|
}
|
|
else -> {
|
|
- val displayMetrics = reactContext.resources.displayMetrics
|
|
+ val displayMetrics = configurationResources.displayMetrics
|
|
|
|
reactContext.currentActivity?.windowManager?.currentWindowMetrics?.bounds?.let {
|
|
val boundsWidth = (it.width() / displayMetrics.density).toDouble()
|
|
@@ -157,7 +194,7 @@ class NativePlatformAndroid(private val reactContext: ReactApplicationContext):
|
|
"com.facebook.react.modules.i18nmanager.I18nUtil",
|
|
Context.MODE_PRIVATE
|
|
)
|
|
- val resourcesLocale = reactContext.resources.configuration.locales[0]
|
|
+ val resourcesLocale = configurationResources.configuration.locales[0]
|
|
val hasForcedRtl = sharedPrefs.getBoolean("RCTI18nUtil_forceRTL", false)
|
|
// user preferences
|
|
val isRtl = TextUtilsCompat.getLayoutDirectionFromLocale(Locale.getDefault()) == ViewCompat.LAYOUT_DIRECTION_RTL
|
|
diff --git a/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+insets.kt b/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+insets.kt
|
|
index a9c1804..f5a3c20 100644
|
|
--- a/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+insets.kt
|
|
+++ b/node_modules/react-native-unistyles/android/src/main/java/com/unistyles/NativePlatform+insets.kt
|
|
@@ -38,7 +38,7 @@ class NativePlatformInsets(
|
|
}
|
|
|
|
fun getInsets(): Insets {
|
|
- val density = reactContext.resources.displayMetrics.density
|
|
+ val density = (reactContext.currentActivity?.resources ?: reactContext.resources).displayMetrics.density
|
|
|
|
return Insets(
|
|
this._insets.top / density,
|
|
diff --git a/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp b/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp
|
|
index 01026dc..3786ec4 100644
|
|
--- a/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp
|
|
+++ b/node_modules/react-native-unistyles/cxx/shadowTree/ShadowTreeManager.cpp
|
|
@@ -17,13 +17,16 @@ void shadow::ShadowTreeManager::updateShadowTree(jsi::Runtime& rt) {
|
|
}
|
|
|
|
#if REACT_NATIVE_VERSION_MINOR >= 81
|
|
- std::unordered_map<Tag, folly::dynamic> tagToProps;
|
|
+ // Paseo backport of https://github.com/jpudysz/react-native-unistyles/pull/1357.
|
|
+ // UIManager::updateShadowTree commits a root cloned before the commit, so when a
|
|
+ // window-size commit (rotation, keyboard) lands in between, the retried Unistyles
|
|
+ // commit puts the previous layout constraints back and the app stays laid out for
|
|
+ // the old size. Commit here instead and clone from the root the commit hands us.
|
|
+ std::unordered_set<SurfaceId> affectedSurfaces;
|
|
|
|
for (const auto& [family, props] : updates) {
|
|
auto safeProps = props.isObject() ? props : folly::dynamic::object();
|
|
|
|
- tagToProps.insert({family->getTag(), safeProps});
|
|
-
|
|
auto* mutableFamily = const_cast<ShadowNodeFamily*>(family);
|
|
|
|
if (mutableFamily->nativeProps_DEPRECATED && mutableFamily->nativeProps_DEPRECATED->isObject()) {
|
|
@@ -31,9 +34,30 @@ void shadow::ShadowTreeManager::updateShadowTree(jsi::Runtime& rt) {
|
|
} else {
|
|
mutableFamily->nativeProps_DEPRECATED = std::make_unique<folly::dynamic>(safeProps);
|
|
}
|
|
+
|
|
+ affectedSurfaces.insert(family->getSurfaceId());
|
|
}
|
|
|
|
- UIManagerBinding::getBinding(rt)->getUIManager().updateShadowTree(std::move(tagToProps));
|
|
+ const auto& shadowTreeRegistry = UIManagerBinding::getBinding(rt)->getUIManager().getShadowTreeRegistry();
|
|
+
|
|
+ shadowTreeRegistry.enumerate([&updates, &affectedSurfaces](const ShadowTree& shadowTree, bool&){
|
|
+ if (!affectedSurfaces.contains(shadowTree.getSurfaceId())) {
|
|
+ return;
|
|
+ }
|
|
+
|
|
+ auto transaction = [&updates](const RootShadowNode& oldRootShadowNode) -> RootShadowNode::Unshared {
|
|
+ auto affectedNodes = shadow::ShadowTreeManager::findAffectedNodes(oldRootShadowNode, updates);
|
|
+
|
|
+ return std::static_pointer_cast<RootShadowNode>(shadow::ShadowTreeManager::cloneShadowTree(
|
|
+ oldRootShadowNode,
|
|
+ updates,
|
|
+ affectedNodes
|
|
+ ));
|
|
+ };
|
|
+
|
|
+ // mountSynchronously: this is an update from C++, not React
|
|
+ shadowTree.commit(transaction, {false, true});
|
|
+ });
|
|
#else
|
|
const auto& shadowTreeRegistry = UIManagerBinding::getBinding(rt)->getUIManager().getShadowTreeRegistry();
|
|
|