@mpxjs/webpack-plugin 2.9.59 → 2.9.64
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/lib/index.js +1 -3
- package/lib/platform/style/wx/index.js +344 -270
- package/lib/platform/template/wx/component-config/checkbox-group.js +8 -0
- package/lib/platform/template/wx/component-config/checkbox.js +8 -0
- package/lib/platform/template/wx/component-config/cover-image.js +15 -0
- package/lib/platform/template/wx/component-config/cover-view.js +9 -0
- package/lib/platform/template/wx/component-config/form.js +13 -1
- package/lib/platform/template/wx/component-config/icon.js +8 -0
- package/lib/platform/template/wx/component-config/index.js +5 -1
- package/lib/platform/template/wx/component-config/label.js +15 -0
- package/lib/platform/template/wx/component-config/movable-area.js +18 -1
- package/lib/platform/template/wx/component-config/movable-view.js +18 -1
- package/lib/platform/template/wx/component-config/navigator.js +8 -0
- package/lib/platform/template/wx/component-config/picker-view-column.js +8 -0
- package/lib/platform/template/wx/component-config/picker-view.js +18 -2
- package/lib/platform/template/wx/component-config/picker.js +14 -1
- package/lib/platform/template/wx/component-config/radio-group.js +8 -0
- package/lib/platform/template/wx/component-config/radio.js +8 -0
- package/lib/platform/template/wx/component-config/root-portal.js +15 -0
- package/lib/platform/template/wx/component-config/switch.js +8 -0
- package/lib/platform/template/wx/component-config/unsupported.js +1 -3
- package/lib/react/processScript.js +2 -0
- package/lib/react/processStyles.js +1 -0
- package/lib/react/processTemplate.js +2 -3
- package/lib/react/style-helper.js +12 -7
- package/lib/runtime/components/react/context.ts +40 -0
- package/lib/runtime/components/react/dist/context.js +8 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +34 -12
- package/lib/runtime/components/react/dist/mpx-button.jsx +88 -88
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +82 -0
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +139 -0
- package/lib/runtime/components/react/dist/mpx-form.jsx +61 -0
- package/lib/runtime/components/react/dist/mpx-icon.jsx +48 -0
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +39 -43
- package/lib/runtime/components/react/dist/mpx-image/svg.jsx +3 -2
- package/lib/runtime/components/react/dist/mpx-input.jsx +63 -37
- package/lib/runtime/components/react/dist/mpx-label.jsx +55 -0
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +41 -0
- package/lib/runtime/components/react/dist/mpx-movable-view.jsx +346 -0
- package/lib/runtime/components/react/dist/mpx-navigator.jsx +35 -0
- package/lib/runtime/components/react/dist/mpx-picker/date.jsx +69 -0
- package/lib/runtime/components/react/dist/mpx-picker/index.jsx +138 -0
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +142 -0
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +94 -0
- package/lib/runtime/components/react/dist/mpx-picker/regionData.js +6099 -0
- package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +76 -0
- package/lib/runtime/components/react/dist/mpx-picker/time.jsx +244 -0
- package/lib/runtime/components/react/dist/mpx-picker/type.js +1 -0
- package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +107 -0
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +162 -0
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +80 -0
- package/lib/runtime/components/react/dist/mpx-radio.jsx +154 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +15 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +93 -70
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +281 -157
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +21 -11
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +19 -11
- package/lib/runtime/components/react/dist/mpx-switch.jsx +79 -0
- package/lib/runtime/components/react/dist/mpx-text.jsx +21 -49
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-view.jsx +451 -146
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +17 -20
- package/lib/runtime/components/react/dist/parser.js +218 -0
- package/lib/runtime/components/react/dist/types/common.js +1 -0
- package/lib/runtime/components/react/dist/useNodesRef.js +3 -8
- package/lib/runtime/components/react/dist/utils.jsx +433 -0
- package/lib/runtime/components/react/getInnerListeners.ts +43 -21
- package/lib/runtime/components/react/mpx-button.tsx +129 -119
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +152 -0
- package/lib/runtime/components/react/mpx-checkbox.tsx +234 -0
- package/lib/runtime/components/react/mpx-form.tsx +117 -0
- package/lib/runtime/components/react/mpx-icon.tsx +106 -0
- package/lib/runtime/components/react/mpx-image/index.tsx +62 -68
- package/lib/runtime/components/react/mpx-image/svg.tsx +7 -5
- package/lib/runtime/components/react/mpx-input.tsx +90 -42
- package/lib/runtime/components/react/mpx-label.tsx +110 -0
- package/lib/runtime/components/react/mpx-movable-area.tsx +81 -0
- package/lib/runtime/components/react/mpx-movable-view.tsx +424 -0
- package/lib/runtime/components/react/mpx-navigator.tsx +67 -0
- package/lib/runtime/components/react/mpx-picker/date.tsx +82 -0
- package/lib/runtime/components/react/mpx-picker/index.tsx +155 -0
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +156 -0
- package/lib/runtime/components/react/mpx-picker/region.tsx +107 -0
- package/lib/runtime/components/react/mpx-picker/regionData.ts +6101 -0
- package/lib/runtime/components/react/mpx-picker/selector.tsx +91 -0
- package/lib/runtime/components/react/mpx-picker/time.tsx +270 -0
- package/lib/runtime/components/react/mpx-picker/type.ts +107 -0
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +156 -0
- package/lib/runtime/components/react/mpx-picker-view.tsx +220 -0
- package/lib/runtime/components/react/mpx-radio-group.tsx +150 -0
- package/lib/runtime/components/react/mpx-radio.tsx +230 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +27 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +184 -130
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +308 -183
- package/lib/runtime/components/react/mpx-swiper/index.tsx +27 -19
- package/lib/runtime/components/react/mpx-swiper/type.ts +23 -5
- package/lib/runtime/components/react/mpx-swiper-item.tsx +49 -14
- package/lib/runtime/components/react/mpx-switch.tsx +148 -0
- package/lib/runtime/components/react/mpx-text.tsx +53 -77
- package/lib/runtime/components/react/mpx-textarea.tsx +3 -3
- package/lib/runtime/components/react/mpx-view.tsx +576 -195
- package/lib/runtime/components/react/mpx-web-view.tsx +34 -39
- package/lib/runtime/components/react/parser.ts +245 -0
- package/lib/runtime/components/react/types/common.ts +12 -0
- package/lib/runtime/components/react/types/getInnerListeners.ts +2 -1
- package/lib/runtime/components/react/types/global.d.ts +17 -1
- package/lib/runtime/components/react/useNodesRef.ts +4 -10
- package/lib/runtime/components/react/utils.tsx +505 -0
- package/lib/runtime/optionProcessor.js +19 -17
- package/lib/template-compiler/compiler.js +84 -61
- package/lib/template-compiler/gen-node-react.js +7 -9
- package/lib/web/processStyles.js +2 -5
- package/package.json +8 -3
- package/lib/runtime/components/react/dist/utils.js +0 -80
- package/lib/runtime/components/react/utils.ts +0 -92
|
@@ -2,23 +2,49 @@ const { hump2dash } = require('../../../utils/hump-dash')
|
|
|
2
2
|
|
|
3
3
|
module.exports = function getSpec ({ warn, error }) {
|
|
4
4
|
// React Native 双端都不支持的 CSS property
|
|
5
|
-
const unsupportedPropExp = /^(
|
|
5
|
+
const unsupportedPropExp = /^(white-space|text-overflow|animation|transition|font-variant-caps|font-variant-numeric|font-variant-east-asian|font-variant-alternates|font-variant-ligatures|background-position|caret-color)$/
|
|
6
6
|
const unsupportedPropMode = {
|
|
7
7
|
// React Native ios 不支持的 CSS property
|
|
8
8
|
ios: /^(vertical-align)$/,
|
|
9
9
|
// React Native android 不支持的 CSS property
|
|
10
10
|
android: /^(text-decoration-style|text-decoration-color|shadow-offset|shadow-opacity|shadow-radius)$/
|
|
11
11
|
}
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
// var(xx)
|
|
13
|
+
const cssVariableExp = /var\(/
|
|
14
|
+
// calc(xx)
|
|
15
|
+
const calcExp = /calc\(/
|
|
16
|
+
// 不支持的属性提示
|
|
17
|
+
const unsupportedPropError = ({ prop, value, selector }, { mode }, isError = true) => {
|
|
18
|
+
const tips = isError ? error : warn
|
|
19
|
+
tips(`Property [${prop}] on ${selector} is not supported in ${mode} environment!`)
|
|
20
|
+
}
|
|
21
|
+
// prop 校验
|
|
22
|
+
const verifyProps = ({ prop, value, selector }, { mode }, isError = true) => {
|
|
23
|
+
prop = prop.trim()
|
|
24
|
+
if (unsupportedPropExp.test(prop) || unsupportedPropMode[mode].test(prop)) {
|
|
25
|
+
unsupportedPropError({ prop, value, selector }, { mode }, isError)
|
|
26
|
+
return false
|
|
27
|
+
}
|
|
28
|
+
return true
|
|
29
|
+
}
|
|
30
|
+
// 值类型
|
|
31
|
+
const ValueType = {
|
|
32
|
+
number: 'number',
|
|
33
|
+
color: 'color',
|
|
34
|
+
enum: 'enum'
|
|
14
35
|
}
|
|
15
|
-
|
|
16
36
|
// React 属性支持的枚举值
|
|
17
37
|
const SUPPORTED_PROP_VAL_ARR = {
|
|
38
|
+
'box-sizing': ['border-box'],
|
|
39
|
+
'backface-visibility': ['visible', 'hidden'],
|
|
18
40
|
overflow: ['visible', 'hidden', 'scroll'],
|
|
19
41
|
'border-style': ['solid', 'dotted', 'dashed'],
|
|
42
|
+
'object-fit': ['cover', 'contain', 'fill', 'scale-down'],
|
|
43
|
+
direction: ['inherit', 'ltr', 'rtl'],
|
|
20
44
|
display: ['flex', 'none'],
|
|
21
|
-
'
|
|
45
|
+
'flex-direction': ['row', 'row-reverse', 'column', 'column-reverse'],
|
|
46
|
+
'flex-wrap': ['wrap', 'nowrap', 'wrap-reverse'],
|
|
47
|
+
'pointer-events': ['auto', 'box-none', 'box-only', 'none'],
|
|
22
48
|
'vertical-align': ['auto', 'top', 'bottom', 'center'],
|
|
23
49
|
position: ['relative', 'absolute'],
|
|
24
50
|
'font-variant': ['small-caps', 'oldstyle-nums', 'lining-nums', 'tabular-nums', 'proportional-nums'],
|
|
@@ -26,148 +52,149 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
26
52
|
'font-style': ['normal', 'italic'],
|
|
27
53
|
'font-weight': ['normal', 'bold', '100', '200', '300', '400', '500', '600', '700', '800', '900'],
|
|
28
54
|
'text-decoration-line': ['none', 'underline', 'line-through', 'underline line-through'],
|
|
55
|
+
'text-decoration-style': ['solid', 'double', 'dotted', 'dashed'],
|
|
29
56
|
'text-transform': ['none', 'uppercase', 'lowercase', 'capitalize'],
|
|
30
57
|
'user-select': ['auto', 'text', 'none', 'contain', 'all'],
|
|
31
|
-
'align-content': ['flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-around'],
|
|
58
|
+
'align-content': ['flex-start', 'flex-end', 'center', 'stretch', 'space-between', 'space-around', 'space-evenly'],
|
|
32
59
|
'align-items': ['flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
|
|
33
60
|
'align-self': ['auto', 'flex-start', 'flex-end', 'center', 'stretch', 'baseline'],
|
|
34
|
-
'justify-content': ['flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'
|
|
35
|
-
'background-size': ['contain', 'cover', 'auto'],
|
|
36
|
-
'background-
|
|
61
|
+
'justify-content': ['flex-start', 'flex-end', 'center', 'space-between', 'space-around', 'space-evenly'],
|
|
62
|
+
'background-size': ['contain', 'cover', 'auto', ValueType.number],
|
|
63
|
+
'background-position': ['left', 'right', 'top', 'bottom', 'center', ValueType.number],
|
|
64
|
+
'background-repeat': ['no-repeat'],
|
|
65
|
+
width: ['auto', ValueType.number],
|
|
66
|
+
height: ['auto', ValueType.number],
|
|
67
|
+
'flex-basis': ['auto', ValueType.number],
|
|
68
|
+
margin: ['auto', ValueType.number],
|
|
69
|
+
'margin-top': ['auto', ValueType.number],
|
|
70
|
+
'margin-left': ['auto', ValueType.number],
|
|
71
|
+
'margin-bottom': ['auto', ValueType.number],
|
|
72
|
+
'margin-right': ['auto', ValueType.number],
|
|
73
|
+
'margin-horizontal': ['auto', ValueType.number],
|
|
74
|
+
'margin-vertical': ['auto', ValueType.number]
|
|
37
75
|
}
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
return false
|
|
49
|
-
}
|
|
50
|
-
if (isIllegalValue({ prop, value })) {
|
|
51
|
-
unsupportedValueError({ prop, value })
|
|
52
|
-
return false
|
|
76
|
+
// 获取值类型
|
|
77
|
+
const getValueType = (prop) => {
|
|
78
|
+
const propValueTypeRules = [
|
|
79
|
+
// 重要!!优先判断是不是枚举类型
|
|
80
|
+
[ValueType.enum, new RegExp('^(' + Object.keys(SUPPORTED_PROP_VAL_ARR).join('|') + ')$')],
|
|
81
|
+
[ValueType.number, /^((opacity|flex-grow|flex-shrink|gap|left|right|top|bottom)|(.+-(width|height|left|right|top|bottom|radius|spacing|size|gap|index|offset|opacity)))$/],
|
|
82
|
+
[ValueType.color, /^(color|(.+-color))$/]
|
|
83
|
+
]
|
|
84
|
+
for (const rule of propValueTypeRules) {
|
|
85
|
+
if (rule[1].test(prop)) return rule[0]
|
|
53
86
|
}
|
|
54
87
|
}
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const isUnsupporttedColor = colorRegExp.test(value)
|
|
73
|
-
isNumber && warn(`Property [${prop}] receives a valid color as value, not a number.`)
|
|
74
|
-
isUnsupporttedColor && warn('React Native\'s supported color format does not contain [lab,lch,oklab,oklch,color-mix,color,hwb,lch,light-dark].')
|
|
75
|
-
return !isNumber && !isUnsupporttedColor
|
|
88
|
+
// 属性值校验
|
|
89
|
+
const verifyValues = ({ prop, value, selector }, isError = true) => {
|
|
90
|
+
prop = prop.trim()
|
|
91
|
+
value = value.trim()
|
|
92
|
+
const tips = isError ? error : warn
|
|
93
|
+
if (cssVariableExp.test(value) || calcExp.test(value)) return true
|
|
94
|
+
const namedColor = ['transparent', 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige', 'bisque', 'black', 'blanchedalmond', 'blue', 'blueviolet', 'brown', 'burlywood', 'cadetblue', 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson', 'cyan', 'darkblue', 'darkcyan', 'darkgoldenrod', 'darkgray', 'darkgreen', 'darkgrey', 'darkkhaki', 'darkmagenta', 'darkolivegreen', 'darkorange', 'darkorchid', 'darkred', 'darksalmon', 'darkseagreen', 'darkslateblue', 'darkslategrey', 'darkturquoise', 'darkviolet', 'deeppink', 'deepskyblue', 'dimgray', 'dimgrey', 'dodgerblue', 'firebrick', 'floralwhite', 'forestgreen', 'fuchsia', 'gainsboro', 'ghostwhite', 'gold', 'goldenrod', 'gray', 'green', 'greenyellow', 'grey', 'honeydew', 'hotpink', 'indianred', 'indigo', 'ivory', 'khaki', 'lavender', 'lavenderblush', 'lawngreen', 'lemonchiffon', 'lightblue', 'lightcoral', 'lightcyan', 'lightgoldenrodyellow', 'lightgray', 'lightgreen', 'lightgrey', 'lightpink', 'lightsalmon', 'lightseagreen', 'lightskyblue', 'lightslategrey', 'lightsteelblue', 'lightyellow', 'lime', 'limegreen', 'linen', 'magenta', 'maroon', 'mediumaquamarine', 'mediumblue', 'mediumorchid', 'mediumpurple', 'mediumseagreen', 'mediumslateblue', 'mediumspringgreen', 'mediumturquoise', 'mediumvioletred', 'midnightblue', 'mintcream', 'mistyrose', 'moccasin', 'navajowhite', 'navy', 'oldlace', 'olive', 'olivedrab', 'orange', 'orangered', 'orchid', 'palegoldenrod', 'palegreen', 'paleturquoise', 'palevioletred', 'papayawhip', 'peachpuff', 'peru', 'pink', 'plum', 'powderblue', 'purple', 'rebeccapurple', 'red', 'rosybrown', 'royalblue', 'saddlebrown', 'salmon', 'sandybrown', 'seagreen', 'seashell', 'sienna', 'silver', 'skyblue', 'slateblue', 'slategray', 'snow', 'springgreen', 'steelblue', 'tan', 'teal', 'thistle', 'tomato', 'turquoise', 'violet', 'wheat', 'white', 'whitesmoke', 'yellow', 'yellowgreen']
|
|
95
|
+
const valueExp = {
|
|
96
|
+
number: /^((-?\d+(\.\d+)?)(rpx|px|%|vw|vh)?|hairlineWidth)$/,
|
|
97
|
+
color: new RegExp(('^(' + namedColor.join('|') + ')$') + '|(^#([0-9a-fA-f]{3}|[0-9a-fA-f]{6})$)|^(rgb|rgba|hsl|hsla|hwb)\\(.+\\)$')
|
|
98
|
+
}
|
|
99
|
+
const type = getValueType(prop)
|
|
100
|
+
const tipsType = (type) => {
|
|
101
|
+
const info = {
|
|
102
|
+
[ValueType.number]: '2rpx,10%,30rpx',
|
|
103
|
+
[ValueType.color]: 'rgb,rgba,hsl,hsla,hwb,named color,#000000',
|
|
104
|
+
[ValueType.enum]: `${SUPPORTED_PROP_VAL_ARR[prop]?.join(',')}`
|
|
76
105
|
}
|
|
106
|
+
tips(`Value of ${prop} in ${selector} should be ${type}, eg ${info[type]}, received [${value}], please check again!`)
|
|
107
|
+
}
|
|
108
|
+
switch (type) {
|
|
77
109
|
case ValueType.number: {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
110
|
+
if (!valueExp.number.test(value)) {
|
|
111
|
+
tipsType(type)
|
|
112
|
+
return false
|
|
113
|
+
}
|
|
114
|
+
return true
|
|
115
|
+
}
|
|
116
|
+
case ValueType.color: {
|
|
117
|
+
if (!valueExp.color.test(value)) {
|
|
118
|
+
tipsType(type)
|
|
119
|
+
return false
|
|
120
|
+
}
|
|
121
|
+
return true
|
|
81
122
|
}
|
|
82
|
-
|
|
123
|
+
case ValueType.enum: {
|
|
124
|
+
const isIn = SUPPORTED_PROP_VAL_ARR[prop].includes(value)
|
|
125
|
+
const isType = Object.keys(valueExp).some(item => valueExp[item].test(value) && SUPPORTED_PROP_VAL_ARR[prop].includes(ValueType[item]))
|
|
126
|
+
if (!isIn && !isType) {
|
|
127
|
+
tipsType(type)
|
|
128
|
+
return false
|
|
129
|
+
}
|
|
83
130
|
return true
|
|
131
|
+
}
|
|
84
132
|
}
|
|
133
|
+
return true
|
|
85
134
|
}
|
|
86
|
-
//
|
|
87
|
-
const
|
|
88
|
-
verifyValues({ prop, value,
|
|
135
|
+
// prop & value 校验:过滤的不合法的属性和属性值
|
|
136
|
+
const verification = ({ prop, value, selector }, { mode }) => {
|
|
137
|
+
return verifyProps({ prop, value, selector }, { mode }) && verifyValues({ prop, value, selector }) && ({ prop, value })
|
|
89
138
|
}
|
|
90
139
|
|
|
91
140
|
// 简写转换规则
|
|
92
141
|
const AbbreviationMap = {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
'border-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
'border-top': { // 仅支持 width | style | color 这种排序
|
|
115
|
-
borderTopWidth: ValueType.number,
|
|
116
|
-
borderTopStyle: ValueType.default,
|
|
117
|
-
borderTopColor: ValueType.color
|
|
118
|
-
},
|
|
119
|
-
'border-bottom': { // 仅支持 width | style | color 这种排序
|
|
120
|
-
borderBottomWidth: ValueType.number,
|
|
121
|
-
borderBottomStyle: ValueType.default,
|
|
122
|
-
borderBottomColor: ValueType.color
|
|
123
|
-
},
|
|
124
|
-
'box-shadow': { // 仅支持 offset-x | offset-y | blur-radius | color 排序
|
|
125
|
-
'shadowOffset.width': ValueType.number,
|
|
126
|
-
'shadowOffset.height': ValueType.number,
|
|
127
|
-
shadowRadius: ValueType.number,
|
|
128
|
-
shadowColor: ValueType.color
|
|
129
|
-
},
|
|
130
|
-
'text-decoration': { // 仅支持 text-decoration-line text-decoration-style text-decoration-color 这种格式
|
|
131
|
-
textDecorationLine: ValueType.default,
|
|
132
|
-
textDecorationStyle: ValueType.default,
|
|
133
|
-
textDecorationColor: ValueType.color
|
|
134
|
-
},
|
|
135
|
-
flex: { // /* Three values: flex-grow | flex-shrink | flex-basis */
|
|
136
|
-
flexGrow: ValueType.number,
|
|
137
|
-
flexShrink: ValueType.number,
|
|
138
|
-
flexBasis: ValueType.number
|
|
139
|
-
},
|
|
140
|
-
'flex-flow': { // 仅支持 flex-flow: <'flex-direction'> or flex-flow: <'flex-direction'> and <'flex-wrap'>
|
|
141
|
-
flexDirection: ValueType.default,
|
|
142
|
-
flexWrap: ValueType.default
|
|
143
|
-
},
|
|
144
|
-
'border-radius': {
|
|
145
|
-
borderTopLeftRadius: ValueType.number,
|
|
146
|
-
borderTopRightRadius: ValueType.number,
|
|
147
|
-
borderBottomRightRadius: ValueType.number,
|
|
148
|
-
borderBottomLeftRadius: ValueType.number
|
|
149
|
-
}
|
|
142
|
+
// 仅支持 offset-x | offset-y | blur-radius | color 排序
|
|
143
|
+
'text-shadow': ['textShadowOffset.width', 'textShadowOffset.height', 'textShadowRadius', 'textShadowColor'],
|
|
144
|
+
// 仅支持 width | style | color 这种排序
|
|
145
|
+
border: ['borderWidth', 'borderStyle', 'borderColor'],
|
|
146
|
+
// 仅支持 width | style | color 这种排序
|
|
147
|
+
'border-left': ['borderLeftWidth', 'borderLeftStyle', 'borderLeftColor'],
|
|
148
|
+
// 仅支持 width | style | color 这种排序
|
|
149
|
+
'border-right': ['borderRightWidth', 'borderRightStyle', 'borderRightColor'],
|
|
150
|
+
// 仅支持 width | style | color 这种排序
|
|
151
|
+
'border-top': ['borderTopWidth', 'borderTopStyle', 'borderTopColor'],
|
|
152
|
+
// 仅支持 width | style | color 这种排序
|
|
153
|
+
'border-bottom': ['borderBottomWidth', 'borderBottomStyle', 'borderBottomColor'],
|
|
154
|
+
// 仅支持 offset-x | offset-y | blur-radius | color 排序
|
|
155
|
+
'box-shadow': ['shadowOffset.width', 'shadowOffset.height', 'shadowRadius', 'shadowColor'],
|
|
156
|
+
// 仅支持 text-decoration-line text-decoration-style text-decoration-color 这种格式
|
|
157
|
+
'text-decoration': ['textDecorationLine', 'textDecorationStyle', 'textDecorationColor'],
|
|
158
|
+
// flex-grow | flex-shrink | flex-basis
|
|
159
|
+
flex: ['flexGrow', 'flexShrink', 'flexBasis'],
|
|
160
|
+
// flex-flow: <'flex-direction'> or flex-flow: <'flex-direction'> and <'flex-wrap'>
|
|
161
|
+
'flex-flow': ['flexDirection', 'flexWrap'],
|
|
162
|
+
'border-radius': ['borderTopLeftRadius', 'borderTopRightRadius', 'borderBottomRightRadius', 'borderBottomLeftRadius']
|
|
150
163
|
}
|
|
151
|
-
const formatAbbreviation = ({ value,
|
|
164
|
+
const formatAbbreviation = ({ prop, value, selector }, { mode }) => {
|
|
165
|
+
const original = `${prop}:${value}`
|
|
166
|
+
const props = AbbreviationMap[prop]
|
|
152
167
|
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
153
168
|
const cssMap = []
|
|
154
|
-
const props = Object.getOwnPropertyNames(keyMap)
|
|
155
169
|
let idx = 0
|
|
156
170
|
let propsIdx = 0
|
|
157
|
-
|
|
158
|
-
while (idx < values.length
|
|
171
|
+
const diff = values.length - props.length
|
|
172
|
+
while (idx < values.length) {
|
|
159
173
|
const prop = props[propsIdx]
|
|
160
|
-
|
|
161
|
-
|
|
174
|
+
if (!prop) {
|
|
175
|
+
error(`Value of [${original}] in ${selector} has not enough props to assign, please check again!`)
|
|
176
|
+
break
|
|
177
|
+
}
|
|
162
178
|
const value = values[idx]
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
179
|
+
const newProp = hump2dash(prop.replace(/\..+/, ''))
|
|
180
|
+
if (!verifyProps({ prop: newProp, value, selector }, { mode }, diff === 0)) {
|
|
181
|
+
// 有 ios or android 不支持的 prop,跳过 prop
|
|
182
|
+
if (diff === 0) {
|
|
183
|
+
propsIdx++
|
|
184
|
+
idx++
|
|
185
|
+
} else {
|
|
186
|
+
propsIdx++
|
|
187
|
+
}
|
|
188
|
+
} else if (!verifyValues({ prop: newProp, value, selector }, diff === 0)) {
|
|
189
|
+
// 值不合法 跳过 value
|
|
190
|
+
if (diff === 0) {
|
|
191
|
+
propsIdx++
|
|
192
|
+
idx++
|
|
193
|
+
} else if (diff < 0) {
|
|
194
|
+
propsIdx++
|
|
195
|
+
} else {
|
|
196
|
+
idx++
|
|
197
|
+
}
|
|
171
198
|
} else if (prop.includes('.')) {
|
|
172
199
|
// 多个属性值的prop
|
|
173
200
|
const [main, sub] = prop.split('.')
|
|
@@ -196,30 +223,10 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
196
223
|
}
|
|
197
224
|
return cssMap
|
|
198
225
|
}
|
|
199
|
-
const getAbbreviation = ({ prop, value }) => {
|
|
200
|
-
const keyMap = AbbreviationMap[prop]
|
|
201
|
-
return formatAbbreviation({ prop, value, keyMap })
|
|
202
|
-
}
|
|
203
|
-
// 简写过滤安卓不支持的类型
|
|
204
|
-
const getAbbreviationAndroid = ({ prop, value }, { mode }) => {
|
|
205
|
-
const cssMap = getAbbreviation({ prop, value })
|
|
206
|
-
// android 不支持的 shadowOffset shadowOpacity shadowRadius textDecorationStyle 和 textDecorationStyle
|
|
207
|
-
return cssMap.filter(({ prop }) => { // 不支持的 prop 提示 & 过滤不支持的 prop
|
|
208
|
-
const dashProp = hump2dash(prop)
|
|
209
|
-
if (unsupportedPropMode.android.test(dashProp)) {
|
|
210
|
-
unsupportedPropError({ prop: dashProp, mode })
|
|
211
|
-
return false
|
|
212
|
-
}
|
|
213
|
-
return true
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
226
|
|
|
217
|
-
|
|
227
|
+
// margin padding
|
|
228
|
+
const formatMargins = ({ prop, value, selector }) => {
|
|
218
229
|
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
219
|
-
// validate
|
|
220
|
-
for (let i = 0; i < values.length; i++) {
|
|
221
|
-
verifyValues({ prop, value: values[i], valueType: ValueType.number })
|
|
222
|
-
}
|
|
223
230
|
// format
|
|
224
231
|
let suffix = []
|
|
225
232
|
switch (values.length) {
|
|
@@ -235,65 +242,49 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
235
242
|
break
|
|
236
243
|
}
|
|
237
244
|
return values.map((value, index) => {
|
|
245
|
+
const newProp = `${prop}${suffix[index] || ''}`
|
|
246
|
+
// validate
|
|
247
|
+
verifyValues({ prop: hump2dash(newProp), value, selector }, false)
|
|
238
248
|
return {
|
|
239
|
-
prop:
|
|
249
|
+
prop: newProp,
|
|
240
250
|
value: value
|
|
241
251
|
}
|
|
242
252
|
})
|
|
243
253
|
}
|
|
244
254
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
return {
|
|
255
|
+
// line-height
|
|
256
|
+
const formatLineHeight = ({ prop, value, selector }) => {
|
|
257
|
+
return verifyValues({ prop, value, selector }) && ({
|
|
249
258
|
prop,
|
|
250
259
|
value: /^\s*-?\d+(\.\d+)?\s*$/.test(value) ? `${Math.round(value * 100)}%` : value
|
|
251
|
-
}
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
const getFontVariant = ({ prop, value }) => {
|
|
255
|
-
if (/^(font-variant-caps|font-variant-numeric|font-variant-east-asian|font-variant-alternates|font-variant-ligatures)$/.test(prop)) {
|
|
256
|
-
error(`Property [${prop}] is not supported in React Native environment, please replace [font-variant]!`)
|
|
257
|
-
}
|
|
258
|
-
prop = 'font-variant'
|
|
259
|
-
// 校验枚举值
|
|
260
|
-
if (isIllegalValue({ prop, value })) {
|
|
261
|
-
unsupportedValueError({ prop, value })
|
|
262
|
-
return false
|
|
263
|
-
}
|
|
264
|
-
return {
|
|
265
|
-
prop,
|
|
266
|
-
value
|
|
267
|
-
}
|
|
260
|
+
})
|
|
268
261
|
}
|
|
269
262
|
|
|
270
|
-
// background
|
|
271
|
-
|
|
263
|
+
// background 相关属性的转换 Todo
|
|
264
|
+
// 仅支持以下属性,不支持其他背景相关的属性
|
|
265
|
+
// /^((?!(-color)).)*background((?!(-color)).)*$/ 包含background且不包含background-color
|
|
266
|
+
const checkBackgroundImage = ({ prop, value, selector }, { mode }) => {
|
|
272
267
|
const bgPropMap = {
|
|
273
268
|
image: 'background-image',
|
|
274
269
|
color: 'background-color',
|
|
275
270
|
size: 'background-size',
|
|
276
271
|
repeat: 'background-repeat',
|
|
277
|
-
|
|
272
|
+
position: 'background-position',
|
|
278
273
|
all: 'background'
|
|
279
274
|
}
|
|
280
275
|
const urlExp = /url\(["']?(.*?)["']?\)/
|
|
276
|
+
const linerExp = /linear-gradient\(["']?(.*?)["']?\)/
|
|
281
277
|
switch (prop) {
|
|
282
|
-
case bgPropMap.color: {
|
|
283
|
-
// background-color 背景色校验一下颜色值
|
|
284
|
-
verifyValues({ prop, value, valueType: ValueType.color })
|
|
285
|
-
return { prop, value }
|
|
286
|
-
}
|
|
287
278
|
case bgPropMap.image: {
|
|
288
279
|
// background-image 仅支持背景图
|
|
289
280
|
const imgUrl = value.match(urlExp)?.[0]
|
|
290
|
-
|
|
291
|
-
error(`<linear-gradient()> is not supported in React Native ${mode} environment!`)
|
|
292
|
-
}
|
|
281
|
+
const linerVal = value.match(linerExp)?.[0]
|
|
293
282
|
if (imgUrl) {
|
|
294
283
|
return { prop, value: imgUrl }
|
|
284
|
+
} else if (linerVal) {
|
|
285
|
+
return { prop, value: linerVal }
|
|
295
286
|
} else {
|
|
296
|
-
error(`
|
|
287
|
+
error(`Value of ${prop} in ${selector} selector only support value <url()> or <linear-gradient()>, received ${value}, please check again!`)
|
|
297
288
|
return false
|
|
298
289
|
}
|
|
299
290
|
}
|
|
@@ -303,28 +294,30 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
303
294
|
// 支持一个值:这个值指定图片的宽度,图片的高度隐式的为 auto
|
|
304
295
|
// 支持两个值:第一个值指定图片的宽度,第二个值指定图片的高度
|
|
305
296
|
if (value.includes(',')) { // commas are not allowed in values
|
|
306
|
-
error(`
|
|
297
|
+
error(`Value of [${bgPropMap.size}] in ${selector} does not support commas, received [${value}], please check again!`)
|
|
307
298
|
return false
|
|
308
299
|
}
|
|
309
300
|
const values = []
|
|
310
301
|
value.trim().split(/\s(?![^()]*\))/).forEach(item => {
|
|
311
|
-
if (
|
|
302
|
+
if (verifyValues({ prop, value: item, selector })) {
|
|
312
303
|
// 支持 number 值 / container cover auto 枚举
|
|
313
304
|
values.push(item)
|
|
314
|
-
} else {
|
|
315
|
-
error(`background size value[${value}] does not support in React Native ${mode} environment!`)
|
|
316
305
|
}
|
|
317
306
|
})
|
|
318
307
|
// value 无有效值时返回false
|
|
319
308
|
return values.length === 0 ? false : { prop, value: values }
|
|
320
309
|
}
|
|
321
|
-
case bgPropMap.
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
310
|
+
case bgPropMap.position: {
|
|
311
|
+
const values = []
|
|
312
|
+
value.trim().split(/\s(?![^()]*\))/).forEach(item => {
|
|
313
|
+
if (verifyValues({ prop, value: item, selector })) {
|
|
314
|
+
// 支持 number 值 / 枚举, center与50%等价
|
|
315
|
+
values.push(item === 'center' ? '50%' : item)
|
|
316
|
+
} else {
|
|
317
|
+
error(`Value of [${bgPropMap.size}] in ${selector} does not support commas, received [${value}], please check again!`)
|
|
318
|
+
}
|
|
319
|
+
})
|
|
320
|
+
return { prop, value: values }
|
|
328
321
|
}
|
|
329
322
|
case bgPropMap.all: {
|
|
330
323
|
// background: 仅支持 background-image & background-color & background-repeat
|
|
@@ -332,43 +325,48 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
332
325
|
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
333
326
|
values.forEach(item => {
|
|
334
327
|
const url = item.match(urlExp)?.[0]
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
} else if (url) {
|
|
328
|
+
const linerVal = item.match(linerExp)?.[0]
|
|
329
|
+
if (url) {
|
|
338
330
|
bgMap.push({ prop: bgPropMap.image, value: url })
|
|
339
|
-
} else if (
|
|
331
|
+
} else if (linerVal) {
|
|
332
|
+
bgMap.push({ prop: bgPropMap.image, value: linerVal })
|
|
333
|
+
} else if (verifyValues({ prop: bgPropMap.color, value: item }, false)) {
|
|
340
334
|
bgMap.push({ prop: bgPropMap.color, value: item })
|
|
341
|
-
} else if (
|
|
335
|
+
} else if (verifyValues({ prop: bgPropMap.repeat, value: item, selector }, false)) {
|
|
342
336
|
bgMap.push({ prop: bgPropMap.repeat, value: item })
|
|
343
337
|
}
|
|
344
|
-
// else if (SUPPORTED_PROP_VAL_ARR[bgPropMap.size].includes(item)) {
|
|
345
|
-
// bgMap.push({ prop: bgPropMap.size, value: item })
|
|
346
|
-
// }
|
|
347
338
|
})
|
|
348
339
|
return bgMap.length ? bgMap : false
|
|
349
340
|
}
|
|
350
341
|
}
|
|
351
|
-
unsupportedPropError({ prop, mode })
|
|
342
|
+
unsupportedPropError({ prop, value, selector }, { mode })
|
|
352
343
|
return false
|
|
353
344
|
}
|
|
354
345
|
|
|
355
|
-
|
|
346
|
+
// border-radius 缩写转换
|
|
347
|
+
const getBorderRadius = ({ prop, value, selector }, { mode }) => {
|
|
356
348
|
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
357
349
|
if (values.length === 1) {
|
|
358
|
-
verifyValues({ prop, value,
|
|
350
|
+
verifyValues({ prop, value, selector }, false)
|
|
359
351
|
return { prop, value }
|
|
360
352
|
} else {
|
|
361
|
-
|
|
353
|
+
if (values.length === 2) {
|
|
354
|
+
values.push(...values)
|
|
355
|
+
} else if (values.length === 3) {
|
|
356
|
+
values.push(values[1])
|
|
357
|
+
}
|
|
358
|
+
return formatAbbreviation({ prop, value: values.join(' ') }, { mode })
|
|
362
359
|
}
|
|
363
360
|
}
|
|
364
361
|
|
|
365
|
-
|
|
362
|
+
// transform 转换
|
|
363
|
+
const formatTransform = ({ prop, value, selector }, { mode }) => {
|
|
366
364
|
if (Array.isArray(value)) return { prop, value }
|
|
367
365
|
const values = value.trim().split(/\s(?![^()]*\))/)
|
|
368
366
|
const transform = []
|
|
369
367
|
values.forEach(item => {
|
|
370
368
|
const match = item.match(/([/\w]+)\(([^)]+)\)/)
|
|
371
|
-
if (match.length >= 3) {
|
|
369
|
+
if (match && match.length >= 3) {
|
|
372
370
|
let key = match[1]
|
|
373
371
|
const val = match[2]
|
|
374
372
|
switch (key) {
|
|
@@ -382,6 +380,7 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
382
380
|
case 'rotate':
|
|
383
381
|
case 'skewX':
|
|
384
382
|
case 'skewY':
|
|
383
|
+
case 'perspective':
|
|
385
384
|
// 单个值处理
|
|
386
385
|
transform.push({ [key]: val })
|
|
387
386
|
break
|
|
@@ -395,28 +394,28 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
395
394
|
case 'rotate3d': // x y z angle
|
|
396
395
|
case 'translate3d': // x y 支持 z不支持
|
|
397
396
|
case 'scale3d': // x y 支持 z不支持
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
397
|
+
{
|
|
398
|
+
// 2 个以上的值处理
|
|
399
|
+
key = key.replace('3d', '')
|
|
400
|
+
const vals = val.split(',').splice(0, key === 'rotate' ? 4 : 3)
|
|
401
|
+
const xyz = ['X', 'Y', 'Z']
|
|
402
|
+
transform.push(...vals.map((v, index) => {
|
|
403
|
+
if (key !== 'rotate' && index > 1) {
|
|
404
|
+
unsupportedPropError({ prop: `${key}Z`, value, selector }, { mode })
|
|
405
|
+
}
|
|
406
|
+
return { [`${key}${xyz[index] || ''}`]: v.trim() }
|
|
407
|
+
}))
|
|
408
|
+
break
|
|
409
|
+
}
|
|
411
410
|
case 'translateZ':
|
|
412
411
|
case 'scaleZ':
|
|
413
412
|
default:
|
|
414
413
|
// 不支持的属性处理
|
|
415
|
-
unsupportedPropError({ prop
|
|
414
|
+
unsupportedPropError({ prop, value, selector }, { mode })
|
|
416
415
|
break
|
|
417
416
|
}
|
|
418
417
|
} else {
|
|
419
|
-
error(`Property [${prop}] is invalid, please check
|
|
418
|
+
error(`Property [${prop}] is invalid in ${selector}, received [${value}], please check again!`)
|
|
420
419
|
}
|
|
421
420
|
})
|
|
422
421
|
return {
|
|
@@ -425,47 +424,113 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
425
424
|
}
|
|
426
425
|
}
|
|
427
426
|
|
|
428
|
-
const
|
|
427
|
+
const isNumber = (value) => {
|
|
428
|
+
return !isNaN(+value)
|
|
429
|
+
}
|
|
430
|
+
|
|
431
|
+
const getIntegersFlex = ({ prop, value, selector }) => {
|
|
432
|
+
if (isNumber(value) && value >= 0) {
|
|
433
|
+
return { prop, value }
|
|
434
|
+
} else {
|
|
435
|
+
error(`Value of [${prop}] in ${selector} accepts any floating point value >= 0, received [${value}], please check again!`)
|
|
436
|
+
return false
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const formatFlex = ({ prop, value, selector }) => {
|
|
441
|
+
let values = value.trim().split(/\s(?![^()]*\))/)
|
|
442
|
+
if (values.length > 3) {
|
|
443
|
+
error(`Value of [flex] in ${selector} supports up to three values, received [${value}], please check again!`)
|
|
444
|
+
values = values.splice(0, 3)
|
|
445
|
+
}
|
|
446
|
+
const cssMap = []
|
|
447
|
+
const lastOne = values[values.length - 1]
|
|
448
|
+
const isAuto = lastOne === 'auto'
|
|
449
|
+
// 枚举值 none initial
|
|
450
|
+
if (values.includes('initial') || values.includes('none')) {
|
|
451
|
+
// css flex: initial ===> flex: 0 1 ===> rn flex 0 1
|
|
452
|
+
// css flex: none ===> css flex: 0 0 ===> rn flex 0 0
|
|
453
|
+
if (values.length === 1) {
|
|
454
|
+
// 添加 basis 和 shrink
|
|
455
|
+
// value=initial 则 flexShrink=1,其他场景都是0
|
|
456
|
+
cssMap.push(...[{ prop: 'flexGrow', value: 0 }, { prop: 'flexShrink', value: +(values[0] === 'initial') }])
|
|
457
|
+
} else {
|
|
458
|
+
error(`Value of [${prop}] in ${selector} is invalid, When setting the value of flex to none or initial, only one value is supported.`)
|
|
459
|
+
}
|
|
460
|
+
return cssMap
|
|
461
|
+
}
|
|
462
|
+
// 最后一个值是flexBasis 的有效值(auto或者有单位百分比、px等)
|
|
463
|
+
// flex 0 1 auto flex auto flex 1 auto flex 1 30px flex 1 10% flex 1 1 auto
|
|
464
|
+
if (!isNumber(lastOne)) {
|
|
465
|
+
// 添加 grow 和 shrink
|
|
466
|
+
// 在设置 flex basis 有效值的场景下,如果没有设置 grow 和 shrink,则默认为1
|
|
467
|
+
// 单值 flex: 1 1 <flex-basis>
|
|
468
|
+
// 双值 flex: <flex-grow> 1 <flex-basis>
|
|
469
|
+
// 三值 flex: <flex-grow> <flex-shrink> <flex-basis>
|
|
470
|
+
for (let i = 0; i < 2; i++) {
|
|
471
|
+
const item = getIntegersFlex({ prop: AbbreviationMap[prop][i], value: isNumber(values[i]) ? values[i] : 1 })
|
|
472
|
+
item && cssMap.push(item)
|
|
473
|
+
}
|
|
474
|
+
if (!isAuto) {
|
|
475
|
+
// 有单位(百分比、px等) 的 value 赋值 flexBasis,auto 不处理
|
|
476
|
+
cssMap.push({
|
|
477
|
+
prop: 'flexBasis',
|
|
478
|
+
value: lastOne
|
|
479
|
+
})
|
|
480
|
+
}
|
|
481
|
+
return cssMap
|
|
482
|
+
}
|
|
483
|
+
// 纯数值:value 按flex-grow flex-shrink flex-basis 顺序赋值
|
|
484
|
+
// 兜底 shrink & basis
|
|
485
|
+
if (values.length === 1) {
|
|
486
|
+
values.push(...[1, 0])
|
|
487
|
+
} else if (values.length === 2) {
|
|
488
|
+
values.push(0)
|
|
489
|
+
}
|
|
490
|
+
// 循环赋值
|
|
491
|
+
for (let i = 0; i < values.length; i++) {
|
|
492
|
+
const item = getIntegersFlex({ prop: AbbreviationMap[prop][i], value: values[i] })
|
|
493
|
+
item && cssMap.push(item)
|
|
494
|
+
}
|
|
495
|
+
return cssMap
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
const formatFontFamily = ({ prop, value, selector }) => {
|
|
499
|
+
// 去掉引号 取逗号分隔后的第一个
|
|
500
|
+
const newVal = value.replace(/"|'/g, '').trim()
|
|
501
|
+
const values = newVal.split(',').filter(i => i)
|
|
502
|
+
if (!newVal || !values.length) {
|
|
503
|
+
error(`Value of [${prop}] is invalid in ${selector}, received [${value}], please check again!`)
|
|
504
|
+
return false
|
|
505
|
+
} else if (values.length > 1) {
|
|
506
|
+
warn(`Value of [${prop}] only supports one in ${selector}, received [${value}], and the first one is used by default.`)
|
|
507
|
+
}
|
|
508
|
+
return { prop, value: values[0].trim() }
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
const formatBoxShadow = ({ prop, value, selector }, { mode }) => {
|
|
512
|
+
value = value.trim()
|
|
513
|
+
if (value === 'none') {
|
|
514
|
+
return false
|
|
515
|
+
}
|
|
516
|
+
const cssMap = formatAbbreviation({ prop, value, selector }, { mode })
|
|
517
|
+
if (mode === 'android') return cssMap
|
|
518
|
+
// ios 阴影需要额外设置 shadowOpacity=1
|
|
519
|
+
cssMap.push({
|
|
520
|
+
prop: 'shadowOpacity',
|
|
521
|
+
value: 1
|
|
522
|
+
})
|
|
523
|
+
return cssMap
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
return {
|
|
429
527
|
supportedModes: ['ios', 'android'],
|
|
430
528
|
rules: [
|
|
431
529
|
{ // 背景相关属性的处理
|
|
432
|
-
test: /^(background|background-image|background-
|
|
530
|
+
test: /^(background|background-image|background-size|background-position)$/,
|
|
433
531
|
ios: checkBackgroundImage,
|
|
434
532
|
android: checkBackgroundImage
|
|
435
533
|
},
|
|
436
|
-
{ // RN 不支持的 CSS property
|
|
437
|
-
test: unsupportedPropExp,
|
|
438
|
-
ios: delRule,
|
|
439
|
-
android: delRule
|
|
440
|
-
},
|
|
441
|
-
{ // React Native android 不支持的 CSS property
|
|
442
|
-
test: unsupportedPropMode.android,
|
|
443
|
-
android: delRule
|
|
444
|
-
},
|
|
445
|
-
{ // React Native ios 不支持的 CSS property
|
|
446
|
-
test: unsupportedPropMode.ios,
|
|
447
|
-
ios: delRule
|
|
448
|
-
},
|
|
449
|
-
{ // RN 支持的 CSS property value
|
|
450
|
-
test: propValExp,
|
|
451
|
-
ios: delRule,
|
|
452
|
-
android: delRule
|
|
453
|
-
},
|
|
454
|
-
{
|
|
455
|
-
test: 'box-shadow',
|
|
456
|
-
ios: getAbbreviation,
|
|
457
|
-
android: getAbbreviationAndroid
|
|
458
|
-
},
|
|
459
|
-
{
|
|
460
|
-
test: 'text-decoration',
|
|
461
|
-
ios: getAbbreviation,
|
|
462
|
-
android: getAbbreviationAndroid
|
|
463
|
-
},
|
|
464
|
-
{
|
|
465
|
-
test: /^(font-variant|font-variant-caps|font-variant-numeric|font-variant-east-asian|font-variant-alternates|font-variant-ligatures)$/,
|
|
466
|
-
ios: getFontVariant,
|
|
467
|
-
android: getFontVariant
|
|
468
|
-
},
|
|
469
534
|
{
|
|
470
535
|
test: 'border-radius',
|
|
471
536
|
ios: getBorderRadius,
|
|
@@ -476,12 +541,6 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
476
541
|
ios: formatMargins,
|
|
477
542
|
android: formatMargins
|
|
478
543
|
},
|
|
479
|
-
// 通用的简写格式匹配
|
|
480
|
-
{
|
|
481
|
-
test: new RegExp('^(' + Object.keys(AbbreviationMap).join('|') + ')$'),
|
|
482
|
-
ios: getAbbreviation,
|
|
483
|
-
android: getAbbreviation
|
|
484
|
-
},
|
|
485
544
|
{ // line-height 换算
|
|
486
545
|
test: 'line-height',
|
|
487
546
|
ios: formatLineHeight,
|
|
@@ -492,18 +551,33 @@ module.exports = function getSpec ({ warn, error }) {
|
|
|
492
551
|
ios: formatTransform,
|
|
493
552
|
android: formatTransform
|
|
494
553
|
},
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
554
|
+
{
|
|
555
|
+
test: 'flex',
|
|
556
|
+
ios: formatFlex,
|
|
557
|
+
android: formatFlex
|
|
558
|
+
},
|
|
559
|
+
{
|
|
560
|
+
test: 'font-family',
|
|
561
|
+
ios: formatFontFamily,
|
|
562
|
+
android: formatFontFamily
|
|
500
563
|
},
|
|
501
|
-
{
|
|
502
|
-
test:
|
|
503
|
-
ios:
|
|
504
|
-
android:
|
|
564
|
+
{
|
|
565
|
+
test: 'box-shadow',
|
|
566
|
+
ios: formatBoxShadow,
|
|
567
|
+
android: formatBoxShadow
|
|
568
|
+
},
|
|
569
|
+
// 通用的简写格式匹配
|
|
570
|
+
{
|
|
571
|
+
test: new RegExp('^(' + Object.keys(AbbreviationMap).join('|') + ')$'),
|
|
572
|
+
ios: formatAbbreviation,
|
|
573
|
+
android: formatAbbreviation
|
|
574
|
+
},
|
|
575
|
+
// 属性&属性值校验
|
|
576
|
+
{
|
|
577
|
+
test: () => true,
|
|
578
|
+
ios: verification,
|
|
579
|
+
android: verification
|
|
505
580
|
}
|
|
506
581
|
]
|
|
507
582
|
}
|
|
508
|
-
return spec
|
|
509
583
|
}
|