Skip to content

Implement support for box-shadow shorthand #47

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ margin: 5px 7px 2px;

Shorthands will only accept values that are supported in React, so `background` will only accept a colour, `backgroundColor`

There is also support for the `box-shadow` shorthand, and this converts into `shadow-` properties. Note that these only work on iOS.

#### Shorthand Notes

`border{Top,Right,Bottom,Left}` shorthands are not supported, because `borderStyle` cannot be applied to individual border sides.
Expand Down
4 changes: 2 additions & 2 deletions src/TokenStream.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ module.exports = class TokenStream {
return this.throw();
}

matchFunction() {
matchesFunction() {
const node = this.node;
if (node.type !== 'function') return null;
const value = new TokenStream(node.nodes, node);
Expand All @@ -69,7 +69,7 @@ module.exports = class TokenStream {
}

expectFunction() {
const value = this.matchFunction();
const value = this.matchesFunction();
if (value !== null) return value;
return this.throw();
}
Expand Down
42 changes: 42 additions & 0 deletions src/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,48 @@ it('does not transform invalid flex', () => {
expect(() => transformCss([['flex', '1 2px 3']])).toThrow();
});

it('transforms box-shadow into shadow- properties', () => runTest([
['box-shadow', '10px 20px 30px red'],
], {
shadowOffset: { width: 10, height: 20 },
shadowRadius: 30,
shadowColor: 'red',
}));

it('transforms box-shadow without blur-radius', () => runTest([
['box-shadow', '10px 20px red'],
], {
shadowOffset: { width: 10, height: 20 },
shadowRadius: 0,
shadowColor: 'red',
}));

it('transforms box-shadow without color', () => runTest([
['box-shadow', '10px 20px red'],
], {
shadowOffset: { width: 10, height: 20 },
shadowRadius: 0,
shadowColor: 'red',
}));

it('transforms box-shadow without blur-radius, color', () => runTest([
['box-shadow', '10px 20px'],
], {
shadowOffset: { width: 10, height: 20 },
shadowRadius: 0,
shadowColor: 'black',
}));

it('transforms box-shadow enforces offset to be present', () => {
expect(() => transformCss([['box-shadow', 'red']]))
.toThrow('Failed to parse declaration "boxShadow: red"');
});

it('transforms box-shadow and enforces offset-y if offset-x present', () => {
expect(() => transformCss([['box-shadow', '10px']]))
.toThrow('Failed to parse declaration "boxShadow: 10px"');
});

it('allows blacklisting shorthands', () => {
const actualStyles = transformCss([['border-radius', '50']], ['borderRadius']);
expect(actualStyles).toEqual({ borderRadius: 50 });
Expand Down
50 changes: 50 additions & 0 deletions src/transforms/boxShadow.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
const { tokens } = require('../tokenTypes');

const { NONE, SPACE, WORD, LENGTH } = tokens;

module.exports = (tokenStream) => {
let offsetX;
let offsetY;
let blurRadius;
let color;

if (tokenStream.matches(NONE)) {
tokenStream.expectEmpty();
return {
$merge: { shadowOffset: { width: 0, height: 0 }, shadowRadius: 0, shadowColor: 'black' },
};
}

let didParseFirst = false;
while (tokenStream.hasTokens()) {
if (didParseFirst) tokenStream.expect(SPACE);

if (offsetX === undefined && tokenStream.matches(LENGTH)) {
offsetX = tokenStream.lastValue;
tokenStream.expect(SPACE);
offsetY = tokenStream.expect(LENGTH);

if (tokenStream.lookAhead().matches(LENGTH)) {
tokenStream.expect(SPACE);
blurRadius = tokenStream.expect(LENGTH);
}
} else if (color === undefined && (
tokenStream.matchesFunction() || tokenStream.matches(WORD)
)) {
color = String(tokenStream.lastValue);
} else {
tokenStream.throw();
}

didParseFirst = true;
}

if (offsetX === undefined) tokenStream.throw();

const $merge = {
shadowOffset: { width: offsetX, height: offsetY },
shadowRadius: blurRadius !== undefined ? blurRadius : 0,
shadowColor: color !== undefined ? color : 'black',
};
return { $merge };
};
2 changes: 2 additions & 0 deletions src/transforms/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
const { regExpToken, tokens } = require('../tokenTypes');
const boxShadow = require('./boxShadow');
const flex = require('./flex');
const font = require('./font');
const fontFamily = require('./fontFamily');
Expand Down Expand Up @@ -56,6 +57,7 @@ module.exports = {
borderColor,
borderRadius,
borderWidth,
boxShadow,
flex,
flexFlow,
font,
Expand Down