From f96a4c0d5d5e4c70be230faca20a8a21032934c4 Mon Sep 17 00:00:00 2001 From: Nick Gerleman Date: Wed, 17 Jul 2024 20:35:17 -0700 Subject: [PATCH] Camelize filter function names in object notation (#45503) Summary: Pull Request resolved: https://github.com/facebook/react-native/pull/45503 Kebab case object literals are a pain as an API to give folks. Keep string parsing using the kebab-case web names, like in CSS, but keep object notation camelCase. This is super super hacked up, and we should burn away all these viewconfig processors as soon as we can. Changelog: [Internal] Reviewed By: cortinico Differential Revision: D59793095 fbshipit-source-id: 888cad31142d7aeed42687ab23c2023ac7e4882d --- .../Libraries/StyleSheet/StyleSheetTypes.d.ts | 4 +- .../Libraries/StyleSheet/StyleSheetTypes.js | 4 +- .../__tests__/processFilter-test.js | 56 ++++++++----------- .../Libraries/StyleSheet/processFilter.js | 22 +++++--- .../__snapshots__/public-api-test.js.snap | 8 +-- .../facebook/react/uimanager/FilterHelper.kt | 7 +-- .../react/renderer/graphics/Filter.h | 4 +- .../js/examples/Filter/FilterExample.js | 8 +-- 8 files changed, 54 insertions(+), 59 deletions(-) diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts index 24968554e1b..78a9e732c48 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.d.ts @@ -232,12 +232,12 @@ export type FilterPrimitive = | {blur: number | string} | {contrast: number | string} | {grayscale: number | string} - | {'hue-rotate': number | string} + | {hueRotate: number | string} | {invert: number | string} | {opacity: number | string} | {saturate: number | string} | {sepia: number | string} - | {'drop-shadow': DropShadowPrimitive | string}; + | {dropShadow: DropShadowPrimitive | string}; export type DropShadowPrimitive = { offsetX: number | string; diff --git a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js index a582a57b2a4..561cc30cdfa 100644 --- a/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js +++ b/packages/react-native/Libraries/StyleSheet/StyleSheetTypes.js @@ -695,12 +695,12 @@ export type FilterPrimitive = | {blur: number | string} | {contrast: number | string} | {grayscale: number | string} - | {'hue-rotate': number | string} + | {hueRotate: number | string} | {invert: number | string} | {opacity: number | string} | {saturate: number | string} | {sepia: number | string} - | {'drop-shadow': DropShadowPrimitive | string}; + | {dropShadow: DropShadowPrimitive | string}; export type DropShadowPrimitive = { offsetX: number | string, diff --git a/packages/react-native/Libraries/StyleSheet/__tests__/processFilter-test.js b/packages/react-native/Libraries/StyleSheet/__tests__/processFilter-test.js index 0819b304405..1f1357cc3f0 100644 --- a/packages/react-native/Libraries/StyleSheet/__tests__/processFilter-test.js +++ b/packages/react-native/Libraries/StyleSheet/__tests__/processFilter-test.js @@ -40,12 +40,12 @@ describe('processFilter', () => { }, ]); - testNumericFilter('hue-rotate', 0, [{'hue-rotate': 0}]); - testUnitFilter('hue-rotate', 90, 'deg', [{'hue-rotate': 90}]); + testNumericFilter('hue-rotate', 0, [{hueRotate: 0}]); + testUnitFilter('hue-rotate', 90, 'deg', [{hueRotate: 90}]); testUnitFilter('hue-rotate', 1.5708, 'rad', [ - {'hue-rotate': (180 * 1.5708) / Math.PI}, + {hueRotate: (180 * 1.5708) / Math.PI}, ]); - testUnitFilter('hue-rotate', -90, 'deg', [{'hue-rotate': -90}]); + testUnitFilter('hue-rotate', -90, 'deg', [{hueRotate: -90}]); testUnitFilter('hue-rotate', 1.5, 'grad', []); testNumericFilter('hue-rotate', 90, []); testUnitFilter('hue-rotate', 50, '%', []); @@ -56,14 +56,9 @@ describe('processFilter', () => { {brightness: 0.5}, {opacity: 0.5}, {blur: 5}, - {'hue-rotate': '90deg'}, + {hueRotate: '90deg'}, ]), - ).toEqual([ - {brightness: 0.5}, - {opacity: 0.5}, - {blur: 5}, - {'hue-rotate': 90}, - ]); + ).toEqual([{brightness: 0.5}, {opacity: 0.5}, {blur: 5}, {hueRotate: 90}]); }); it('multiple filters one invalid', () => { expect( @@ -71,7 +66,7 @@ describe('processFilter', () => { {brightness: 0.5}, {opacity: 0.5}, {blur: 5}, - {'hue-rotate': '90foo'}, + {hueRotate: '90foo'}, ]), ).toEqual([]); }); @@ -98,7 +93,7 @@ describe('processFilter', () => { ), ).toEqual([ {brightness: 0.5}, - {'hue-rotate': 90}, + {hueRotate: 90}, {brightness: 0.5}, {brightness: 0.5}, ]); @@ -118,12 +113,7 @@ describe('processFilter', () => { it('string multiple filters', () => { expect( processFilter('brightness(0.5) opacity(0.5) blur(5) hue-rotate(90deg)'), - ).toEqual([ - {brightness: 0.5}, - {opacity: 0.5}, - {blur: 5}, - {'hue-rotate': 90}, - ]); + ).toEqual([{brightness: 0.5}, {opacity: 0.5}, {blur: 5}, {hueRotate: 90}]); }); it('string multiple filters one invalid', () => { expect( @@ -220,7 +210,7 @@ function createFilterPrimitive( case 'grayscale': return {grayscale: value}; case 'hue-rotate': - return {'hue-rotate': value}; + return {hueRotate: value}; case 'invert': return {invert: value}; case 'opacity': @@ -238,7 +228,7 @@ function testDropShadow() { it('should parse string drop-shadow', () => { expect(processFilter('drop-shadow(4px 4 10px red)')).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, color: processColor('red'), @@ -251,7 +241,7 @@ function testDropShadow() { it('should parse string negative offsets drop-shadow', () => { expect(processFilter('drop-shadow(-4 -4)')).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: -4, offsetY: -4, }, @@ -264,19 +254,19 @@ function testDropShadow() { processFilter('drop-shadow(4 4) drop-shadow(4 4) drop-shadow(4 4)'), ).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, }, }, { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, }, }, { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, }, @@ -289,7 +279,7 @@ function testDropShadow() { processFilter(' drop-shadow(4px 4 10px red) '), ).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, color: processColor('red'), @@ -306,7 +296,7 @@ function testDropShadow() { ), ).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, color: processColor('red'), @@ -321,7 +311,7 @@ function testDropShadow() { it('should parse string drop-shadow with color', () => { expect(processFilter('drop-shadow(50 50 purple)')).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: 50, offsetY: 50, color: processColor('purple'), @@ -333,7 +323,7 @@ function testDropShadow() { it('should parse string with mixed case drop-shadow', () => { expect(processFilter('DroP-sHaDOw(50 50 purple)')).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: 50, offsetY: 50, color: processColor('purple'), @@ -346,7 +336,7 @@ function testDropShadow() { expect( processFilter([ { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, color: '#FFFFFF', @@ -356,7 +346,7 @@ function testDropShadow() { ]), ).toEqual([ { - 'drop-shadow': { + dropShadow: { offsetX: 4, offsetY: 4, standardDeviation: 10, @@ -390,7 +380,7 @@ function testDropShadow() { expect( // $FlowExpectedError[incompatible-call] processFilter([ - {'drop-shadow': {offsetX: 4, offsetY: 5, invalid: 'invalid arg'}}, + {dropShadow: {offsetX: 4, offsetY: 5, invalid: 'invalid arg'}}, ]), ).toEqual([]); }); @@ -398,7 +388,7 @@ function testDropShadow() { it('should fail on invalid argument for drop-shadow object', () => { expect( // $FlowExpectedError[incompatible-call] - processFilter([{'drop-shadow': 8}]), + processFilter([{dropShadow: 8}]), ).toEqual([]); }); } diff --git a/packages/react-native/Libraries/StyleSheet/processFilter.js b/packages/react-native/Libraries/StyleSheet/processFilter.js index d952f3b17ca..45328eb9335 100644 --- a/packages/react-native/Libraries/StyleSheet/processFilter.js +++ b/packages/react-native/Libraries/StyleSheet/processFilter.js @@ -21,12 +21,12 @@ type ParsedFilter = | {blur: number} | {contrast: number} | {grayscale: number} - | {'hue-rotate': number} + | {hueRotate: number} | {invert: number} | {opacity: number} | {saturate: number} | {sepia: number} - | {'drop-shadow': ParsedDropShadow}; + | {dropShadow: ParsedDropShadow}; type ParsedDropShadow = { offsetX: number, @@ -49,17 +49,23 @@ export default function processFilter( if (filterName === 'drop-shadow') { const dropShadow = parseDropShadow(matches[2]); if (dropShadow != null) { - result.push({'drop-shadow': dropShadow}); + result.push({dropShadow}); } else { return []; } } else { - const amount = _getFilterAmount(filterName, matches[2]); + const camelizedName = + filterName === 'drop-shadow' + ? 'dropShadow' + : filterName === 'hue-rotate' + ? 'hueRotate' + : filterName; + const amount = _getFilterAmount(camelizedName, matches[2]); if (amount != null) { const filterPrimitive = {}; // $FlowFixMe The key will be the correct one but flow can't see that. - filterPrimitive[filterName] = amount; + filterPrimitive[camelizedName] = amount; // $FlowFixMe The key will be the correct one but flow can't see that. result.push(filterPrimitive); } else { @@ -73,13 +79,13 @@ export default function processFilter( } else { for (const filterPrimitive of filter) { const [filterName, filterValue] = Object.entries(filterPrimitive)[0]; - if (filterName === 'drop-shadow') { + if (filterName === 'dropShadow') { // $FlowFixMe const dropShadow = parseDropShadow(filterValue); if (dropShadow == null) { return []; } - result.push({'drop-shadow': dropShadow}); + result.push({dropShadow}); } else { const amount = _getFilterAmount(filterName, filterValue); @@ -125,7 +131,7 @@ function _getFilterAmount(filterName: string, filterArgs: mixed): ?number { switch (filterName) { // Hue rotate takes some angle that can have a unit and can be // negative. Additionally, 0 with no unit is allowed. - case 'hue-rotate': + case 'hueRotate': if (filterArgAsNumber === 0) { return 0; } diff --git a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap index 93f88d5f51a..0d106b5adff 100644 --- a/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap +++ b/packages/react-native/Libraries/__tests__/__snapshots__/public-api-test.js.snap @@ -7688,12 +7688,12 @@ export type FilterPrimitive = | { blur: number | string } | { contrast: number | string } | { grayscale: number | string } - | { \\"hue-rotate\\": number | string } + | { hueRotate: number | string } | { invert: number | string } | { opacity: number | string } | { saturate: number | string } | { sepia: number | string } - | { \\"drop-shadow\\": DropShadowPrimitive | string }; + | { dropShadow: DropShadowPrimitive | string }; export type DropShadowPrimitive = { offsetX: number | string, offsetY: number | string, @@ -8049,12 +8049,12 @@ exports[`public API should not change unintentionally Libraries/StyleSheet/proce | { blur: number } | { contrast: number } | { grayscale: number } - | { \\"hue-rotate\\": number } + | { hueRotate: number } | { invert: number } | { opacity: number } | { saturate: number } | { sepia: number } - | { \\"drop-shadow\\": ParsedDropShadow }; + | { dropShadow: ParsedDropShadow }; type ParsedDropShadow = { offsetX: number, offsetY: number, diff --git a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/FilterHelper.kt b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/FilterHelper.kt index 09abb4c17cb..1707fcb36a8 100644 --- a/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/FilterHelper.kt +++ b/packages/react-native/ReactAndroid/src/main/java/com/facebook/react/uimanager/FilterHelper.kt @@ -39,12 +39,11 @@ internal object FilterHelper { "grayscale" -> createGrayscaleEffect((filter.value as Double).toFloat(), chainedEffects) "sepia" -> createSepiaEffect((filter.value as Double).toFloat(), chainedEffects) "saturate" -> createSaturateEffect((filter.value as Double).toFloat(), chainedEffects) - "hue-rotate" -> - createHueRotateEffect((filter.value as Double).toFloat(), chainedEffects) + "hueRotate" -> createHueRotateEffect((filter.value as Double).toFloat(), chainedEffects) "invert" -> createInvertEffect((filter.value as Double).toFloat(), chainedEffects) "blur" -> createBlurEffect((filter.value as Double).toFloat(), chainedEffects) "opacity" -> createOpacityEffect((filter.value as Double).toFloat(), chainedEffects) - "drop-shadow" -> + "dropShadow" -> parseAndCreateDropShadowEffect(filter.value as ReadableMap, chainedEffects) else -> throw IllegalArgumentException("Invalid filter name: $filterName") } @@ -69,7 +68,7 @@ internal object FilterHelper { "grayscale" -> createGrayscaleColorMatrix(amount) "sepia" -> createSepiaColorMatrix(amount) "saturate" -> createSaturateColorMatrix(amount) - "hue-rotate" -> createHueRotateColorMatrix(amount) + "hueRotate" -> createHueRotateColorMatrix(amount) "invert" -> createInvertColorMatrix(amount) "opacity" -> createOpacityColorMatrix(amount) else -> throw IllegalArgumentException("Invalid color matrix filter: $filterName") diff --git a/packages/react-native/ReactCommon/react/renderer/graphics/Filter.h b/packages/react-native/ReactCommon/react/renderer/graphics/Filter.h index 8eec8fafa6c..c4a7f18b068 100644 --- a/packages/react-native/ReactCommon/react/renderer/graphics/Filter.h +++ b/packages/react-native/ReactCommon/react/renderer/graphics/Filter.h @@ -44,7 +44,7 @@ inline FilterType filterTypeFromString(std::string_view filterName) { return FilterType::Contrast; } else if (filterName == "grayscale") { return FilterType::Grayscale; - } else if (filterName == "hue-rotate") { + } else if (filterName == "hueRotate") { return FilterType::HueRotate; } else if (filterName == "invert") { return FilterType::Invert; @@ -54,7 +54,7 @@ inline FilterType filterTypeFromString(std::string_view filterName) { return FilterType::Saturate; } else if (filterName == "sepia") { return FilterType::Sepia; - } else if (filterName == "drop-shadow") { + } else if (filterName == "dropShadow") { return FilterType::DropShadow; } else { throw std::invalid_argument(std::string(filterName)); diff --git a/packages/rn-tester/js/examples/Filter/FilterExample.js b/packages/rn-tester/js/examples/Filter/FilterExample.js index 36ed2d74c71..d527f2008ba 100644 --- a/packages/rn-tester/js/examples/Filter/FilterExample.js +++ b/packages/rn-tester/js/examples/Filter/FilterExample.js @@ -174,13 +174,13 @@ exports.examples = [ }, { title: 'Hue Rotate', - description: 'hue-rotate(-90deg)', - name: 'hue-rotate', + description: 'hueRotate(-90deg)', + name: 'hueRotate', platform: 'android', render(): React.Node { return ( ); }, @@ -219,7 +219,7 @@ exports.examples = [ return (