Files
paseo/patches/react-native-unistyles+3.2.4.patch
T
paseo-bot[bot]anddwyanewang 71e7cf6ff8 Build native Android modules with the project NDK (#7403)
* fix(android): align Unistyles NDK version

* fix(android): use the project NDK for every native module

The diff module still selected the Android Gradle default NDK, causing a second installation after Unistyles was aligned. Inherit the project toolchain and check all configured native projects.

---------

Co-authored-by: dwyanewang <908280968@qq.com>
Co-authored-by: paseo-bot[bot] <266920839+paseo-bot[bot]@users.noreply.github.com>
2026-10-19 20:09:07 +02:00

332 lines
12 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 {