@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
|
@@ -4,153 +4,307 @@
|
|
|
4
4
|
* ✔ hover-start-time
|
|
5
5
|
* ✔ hover-stay-time
|
|
6
6
|
*/
|
|
7
|
-
import { View,
|
|
8
|
-
import { useRef, useState, useEffect, forwardRef, ReactNode, JSX } from 'react'
|
|
9
|
-
// @ts-ignore
|
|
7
|
+
import { View, TextStyle, NativeSyntheticEvent, ViewProps, ImageStyle, ImageResizeMode, StyleSheet, Image, LayoutChangeEvent, Text } from 'react-native'
|
|
8
|
+
import { useRef, useState, useEffect, forwardRef, ReactNode, JSX, Children, cloneElement } from 'react'
|
|
10
9
|
import useInnerProps from './getInnerListeners'
|
|
11
|
-
|
|
12
|
-
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
13
|
-
|
|
14
|
-
import
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
type ExtendedViewStyle = ViewStyle & {
|
|
18
|
-
backgroundImage?: string
|
|
19
|
-
backgroundSize?: ImageResizeMode
|
|
20
|
-
}
|
|
10
|
+
import { ExtendedViewStyle } from './types/common'
|
|
11
|
+
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
12
|
+
import { parseUrl, PERCENT_REGEX, splitStyle, splitProps, useTransformStyle, wrapChildren, useLayout } from './utils'
|
|
13
|
+
import LinearGradient from 'react-native-linear-gradient'
|
|
21
14
|
|
|
22
15
|
export interface _ViewProps extends ViewProps {
|
|
23
|
-
style?:
|
|
24
|
-
children?: ReactNode | ReactNode
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
'enable-
|
|
16
|
+
style?: ExtendedViewStyle
|
|
17
|
+
children?: ReactNode | ReactNode[]
|
|
18
|
+
'hover-style'?: ExtendedViewStyle
|
|
19
|
+
'hover-start-time'?: number
|
|
20
|
+
'hover-stay-time'?: number
|
|
21
|
+
'enable-background'?: boolean
|
|
22
|
+
'enable-var'?: boolean
|
|
23
|
+
'external-var-context'?: Record<string, any>
|
|
24
|
+
'parent-font-size'?: number
|
|
25
|
+
'parent-width'?: number
|
|
26
|
+
'parent-height'?: number
|
|
29
27
|
bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
30
28
|
bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
31
29
|
bindtouchend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
32
30
|
}
|
|
33
31
|
|
|
34
|
-
type
|
|
35
|
-
|
|
36
|
-
type GroupData = Record<string, Record<string, any>>;
|
|
37
|
-
|
|
38
|
-
type Handler = (...args: any []) => void
|
|
32
|
+
type Handler = (...args: any[]) => void
|
|
39
33
|
|
|
40
34
|
type Size = {
|
|
41
|
-
width: number
|
|
35
|
+
width: number
|
|
42
36
|
height: number
|
|
43
37
|
}
|
|
44
38
|
|
|
45
|
-
type DimensionValue = number | 'auto' |
|
|
39
|
+
type DimensionValue = number | `${number}%` | 'auto' | 'contain' | 'cover'
|
|
40
|
+
|
|
41
|
+
type Position = {
|
|
42
|
+
left?: number
|
|
43
|
+
right?: number
|
|
44
|
+
top?: number
|
|
45
|
+
bottom?: number
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
type PositionKey = keyof Position
|
|
49
|
+
|
|
50
|
+
type NumberVal = number | `${number}%`
|
|
51
|
+
|
|
52
|
+
type PositionVal = PositionKey | NumberVal
|
|
53
|
+
|
|
54
|
+
type backgroundPositionList = ['left' | 'right', NumberVal, 'top' | 'bottom', NumberVal] | []
|
|
55
|
+
|
|
56
|
+
type LinearInfo = {
|
|
57
|
+
colors: Array<string>,
|
|
58
|
+
locations: Array<number>,
|
|
59
|
+
direction?: string
|
|
60
|
+
}
|
|
46
61
|
|
|
47
62
|
type PreImageInfo = {
|
|
48
63
|
src?: string,
|
|
49
|
-
sizeList: DimensionValue
|
|
64
|
+
sizeList: DimensionValue[]
|
|
65
|
+
type?: 'image' | 'linear'
|
|
66
|
+
linearInfo?: LinearInfo
|
|
67
|
+
// containPercentSymbol?: boolean
|
|
68
|
+
backgroundPosition: backgroundPositionList
|
|
50
69
|
}
|
|
51
70
|
|
|
52
71
|
type ImageProps = {
|
|
53
72
|
style: ImageStyle,
|
|
54
|
-
src?: string
|
|
73
|
+
src?: string,
|
|
74
|
+
colors: Array<string>,
|
|
75
|
+
locations?: Array<number>
|
|
76
|
+
angle?: number
|
|
55
77
|
}
|
|
56
78
|
|
|
57
|
-
const
|
|
79
|
+
const linearMap = new Map([
|
|
80
|
+
['top', 0],
|
|
81
|
+
['bottom', 180],
|
|
82
|
+
['left', 270],
|
|
83
|
+
['right', 90]
|
|
84
|
+
])
|
|
85
|
+
|
|
86
|
+
// 对角线角度
|
|
87
|
+
const diagonalAngleMap: Record<string, (width: number, height: number) => any> = {
|
|
88
|
+
'top right': (width: number, height: number) => {
|
|
89
|
+
return Math.acos(
|
|
90
|
+
(width / 2) /
|
|
91
|
+
(Math.sqrt(Math.pow(width, 2) + Math.pow(height, 2)) / 2)
|
|
92
|
+
)
|
|
93
|
+
},
|
|
94
|
+
'right top': (width, height) => { return diagonalAngleMap['top right'](width, height) },
|
|
95
|
+
|
|
96
|
+
'bottom right': (width, height) => Math.PI - diagonalAngleMap['top right'](width, height),
|
|
97
|
+
'right bottom': (width, height) => { return diagonalAngleMap['bottom right'](width, height) },
|
|
98
|
+
|
|
99
|
+
'bottom left': (width, height) => Math.PI + diagonalAngleMap['top right'](width, height),
|
|
100
|
+
'left bottom': (width, height) => { return diagonalAngleMap['bottom left'](width, height) },
|
|
101
|
+
|
|
102
|
+
'top left': (width, height) => (2 * Math.PI) - diagonalAngleMap['top right'](width, height),
|
|
103
|
+
'left top': (width, height) => { return diagonalAngleMap['top left'](width, height) }
|
|
104
|
+
}
|
|
58
105
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
if (style.hasOwnProperty(key)) { // 确保处理对象自身的属性
|
|
63
|
-
let val: string = style[key] as string
|
|
64
|
-
groupKey = callback(key, val)
|
|
65
|
-
if (!group[groupKey]) {
|
|
66
|
-
group[groupKey] = {}
|
|
67
|
-
}
|
|
68
|
-
group[groupKey][key] = val
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
return group
|
|
106
|
+
// 弧度转化为角度的公式
|
|
107
|
+
function radToAngle (r: number) {
|
|
108
|
+
return r * 180 / Math.PI
|
|
72
109
|
}
|
|
73
110
|
|
|
74
|
-
const applyHandlers = (handlers: Handler[]
|
|
75
|
-
for (
|
|
111
|
+
const applyHandlers = (handlers: Handler[], args: any[]) => {
|
|
112
|
+
for (const handler of handlers) {
|
|
76
113
|
handler(...args)
|
|
77
114
|
}
|
|
78
115
|
}
|
|
79
116
|
|
|
80
|
-
const
|
|
81
|
-
|
|
82
|
-
|
|
117
|
+
const isPercent = (val: string | number | undefined): val is string => typeof val === 'string' && PERCENT_REGEX.test(val)
|
|
118
|
+
|
|
119
|
+
const isBackgroundSizeKeyword = (val: string | number): boolean => typeof val === 'string' && /^cover|contain$/.test(val)
|
|
120
|
+
|
|
121
|
+
const isNeedLayout = (preImageInfo: PreImageInfo): boolean => {
|
|
122
|
+
const { sizeList, backgroundPosition, linearInfo } = preImageInfo
|
|
123
|
+
const [width, height] = sizeList
|
|
124
|
+
const bp = backgroundPosition
|
|
125
|
+
|
|
126
|
+
// 含有百分号,center 需计算布局
|
|
127
|
+
return isBackgroundSizeKeyword(width) ||
|
|
128
|
+
(isPercent(height) && width === 'auto') ||
|
|
129
|
+
(isPercent(width) && height === 'auto') ||
|
|
130
|
+
isPercent(bp[1]) ||
|
|
131
|
+
isPercent(bp[3]) ||
|
|
132
|
+
isDiagonalAngle(linearInfo)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
const checkNeedLayout = (preImageInfo: PreImageInfo) => {
|
|
136
|
+
const { sizeList } = preImageInfo
|
|
137
|
+
const [width] = sizeList
|
|
138
|
+
// 在渐变的时候,background-size的cover,contain, auto属性值,转化为100%, needLayout计算逻辑和原来保持一致,needImageSize始终为false
|
|
139
|
+
return {
|
|
140
|
+
// 是否开启layout的计算
|
|
141
|
+
needLayout: isNeedLayout(preImageInfo),
|
|
142
|
+
// 是否开启原始宽度的计算
|
|
143
|
+
needImageSize: isBackgroundSizeKeyword(width) || sizeList.includes('auto')
|
|
144
|
+
}
|
|
83
145
|
}
|
|
84
146
|
|
|
85
147
|
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
function calculateSize(h: number,
|
|
91
|
-
let height
|
|
92
|
-
|
|
148
|
+
* h - 用户设置的高度
|
|
149
|
+
* lh - 容器的高度
|
|
150
|
+
* ratio - 原始图片的宽高比
|
|
151
|
+
* **/
|
|
152
|
+
function calculateSize (h: number, ratio: number, lh?: number | boolean, reverse = false): Size | null {
|
|
153
|
+
let height = 0; let width = 0
|
|
154
|
+
|
|
155
|
+
if (typeof lh === 'boolean') {
|
|
156
|
+
reverse = lh
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
if (isPercent(h)) { // auto px/rpx
|
|
93
160
|
if (!lh) return null
|
|
94
|
-
height = (parseFloat(
|
|
161
|
+
height = (parseFloat(h) / 100) * (lh as number)
|
|
95
162
|
width = height * ratio
|
|
96
163
|
} else { // 2. auto px/rpx - 根据比例计算
|
|
97
164
|
height = h
|
|
98
165
|
width = height * ratio
|
|
99
166
|
}
|
|
100
|
-
|
|
101
167
|
return {
|
|
102
|
-
width,
|
|
103
|
-
height
|
|
168
|
+
width: reverse ? height : width,
|
|
169
|
+
height: reverse ? width : height
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
/**
|
|
174
|
+
* 用户设置百分比后,转换为偏移量
|
|
175
|
+
* h - 用户设置图片的高度
|
|
176
|
+
* ch - 容器的高度
|
|
177
|
+
* val - 用户设置的百分比
|
|
178
|
+
* **/
|
|
179
|
+
function calculateSizePosition (h: number, ch: number, val: string): number {
|
|
180
|
+
if (!h || !ch) return 0
|
|
181
|
+
|
|
182
|
+
// 百分比需要单独的计算
|
|
183
|
+
if (isPercent(h)) {
|
|
184
|
+
h = ch * parseFloat(h) / 100
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// (container width - image width) * (position x%) = (x offset value)
|
|
188
|
+
return (ch - h) * parseFloat(val) / 100
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* 获取图片的展示宽高
|
|
193
|
+
* h - 用户设置的高度
|
|
194
|
+
* lh - 容器的高度
|
|
195
|
+
* **/
|
|
196
|
+
const calcPercent = (h: NumberVal, lh: number) => {
|
|
197
|
+
return isPercent(h) ? parseFloat(h) / 100 * lh : +h
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
function backgroundPosition (imageProps: ImageProps, preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) {
|
|
201
|
+
const bps = preImageInfo.backgroundPosition
|
|
202
|
+
if (bps.length === 0) return
|
|
203
|
+
const style: Position = {}
|
|
204
|
+
const imageStyle: ImageStyle = imageProps.style || {}
|
|
205
|
+
|
|
206
|
+
for (let i = 0; i < bps.length; i += 2) {
|
|
207
|
+
const key = bps[i] as PositionKey; const val = bps[i + 1]
|
|
208
|
+
// 需要获取 图片宽度 和 容器的宽度 进行计算
|
|
209
|
+
if (isPercent(val)) {
|
|
210
|
+
if (i === 0) {
|
|
211
|
+
style[key] = calculateSizePosition(imageStyle.width as number, layoutInfo?.width, val)
|
|
212
|
+
} else {
|
|
213
|
+
style[key] = calculateSizePosition(imageStyle.height as number, layoutInfo?.height, val)
|
|
214
|
+
}
|
|
215
|
+
} else {
|
|
216
|
+
style[key] = val as number
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
imageProps.style = {
|
|
221
|
+
...imageProps.style as ImageStyle,
|
|
222
|
+
...style
|
|
104
223
|
}
|
|
105
224
|
}
|
|
106
225
|
|
|
107
226
|
// background-size 转换
|
|
108
227
|
function backgroundSize (imageProps: ImageProps, preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) {
|
|
109
|
-
|
|
228
|
+
const sizeList = preImageInfo.sizeList
|
|
110
229
|
if (!sizeList) return
|
|
230
|
+
const { width: layoutWidth, height: layoutHeight } = layoutInfo || {}
|
|
231
|
+
const { width: imageSizeWidth, height: imageSizeHeight } = imageSize || {}
|
|
232
|
+
const [width, height] = sizeList
|
|
233
|
+
let dimensions: {
|
|
234
|
+
width: NumberVal,
|
|
235
|
+
height: NumberVal
|
|
236
|
+
} | null = { width: 0, height: 0 }
|
|
237
|
+
|
|
111
238
|
// 枚举值
|
|
112
|
-
if (['cover', 'contain'].includes(
|
|
113
|
-
|
|
239
|
+
if (typeof width === 'string' && ['cover', 'contain'].includes(width)) {
|
|
240
|
+
if (layoutInfo && imageSize) {
|
|
241
|
+
const layoutRatio = layoutWidth / imageSizeWidth
|
|
242
|
+
const eleRatio = imageSizeWidth / imageSizeHeight
|
|
243
|
+
// 容器宽高比 大于 图片的宽高比,依据宽度作为基准,否则以高度为基准
|
|
244
|
+
if ((layoutRatio <= eleRatio && (width as string) === 'contain') || (layoutRatio >= eleRatio && (width as string) === 'cover')) {
|
|
245
|
+
dimensions = calculateSize(layoutWidth as number, imageSizeHeight / imageSizeWidth, true) as Size
|
|
246
|
+
} else if ((layoutRatio > eleRatio && (width as string) === 'contain') || (layoutRatio < eleRatio && (width as string) === 'cover')) {
|
|
247
|
+
dimensions = calculateSize(layoutHeight as number, imageSizeWidth / imageSizeHeight) as Size
|
|
248
|
+
}
|
|
249
|
+
}
|
|
114
250
|
} else {
|
|
115
|
-
const [width, height] = sizeList
|
|
116
|
-
let newWidth: ImageStyle['width'] = 0, newHeight: ImageStyle['height'] = 0
|
|
117
|
-
|
|
118
|
-
const { width: imageSizeWidth, height: imageSizeHeight } = imageSize || {}
|
|
119
|
-
|
|
120
251
|
if (width === 'auto' && height === 'auto') { // 均为auto
|
|
121
252
|
if (!imageSize) return
|
|
122
|
-
|
|
123
|
-
|
|
253
|
+
dimensions = {
|
|
254
|
+
width: imageSizeWidth,
|
|
255
|
+
height: imageSizeHeight
|
|
256
|
+
}
|
|
124
257
|
} else if (width === 'auto') { // auto px/rpx/%
|
|
125
258
|
if (!imageSize) return
|
|
126
|
-
|
|
259
|
+
dimensions = calculateSize(height as number, imageSizeWidth / imageSizeHeight, layoutInfo?.height)
|
|
127
260
|
if (!dimensions) return
|
|
128
|
-
|
|
129
|
-
newHeight = dimensions.height
|
|
130
|
-
}else if (height === 'auto') { // auto px/rpx/%
|
|
261
|
+
} else if (height === 'auto') { // auto px/rpx/%
|
|
131
262
|
if (!imageSize) return
|
|
132
|
-
|
|
263
|
+
dimensions = calculateSize(width as number, imageSizeHeight / imageSizeWidth, layoutInfo?.width, true)
|
|
133
264
|
if (!dimensions) return
|
|
134
|
-
newHeight = dimensions.width
|
|
135
|
-
newWidth = dimensions.height
|
|
136
265
|
} else { // 数值类型 ImageStyle
|
|
137
266
|
// 数值类型设置为 stretch
|
|
138
267
|
(imageProps.style as ImageStyle).resizeMode = 'stretch'
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
imageProps.style = {
|
|
144
|
-
...imageProps.style as ImageStyle,
|
|
145
|
-
width: newWidth,
|
|
146
|
-
height: newHeight
|
|
268
|
+
dimensions = {
|
|
269
|
+
width: isPercent(width) ? width : +width,
|
|
270
|
+
height: isPercent(height) ? height : +height
|
|
271
|
+
} as { width: NumberVal, height: NumberVal }
|
|
147
272
|
}
|
|
148
273
|
}
|
|
274
|
+
// 样式合并
|
|
275
|
+
imageProps.style = {
|
|
276
|
+
...imageProps.style as ImageStyle,
|
|
277
|
+
...dimensions
|
|
278
|
+
}
|
|
149
279
|
}
|
|
150
280
|
|
|
151
281
|
// background-image转换为source
|
|
152
|
-
function backgroundImage(imageProps: ImageProps, preImageInfo: PreImageInfo) {
|
|
153
|
-
|
|
282
|
+
function backgroundImage (imageProps: ImageProps, preImageInfo: PreImageInfo) {
|
|
283
|
+
if (preImageInfo.src) {
|
|
284
|
+
imageProps.src = preImageInfo.src
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
// 渐变的转换
|
|
289
|
+
function linearGradient (imageProps: ImageProps, preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) {
|
|
290
|
+
const { type, linearInfo } = preImageInfo
|
|
291
|
+
const { colors = [], locations, direction = '' } = linearInfo || {}
|
|
292
|
+
const { width, height } = imageSize || {}
|
|
293
|
+
|
|
294
|
+
if (type !== 'linear') return
|
|
295
|
+
|
|
296
|
+
// 角度计算
|
|
297
|
+
let angle = +(linearMap.get(direction) || direction.match(/(-?\d+(\.\d+)?)deg/)?.[1] || 180) % 360
|
|
298
|
+
|
|
299
|
+
// 对角线角度计算
|
|
300
|
+
if (layoutInfo && diagonalAngleMap[direction] && imageSize && linearInfo) {
|
|
301
|
+
angle = radToAngle(diagonalAngleMap[direction](width, height)) || 180
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
// 赋值
|
|
305
|
+
imageProps.colors = colors
|
|
306
|
+
imageProps.locations = locations
|
|
307
|
+
imageProps.angle = angle
|
|
154
308
|
}
|
|
155
309
|
|
|
156
310
|
const imageStyleToProps = (preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) => {
|
|
@@ -158,79 +312,265 @@ const imageStyleToProps = (preImageInfo: PreImageInfo, imageSize: Size, layoutIn
|
|
|
158
312
|
const imageProps: ImageProps = {
|
|
159
313
|
style: {
|
|
160
314
|
resizeMode: 'cover' as ImageResizeMode,
|
|
161
|
-
|
|
162
|
-
|
|
315
|
+
position: 'absolute'
|
|
316
|
+
// ...StyleSheet.absoluteFillObject
|
|
317
|
+
},
|
|
318
|
+
colors: []
|
|
163
319
|
}
|
|
320
|
+
applyHandlers([backgroundSize, backgroundImage, backgroundPosition, linearGradient], [imageProps, preImageInfo, imageSize, layoutInfo])
|
|
164
321
|
|
|
165
|
-
applyHandlers([ backgroundSize, backgroundImage ],[imageProps, preImageInfo, imageSize, layoutInfo])
|
|
166
|
-
if (!imageProps?.src) return null
|
|
167
322
|
return imageProps
|
|
168
323
|
}
|
|
169
324
|
|
|
325
|
+
function isHorizontal (val: PositionVal): val is 'left' | 'right' {
|
|
326
|
+
return typeof val === 'string' && /^(left|right)$/.test(val)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
function isVertical (val: PositionVal): val is 'top' | 'bottom' {
|
|
330
|
+
return typeof val === 'string' && /^(top|bottom)$/.test(val)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
function normalizeBackgroundPosition (parts: PositionVal[]): backgroundPositionList {
|
|
334
|
+
if (parts.length === 0) return []
|
|
335
|
+
|
|
336
|
+
// 定义默认值
|
|
337
|
+
let hStart: 'left' | 'right' = 'left'
|
|
338
|
+
let hOffset: PositionVal = 0
|
|
339
|
+
let vStart: 'top' | 'bottom' = 'top'
|
|
340
|
+
let vOffset: PositionVal = 0
|
|
341
|
+
|
|
342
|
+
if (parts.length === 4) return parts as backgroundPositionList
|
|
343
|
+
|
|
344
|
+
// 归一化
|
|
345
|
+
if (parts.length === 1) {
|
|
346
|
+
// 1. center
|
|
347
|
+
// 2. 2px - hOffset, vOffset(center) - center为50%
|
|
348
|
+
// 3. 10% - hOffset, vOffset(center) - center为50%
|
|
349
|
+
// 4. left - hStart, vOffset(center) - center为50%
|
|
350
|
+
// 5. top - hOffset(center), vStart - center为50%
|
|
351
|
+
|
|
352
|
+
if (isHorizontal(parts[0])) {
|
|
353
|
+
hStart = parts[0]
|
|
354
|
+
vOffset = '50%'
|
|
355
|
+
} else if (isVertical(parts[0])) {
|
|
356
|
+
vStart = parts[0]
|
|
357
|
+
hOffset = '50%'
|
|
358
|
+
} else {
|
|
359
|
+
hOffset = parts[0]
|
|
360
|
+
vOffset = '50%'
|
|
361
|
+
}
|
|
362
|
+
} else if (parts.length === 2) {
|
|
363
|
+
// 1. center center - hOffset, vOffset
|
|
364
|
+
// 2. 10px center - hOffset, vStart
|
|
365
|
+
// 3. left center - hStart, vOffset
|
|
366
|
+
// 4. right center - hStart, vOffset
|
|
367
|
+
// 5. 第一位是 left right 覆盖的是 hStart
|
|
368
|
+
// center, 100% 正常的px 覆盖的是 hOffset
|
|
369
|
+
// 第二位是 top bottom 覆盖的是 vStart
|
|
370
|
+
// center, 100% 覆盖的是 vOffset
|
|
371
|
+
//
|
|
372
|
+
// 水平方向
|
|
373
|
+
if (isHorizontal(parts[0])) {
|
|
374
|
+
hStart = parts[0]
|
|
375
|
+
} else { // center, 100% 正常的px 覆盖的是 hOffset
|
|
376
|
+
hOffset = parts[0]
|
|
377
|
+
}
|
|
378
|
+
// 垂直方向
|
|
379
|
+
if (isVertical(parts[1])) {
|
|
380
|
+
vStart = parts[1]
|
|
381
|
+
} else { // center, 100% 正常的px 覆盖的是 hOffset
|
|
382
|
+
vOffset = parts[1]
|
|
383
|
+
}
|
|
384
|
+
} else if (parts.length === 3) {
|
|
385
|
+
// 1. center top 10px / top 10px center 等价 - center为50%
|
|
386
|
+
// 2. right 10px center / center right 10px 等价 - center为50%
|
|
387
|
+
// 2. bottom 50px right
|
|
388
|
+
if (typeof parts[0] === 'string' && typeof parts[1] === 'string' && /^left|bottom|right|top$/.test(parts[0]) && /^left|bottom|right|top$/.test(parts[1])) {
|
|
389
|
+
[hStart, vStart, vOffset] = parts as ['left' | 'right', 'top' | 'bottom', number]
|
|
390
|
+
} else {
|
|
391
|
+
[hStart, hOffset, vStart] = parts as ['left' | 'right', number, 'top' | 'bottom']
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
return [hStart, hOffset, vStart, vOffset] as backgroundPositionList
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
/**
|
|
399
|
+
*
|
|
400
|
+
* calcSteps - 计算起始位置和终点位置之间的差值
|
|
401
|
+
* startVal - 起始位置距离
|
|
402
|
+
* endVal - 终点位置距离
|
|
403
|
+
* len - 数量
|
|
404
|
+
* **/
|
|
405
|
+
function calcSteps (startVal: number, endVal: number, len: number) {
|
|
406
|
+
const diffVal = endVal - startVal
|
|
407
|
+
const step = diffVal / len
|
|
408
|
+
const newArr: Array<number> = []
|
|
409
|
+
for (let i = 1; i < len; i++) {
|
|
410
|
+
const val = startVal + step * i
|
|
411
|
+
newArr.push(+val.toFixed(2))
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return newArr
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
function parseLinearGradient (text: string): LinearInfo | undefined {
|
|
418
|
+
let linearText = text.trim().match(/linear-gradient\((.*)\)/)?.[1]
|
|
419
|
+
if (!linearText) return
|
|
170
420
|
|
|
171
|
-
|
|
421
|
+
// 添加默认的角度
|
|
422
|
+
if (!/^to|^-?\d+deg/.test(linearText)) {
|
|
423
|
+
linearText = '180deg ,' + linearText
|
|
424
|
+
} else {
|
|
425
|
+
linearText = linearText.replace('to', '')
|
|
426
|
+
}
|
|
172
427
|
|
|
173
|
-
|
|
174
|
-
const
|
|
428
|
+
// 把 0deg, red 10%, blue 20% 解析为 ['0deg', 'red, 10%', 'blue, 20%']
|
|
429
|
+
const [direction, ...colorList] = linearText.split(/,(?![^(#]*\))/)
|
|
430
|
+
// 记录需要填充起点的起始位置
|
|
431
|
+
let startIdx = 0; let startVal = 0
|
|
432
|
+
// 把 ['red, 10%', 'blue, 20%']解析为 [[red, 10%], [blue, 20%]]
|
|
433
|
+
const linearInfo = colorList.map(item => item.trim().split(/(?<!,)\s+/))
|
|
434
|
+
.reduce<LinearInfo>((prev, cur, idx, self) => {
|
|
435
|
+
const { colors, locations } = prev
|
|
436
|
+
const [color, val] = cur
|
|
437
|
+
let numberVal: number = parseFloat(val) / 100
|
|
438
|
+
|
|
439
|
+
// 处理渐变默认值
|
|
440
|
+
if (idx === 0) {
|
|
441
|
+
numberVal = numberVal || 0
|
|
442
|
+
} else if (self.length - 1 === idx) {
|
|
443
|
+
numberVal = numberVal || 1
|
|
444
|
+
}
|
|
175
445
|
|
|
176
|
-
|
|
446
|
+
// 出现缺省值时进行填充
|
|
447
|
+
if (idx - startIdx > 1 && !isNaN(numberVal)) {
|
|
448
|
+
locations.push(...calcSteps(startVal, numberVal, idx - startIdx))
|
|
449
|
+
}
|
|
177
450
|
|
|
178
|
-
|
|
451
|
+
if (!isNaN(numberVal)) {
|
|
452
|
+
startIdx = idx
|
|
453
|
+
startVal = numberVal
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// 添加color的数组
|
|
457
|
+
colors.push(color.trim())
|
|
458
|
+
|
|
459
|
+
!isNaN(numberVal) && locations.push(numberVal)
|
|
460
|
+
return prev
|
|
461
|
+
}, { colors: [], locations: [] })
|
|
462
|
+
|
|
463
|
+
return {
|
|
464
|
+
...linearInfo,
|
|
465
|
+
direction: direction.trim()
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
|
|
469
|
+
function parseBgImage (text: string): {
|
|
470
|
+
linearInfo?: LinearInfo;
|
|
471
|
+
direction?: string;
|
|
472
|
+
type?: 'image' | 'linear'
|
|
473
|
+
src?: string
|
|
474
|
+
} {
|
|
475
|
+
if (!text) return {}
|
|
476
|
+
|
|
477
|
+
const src = parseUrl(text)
|
|
478
|
+
if (src) return { src, type: 'image' }
|
|
479
|
+
|
|
480
|
+
const linearInfo = parseLinearGradient(text)
|
|
481
|
+
if (!linearInfo) return {}
|
|
482
|
+
return {
|
|
483
|
+
linearInfo,
|
|
484
|
+
type: 'linear'
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
function normalizeBackgroundSize (backgroundSize: Exclude<ExtendedViewStyle['backgroundSize'], undefined>, type: 'image' | 'linear' | undefined) {
|
|
489
|
+
const sizeList = backgroundSize.slice()
|
|
490
|
+
if (sizeList.length === 1) sizeList.push('auto')
|
|
491
|
+
|
|
492
|
+
if (type === 'linear') {
|
|
493
|
+
// 处理当使用渐变的时候,background-size出现cover, contain, auto,当作100%处理
|
|
494
|
+
for (const i in sizeList) {
|
|
495
|
+
const val = sizeList[i]
|
|
496
|
+
sizeList[i] = /^cover|contain|auto$/.test(val as string) ? '100%' : val
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
|
|
500
|
+
return sizeList
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
function preParseImage (imageStyle?: ExtendedViewStyle) {
|
|
504
|
+
const { backgroundImage = '', backgroundSize = ['auto'], backgroundPosition = [0, 0] } = imageStyle || {}
|
|
505
|
+
const { type, src, linearInfo } = parseBgImage(backgroundImage)
|
|
179
506
|
|
|
180
507
|
return {
|
|
181
508
|
src,
|
|
182
|
-
|
|
509
|
+
linearInfo,
|
|
510
|
+
type,
|
|
511
|
+
sizeList: normalizeBackgroundSize(backgroundSize, type),
|
|
512
|
+
backgroundPosition: normalizeBackgroundPosition(backgroundPosition)
|
|
183
513
|
}
|
|
184
514
|
}
|
|
185
515
|
|
|
186
|
-
function
|
|
187
|
-
|
|
516
|
+
function isDiagonalAngle (linearInfo?: LinearInfo): boolean {
|
|
517
|
+
return !!(linearInfo?.direction && diagonalAngleMap[linearInfo.direction])
|
|
518
|
+
}
|
|
519
|
+
|
|
520
|
+
function wrapImage (imageStyle?: ExtendedViewStyle) {
|
|
521
|
+
// 预处理数据
|
|
522
|
+
const preImageInfo: PreImageInfo = preParseImage(imageStyle)
|
|
523
|
+
// 预解析
|
|
524
|
+
const { src, sizeList, type } = preImageInfo
|
|
525
|
+
|
|
526
|
+
// 判断是否可挂载onLayout
|
|
527
|
+
const { needLayout, needImageSize } = checkNeedLayout(preImageInfo)
|
|
528
|
+
|
|
529
|
+
const [show, setShow] = useState<boolean>(((type === 'image' && !!src) || type === 'linear') && !needLayout && !needImageSize)
|
|
188
530
|
const [, setImageSizeWidth] = useState<number | null>(null)
|
|
189
531
|
const [, setImageSizeHeight] = useState<number | null>(null)
|
|
190
532
|
const [, setLayoutInfoWidth] = useState<number | null>(null)
|
|
191
533
|
const [, setLayoutInfoHeight] = useState<number | null>(null)
|
|
192
534
|
const sizeInfo = useRef<Size | null>(null)
|
|
193
535
|
const layoutInfo = useRef<Size | null>(null)
|
|
194
|
-
|
|
195
|
-
// 预解析
|
|
196
|
-
const preImageInfo: PreImageInfo = preParseImage(imageStyle)
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
// 判断是否可挂载onLayout
|
|
200
|
-
const needLayout = checkNeedLayout(preImageInfo)
|
|
201
|
-
const { src, sizeList } = preImageInfo
|
|
202
|
-
|
|
203
536
|
useEffect(() => {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
return
|
|
537
|
+
sizeInfo.current = null
|
|
538
|
+
if (type === 'linear') {
|
|
539
|
+
if (!needLayout) setShow(true)
|
|
540
|
+
return
|
|
209
541
|
}
|
|
210
|
-
|
|
211
|
-
if (!
|
|
542
|
+
|
|
543
|
+
if (!src) {
|
|
544
|
+
setShow(false)
|
|
545
|
+
return
|
|
546
|
+
// 一开始未出现,数据改变时出现
|
|
547
|
+
} else if (!(needLayout || needImageSize)) {
|
|
212
548
|
setShow(true)
|
|
213
549
|
return
|
|
214
550
|
}
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
if (!needLayout || layoutInfo.current) {
|
|
222
|
-
setImageSizeWidth(width)
|
|
223
|
-
setImageSizeHeight(height)
|
|
224
|
-
if(layoutInfo.current) {
|
|
225
|
-
setLayoutInfoWidth(layoutInfo.current.width)
|
|
226
|
-
setLayoutInfoHeight(layoutInfo.current.height)
|
|
551
|
+
|
|
552
|
+
if (needImageSize) {
|
|
553
|
+
Image.getSize(src, (width, height) => {
|
|
554
|
+
sizeInfo.current = {
|
|
555
|
+
width,
|
|
556
|
+
height
|
|
227
557
|
}
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
558
|
+
// 1. 当需要绑定onLayout 2. 获取到布局信息
|
|
559
|
+
if (!needLayout || layoutInfo.current) {
|
|
560
|
+
setImageSizeWidth(width)
|
|
561
|
+
setImageSizeHeight(height)
|
|
562
|
+
if (layoutInfo.current) {
|
|
563
|
+
setLayoutInfoWidth(layoutInfo.current.width)
|
|
564
|
+
setLayoutInfoHeight(layoutInfo.current.height)
|
|
565
|
+
}
|
|
566
|
+
setShow(true)
|
|
567
|
+
}
|
|
568
|
+
})
|
|
569
|
+
}
|
|
570
|
+
// type 添加type 处理无渐变 有渐变的场景
|
|
571
|
+
}, [src, type])
|
|
232
572
|
|
|
233
|
-
if (!
|
|
573
|
+
if (!type) return null
|
|
234
574
|
|
|
235
575
|
const onLayout = (res: LayoutChangeEvent) => {
|
|
236
576
|
const { width, height } = res?.nativeEvent?.layout || {}
|
|
@@ -238,67 +578,78 @@ function wrapImage(imageStyle?: ExtendedViewStyle) {
|
|
|
238
578
|
width,
|
|
239
579
|
height
|
|
240
580
|
}
|
|
241
|
-
if (
|
|
581
|
+
if (!needImageSize) {
|
|
582
|
+
setLayoutInfoWidth(width)
|
|
583
|
+
setLayoutInfoHeight(height)
|
|
584
|
+
// 有渐变角度的时候,才触发渲染组件
|
|
585
|
+
if (type === 'linear') {
|
|
586
|
+
sizeInfo.current = {
|
|
587
|
+
width: calcPercent(sizeList[0] as NumberVal, width),
|
|
588
|
+
height: calcPercent(sizeList[1] as NumberVal, height)
|
|
589
|
+
}
|
|
590
|
+
setImageSizeWidth(sizeInfo.current.width)
|
|
591
|
+
setImageSizeHeight(sizeInfo.current.height)
|
|
592
|
+
setShow(true)
|
|
593
|
+
}
|
|
594
|
+
} else if (sizeInfo.current) {
|
|
595
|
+
setLayoutInfoWidth(width)
|
|
596
|
+
setLayoutInfoHeight(height)
|
|
242
597
|
setImageSizeWidth(sizeInfo.current.width)
|
|
243
598
|
setImageSizeHeight(sizeInfo.current.height)
|
|
244
|
-
setLayoutInfoWidth(width)
|
|
245
|
-
setLayoutInfoHeight(height)
|
|
246
599
|
setShow(true)
|
|
247
600
|
}
|
|
248
601
|
}
|
|
249
|
-
|
|
250
|
-
return <View key='viewBgImg' {...needLayout ? {onLayout} : null } style={{ ...StyleSheet.absoluteFillObject, width: '100%', height: '100%', overflow: 'hidden'}}>
|
|
251
|
-
{show && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size)} />}
|
|
252
|
-
</View>
|
|
253
|
-
}
|
|
254
602
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
else if (IMAGE_STYLE_REGEX.test(key)) return 'imageStyle'
|
|
260
|
-
return 'innerStyle'
|
|
261
|
-
}, {})
|
|
603
|
+
return <View key='backgroundImage' {...needLayout ? { onLayout } : null} style={{ ...StyleSheet.absoluteFillObject, width: '100%', height: '100%', overflow: 'hidden' }}>
|
|
604
|
+
{show && type === 'linear' && <LinearGradient useAngle={true} {...imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size)} /> }
|
|
605
|
+
{show && type === 'image' && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size)} />}
|
|
606
|
+
</View>
|
|
262
607
|
}
|
|
263
608
|
|
|
264
|
-
|
|
265
|
-
|
|
609
|
+
interface WrapChildrenConfig {
|
|
610
|
+
hasVarDec: boolean
|
|
611
|
+
enableBackground: boolean
|
|
612
|
+
textStyle?: TextStyle
|
|
613
|
+
backgroundStyle?: ExtendedViewStyle
|
|
614
|
+
varContext?: Record<string, any>
|
|
615
|
+
textProps?: Record<string, any>
|
|
266
616
|
}
|
|
267
617
|
|
|
268
|
-
function
|
|
269
|
-
children =
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
}
|
|
618
|
+
function wrapWithChildren (props: _ViewProps, { hasVarDec, enableBackground, textStyle, backgroundStyle, varContext, textProps }: WrapChildrenConfig) {
|
|
619
|
+
const children = wrapChildren(props, {
|
|
620
|
+
hasVarDec,
|
|
621
|
+
varContext,
|
|
622
|
+
textStyle,
|
|
623
|
+
textProps
|
|
624
|
+
})
|
|
275
625
|
|
|
276
626
|
return [
|
|
277
|
-
wrapImage(
|
|
278
|
-
|
|
627
|
+
enableBackground ? wrapImage(backgroundStyle) : null,
|
|
628
|
+
children
|
|
279
629
|
]
|
|
280
630
|
}
|
|
281
631
|
|
|
282
|
-
const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((
|
|
283
|
-
const {
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
hoverStyle,
|
|
632
|
+
const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((viewProps, ref): JSX.Element => {
|
|
633
|
+
const { textProps, innerProps: props = {} } = splitProps(viewProps)
|
|
634
|
+
let {
|
|
635
|
+
style = {},
|
|
636
|
+
'hover-style': hoverStyle,
|
|
287
637
|
'hover-start-time': hoverStartTime = 50,
|
|
288
638
|
'hover-stay-time': hoverStayTime = 400,
|
|
289
|
-
'enable-
|
|
639
|
+
'enable-var': enableVar,
|
|
640
|
+
'external-var-context': externalVarContext,
|
|
641
|
+
'enable-background': enableBackground,
|
|
642
|
+
'parent-font-size': parentFontSize,
|
|
643
|
+
'parent-width': parentWidth,
|
|
644
|
+
'parent-height': parentHeight
|
|
290
645
|
} = props
|
|
291
646
|
|
|
292
647
|
const [isHover, setIsHover] = useState(false)
|
|
293
648
|
|
|
294
|
-
const layoutRef = useRef({})
|
|
295
|
-
|
|
296
|
-
// 打平 style 数组
|
|
297
|
-
const styleObj:ExtendedViewStyle = StyleSheet.flatten(style)
|
|
298
649
|
// 默认样式
|
|
299
|
-
const defaultStyle:ExtendedViewStyle = {
|
|
650
|
+
const defaultStyle: ExtendedViewStyle = {
|
|
300
651
|
// flex 布局相关的默认样式
|
|
301
|
-
...
|
|
652
|
+
...style.display === 'flex' && {
|
|
302
653
|
flexDirection: 'row',
|
|
303
654
|
flexBasis: 'auto',
|
|
304
655
|
flexShrink: 1,
|
|
@@ -306,6 +657,35 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
306
657
|
}
|
|
307
658
|
}
|
|
308
659
|
|
|
660
|
+
const styleObj: ExtendedViewStyle = {
|
|
661
|
+
...defaultStyle,
|
|
662
|
+
...style,
|
|
663
|
+
...(isHover ? hoverStyle : null)
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
const {
|
|
667
|
+
normalStyle,
|
|
668
|
+
hasSelfPercent,
|
|
669
|
+
hasVarDec,
|
|
670
|
+
varContextRef,
|
|
671
|
+
setWidth,
|
|
672
|
+
setHeight
|
|
673
|
+
} = useTransformStyle(styleObj, {
|
|
674
|
+
enableVar,
|
|
675
|
+
externalVarContext,
|
|
676
|
+
parentFontSize,
|
|
677
|
+
parentWidth,
|
|
678
|
+
parentHeight
|
|
679
|
+
})
|
|
680
|
+
|
|
681
|
+
const { textStyle, backgroundStyle, innerStyle } = splitStyle(normalStyle)
|
|
682
|
+
|
|
683
|
+
enableBackground = enableBackground || !!backgroundStyle
|
|
684
|
+
const enableBackgroundRef = useRef(enableBackground)
|
|
685
|
+
if (enableBackgroundRef.current !== enableBackground) {
|
|
686
|
+
throw new Error('[Mpx runtime error]: background use should be stable in the component lifecycle, or you can set [enable-background] with true.')
|
|
687
|
+
}
|
|
688
|
+
|
|
309
689
|
const { nodeRef } = useNodesRef<View, _ViewProps>(props, ref, {
|
|
310
690
|
defaultStyle
|
|
311
691
|
})
|
|
@@ -325,7 +705,7 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
325
705
|
const setStartTimer = () => {
|
|
326
706
|
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
|
|
327
707
|
dataRef.current.startTimer = setTimeout(() => {
|
|
328
|
-
setIsHover(
|
|
708
|
+
setIsHover(true)
|
|
329
709
|
}, +hoverStartTime)
|
|
330
710
|
}
|
|
331
711
|
|
|
@@ -333,50 +713,41 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
333
713
|
dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
|
|
334
714
|
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
|
|
335
715
|
dataRef.current.stayTimer = setTimeout(() => {
|
|
336
|
-
setIsHover(
|
|
716
|
+
setIsHover(false)
|
|
337
717
|
}, +hoverStayTime)
|
|
338
718
|
}
|
|
339
719
|
|
|
340
|
-
function onTouchStart(e: NativeSyntheticEvent<TouchEvent>){
|
|
341
|
-
const { bindtouchstart } = props
|
|
720
|
+
function onTouchStart (e: NativeSyntheticEvent<TouchEvent>) {
|
|
721
|
+
const { bindtouchstart } = props
|
|
342
722
|
bindtouchstart && bindtouchstart(e)
|
|
343
723
|
setStartTimer()
|
|
344
724
|
}
|
|
345
725
|
|
|
346
|
-
function onTouchEnd(e: NativeSyntheticEvent<TouchEvent>){
|
|
347
|
-
const { bindtouchend } = props
|
|
726
|
+
function onTouchEnd (e: NativeSyntheticEvent<TouchEvent>) {
|
|
727
|
+
const { bindtouchend } = props
|
|
348
728
|
bindtouchend && bindtouchend(e)
|
|
349
729
|
setStayTimer()
|
|
350
730
|
}
|
|
351
731
|
|
|
352
|
-
const
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
}
|
|
358
|
-
|
|
359
|
-
const {textStyle, imageStyle, innerStyle} = splitStyle(StyleSheet.flatten<ExtendedViewStyle>([
|
|
360
|
-
defaultStyle,
|
|
361
|
-
styleObj,
|
|
362
|
-
...(isHover ? hoverStyle : [])]
|
|
363
|
-
))
|
|
732
|
+
const {
|
|
733
|
+
layoutRef,
|
|
734
|
+
layoutStyle,
|
|
735
|
+
layoutProps
|
|
736
|
+
} = useLayout({ props, hasSelfPercent, setWidth, setHeight, nodeRef })
|
|
364
737
|
|
|
365
738
|
const innerProps = useInnerProps(props, {
|
|
366
739
|
ref: nodeRef,
|
|
367
|
-
|
|
740
|
+
style: { ...innerStyle, ...layoutStyle },
|
|
741
|
+
...layoutProps,
|
|
368
742
|
...(hoverStyle && {
|
|
369
743
|
bindtouchstart: onTouchStart,
|
|
370
744
|
bindtouchend: onTouchEnd
|
|
371
745
|
})
|
|
372
746
|
}, [
|
|
373
|
-
'style',
|
|
374
|
-
'children',
|
|
375
747
|
'hover-start-time',
|
|
376
748
|
'hover-stay-time',
|
|
377
|
-
'
|
|
378
|
-
'hover-class'
|
|
379
|
-
'enable-offset'
|
|
749
|
+
'hover-style',
|
|
750
|
+
'hover-class'
|
|
380
751
|
], {
|
|
381
752
|
layoutRef
|
|
382
753
|
})
|
|
@@ -384,9 +755,20 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
384
755
|
return (
|
|
385
756
|
<View
|
|
386
757
|
{...innerProps}
|
|
387
|
-
style={innerStyle}
|
|
388
758
|
>
|
|
389
|
-
{
|
|
759
|
+
{
|
|
760
|
+
wrapWithChildren(
|
|
761
|
+
props,
|
|
762
|
+
{
|
|
763
|
+
hasVarDec,
|
|
764
|
+
enableBackground: enableBackgroundRef.current,
|
|
765
|
+
textStyle,
|
|
766
|
+
backgroundStyle,
|
|
767
|
+
varContext: varContextRef.current,
|
|
768
|
+
textProps
|
|
769
|
+
}
|
|
770
|
+
)
|
|
771
|
+
}
|
|
390
772
|
</View>
|
|
391
773
|
)
|
|
392
774
|
})
|
|
@@ -394,4 +776,3 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
394
776
|
_View.displayName = 'mpx-view'
|
|
395
777
|
|
|
396
778
|
export default _View
|
|
397
|
-
|