-
Notifications
You must be signed in to change notification settings - Fork 24.5k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Implement transform-origin for old arch iOS
- Loading branch information
Showing
12 changed files
with
431 additions
and
5 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
5 changes: 5 additions & 0 deletions
5
...t-native/Libraries/StyleSheet/__tests__/__snapshots__/processTransformOrigin-test.js.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
// Jest Snapshot v1, https://goo.gl/fbAQLP | ||
|
||
exports[`processTransformOrigin validation only accepts three values 1`] = `"Transform origin must have exactly 3 values."`; | ||
|
||
exports[`processTransformOrigin validation only accepts three values 2`] = `"Transform origin must have exactly 3 values."`; |
134 changes: 134 additions & 0 deletions
134
packages/react-native/Libraries/StyleSheet/__tests__/processTransformOrigin-test.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @format | ||
* @oncall react_native | ||
*/ | ||
|
||
import processTransformOrigin from '../processTransformOrigin'; | ||
|
||
describe('processTransformOrigin', () => { | ||
describe('validation', () => { | ||
it('only accepts three values', () => { | ||
expect(() => { | ||
processTransformOrigin([]); | ||
}).toThrowErrorMatchingSnapshot(); | ||
expect(() => { | ||
processTransformOrigin(['50%', '50%']); | ||
}).toThrowErrorMatchingSnapshot(); | ||
}); | ||
|
||
it('should transform a string', () => { | ||
expect(processTransformOrigin('50% 50% 5px')).toEqual(['50%', '50%', 5]); | ||
}); | ||
|
||
it('should handle one value', () => { | ||
expect(processTransformOrigin('top')).toEqual(['50%', 0, 0]); | ||
expect(processTransformOrigin('right')).toEqual(['100%', '50%', 0]); | ||
expect(processTransformOrigin('bottom')).toEqual(['50%', '100%', 0]); | ||
expect(processTransformOrigin('left')).toEqual([0, '50%', 0]); | ||
}); | ||
|
||
it('should handle two values', () => { | ||
expect(processTransformOrigin('30% top')).toEqual(['30%', 0, 0]); | ||
expect(processTransformOrigin('right 30%')).toEqual(['100%', '30%', 0]); | ||
expect(processTransformOrigin('30% bottom')).toEqual(['30%', '100%', 0]); | ||
expect(processTransformOrigin('left 30%')).toEqual([0, '30%', 0]); | ||
}); | ||
|
||
it('should handle two keywords in either order', () => { | ||
expect(processTransformOrigin('right bottom')).toEqual([ | ||
'100%', | ||
'100%', | ||
0, | ||
]); | ||
expect(processTransformOrigin('bottom right')).toEqual([ | ||
'100%', | ||
'100%', | ||
0, | ||
]); | ||
expect(processTransformOrigin('right bottom 5px')).toEqual([ | ||
'100%', | ||
'100%', | ||
5, | ||
]); | ||
expect(processTransformOrigin('bottom right 5px')).toEqual([ | ||
'100%', | ||
'100%', | ||
5, | ||
]); | ||
}); | ||
|
||
it('should not allow specifying same position twice', () => { | ||
expect(() => { | ||
processTransformOrigin('top top'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Could not parse transform-origin: top top"`, | ||
); | ||
expect(() => { | ||
processTransformOrigin('right right'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Transform-origin right can only be used for x-position"`, | ||
); | ||
expect(() => { | ||
processTransformOrigin('bottom bottom'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Could not parse transform-origin: bottom bottom"`, | ||
); | ||
expect(() => { | ||
processTransformOrigin('left left'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Transform-origin left can only be used for x-position"`, | ||
); | ||
expect(() => { | ||
processTransformOrigin('top bottom'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Could not parse transform-origin: top bottom"`, | ||
); | ||
expect(() => { | ||
processTransformOrigin('left right'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Transform-origin right can only be used for x-position"`, | ||
); | ||
}); | ||
|
||
it('should handle three values', () => { | ||
expect(processTransformOrigin('30% top 10px')).toEqual(['30%', 0, 10]); | ||
expect(processTransformOrigin('right 30% 10px')).toEqual([ | ||
'100%', | ||
'30%', | ||
10, | ||
]); | ||
expect(processTransformOrigin('30% bottom 10px')).toEqual([ | ||
'30%', | ||
'100%', | ||
10, | ||
]); | ||
expect(processTransformOrigin('left 30% 10px')).toEqual([0, '30%', 10]); | ||
}); | ||
|
||
it('should enforce two value ordering', () => { | ||
expect(() => { | ||
processTransformOrigin('top 30%'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Could not parse transform-origin: top 30%"`, | ||
); | ||
}); | ||
|
||
it('should not allow percents for z-position', () => { | ||
expect(() => { | ||
processTransformOrigin('top 30% 30%'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Could not parse transform-origin: top 30% 30%"`, | ||
); | ||
expect(() => { | ||
processTransformOrigin('top 30% center'); | ||
}).toThrowErrorMatchingInlineSnapshot( | ||
`"Could not parse transform-origin: top 30% center"`, | ||
); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
136 changes: 136 additions & 0 deletions
136
packages/react-native/Libraries/StyleSheet/processTransformOrigin.js
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,136 @@ | ||
/** | ||
* Copyright (c) Meta Platforms, Inc. and affiliates. | ||
* | ||
* This source code is licensed under the MIT license found in the | ||
* LICENSE file in the root directory of this source tree. | ||
* | ||
* @format | ||
* @flow | ||
*/ | ||
|
||
import invariant from 'invariant'; | ||
|
||
const INDEX_X = 0; | ||
const INDEX_Y = 1; | ||
const INDEX_Z = 2; | ||
|
||
/* eslint-disable no-labels */ | ||
export default function processTransformOrigin( | ||
transformOrigin: Array<string | number> | string, | ||
): Array<string | number> { | ||
if (typeof transformOrigin === 'string') { | ||
const transformOriginString = transformOrigin; | ||
const regex = /(top|bottom|left|right|center|\d+(?:%|px)|0)/gi; | ||
const transformOriginArray: Array<string | number> = ['50%', '50%', 0]; | ||
|
||
let index = INDEX_X; | ||
let matches; | ||
outer: while ((matches = regex.exec(transformOriginString))) { | ||
let nextIndex = index + 1; | ||
|
||
const value = matches[0]; | ||
const valueLower = value.toLowerCase(); | ||
|
||
switch (valueLower) { | ||
case 'left': | ||
case 'right': { | ||
invariant( | ||
index === INDEX_X, | ||
'Transform-origin %s can only be used for x-position', | ||
value, | ||
); | ||
transformOriginArray[INDEX_X] = valueLower === 'left' ? 0 : '100%'; | ||
break; | ||
} | ||
case 'top': | ||
case 'bottom': { | ||
invariant( | ||
index !== INDEX_Z, | ||
'Transform-origin %s can only be used for y-position', | ||
value, | ||
); | ||
transformOriginArray[INDEX_Y] = valueLower === 'top' ? 0 : '100%'; | ||
|
||
// Handle [[ center | left | right ] && [ center | top | bottom ]] <length>? | ||
if (index === INDEX_X) { | ||
const horizontal = regex.exec(transformOriginString); | ||
if (horizontal == null) { | ||
break outer; | ||
} | ||
|
||
switch (horizontal[0].toLowerCase()) { | ||
case 'left': | ||
transformOriginArray[INDEX_X] = 0; | ||
break; | ||
case 'right': | ||
transformOriginArray[INDEX_X] = '100%'; | ||
break; | ||
case 'center': | ||
transformOriginArray[INDEX_X] = '50%'; | ||
break; | ||
default: | ||
invariant( | ||
false, | ||
'Could not parse transform-origin: %s', | ||
transformOriginString, | ||
); | ||
} | ||
nextIndex = INDEX_Z; | ||
} | ||
|
||
break; | ||
} | ||
case 'center': { | ||
invariant( | ||
index !== INDEX_Z, | ||
'Transform-origin value %s cannot be used for z-position', | ||
value, | ||
); | ||
transformOriginArray[index] = '50%'; | ||
break; | ||
} | ||
default: { | ||
if (value.endsWith('%')) { | ||
transformOriginArray[index] = value; | ||
} else { | ||
transformOriginArray[index] = parseFloat(value); // Remove `px` | ||
} | ||
break; | ||
} | ||
} | ||
|
||
index = nextIndex; | ||
} | ||
|
||
transformOrigin = transformOriginArray; | ||
} | ||
|
||
if (__DEV__) { | ||
_validateTransformOrigin(transformOrigin); | ||
} | ||
|
||
return transformOrigin; | ||
} | ||
|
||
function _validateTransformOrigin(transformOrigin: Array<string | number>) { | ||
invariant( | ||
transformOrigin.length === 3, | ||
'Transform origin must have exactly 3 values.', | ||
); | ||
const [x, y, z] = transformOrigin; | ||
invariant( | ||
typeof x === 'number' || (typeof x === 'string' && x.endsWith('%')), | ||
'Transform origin x-position must be a number. Passed value: %s.', | ||
x, | ||
); | ||
invariant( | ||
typeof y === 'number' || (typeof y === 'string' && y.endsWith('%')), | ||
'Transform origin y-position must be a number. Passed value: %s.', | ||
y, | ||
); | ||
invariant( | ||
typeof z === 'number', | ||
'Transform origin z-position must be a number. Passed value: %s.', | ||
z, | ||
); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.