@cssxjs/css-to-react-native 3.2.0-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +21 -0
- package/README.md +115 -0
- package/index.d.ts +17 -0
- package/index.js +930 -0
- package/package.json +68 -0
- package/src/TokenStream.js +74 -0
- package/src/__tests__/aspectRatio.js +23 -0
- package/src/__tests__/border.js +141 -0
- package/src/__tests__/borderColor.js +92 -0
- package/src/__tests__/boxModel.js +136 -0
- package/src/__tests__/boxShadow.js +167 -0
- package/src/__tests__/colors.js +31 -0
- package/src/__tests__/flex.js +122 -0
- package/src/__tests__/flexFlow.js +22 -0
- package/src/__tests__/font.js +117 -0
- package/src/__tests__/fontFamily.js +43 -0
- package/src/__tests__/fontVariant.js +15 -0
- package/src/__tests__/fontWeight.js +8 -0
- package/src/__tests__/index.js +238 -0
- package/src/__tests__/placeContent.js +19 -0
- package/src/__tests__/shadowOffsets.js +13 -0
- package/src/__tests__/textDecoration.js +165 -0
- package/src/__tests__/textDecorationLine.js +23 -0
- package/src/__tests__/textShadow.js +107 -0
- package/src/__tests__/transform.js +69 -0
- package/src/__tests__/units.js +132 -0
- package/src/devPropertiesWithoutUnitsRegExp.js +19 -0
- package/src/index.js +90 -0
- package/src/tokenTypes.js +112 -0
- package/src/transforms/aspectRatio.js +12 -0
- package/src/transforms/border.js +57 -0
- package/src/transforms/boxShadow.js +11 -0
- package/src/transforms/flex.js +65 -0
- package/src/transforms/flexFlow.js +37 -0
- package/src/transforms/font.js +63 -0
- package/src/transforms/fontFamily.js +20 -0
- package/src/transforms/fontVariant.js +14 -0
- package/src/transforms/index.js +78 -0
- package/src/transforms/placeContent.js +24 -0
- package/src/transforms/textDecoration.js +56 -0
- package/src/transforms/textDecorationLine.js +18 -0
- package/src/transforms/textShadow.js +10 -0
- package/src/transforms/transform.js +74 -0
- package/src/transforms/util.js +103 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
import { stringify } from 'postcss-value-parser'
|
|
2
|
+
import cssColorKeywords from 'css-color-keywords'
|
|
3
|
+
|
|
4
|
+
const matchString = node => {
|
|
5
|
+
if (node.type !== 'string') return null
|
|
6
|
+
return node.value
|
|
7
|
+
.replace(/\\([0-9a-f]{1,6})(?:\s|$)/gi, (match, charCode) =>
|
|
8
|
+
String.fromCharCode(parseInt(charCode, 16))
|
|
9
|
+
)
|
|
10
|
+
.replace(/\\/g, '')
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
const hexColorRe = /^(#(?:[0-9a-f]{3,4}){1,2})$/i
|
|
14
|
+
const cssFunctionNameRe = /^(rgba?|hsla?|hwb|lab|lch|gray|color)$/
|
|
15
|
+
|
|
16
|
+
const matchColor = node => {
|
|
17
|
+
if (
|
|
18
|
+
node.type === 'word' &&
|
|
19
|
+
(hexColorRe.test(node.value) ||
|
|
20
|
+
node.value in cssColorKeywords ||
|
|
21
|
+
node.value === 'transparent')
|
|
22
|
+
) {
|
|
23
|
+
return node.value
|
|
24
|
+
} else if (node.type === 'function' && cssFunctionNameRe.test(node.value)) {
|
|
25
|
+
return stringify(node)
|
|
26
|
+
}
|
|
27
|
+
return null
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const matchVariable = node => {
|
|
31
|
+
if (
|
|
32
|
+
(node.type !== 'function' && node.value !== 'var') ||
|
|
33
|
+
node.nodes.length === 0
|
|
34
|
+
)
|
|
35
|
+
return null
|
|
36
|
+
|
|
37
|
+
const variableName = node.nodes[0].value
|
|
38
|
+
|
|
39
|
+
if (node.nodes.length === 1) {
|
|
40
|
+
return `var(${variableName})`
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const defaultValues = node.nodes
|
|
44
|
+
.slice(1)
|
|
45
|
+
.filter(subnode => subnode.type !== 'div')
|
|
46
|
+
.map(subnode => {
|
|
47
|
+
if (subnode.type === 'string') {
|
|
48
|
+
return `'${matchString(subnode)}'`
|
|
49
|
+
}
|
|
50
|
+
if (
|
|
51
|
+
subnode.type === 'function' &&
|
|
52
|
+
['rgb', 'rgba', 'hls', 'hlsa'].includes(subnode.value)
|
|
53
|
+
) {
|
|
54
|
+
return `${subnode.value}(${subnode.nodes.map(n => n.value).join('')})`
|
|
55
|
+
}
|
|
56
|
+
return subnode.value
|
|
57
|
+
})
|
|
58
|
+
|
|
59
|
+
if (defaultValues.length !== (node.nodes.length - 1) / 2) {
|
|
60
|
+
return null
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
return `var(${variableName}, ${defaultValues.join`, `})`
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const noneRe = /^(none)$/i
|
|
67
|
+
const autoRe = /^(auto)$/i
|
|
68
|
+
const identRe = /(^-?[_a-z][_a-z0-9-]*$)/i
|
|
69
|
+
// Note if these are wrong, you'll need to change index.js too
|
|
70
|
+
const numberRe = /^([+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?)$/i
|
|
71
|
+
// Note lengthRe is sneaky: you can omit units for 0
|
|
72
|
+
const lengthRe = /^(0$|(?:[+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?)(?=px$))/i
|
|
73
|
+
const unsupportedUnitRe = /^([+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?(ch|em|ex|rem|vh|vw|vmin|vmax|cm|mm|in|pc|pt))$/i
|
|
74
|
+
const angleRe = /^([+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?(?:deg|rad|grad|turn))$/i
|
|
75
|
+
const percentRe = /^([+-]?(?:\d*\.)?\d+(?:e[+-]?\d+)?%)$/i
|
|
76
|
+
|
|
77
|
+
const noopToken = predicate => node => (predicate(node) ? '<token>' : null)
|
|
78
|
+
|
|
79
|
+
const valueForTypeToken = type => node =>
|
|
80
|
+
node.type === type ? node.value : null
|
|
81
|
+
|
|
82
|
+
export const regExpToken = (regExp, transform = String) => node => {
|
|
83
|
+
if (node.type !== 'word') return null
|
|
84
|
+
|
|
85
|
+
const match = node.value.match(regExp)
|
|
86
|
+
if (match === null) return null
|
|
87
|
+
|
|
88
|
+
const value = transform(match[1])
|
|
89
|
+
|
|
90
|
+
return value
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export const SPACE = noopToken(node => node.type === 'space')
|
|
94
|
+
export const SLASH = noopToken(
|
|
95
|
+
node => node.type === 'div' && node.value === '/'
|
|
96
|
+
)
|
|
97
|
+
export const COMMA = noopToken(
|
|
98
|
+
node => node.type === 'div' && node.value === ','
|
|
99
|
+
)
|
|
100
|
+
export const WORD = valueForTypeToken('word')
|
|
101
|
+
export const NONE = regExpToken(noneRe)
|
|
102
|
+
export const AUTO = regExpToken(autoRe)
|
|
103
|
+
export const NUMBER = regExpToken(numberRe, Number)
|
|
104
|
+
export const LENGTH = regExpToken(lengthRe, Number)
|
|
105
|
+
export const UNSUPPORTED_LENGTH_UNIT = regExpToken(unsupportedUnitRe)
|
|
106
|
+
export const ANGLE = regExpToken(angleRe, angle => angle.toLowerCase())
|
|
107
|
+
export const PERCENT = regExpToken(percentRe)
|
|
108
|
+
export const IDENT = regExpToken(identRe)
|
|
109
|
+
export const STRING = matchString
|
|
110
|
+
export const COLOR = matchColor
|
|
111
|
+
export const LINE = regExpToken(/^(none|underline|line-through)$/i)
|
|
112
|
+
export const VARIABLE = matchVariable
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { NUMBER, SLASH } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
export default tokenStream => {
|
|
4
|
+
let aspectRatio = tokenStream.expect(NUMBER)
|
|
5
|
+
|
|
6
|
+
if (tokenStream.hasTokens()) {
|
|
7
|
+
tokenStream.expect(SLASH)
|
|
8
|
+
aspectRatio /= tokenStream.expect(NUMBER)
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return { aspectRatio }
|
|
12
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import {
|
|
2
|
+
regExpToken,
|
|
3
|
+
NONE,
|
|
4
|
+
COLOR,
|
|
5
|
+
LENGTH,
|
|
6
|
+
UNSUPPORTED_LENGTH_UNIT,
|
|
7
|
+
SPACE,
|
|
8
|
+
VARIABLE,
|
|
9
|
+
} from '../tokenTypes'
|
|
10
|
+
|
|
11
|
+
const BORDER_STYLE = regExpToken(/^(solid|dashed|dotted)$/)
|
|
12
|
+
|
|
13
|
+
const defaultBorderWidth = 1
|
|
14
|
+
const defaultBorderColor = 'black'
|
|
15
|
+
const defaultBorderStyle = 'solid'
|
|
16
|
+
|
|
17
|
+
export default tokenStream => {
|
|
18
|
+
let borderWidth
|
|
19
|
+
let borderColor
|
|
20
|
+
let borderStyle
|
|
21
|
+
|
|
22
|
+
if (tokenStream.matches(NONE)) {
|
|
23
|
+
tokenStream.expectEmpty()
|
|
24
|
+
return { borderWidth: 0, borderColor: 'black', borderStyle: 'solid' }
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
let partsParsed = 0
|
|
28
|
+
while (partsParsed < 3 && tokenStream.hasTokens()) {
|
|
29
|
+
if (partsParsed !== 0) tokenStream.expect(SPACE)
|
|
30
|
+
|
|
31
|
+
if (
|
|
32
|
+
borderWidth === undefined &&
|
|
33
|
+
tokenStream.matches(LENGTH, UNSUPPORTED_LENGTH_UNIT)
|
|
34
|
+
) {
|
|
35
|
+
borderWidth = tokenStream.lastValue
|
|
36
|
+
} else if (
|
|
37
|
+
borderColor === undefined &&
|
|
38
|
+
(tokenStream.matches(COLOR) || tokenStream.matches(VARIABLE))
|
|
39
|
+
) {
|
|
40
|
+
borderColor = tokenStream.lastValue
|
|
41
|
+
} else if (borderStyle === undefined && tokenStream.matches(BORDER_STYLE)) {
|
|
42
|
+
borderStyle = tokenStream.lastValue
|
|
43
|
+
} else {
|
|
44
|
+
tokenStream.throw()
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
partsParsed += 1
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
tokenStream.expectEmpty()
|
|
51
|
+
|
|
52
|
+
if (borderWidth === undefined) borderWidth = defaultBorderWidth
|
|
53
|
+
if (borderColor === undefined) borderColor = defaultBorderColor
|
|
54
|
+
if (borderStyle === undefined) borderStyle = defaultBorderStyle
|
|
55
|
+
|
|
56
|
+
return { borderWidth, borderColor, borderStyle }
|
|
57
|
+
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import {
|
|
2
|
+
NONE,
|
|
3
|
+
AUTO,
|
|
4
|
+
NUMBER,
|
|
5
|
+
LENGTH,
|
|
6
|
+
UNSUPPORTED_LENGTH_UNIT,
|
|
7
|
+
PERCENT,
|
|
8
|
+
SPACE,
|
|
9
|
+
} from '../tokenTypes'
|
|
10
|
+
|
|
11
|
+
const defaultFlexGrow = 1
|
|
12
|
+
const defaultFlexShrink = 1
|
|
13
|
+
const defaultFlexBasis = 0
|
|
14
|
+
|
|
15
|
+
export default tokenStream => {
|
|
16
|
+
let flexGrow
|
|
17
|
+
let flexShrink
|
|
18
|
+
let flexBasis
|
|
19
|
+
|
|
20
|
+
if (tokenStream.matches(NONE)) {
|
|
21
|
+
tokenStream.expectEmpty()
|
|
22
|
+
return { flexGrow: 0, flexShrink: 0, flexBasis: 'auto' }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
tokenStream.saveRewindPoint()
|
|
26
|
+
if (tokenStream.matches(AUTO) && !tokenStream.hasTokens()) {
|
|
27
|
+
return { flexGrow: 1, flexShrink: 1, flexBasis: 'auto' }
|
|
28
|
+
}
|
|
29
|
+
tokenStream.rewind()
|
|
30
|
+
|
|
31
|
+
let partsParsed = 0
|
|
32
|
+
while (partsParsed < 2 && tokenStream.hasTokens()) {
|
|
33
|
+
if (partsParsed !== 0) tokenStream.expect(SPACE)
|
|
34
|
+
|
|
35
|
+
if (flexGrow === undefined && tokenStream.matches(NUMBER)) {
|
|
36
|
+
flexGrow = tokenStream.lastValue
|
|
37
|
+
|
|
38
|
+
tokenStream.saveRewindPoint()
|
|
39
|
+
if (tokenStream.matches(SPACE) && tokenStream.matches(NUMBER)) {
|
|
40
|
+
flexShrink = tokenStream.lastValue
|
|
41
|
+
} else {
|
|
42
|
+
tokenStream.rewind()
|
|
43
|
+
}
|
|
44
|
+
} else if (
|
|
45
|
+
flexBasis === undefined &&
|
|
46
|
+
tokenStream.matches(LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT)
|
|
47
|
+
) {
|
|
48
|
+
flexBasis = tokenStream.lastValue
|
|
49
|
+
} else if (flexBasis === undefined && tokenStream.matches(AUTO)) {
|
|
50
|
+
flexBasis = 'auto'
|
|
51
|
+
} else {
|
|
52
|
+
tokenStream.throw()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
partsParsed += 1
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
tokenStream.expectEmpty()
|
|
59
|
+
|
|
60
|
+
if (flexGrow === undefined) flexGrow = defaultFlexGrow
|
|
61
|
+
if (flexShrink === undefined) flexShrink = defaultFlexShrink
|
|
62
|
+
if (flexBasis === undefined) flexBasis = defaultFlexBasis
|
|
63
|
+
|
|
64
|
+
return { flexGrow, flexShrink, flexBasis }
|
|
65
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { regExpToken, SPACE } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
const FLEX_WRAP = regExpToken(/(nowrap|wrap|wrap-reverse)/)
|
|
4
|
+
const FLEX_DIRECTION = regExpToken(/(row|row-reverse|column|column-reverse)/)
|
|
5
|
+
|
|
6
|
+
const defaultFlexWrap = 'nowrap'
|
|
7
|
+
const defaultFlexDirection = 'row'
|
|
8
|
+
|
|
9
|
+
export default tokenStream => {
|
|
10
|
+
let flexWrap
|
|
11
|
+
let flexDirection
|
|
12
|
+
|
|
13
|
+
let partsParsed = 0
|
|
14
|
+
while (partsParsed < 2 && tokenStream.hasTokens()) {
|
|
15
|
+
if (partsParsed !== 0) tokenStream.expect(SPACE)
|
|
16
|
+
|
|
17
|
+
if (flexWrap === undefined && tokenStream.matches(FLEX_WRAP)) {
|
|
18
|
+
flexWrap = tokenStream.lastValue
|
|
19
|
+
} else if (
|
|
20
|
+
flexDirection === undefined &&
|
|
21
|
+
tokenStream.matches(FLEX_DIRECTION)
|
|
22
|
+
) {
|
|
23
|
+
flexDirection = tokenStream.lastValue
|
|
24
|
+
} else {
|
|
25
|
+
tokenStream.throw()
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
partsParsed += 1
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
tokenStream.expectEmpty()
|
|
32
|
+
|
|
33
|
+
if (flexWrap === undefined) flexWrap = defaultFlexWrap
|
|
34
|
+
if (flexDirection === undefined) flexDirection = defaultFlexDirection
|
|
35
|
+
|
|
36
|
+
return { flexWrap, flexDirection }
|
|
37
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import parseFontFamily from './fontFamily'
|
|
2
|
+
import {
|
|
3
|
+
regExpToken,
|
|
4
|
+
SPACE,
|
|
5
|
+
LENGTH,
|
|
6
|
+
UNSUPPORTED_LENGTH_UNIT,
|
|
7
|
+
SLASH,
|
|
8
|
+
} from '../tokenTypes'
|
|
9
|
+
|
|
10
|
+
const NORMAL = regExpToken(/^(normal)$/)
|
|
11
|
+
const STYLE = regExpToken(/^(italic)$/)
|
|
12
|
+
const WEIGHT = regExpToken(/^([1-9]00|bold)$/)
|
|
13
|
+
const VARIANT = regExpToken(/^(small-caps)$/)
|
|
14
|
+
|
|
15
|
+
const defaultFontStyle = 'normal'
|
|
16
|
+
const defaultFontWeight = 'normal'
|
|
17
|
+
const defaultFontVariant = []
|
|
18
|
+
|
|
19
|
+
export default tokenStream => {
|
|
20
|
+
let fontStyle
|
|
21
|
+
let fontWeight
|
|
22
|
+
let fontVariant
|
|
23
|
+
// let fontSize;
|
|
24
|
+
let lineHeight
|
|
25
|
+
// let fontFamily;
|
|
26
|
+
|
|
27
|
+
let numStyleWeightVariantMatched = 0
|
|
28
|
+
while (numStyleWeightVariantMatched < 3 && tokenStream.hasTokens()) {
|
|
29
|
+
if (tokenStream.matches(NORMAL)) {
|
|
30
|
+
/* pass */
|
|
31
|
+
} else if (fontStyle === undefined && tokenStream.matches(STYLE)) {
|
|
32
|
+
fontStyle = tokenStream.lastValue
|
|
33
|
+
} else if (fontWeight === undefined && tokenStream.matches(WEIGHT)) {
|
|
34
|
+
fontWeight = tokenStream.lastValue
|
|
35
|
+
} else if (fontVariant === undefined && tokenStream.matches(VARIANT)) {
|
|
36
|
+
fontVariant = [tokenStream.lastValue]
|
|
37
|
+
} else {
|
|
38
|
+
break
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
tokenStream.expect(SPACE)
|
|
42
|
+
numStyleWeightVariantMatched += 1
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const fontSize = tokenStream.expect(LENGTH, UNSUPPORTED_LENGTH_UNIT)
|
|
46
|
+
|
|
47
|
+
if (tokenStream.matches(SLASH)) {
|
|
48
|
+
lineHeight = tokenStream.expect(LENGTH, UNSUPPORTED_LENGTH_UNIT)
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
tokenStream.expect(SPACE)
|
|
52
|
+
|
|
53
|
+
const { fontFamily } = parseFontFamily(tokenStream)
|
|
54
|
+
|
|
55
|
+
if (fontStyle === undefined) fontStyle = defaultFontStyle
|
|
56
|
+
if (fontWeight === undefined) fontWeight = defaultFontWeight
|
|
57
|
+
if (fontVariant === undefined) fontVariant = defaultFontVariant
|
|
58
|
+
|
|
59
|
+
const out = { fontStyle, fontWeight, fontVariant, fontSize, fontFamily }
|
|
60
|
+
if (lineHeight !== undefined) out.lineHeight = lineHeight
|
|
61
|
+
|
|
62
|
+
return out
|
|
63
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { SPACE, IDENT, STRING } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
export default tokenStream => {
|
|
4
|
+
let fontFamily
|
|
5
|
+
|
|
6
|
+
if (tokenStream.matches(STRING)) {
|
|
7
|
+
fontFamily = tokenStream.lastValue
|
|
8
|
+
} else {
|
|
9
|
+
fontFamily = tokenStream.expect(IDENT)
|
|
10
|
+
while (tokenStream.hasTokens()) {
|
|
11
|
+
tokenStream.expect(SPACE)
|
|
12
|
+
const nextIdent = tokenStream.expect(IDENT)
|
|
13
|
+
fontFamily += ` ${nextIdent}`
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
tokenStream.expectEmpty()
|
|
18
|
+
|
|
19
|
+
return { fontFamily }
|
|
20
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { SPACE, IDENT } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
export default tokenStream => {
|
|
4
|
+
const values = [tokenStream.expect(IDENT)]
|
|
5
|
+
|
|
6
|
+
while (tokenStream.hasTokens()) {
|
|
7
|
+
tokenStream.expect(SPACE)
|
|
8
|
+
values.push(tokenStream.expect(IDENT))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
return {
|
|
12
|
+
fontVariant: values,
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import {
|
|
2
|
+
AUTO,
|
|
3
|
+
COLOR,
|
|
4
|
+
LENGTH,
|
|
5
|
+
PERCENT,
|
|
6
|
+
UNSUPPORTED_LENGTH_UNIT,
|
|
7
|
+
WORD,
|
|
8
|
+
VARIABLE,
|
|
9
|
+
} from '../tokenTypes'
|
|
10
|
+
import aspectRatio from './aspectRatio'
|
|
11
|
+
import border from './border'
|
|
12
|
+
import boxShadow from './boxShadow'
|
|
13
|
+
import flex from './flex'
|
|
14
|
+
import flexFlow from './flexFlow'
|
|
15
|
+
import font from './font'
|
|
16
|
+
import fontFamily from './fontFamily'
|
|
17
|
+
import fontVariant from './fontVariant'
|
|
18
|
+
import placeContent from './placeContent'
|
|
19
|
+
import textDecoration from './textDecoration'
|
|
20
|
+
import textDecorationLine from './textDecorationLine'
|
|
21
|
+
import textShadow from './textShadow'
|
|
22
|
+
import transform from './transform'
|
|
23
|
+
import { directionFactory, parseShadowOffset } from './util'
|
|
24
|
+
|
|
25
|
+
const background = tokenStream => ({
|
|
26
|
+
backgroundColor: tokenStream.expect(COLOR, VARIABLE),
|
|
27
|
+
})
|
|
28
|
+
const borderColor = directionFactory({
|
|
29
|
+
types: [COLOR, VARIABLE],
|
|
30
|
+
prefix: 'border',
|
|
31
|
+
suffix: 'Color',
|
|
32
|
+
})
|
|
33
|
+
const borderRadius = directionFactory({
|
|
34
|
+
directions: ['TopLeft', 'TopRight', 'BottomRight', 'BottomLeft'],
|
|
35
|
+
prefix: 'border',
|
|
36
|
+
suffix: 'Radius',
|
|
37
|
+
})
|
|
38
|
+
const borderWidth = directionFactory({ prefix: 'border', suffix: 'Width' })
|
|
39
|
+
const margin = directionFactory({
|
|
40
|
+
types: [LENGTH, UNSUPPORTED_LENGTH_UNIT, PERCENT, AUTO],
|
|
41
|
+
prefix: 'margin',
|
|
42
|
+
})
|
|
43
|
+
const padding = directionFactory({ prefix: 'padding' })
|
|
44
|
+
|
|
45
|
+
const fontWeight = tokenStream => ({
|
|
46
|
+
fontWeight: tokenStream.expect(WORD), // Also match numbers as strings
|
|
47
|
+
})
|
|
48
|
+
const shadowOffset = tokenStream => ({
|
|
49
|
+
shadowOffset: parseShadowOffset(tokenStream),
|
|
50
|
+
})
|
|
51
|
+
const textShadowOffset = tokenStream => ({
|
|
52
|
+
textShadowOffset: parseShadowOffset(tokenStream),
|
|
53
|
+
})
|
|
54
|
+
|
|
55
|
+
export default {
|
|
56
|
+
aspectRatio,
|
|
57
|
+
background,
|
|
58
|
+
border,
|
|
59
|
+
borderColor,
|
|
60
|
+
borderRadius,
|
|
61
|
+
borderWidth,
|
|
62
|
+
boxShadow,
|
|
63
|
+
flex,
|
|
64
|
+
flexFlow,
|
|
65
|
+
font,
|
|
66
|
+
fontFamily,
|
|
67
|
+
fontVariant,
|
|
68
|
+
fontWeight,
|
|
69
|
+
margin,
|
|
70
|
+
padding,
|
|
71
|
+
placeContent,
|
|
72
|
+
shadowOffset,
|
|
73
|
+
textShadow,
|
|
74
|
+
textShadowOffset,
|
|
75
|
+
textDecoration,
|
|
76
|
+
textDecorationLine,
|
|
77
|
+
transform,
|
|
78
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { regExpToken, SPACE } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
const ALIGN_CONTENT = regExpToken(
|
|
4
|
+
/(flex-(?:start|end)|center|stretch|space-(?:between|around))/
|
|
5
|
+
)
|
|
6
|
+
const JUSTIFY_CONTENT = regExpToken(
|
|
7
|
+
/(flex-(?:start|end)|center|space-(?:between|around|evenly))/
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
export default tokenStream => {
|
|
11
|
+
const alignContent = tokenStream.expect(ALIGN_CONTENT)
|
|
12
|
+
|
|
13
|
+
let justifyContent
|
|
14
|
+
if (tokenStream.hasTokens()) {
|
|
15
|
+
tokenStream.expect(SPACE)
|
|
16
|
+
justifyContent = tokenStream.expect(JUSTIFY_CONTENT)
|
|
17
|
+
} else {
|
|
18
|
+
justifyContent = 'stretch'
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
tokenStream.expectEmpty()
|
|
22
|
+
|
|
23
|
+
return { alignContent, justifyContent }
|
|
24
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { regExpToken, SPACE, LINE, COLOR, VARIABLE } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
const STYLE = regExpToken(/^(solid|double|dotted|dashed)$/)
|
|
4
|
+
|
|
5
|
+
const defaultTextDecorationLine = 'none'
|
|
6
|
+
const defaultTextDecorationStyle = 'solid'
|
|
7
|
+
const defaultTextDecorationColor = 'black'
|
|
8
|
+
|
|
9
|
+
export default tokenStream => {
|
|
10
|
+
let line
|
|
11
|
+
let style
|
|
12
|
+
let color
|
|
13
|
+
|
|
14
|
+
let didParseFirst = false
|
|
15
|
+
while (tokenStream.hasTokens()) {
|
|
16
|
+
if (didParseFirst) tokenStream.expect(SPACE)
|
|
17
|
+
|
|
18
|
+
if (line === undefined && tokenStream.matches(LINE)) {
|
|
19
|
+
const lines = [tokenStream.lastValue.toLowerCase()]
|
|
20
|
+
|
|
21
|
+
tokenStream.saveRewindPoint()
|
|
22
|
+
if (
|
|
23
|
+
lines[0] !== 'none' &&
|
|
24
|
+
tokenStream.matches(SPACE) &&
|
|
25
|
+
tokenStream.matches(LINE)
|
|
26
|
+
) {
|
|
27
|
+
lines.push(tokenStream.lastValue.toLowerCase())
|
|
28
|
+
// Underline comes before line-through
|
|
29
|
+
lines.sort().reverse()
|
|
30
|
+
} else {
|
|
31
|
+
tokenStream.rewind()
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
line = lines.join(' ')
|
|
35
|
+
} else if (style === undefined && tokenStream.matches(STYLE)) {
|
|
36
|
+
style = tokenStream.lastValue
|
|
37
|
+
} else if (
|
|
38
|
+
color === undefined &&
|
|
39
|
+
(tokenStream.matches(COLOR) || tokenStream.matches(VARIABLE))
|
|
40
|
+
) {
|
|
41
|
+
color = tokenStream.lastValue
|
|
42
|
+
} else {
|
|
43
|
+
tokenStream.throw()
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
didParseFirst = true
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
textDecorationLine: line !== undefined ? line : defaultTextDecorationLine,
|
|
51
|
+
textDecorationColor:
|
|
52
|
+
color !== undefined ? color : defaultTextDecorationColor,
|
|
53
|
+
textDecorationStyle:
|
|
54
|
+
style !== undefined ? style : defaultTextDecorationStyle,
|
|
55
|
+
}
|
|
56
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { SPACE, LINE } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
export default tokenStream => {
|
|
4
|
+
const lines = []
|
|
5
|
+
|
|
6
|
+
let didParseFirst = false
|
|
7
|
+
while (tokenStream.hasTokens()) {
|
|
8
|
+
if (didParseFirst) tokenStream.expect(SPACE)
|
|
9
|
+
|
|
10
|
+
lines.push(tokenStream.expect(LINE).toLowerCase())
|
|
11
|
+
|
|
12
|
+
didParseFirst = true
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
lines.sort().reverse()
|
|
16
|
+
|
|
17
|
+
return { textDecorationLine: lines.join(' ') }
|
|
18
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { SPACE, COMMA, LENGTH, NUMBER, ANGLE, PERCENT } from '../tokenTypes'
|
|
2
|
+
|
|
3
|
+
const oneOfTypes = tokenTypes => functionStream => {
|
|
4
|
+
const value = functionStream.expect(...tokenTypes)
|
|
5
|
+
functionStream.expectEmpty()
|
|
6
|
+
return value
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const singleNumber = oneOfTypes([NUMBER])
|
|
10
|
+
const singleLengthOrPercent = oneOfTypes([LENGTH, PERCENT])
|
|
11
|
+
const singleAngle = oneOfTypes([ANGLE])
|
|
12
|
+
const xyTransformFactory = tokenTypes => (
|
|
13
|
+
key,
|
|
14
|
+
valueIfOmitted
|
|
15
|
+
) => functionStream => {
|
|
16
|
+
const x = functionStream.expect(...tokenTypes)
|
|
17
|
+
|
|
18
|
+
let y
|
|
19
|
+
if (functionStream.hasTokens()) {
|
|
20
|
+
functionStream.expect(COMMA)
|
|
21
|
+
y = functionStream.expect(...tokenTypes)
|
|
22
|
+
} else if (valueIfOmitted !== undefined) {
|
|
23
|
+
y = valueIfOmitted
|
|
24
|
+
} else {
|
|
25
|
+
// Assumption, if x === y, then we can omit XY
|
|
26
|
+
// I.e. scale(5) => [{ scale: 5 }] rather than [{ scaleX: 5 }, { scaleY: 5 }]
|
|
27
|
+
return x
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
functionStream.expectEmpty()
|
|
31
|
+
|
|
32
|
+
return [{ [`${key}Y`]: y }, { [`${key}X`]: x }]
|
|
33
|
+
}
|
|
34
|
+
const xyNumber = xyTransformFactory([NUMBER])
|
|
35
|
+
const xyLengthOrPercent = xyTransformFactory([LENGTH, PERCENT])
|
|
36
|
+
const xyAngle = xyTransformFactory([ANGLE])
|
|
37
|
+
|
|
38
|
+
const partTransforms = {
|
|
39
|
+
perspective: singleNumber,
|
|
40
|
+
scale: xyNumber('scale'),
|
|
41
|
+
scaleX: singleNumber,
|
|
42
|
+
scaleY: singleNumber,
|
|
43
|
+
translate: xyLengthOrPercent('translate', 0),
|
|
44
|
+
translateX: singleLengthOrPercent,
|
|
45
|
+
translateY: singleLengthOrPercent,
|
|
46
|
+
rotate: singleAngle,
|
|
47
|
+
rotateX: singleAngle,
|
|
48
|
+
rotateY: singleAngle,
|
|
49
|
+
rotateZ: singleAngle,
|
|
50
|
+
skewX: singleAngle,
|
|
51
|
+
skewY: singleAngle,
|
|
52
|
+
skew: xyAngle('skew', '0deg'),
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export default tokenStream => {
|
|
56
|
+
let transforms = []
|
|
57
|
+
|
|
58
|
+
let didParseFirst = false
|
|
59
|
+
while (tokenStream.hasTokens()) {
|
|
60
|
+
if (didParseFirst) tokenStream.expect(SPACE)
|
|
61
|
+
|
|
62
|
+
const functionStream = tokenStream.expectFunction()
|
|
63
|
+
const { functionName } = functionStream
|
|
64
|
+
let transformedValues = partTransforms[functionName](functionStream)
|
|
65
|
+
if (!Array.isArray(transformedValues)) {
|
|
66
|
+
transformedValues = [{ [functionName]: transformedValues }]
|
|
67
|
+
}
|
|
68
|
+
transforms = transformedValues.concat(transforms)
|
|
69
|
+
|
|
70
|
+
didParseFirst = true
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
return { transform: transforms }
|
|
74
|
+
}
|