From dcee5e35e893b7b5a02f8bb5211f2a2a8ea098f5 Mon Sep 17 00:00:00 2001 From: Wojciech Maj Date: Fri, 20 Mar 2026 00:16:44 +0100 Subject: [PATCH 1/2] Add support for box-shadow and filter properties React Native supports box-shadow and filter properties natively since version 0.76. This means that every version of React Native that is stil supported can benefit from box-shadow and filter properties. --- README.md | 5 ++- src/__tests__/boxShadow.js | 85 ------------------------------------- src/__tests__/index.js | 26 ++++++++++++ src/__tests__/units.js | 7 +-- src/transforms/boxShadow.js | 11 ----- src/transforms/index.js | 2 - 6 files changed, 31 insertions(+), 105 deletions(-) delete mode 100644 src/__tests__/boxShadow.js delete mode 100644 src/transforms/boxShadow.js diff --git a/README.md b/README.md index 5ad9890..155508f 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,10 @@ margin: 5px 7px 2px; } ``` -Shorthands will only accept values that are supported in React, so `background` will only accept a colour, `backgroundColor` +Shorthands will only accept values that are supported in React Native, so `background` will only accept a colour, `backgroundColor` will not accept an image, and `font` will not accept font-variant values that React Native does not support. -There is also support for the `box-shadow` shorthand, and this converts into `shadow-` properties. Note that these only work on iOS. +React Native's `box-shadow` and `filter` properties are passed through as +`boxShadow` and `filter`, so support depends on your React Native version. #### Shorthand Notes diff --git a/src/__tests__/boxShadow.js b/src/__tests__/boxShadow.js deleted file mode 100644 index 36b31c1..0000000 --- a/src/__tests__/boxShadow.js +++ /dev/null @@ -1,85 +0,0 @@ -import { expect, it } from 'vitest' - -import transformCss from '..' - -it('transforms box-shadow into shadow- properties', () => { - expect(transformCss([['box-shadow', '10px 20px 30px red']])).toEqual({ - shadowOffset: { width: 10, height: 20 }, - shadowRadius: 30, - shadowColor: 'red', - shadowOpacity: 1, - }) -}) - -it('transforms box-shadow without blur-radius', () => { - expect(transformCss([['box-shadow', '10px 20px red']])).toEqual({ - shadowOffset: { width: 10, height: 20 }, - shadowRadius: 0, - shadowColor: 'red', - shadowOpacity: 1, - }) -}) - -it('transforms box-shadow without color', () => { - expect(transformCss([['box-shadow', '10px 20px']])).toEqual({ - shadowOffset: { width: 10, height: 20 }, - shadowRadius: 0, - shadowColor: 'black', - shadowOpacity: 1, - }) -}) - -it('transforms box-shadow with rgb color', () => { - expect( - transformCss([['box-shadow', '10px 20px rgb(100, 100, 100)']]) - ).toEqual({ - shadowOffset: { width: 10, height: 20 }, - shadowRadius: 0, - shadowColor: 'rgb(100, 100, 100)', - shadowOpacity: 1, - }) -}) - -it('transforms box-shadow with rgba color', () => { - expect( - transformCss([['box-shadow', '10px 20px rgba(100, 100, 100, 0.5)']]) - ).toEqual({ - shadowOffset: { width: 10, height: 20 }, - shadowRadius: 0, - shadowColor: 'rgba(100, 100, 100, 0.5)', - shadowOpacity: 1, - }) -}) - -it('transforms box-shadow with hsl color', () => { - expect( - transformCss([['box-shadow', '10px 20px hsl(120, 100%, 50%)']]) - ).toEqual({ - shadowOffset: { width: 10, height: 20 }, - shadowRadius: 0, - shadowColor: 'hsl(120, 100%, 50%)', - shadowOpacity: 1, - }) -}) - -it('transforms box-shadow with hsla color', () => { - expect( - transformCss([['box-shadow', '10px 20px hsla(120, 100%, 50%, 0.7)']]) - ).toEqual({ - shadowOffset: { width: 10, height: 20 }, - shadowRadius: 0, - shadowColor: 'hsla(120, 100%, 50%, 0.7)', - shadowOpacity: 1, - }) -}) - -it('transforms box-shadow and throws if multiple colors are used', () => { - expect(() => - transformCss([['box-shadow', '0 0 0 red yellow green blue']]) - ).toThrow() -}) - -it('transforms box-shadow enforces offset to be present', () => { - expect(() => transformCss([['box-shadow', 'red']])).toThrow() - expect(() => transformCss([['box-shadow', '10px red']])).toThrow() -}) diff --git a/src/__tests__/index.js b/src/__tests__/index.js index cbd03e7..3bd0be2 100644 --- a/src/__tests__/index.js +++ b/src/__tests__/index.js @@ -90,6 +90,32 @@ it('allows CSS custom properties to pass through', () => { expect(transformCss([['--my-prop', '0%']])).toEqual({ '--my-prop': '0%' }) }) +it('passes filter through as a raw React Native property', () => { + expect(transformCss([['filter', 'opacity(0.5)']])).toEqual({ + filter: 'opacity(0.5)', + }) +}) + +it('passes multiple filter functions through unchanged', () => { + expect(transformCss([['filter', 'opacity(0.5) blur(5px)']])).toEqual({ + filter: 'opacity(0.5) blur(5px)', + }) +}) + +it('passes box-shadow through as a raw React Native property', () => { + expect(transformCss([['box-shadow', '10px 20px 30px red']])).toEqual({ + boxShadow: '10px 20px 30px red', + }) +}) + +it('passes multiple box-shadow values through unchanged', () => { + expect( + transformCss([['box-shadow', '5px 5px 5px red, -5px -5px 5px green']]) + ).toEqual({ + boxShadow: '5px 5px 5px red, -5px -5px 5px green', + }) +}) + it('allows percent in unspecialized transform', () => { expect(transformCss([['top', '0%']])).toEqual({ top: '0%' }) }) diff --git a/src/__tests__/units.js b/src/__tests__/units.js index baa4879..a05d2dd 100644 --- a/src/__tests__/units.js +++ b/src/__tests__/units.js @@ -115,14 +115,11 @@ lengthUnits.forEach(unit => { }) }) - it('allows untis to be used with box-shadow', () => { + it('allows units to be used with box-shadow', () => { expect( transformCss([['box-shadow', `10px ${value} ${value} red`]]) ).toEqual({ - shadowOffset: { width: 10, height: value }, - shadowRadius: value, - shadowColor: 'red', - shadowOpacity: 1, + boxShadow: `10px ${value} ${value} red`, }) }) }) diff --git a/src/transforms/boxShadow.js b/src/transforms/boxShadow.js deleted file mode 100644 index b581658..0000000 --- a/src/transforms/boxShadow.js +++ /dev/null @@ -1,11 +0,0 @@ -import { parseShadow } from './util' - -export default tokenStream => { - const { offset, radius, color } = parseShadow(tokenStream) - return { - shadowOffset: offset, - shadowRadius: radius, - shadowColor: color, - shadowOpacity: 1, - } -} diff --git a/src/transforms/index.js b/src/transforms/index.js index 8474556..ae84fb8 100644 --- a/src/transforms/index.js +++ b/src/transforms/index.js @@ -8,7 +8,6 @@ import { } from '../tokenTypes' import aspectRatio from './aspectRatio' import border from './border' -import boxShadow from './boxShadow' import flex from './flex' import flexFlow from './flexFlow' import font from './font' @@ -58,7 +57,6 @@ export default { borderColor, borderRadius, borderWidth, - boxShadow, flex, flexFlow, font, From 0c0a79ae2d9cb44e68e529e68e6bde05fea92b25 Mon Sep 17 00:00:00 2001 From: Wojciech Maj Date: Fri, 20 Mar 2026 10:33:23 +0100 Subject: [PATCH 2/2] Bump version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 73e1a3b..95f47a6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "css-to-react-native", - "version": "3.2.0", + "version": "4.0.0", "description": "Convert CSS text to a React Native stylesheet object", "main": "index.js", "types": "index.d.ts",