From ea3718d4fd1a95b111116833d865af28912e8335 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 21 Jul 2025 13:30:26 -0700 Subject: [PATCH 1/3] Revert "Use built-in React Native support for logical CSS" This reverts commit 4b556989b74deebfb35333f78bb55b965a0e86d7. --- apps/website/docs/api/02-css/index.md | 40 +++++++------- .../src/native/stylex/index.js | 53 ++++++++++++++++++ .../compat-test.native.js.snap-native | 4 +- .../css-test.native.js.snap-native | 55 ++++++++----------- .../react-strict-dom/tests/css-test.native.js | 6 -- 5 files changed, 99 insertions(+), 59 deletions(-) diff --git a/apps/website/docs/api/02-css/index.md b/apps/website/docs/api/02-css/index.md index 4a1b567d..ed30d4c8 100644 --- a/apps/website/docs/api/02-css/index.md +++ b/apps/website/docs/api/02-css/index.md @@ -130,7 +130,7 @@ The following tables represent the compatibility status of the strict CSS API fo | color | ✅ | ✅ | | | columnGap | ✅ | ✅ | | | cursor | ❌ | ✅ Partial | | -| direction | ✅ | ✅ | | +| direction | ❌ | ❌ | | | display: block | 🟡 Partial | 🟡 Partial | [#2](https://github.com/facebook/react-strict-dom/issues/2) | | display: contents | ✅ | ✅ | | | display: flex | ✅ | ✅ | | @@ -156,13 +156,13 @@ The following tables represent the compatibility status of the strict CSS API fo | gap | ✅ | ✅ | | | height | ✅ | ✅ | | | inlineSize | 🟡 | 🟡 | | -| inset | ✅ | ✅ | | -| insetBlock | ✅ | ✅ | | -| insetBlockEnd | ✅ | ✅ | | -| insetBlockStart | ✅ | ✅ | | -| insetInline | ✅ | ✅ | | -| insetInlineEnd | ✅ | ✅ | | -| insetInlineStart | ✅ | ✅ | | +| inset | 🟡 | 🟡 | | +| insetBlock | 🟡 | 🟡 | | +| insetBlockEnd | 🟡 | 🟡 | | +| insetBlockStart | 🟡 | 🟡 | | +| insetInline | 🟡 | 🟡 | | +| insetInlineEnd | 🟡 | 🟡 | | +| insetInlineStart | 🟡 | 🟡 | | | isolation | ✅ | ✅ | | | justifyContent | ✅ | ✅ | | | justifyItems | ❌ | ❌ | | @@ -175,13 +175,13 @@ The following tables represent the compatibility status of the strict CSS API fo | listStylePosition | ❌ | ❌ | | | listStyleType | ❌ | ❌ | | | margin | ✅ | ✅ | | -| marginBlock | ✅ | ✅ | | -| marginBlockEnd | ✅ | ✅ | | -| marginBlockStart | ✅ | ✅ | | +| marginBlock | 🟡 | 🟡 | | +| marginBlockEnd | 🟡 | 🟡 | | +| marginBlockStart | 🟡 | 🟡 | | | marginBottom | ✅ | ✅ | | -| marginInline | ✅ | ✅ | | -| marginInlineEnd | ✅ | ✅ | | -| marginInlineStart | ✅ | ✅ | | +| marginInline | 🟡 | 🟡 | | +| marginInlineEnd | 🟡 | 🟡 | | +| marginInlineStart | 🟡 | 🟡 | | | marginLeft | ✅ | ✅ | | | marginRight | ✅ | ✅ | | | marginTop | ✅ | ✅ | | @@ -208,13 +208,13 @@ The following tables represent the compatibility status of the strict CSS API fo | overflowX | ❌ | ❌ | | | overflowY | ❌ | ❌ | | | padding | ✅ | ✅ | | -| paddingBlock | ✅ | ✅ | | -| paddingBlockEnd | ✅ | ✅ | | -| paddingBlockStart | ✅ | ✅ | | +| paddingBlock | 🟡 | 🟡 | | +| paddingBlockEnd | 🟡 | 🟡 | | +| paddingBlockStart | 🟡 | 🟡 | | | paddingBottom | ✅ | ✅ | | -| paddingInline | ✅ | ✅ | | -| paddingInlineEnd | ✅ | ✅ | | -| paddingInlineStart | ✅ | ✅ | | +| paddingInline | 🟡 | 🟡 | | +| paddingInlineEnd | 🟡 | 🟡 | | +| paddingInlineStart | 🟡 | 🟡 | | | paddingLeft | ✅ | ✅ | | | paddingRight | ✅ | ✅ | | | paddingTop | ✅ | ✅ | | diff --git a/packages/react-strict-dom/src/native/stylex/index.js b/packages/react-strict-dom/src/native/stylex/index.js index a743c29d..9931568d 100644 --- a/packages/react-strict-dom/src/native/stylex/index.js +++ b/packages/react-strict-dom/src/native/stylex/index.js @@ -605,10 +605,63 @@ export function props( nativeProps.cursorColor = styleValue; } } + // inset + else if (styleProp === 'inset') { + nextStyle.top ??= styleValue; + nextStyle.start ??= styleValue; + nextStyle.end ??= styleValue; + nextStyle.bottom ??= styleValue; + } else if (styleProp === 'insetBlock') { + nextStyle.top ??= styleValue; + nextStyle.bottom ??= styleValue; + } else if (styleProp === 'insetBlockEnd') { + nextStyle.bottom = flatStyle.bottom ?? styleValue; + } else if (styleProp === 'insetBlockStart') { + nextStyle.top = flatStyle.top ?? styleValue; + } else if (styleProp === 'insetInline') { + nextStyle.end ??= styleValue; + nextStyle.start ??= styleValue; + } else if (styleProp === 'insetInlineEnd') { + nextStyle.end = flatStyle.end ?? styleValue; + } else if (styleProp === 'insetInlineStart') { + nextStyle.start = flatStyle.start ?? styleValue; + } // lineClamp polyfill else if (styleProp === 'lineClamp') { nativeProps.numberOfLines = styleValue; } + // marginBlock + else if (styleProp === 'marginBlock') { + nextStyle.marginVertical = styleValue; + } else if (styleProp === 'marginBlockStart') { + nextStyle.marginTop ??= styleValue; + } else if (styleProp === 'marginBlockEnd') { + nextStyle.marginBottom ??= styleValue; + } + // marginInline + else if (styleProp === 'marginInline') { + nextStyle.marginHorizontal = styleValue; + } else if (styleProp === 'marginInlineStart') { + nextStyle.marginStart = styleValue; + } else if (styleProp === 'marginInlineEnd') { + nextStyle.marginEnd = styleValue; + } + // paddingBlock + else if (styleProp === 'paddingBlock') { + nextStyle.paddingVertical = styleValue; + } else if (styleProp === 'paddingBlockStart') { + nextStyle.paddingTop ??= styleValue; + } else if (styleProp === 'paddingBlockEnd') { + nextStyle.paddingBottom ??= styleValue; + } + // paddingInline + else if (styleProp === 'paddingInline') { + nextStyle.paddingHorizontal = styleValue; + } else if (styleProp === 'paddingInlineStart') { + nextStyle.paddingStart = styleValue; + } else if (styleProp === 'paddingInlineEnd') { + nextStyle.paddingEnd = styleValue; + } // '::placeholder' polyfill else if (styleProp === 'placeholderTextColor') { nativeProps.placeholderTextColor = styleValue; diff --git a/packages/react-strict-dom/tests/__snapshots__/compat-test.native.js.snap-native b/packages/react-strict-dom/tests/__snapshots__/compat-test.native.js.snap-native index 08f72854..49a90201 100644 --- a/packages/react-strict-dom/tests/__snapshots__/compat-test.native.js.snap-native +++ b/packages/react-strict-dom/tests/__snapshots__/compat-test.native.js.snap-native @@ -68,7 +68,7 @@ exports[` "as" equals "view": as=view 1`] = ` style={ { "boxSizing": "content-box", - "paddingInline": 32, + "paddingHorizontal": 32, "position": "static", } } @@ -82,7 +82,7 @@ exports[` default: default 1`] = ` style={ { "boxSizing": "content-box", - "paddingInline": 32, + "paddingHorizontal": 32, "position": "static", } } diff --git a/packages/react-strict-dom/tests/__snapshots__/css-test.native.js.snap-native b/packages/react-strict-dom/tests/__snapshots__/css-test.native.js.snap-native index a97b6fc0..1e18e109 100644 --- a/packages/react-strict-dom/tests/__snapshots__/css-test.native.js.snap-native +++ b/packages/react-strict-dom/tests/__snapshots__/css-test.native.js.snap-native @@ -161,14 +161,6 @@ exports[`properties: general caretColor: unsupported caret color 1`] = ` } `; -exports[`properties: general direction: inherit 1`] = ` -{ - "style": { - "direction": "inherit", - }, -} -`; - exports[`properties: general direction: ltr 1`] = ` { "style": { @@ -1030,7 +1022,10 @@ exports[`properties: logical direction inlineSize: minInlineSize after minWidth exports[`properties: logical direction inset: inset 1`] = ` { "style": { - "inset": 1, + "bottom": 1, + "end": 1, + "start": 1, + "top": 1, }, } `; @@ -1039,7 +1034,6 @@ exports[`properties: logical direction inset: inset vs top 1`] = ` { "style": { "bottom": 100, - "insetBlockStart": 3, "left": 10, "right": 10, "top": 100, @@ -1050,7 +1044,8 @@ exports[`properties: logical direction inset: inset vs top 1`] = ` exports[`properties: logical direction inset: insetBlock 1`] = ` { "style": { - "insetBlock": 2, + "bottom": 2, + "top": 2, }, } `; @@ -1059,7 +1054,6 @@ exports[`properties: logical direction inset: insetBlock vs top 1`] = ` { "style": { "bottom": 100, - "insetBlockStart": 3, "top": 100, }, } @@ -1068,7 +1062,7 @@ exports[`properties: logical direction inset: insetBlock vs top 1`] = ` exports[`properties: logical direction inset: insetBlockEnd 1`] = ` { "style": { - "insetBlockEnd": 4, + "bottom": 4, }, } `; @@ -1077,7 +1071,6 @@ exports[`properties: logical direction inset: insetBlockEnd vs bottom 1`] = ` { "style": { "bottom": 100, - "insetBlockEnd": 4, }, } `; @@ -1085,7 +1078,7 @@ exports[`properties: logical direction inset: insetBlockEnd vs bottom 1`] = ` exports[`properties: logical direction inset: insetBlockStart 1`] = ` { "style": { - "insetBlockStart": 3, + "top": 3, }, } `; @@ -1093,7 +1086,6 @@ exports[`properties: logical direction inset: insetBlockStart 1`] = ` exports[`properties: logical direction inset: insetBlockStart vs top 1`] = ` { "style": { - "insetBlockStart": 3, "top": 100, }, } @@ -1102,7 +1094,8 @@ exports[`properties: logical direction inset: insetBlockStart vs top 1`] = ` exports[`properties: logical direction inset: insetInline 1`] = ` { "style": { - "insetInline": 5, + "end": 5, + "start": 5, }, } `; @@ -1110,7 +1103,7 @@ exports[`properties: logical direction inset: insetInline 1`] = ` exports[`properties: logical direction inset: insetInlineEnd 1`] = ` { "style": { - "insetInlineEnd": 7, + "end": 7, }, } `; @@ -1118,7 +1111,7 @@ exports[`properties: logical direction inset: insetInlineEnd 1`] = ` exports[`properties: logical direction inset: insetInlineStart 1`] = ` { "style": { - "insetInlineStart": 6, + "start": 6, }, } `; @@ -1126,7 +1119,7 @@ exports[`properties: logical direction inset: insetInlineStart 1`] = ` exports[`properties: logical direction margin: marginBlock 1`] = ` { "style": { - "marginBlock": 1, + "marginVertical": 1, }, } `; @@ -1134,7 +1127,7 @@ exports[`properties: logical direction margin: marginBlock 1`] = ` exports[`properties: logical direction margin: marginBlockEnd 1`] = ` { "style": { - "marginBlockEnd": 3, + "marginBottom": 3, }, } `; @@ -1142,7 +1135,7 @@ exports[`properties: logical direction margin: marginBlockEnd 1`] = ` exports[`properties: logical direction margin: marginBlockStart 1`] = ` { "style": { - "marginBlockStart": 2, + "marginTop": 2, }, } `; @@ -1150,7 +1143,7 @@ exports[`properties: logical direction margin: marginBlockStart 1`] = ` exports[`properties: logical direction margin: marginInline 1`] = ` { "style": { - "marginInline": 1, + "marginHorizontal": 1, }, } `; @@ -1158,7 +1151,7 @@ exports[`properties: logical direction margin: marginInline 1`] = ` exports[`properties: logical direction margin: marginInlineEnd 1`] = ` { "style": { - "marginInlineEnd": 3, + "marginEnd": 3, }, } `; @@ -1166,7 +1159,7 @@ exports[`properties: logical direction margin: marginInlineEnd 1`] = ` exports[`properties: logical direction margin: marginInlineStart 1`] = ` { "style": { - "marginInlineStart": 2, + "marginStart": 2, }, } `; @@ -1174,7 +1167,7 @@ exports[`properties: logical direction margin: marginInlineStart 1`] = ` exports[`properties: logical direction padding: paddingBlock 1`] = ` { "style": { - "paddingBlock": 1, + "paddingVertical": 1, }, } `; @@ -1182,7 +1175,7 @@ exports[`properties: logical direction padding: paddingBlock 1`] = ` exports[`properties: logical direction padding: paddingBlockEnd 1`] = ` { "style": { - "paddingBlockEnd": 3, + "paddingBottom": 3, }, } `; @@ -1190,7 +1183,7 @@ exports[`properties: logical direction padding: paddingBlockEnd 1`] = ` exports[`properties: logical direction padding: paddingBlockStart 1`] = ` { "style": { - "paddingBlockStart": 2, + "paddingTop": 2, }, } `; @@ -1198,7 +1191,7 @@ exports[`properties: logical direction padding: paddingBlockStart 1`] = ` exports[`properties: logical direction padding: paddingInline 1`] = ` { "style": { - "paddingInline": 1, + "paddingHorizontal": 1, }, } `; @@ -1206,7 +1199,7 @@ exports[`properties: logical direction padding: paddingInline 1`] = ` exports[`properties: logical direction padding: paddingInlineEnd 1`] = ` { "style": { - "paddingInlineEnd": 3, + "paddingEnd": 3, }, } `; @@ -1214,7 +1207,7 @@ exports[`properties: logical direction padding: paddingInlineEnd 1`] = ` exports[`properties: logical direction padding: paddingInlineStart 1`] = ` { "style": { - "paddingInlineStart": 2, + "paddingStart": 2, }, } `; diff --git a/packages/react-strict-dom/tests/css-test.native.js b/packages/react-strict-dom/tests/css-test.native.js index 507891cc..e1b52a48 100644 --- a/packages/react-strict-dom/tests/css-test.native.js +++ b/packages/react-strict-dom/tests/css-test.native.js @@ -241,9 +241,6 @@ describe('properties: general', () => { test('direction', () => { const styles = css.create({ - inherit: { - direction: 'inherit' - }, ltr: { direction: 'ltr' }, @@ -251,9 +248,6 @@ describe('properties: general', () => { direction: 'rtl' } }); - expect(css.props.call(mockOptions, styles.inherit)).toMatchSnapshot( - 'inherit' - ); expect(css.props.call(mockOptions, styles.ltr)).toMatchSnapshot('ltr'); expect(css.props.call(mockOptions, styles.rtl)).toMatchSnapshot('rtl'); }); From 2ef8ff57ccaecf341be3989b70536f622c238463 Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 21 Jul 2025 13:08:38 -0700 Subject: [PATCH 2/3] Add logical CSS to examples app --- apps/examples/src/components/App.js | 43 +++++++++++++++++++++++++++-- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/apps/examples/src/components/App.js b/apps/examples/src/components/App.js index 311de906..ceab9d99 100644 --- a/apps/examples/src/components/App.js +++ b/apps/examples/src/components/App.js @@ -52,6 +52,7 @@ const greenPinkTheme = css.createTheme(themeColors, { const themedStyles = css.create({ container: { + display: 'flex', flex: 1, justifyContent: 'center', backgroundColor: '#bbb', @@ -323,6 +324,15 @@ function Shell(): React.MixedElement { + {/* logical styles emulation */} + + + + + + + + {/* CSS positioning (static by default) */} @@ -571,7 +581,7 @@ function Shell(): React.MixedElement { > {clickData.text} - + {clickEventData.altKey ? '✅' : '🚫'} altKey @@ -593,7 +603,7 @@ function Shell(): React.MixedElement { - + button: {clickEventData.button} @@ -846,5 +856,34 @@ const styles = css.create({ borderWidth: 1, borderStyle: 'solid', borderColor: 'black' + }, + logicalMargin: { + backgroundColor: 'pink', + width: 50, + height: 50, + marginBlock: 20, + marginInline: 20, + borderColor: 'black', + borderWidth: 1, + borderStyle: 'solid' + }, + logicalPadding: { + backgroundColor: 'pink', + width: 50, + height: 50, + paddingBlock: 20, + paddingInline: 20, + borderColor: 'black', + borderWidth: 1, + borderStyle: 'solid' + }, + logicalBorder: { + backgroundColor: 'pink', + width: 50, + height: 50, + borderColor: 'red', + borderBlockWidth: 20, + borderInlineWidth: 20, + borderStyle: 'solid' } }); From d9c9744bed415a3ba446aadaa712f43a2490eaed Mon Sep 17 00:00:00 2001 From: Nicolas Gallagher Date: Mon, 21 Jul 2025 13:23:57 -0700 Subject: [PATCH 3/3] Add logical CSS to contentBox tests --- .../__snapshots__/fixContentBox-test.js.snap | 13 +++++++++++++ .../native/stylex/__tests__/fixContentBox-test.js | 12 ++++++++++++ 2 files changed, 25 insertions(+) diff --git a/packages/react-strict-dom/src/native/stylex/__tests__/__snapshots__/fixContentBox-test.js.snap b/packages/react-strict-dom/src/native/stylex/__tests__/__snapshots__/fixContentBox-test.js.snap index 8ebb16b4..90399ff4 100644 --- a/packages/react-strict-dom/src/native/stylex/__tests__/__snapshots__/fixContentBox-test.js.snap +++ b/packages/react-strict-dom/src/native/stylex/__tests__/__snapshots__/fixContentBox-test.js.snap @@ -32,6 +32,19 @@ exports[`fixContentBox boxSizing: content-box: height 1`] = ` } `; +exports[`fixContentBox boxSizing: content-box: logical 1`] = ` +{ + "borderBlockWidth": 5, + "borderInlineWidth": 5, + "height": 100, + "paddingBlock": 10, + "paddingInline": 20, + "paddingInlineEnd": 30, + "paddingLeft": 40, + "width": 140, +} +`; + exports[`fixContentBox boxSizing: content-box: maxHeight 1`] = ` { "borderWidth": 2, diff --git a/packages/react-strict-dom/src/native/stylex/__tests__/fixContentBox-test.js b/packages/react-strict-dom/src/native/stylex/__tests__/fixContentBox-test.js index eb5a4478..bc69805b 100644 --- a/packages/react-strict-dom/src/native/stylex/__tests__/fixContentBox-test.js +++ b/packages/react-strict-dom/src/native/stylex/__tests__/fixContentBox-test.js @@ -70,6 +70,17 @@ describe('fixContentBox', () => { width: 100, height: 100 }, + logical: { + boxSizing: 'content-box', + borderBlockWidth: 5, + borderInlineWidth: 5, + paddingBlock: 10, + paddingInline: 20, + paddingInlineEnd: 30, + paddingLeft: 40, + width: 100, + height: 100 + }, auto: { boxSizing: 'content-box', borderWidth: 2, @@ -100,6 +111,7 @@ describe('fixContentBox', () => { expect(fixContentBox(styles.minWidth)).toMatchSnapshot('minWidth'); expect(fixContentBox(styles.minHeight)).toMatchSnapshot('minHeight'); expect(fixContentBox(styles.allDifferent)).toMatchSnapshot('allDifferent'); + expect(fixContentBox(styles.logical)).toMatchSnapshot('logical'); expect(fixContentBox(styles.auto)).toMatchSnapshot('auto'); expect(fixContentBox(styles.null)).toMatchSnapshot('null'); expect(fixContentBox(styles.string)).toMatchSnapshot('string');