From 0be14f7ce5800d786007944e0a49a8cfda304b63 Mon Sep 17 00:00:00 2001 From: Eddie Kimmel Date: Mon, 9 Feb 2026 16:35:22 -0500 Subject: [PATCH 1/3] Update styleq, bring localizeStyle transform locally --- package-lock.json | 8 ++- packages/react-native-web/package.json | 2 +- .../src/exports/StyleSheet/index.js | 2 +- .../src/exports/StyleSheet/localizeStyle.js | 62 +++++++++++++++++++ 4 files changed, 71 insertions(+), 3 deletions(-) create mode 100644 packages/react-native-web/src/exports/StyleSheet/localizeStyle.js diff --git a/package-lock.json b/package-lock.json index 9027a0c7b..13da8982d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15419,7 +15419,7 @@ "memoize-one": "^6.0.0", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", - "styleq": "^0.1.3" + "styleq": "^0.2.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", @@ -15461,6 +15461,12 @@ "@babel/core": "^7.18.6", "@babel/preset-flow": "^7.18.6" } + }, + "packages/react-native-web/node_modules/styleq": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/styleq/-/styleq-0.2.1.tgz", + "integrity": "sha512-L0TR0NQb+X4/ktDEKmjWyp27gla+LUYi/by5k5SjKXf6/pvZP7wbwEB5J+tqxdFVPgzbsuz+d4RTScO/QZquBw==", + "license": "MIT" } } } diff --git a/packages/react-native-web/package.json b/packages/react-native-web/package.json index 914be31f6..e9b39868c 100644 --- a/packages/react-native-web/package.json +++ b/packages/react-native-web/package.json @@ -29,7 +29,7 @@ "memoize-one": "^6.0.0", "nullthrows": "^1.1.1", "postcss-value-parser": "^4.2.0", - "styleq": "^0.1.3" + "styleq": "^0.2.1" }, "peerDependencies": { "react": "^18.0.0 || ^19.0.0", diff --git a/packages/react-native-web/src/exports/StyleSheet/index.js b/packages/react-native-web/src/exports/StyleSheet/index.js index a13393665..8d7737cdc 100644 --- a/packages/react-native-web/src/exports/StyleSheet/index.js +++ b/packages/react-native-web/src/exports/StyleSheet/index.js @@ -9,7 +9,7 @@ import { atomic, classic, inline } from './compiler'; import { createSheet } from './dom'; -import { localizeStyle } from 'styleq/transform-localize-style'; +import { localizeStyle } from './localizeStyle'; import { preprocess } from './preprocess'; import { styleq } from 'styleq'; import { validate } from './validate'; diff --git a/packages/react-native-web/src/exports/StyleSheet/localizeStyle.js b/packages/react-native-web/src/exports/StyleSheet/localizeStyle.js new file mode 100644 index 000000000..ceddad685 --- /dev/null +++ b/packages/react-native-web/src/exports/StyleSheet/localizeStyle.js @@ -0,0 +1,62 @@ +/** + * Copyright (c) Nicolas Gallagher. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @flow + */ + +const cache = new WeakMap(); +const markerProp = '$$css$localize'; + +/** + * The compiler polyfills logical properties and values, generating a class + * name for both writing directions. The style objects are annotated by + * the compiler as needing this runtime transform. The results are memoized. + * + * { '$$css$localize': true, float: [ 'float-left', 'float-right' ] } + * => { float: 'float-left' } + */ + +function compileStyle(style, isRTL) { + // Create a new compiled style for styleq + const compiledStyle = {}; + for (const prop in style) { + if (prop !== markerProp) { + const value = style[prop]; + if (Array.isArray(value)) { + compiledStyle[prop] = isRTL ? value[1] : value[0]; + } else { + compiledStyle[prop] = value; + } + } + } + return compiledStyle; +} + +export function localizeStyle(style, isRTL) { + if (style[markerProp] != null) { + const compiledStyleIndex = isRTL ? 1 : 0; + // Check the cache in case we've already seen this object + if (cache.has(style)) { + const cachedStyles = cache.get(style); + let compiledStyle = cachedStyles[compiledStyleIndex]; + if (compiledStyle == null) { + // Update the missing cache entry + compiledStyle = compileStyle(style, isRTL); + cachedStyles[compiledStyleIndex] = compiledStyle; + cache.set(style, cachedStyles); + } + return compiledStyle; + } + + // Create a new compiled style for styleq + const compiledStyle = compileStyle(style, isRTL); + const cachedStyles = new Array(2); + cachedStyles[compiledStyleIndex] = compiledStyle; + cache.set(style, cachedStyles); + return compiledStyle; + } + return style; +} From 99c95c5535089ac01df382391a03cc39933b3f98 Mon Sep 17 00:00:00 2001 From: Eddie Kimmel Date: Mon, 9 Feb 2026 16:50:01 -0500 Subject: [PATCH 2/3] Fix flow typing --- .../src/exports/StyleSheet/localizeStyle.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/react-native-web/src/exports/StyleSheet/localizeStyle.js b/packages/react-native-web/src/exports/StyleSheet/localizeStyle.js index ceddad685..9c2b3c825 100644 --- a/packages/react-native-web/src/exports/StyleSheet/localizeStyle.js +++ b/packages/react-native-web/src/exports/StyleSheet/localizeStyle.js @@ -7,7 +7,7 @@ * @flow */ -const cache = new WeakMap(); +const cache = new WeakMap>(); const markerProp = '$$css$localize'; /** @@ -19,7 +19,7 @@ const markerProp = '$$css$localize'; * => { float: 'float-left' } */ -function compileStyle(style, isRTL) { +function compileStyle(style: Object, isRTL: boolean) { // Create a new compiled style for styleq const compiledStyle = {}; for (const prop in style) { @@ -35,12 +35,12 @@ function compileStyle(style, isRTL) { return compiledStyle; } -export function localizeStyle(style, isRTL) { +export function localizeStyle(style: Object, isRTL: boolean): Object { if (style[markerProp] != null) { const compiledStyleIndex = isRTL ? 1 : 0; // Check the cache in case we've already seen this object - if (cache.has(style)) { - const cachedStyles = cache.get(style); + let cachedStyles = cache.get(style); + if (cachedStyles != null) { let compiledStyle = cachedStyles[compiledStyleIndex]; if (compiledStyle == null) { // Update the missing cache entry @@ -53,7 +53,7 @@ export function localizeStyle(style, isRTL) { // Create a new compiled style for styleq const compiledStyle = compileStyle(style, isRTL); - const cachedStyles = new Array(2); + cachedStyles = new Array(2); cachedStyles[compiledStyleIndex] = compiledStyle; cache.set(style, cachedStyles); return compiledStyle; From 011191603b89ae47b7d954525bc597bd39003026 Mon Sep 17 00:00:00 2001 From: Eddie Kimmel Date: Mon, 9 Feb 2026 17:14:57 -0500 Subject: [PATCH 3/3] Update snapshot for new styleq debug string in array --- .../StyleSheet/__tests__/index-test.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/packages/react-native-web/src/exports/StyleSheet/__tests__/index-test.js b/packages/react-native-web/src/exports/StyleSheet/__tests__/index-test.js index 888de2624..9da148db6 100644 --- a/packages/react-native-web/src/exports/StyleSheet/__tests__/index-test.js +++ b/packages/react-native-web/src/exports/StyleSheet/__tests__/index-test.js @@ -68,6 +68,7 @@ describe('StyleSheet', () => { [ "r-position-u8s1d", null, + "", ] `); }); @@ -88,6 +89,7 @@ describe('StyleSheet', () => { [ "r-boxShadow-o3ayyy r-textShadow-1x2q051", null, + "", ] `); }); @@ -159,18 +161,21 @@ describe('StyleSheet', () => { [ "", null, + "", ] `); expect(StyleSheet({})).toMatchInlineSnapshot(` [ "", null, + "", ] `); expect(StyleSheet([])).toMatchInlineSnapshot(` [ "", null, + "", ] `); }); @@ -189,6 +194,7 @@ describe('StyleSheet', () => { [ "position-absolute opacity-05 width-200", null, + "", ] `); }); @@ -219,6 +225,7 @@ describe('StyleSheet', () => { [ "borderWidth-0 borderColor-red display-flex position-absolute opacity-05 width-200", null, + "", ] `); }); @@ -272,6 +279,7 @@ describe('StyleSheet', () => { "paddingRight": "40px", "paddingTop": "8px", }, + "", ] `); @@ -286,6 +294,7 @@ describe('StyleSheet', () => { "marginRight": "8px", "marginTop": "40px", }, + "", ] `); }); @@ -310,6 +319,7 @@ describe('StyleSheet', () => { "marginRight": "10px", "textAlign": "left", }, + "", ] `); expect(StyleSheet(inlineStyle, { writingDirection })) @@ -321,6 +331,7 @@ describe('StyleSheet', () => { "right": "12.34%", "textAlign": "right", }, + "", ] `); expect( @@ -329,6 +340,7 @@ describe('StyleSheet', () => { inlineStyle, { marginLeft: 1, marginEnd: 0, marginStart: 0, marginRight: 11 } ], + { writingDirection } ) ).toMatchInlineSnapshot(` @@ -340,6 +352,7 @@ describe('StyleSheet', () => { "right": "12.34%", "textAlign": "right", }, + "", ] `); expect( @@ -354,6 +367,7 @@ describe('StyleSheet', () => { "right": "12.34%", "textAlign": "right", }, + "", ] `); @@ -363,6 +377,7 @@ describe('StyleSheet', () => { [ "r-insetInlineStart-1xn1m1p r-textAlign-fdjqy7 r-marginInlineEnd-1l8l4mf", null, + "", ] `); expect(StyleSheet(staticStyle, { writingDirection })) @@ -370,6 +385,7 @@ describe('StyleSheet', () => { [ "r-insetInlineStart-1y2vi53 r-textAlign-1ff274t r-marginInlineEnd-t1sew1", null, + "", ] `); const z = StyleSheet.create({ x: { marginRight: 33 } }).x; @@ -377,6 +393,7 @@ describe('StyleSheet', () => { [ "r-insetInlineStart-1xn1m1p r-textAlign-fdjqy7 r-marginInlineEnd-1l8l4mf r-marginRight-j4vy6k", null, + "", ] `); expect( @@ -397,6 +414,7 @@ describe('StyleSheet', () => { "marginLeft": "1px", "marginRight": "11px", }, + "", ] `); // logical can be nulled @@ -408,6 +426,7 @@ describe('StyleSheet', () => { [ "r-insetInlineStart-1y2vi53 r-textAlign-1ff274t", null, + "", ] `); });