@mpxjs/webpack-plugin 2.9.59 → 2.9.62
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/platform/style/wx/index.js +314 -254
- 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/runtime/components/react/context.ts +38 -0
- package/lib/runtime/components/react/dist/context.js +7 -0
- package/lib/runtime/components/react/dist/getInnerListeners.js +22 -11
- package/lib/runtime/components/react/dist/mpx-button.jsx +67 -45
- package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +81 -0
- package/lib/runtime/components/react/dist/mpx-checkbox.jsx +152 -0
- package/lib/runtime/components/react/dist/mpx-form.jsx +59 -0
- package/lib/runtime/components/react/dist/mpx-icon.jsx +51 -0
- package/lib/runtime/components/react/dist/mpx-image/index.jsx +17 -22
- package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -1
- package/lib/runtime/components/react/dist/mpx-input.jsx +38 -16
- package/lib/runtime/components/react/dist/mpx-label.jsx +63 -0
- package/lib/runtime/components/react/dist/mpx-movable-area.jsx +46 -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 +139 -0
- package/lib/runtime/components/react/dist/mpx-picker/region.jsx +90 -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 +15 -0
- package/lib/runtime/components/react/dist/mpx-picker-view.jsx +68 -0
- package/lib/runtime/components/react/dist/mpx-radio-group.jsx +79 -0
- package/lib/runtime/components/react/dist/mpx-radio.jsx +169 -0
- package/lib/runtime/components/react/dist/mpx-root-portal.jsx +11 -0
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +66 -50
- package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +206 -147
- package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +9 -7
- package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +3 -3
- package/lib/runtime/components/react/dist/mpx-switch.jsx +76 -0
- package/lib/runtime/components/react/dist/mpx-text.jsx +7 -19
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
- package/lib/runtime/components/react/dist/mpx-view.jsx +326 -96
- package/lib/runtime/components/react/dist/mpx-web-view.jsx +9 -15
- 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.js +82 -14
- package/lib/runtime/components/react/getInnerListeners.ts +25 -13
- package/lib/runtime/components/react/mpx-button.tsx +87 -67
- package/lib/runtime/components/react/mpx-checkbox-group.tsx +147 -0
- package/lib/runtime/components/react/mpx-checkbox.tsx +245 -0
- package/lib/runtime/components/react/mpx-form.tsx +89 -0
- package/lib/runtime/components/react/mpx-icon.tsx +103 -0
- package/lib/runtime/components/react/mpx-image/index.tsx +20 -32
- package/lib/runtime/components/react/mpx-image/svg.tsx +2 -2
- package/lib/runtime/components/react/mpx-input.tsx +54 -26
- package/lib/runtime/components/react/mpx-label.tsx +115 -0
- package/lib/runtime/components/react/mpx-movable-area.tsx +67 -0
- package/lib/runtime/components/react/mpx-movable-view.tsx +425 -0
- package/lib/runtime/components/react/mpx-navigator.tsx +67 -0
- package/lib/runtime/components/react/mpx-picker/date.tsx +83 -0
- package/lib/runtime/components/react/mpx-picker/index.tsx +155 -0
- package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +153 -0
- package/lib/runtime/components/react/mpx-picker/region.tsx +104 -0
- package/lib/runtime/components/react/mpx-picker/regionData.ts +6101 -0
- package/lib/runtime/components/react/mpx-picker/selector.tsx +92 -0
- package/lib/runtime/components/react/mpx-picker/time.tsx +274 -0
- package/lib/runtime/components/react/mpx-picker/type.ts +107 -0
- package/lib/runtime/components/react/mpx-picker-view-column.tsx +28 -0
- package/lib/runtime/components/react/mpx-picker-view.tsx +104 -0
- package/lib/runtime/components/react/mpx-radio-group.tsx +147 -0
- package/lib/runtime/components/react/mpx-radio.tsx +246 -0
- package/lib/runtime/components/react/mpx-root-portal.tsx +25 -0
- package/lib/runtime/components/react/mpx-scroll-view.tsx +82 -58
- package/lib/runtime/components/react/mpx-swiper/carouse.tsx +203 -156
- package/lib/runtime/components/react/mpx-swiper/index.tsx +12 -13
- package/lib/runtime/components/react/mpx-swiper/type.ts +11 -4
- package/lib/runtime/components/react/mpx-swiper-item.tsx +5 -3
- package/lib/runtime/components/react/mpx-switch.tsx +127 -0
- package/lib/runtime/components/react/mpx-text.tsx +52 -68
- package/lib/runtime/components/react/mpx-textarea.tsx +2 -2
- package/lib/runtime/components/react/mpx-view.tsx +373 -140
- package/lib/runtime/components/react/mpx-web-view.tsx +24 -28
- 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 +4 -0
- package/lib/runtime/components/react/useNodesRef.ts +3 -8
- package/lib/runtime/components/react/utils.ts +93 -15
- package/lib/runtime/optionProcessor.js +19 -17
- package/lib/template-compiler/compiler.js +56 -41
- package/lib/template-compiler/gen-node-react.js +7 -7
- package/package.json +6 -3
|
@@ -4,49 +4,55 @@
|
|
|
4
4
|
* ✔ hover-start-time
|
|
5
5
|
* ✔ hover-stay-time
|
|
6
6
|
*/
|
|
7
|
-
import { View, Text, StyleProp, TextStyle,
|
|
7
|
+
import { View, Text, StyleProp, TextStyle, NativeSyntheticEvent, ViewProps, ImageStyle, ImageResizeMode, StyleSheet, Image, LayoutChangeEvent } from 'react-native'
|
|
8
8
|
import { useRef, useState, useEffect, forwardRef, ReactNode, JSX } from 'react'
|
|
9
|
-
// @ts-ignore
|
|
10
9
|
import useInnerProps from './getInnerListeners'
|
|
11
|
-
|
|
12
|
-
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
13
|
-
|
|
14
|
-
import { parseUrl, TEXT_STYLE_REGEX, PERCENT_REGEX, isText} from './utils'
|
|
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'
|
|
21
12
|
|
|
13
|
+
import { parseUrl, PERCENT_REGEX, isText, every, normalizeStyle, splitStyle, splitProps, throwReactWarning, transformTextStyle } from './utils'
|
|
22
14
|
export interface _ViewProps extends ViewProps {
|
|
23
|
-
style?:
|
|
24
|
-
children?: ReactNode | ReactNode
|
|
25
|
-
hoverStyle
|
|
26
|
-
['hover-start-time']
|
|
27
|
-
['hover-stay-time']
|
|
15
|
+
style?: ExtendedViewStyle
|
|
16
|
+
children?: ReactNode | ReactNode[]
|
|
17
|
+
hoverStyle?: ExtendedViewStyle
|
|
18
|
+
['hover-start-time']?: number
|
|
19
|
+
['hover-stay-time']?: number
|
|
28
20
|
'enable-offset'?: boolean
|
|
21
|
+
'enable-background-image'?: boolean
|
|
29
22
|
bindtouchstart?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
30
23
|
bindtouchmove?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
31
24
|
bindtouchend?: (event: NativeSyntheticEvent<TouchEvent> | unknown) => void
|
|
32
25
|
}
|
|
33
26
|
|
|
34
|
-
type
|
|
35
|
-
|
|
36
|
-
type GroupData = Record<string, Record<string, any>>;
|
|
37
|
-
|
|
38
|
-
type Handler = (...args: any []) => void
|
|
27
|
+
type Handler = (...args: any[]) => void
|
|
39
28
|
|
|
40
29
|
type Size = {
|
|
41
|
-
width: number
|
|
30
|
+
width: number
|
|
42
31
|
height: number
|
|
43
32
|
}
|
|
44
33
|
|
|
45
34
|
type DimensionValue = number | 'auto' | `${number}%`
|
|
46
35
|
|
|
36
|
+
type Position = {
|
|
37
|
+
left?: number
|
|
38
|
+
right?: number
|
|
39
|
+
top?: number
|
|
40
|
+
bottom?: number
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
type PositionKey = keyof Position
|
|
44
|
+
|
|
45
|
+
type NumberVal = number | `${number}%`
|
|
46
|
+
|
|
47
|
+
type PositionVal = PositionKey | NumberVal
|
|
48
|
+
|
|
49
|
+
type backgroundPositionList = ['left' | 'right', NumberVal, 'top' | 'bottom', NumberVal] | []
|
|
50
|
+
|
|
47
51
|
type PreImageInfo = {
|
|
48
52
|
src?: string,
|
|
49
|
-
sizeList: DimensionValue
|
|
53
|
+
sizeList: DimensionValue[]
|
|
54
|
+
containPercentSymbol?: boolean
|
|
55
|
+
backgroundPosition: backgroundPositionList
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
type ImageProps = {
|
|
@@ -54,98 +60,150 @@ type ImageProps = {
|
|
|
54
60
|
src?: string
|
|
55
61
|
}
|
|
56
62
|
|
|
57
|
-
const
|
|
58
|
-
|
|
59
|
-
function groupBy(style: Obj, callback: (key: string, val: string) => string, group:GroupData = {}):GroupData {
|
|
60
|
-
let groupKey = ''
|
|
61
|
-
for (let key in style) {
|
|
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
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
const applyHandlers = (handlers: Handler[] , args: any [] ) => {
|
|
63
|
+
const applyHandlers = (handlers: Handler[], args: any[]) => {
|
|
75
64
|
for (let handler of handlers) {
|
|
76
65
|
handler(...args)
|
|
77
66
|
}
|
|
78
67
|
}
|
|
79
68
|
|
|
80
|
-
const checkNeedLayout = (style: PreImageInfo) => {
|
|
69
|
+
const checkNeedLayout = (style: PreImageInfo) => {
|
|
81
70
|
const [width, height] = style.sizeList
|
|
82
|
-
|
|
71
|
+
const bp = style.backgroundPosition
|
|
72
|
+
// 含有百分号,center 需计算布局
|
|
73
|
+
const containPercentSymbol = typeof bp[1] === 'string' && PERCENT_REGEX.test(bp[1]) || typeof bp[3] === 'string' && PERCENT_REGEX.test(bp[3])
|
|
74
|
+
|
|
75
|
+
return {
|
|
76
|
+
// 是否开启layout的计算
|
|
77
|
+
needLayout: typeof width === 'string' && /^cover|contain$/.test(width) || (typeof height === 'string' && PERCENT_REGEX.test(height) && width === 'auto') || (typeof width === 'string' && PERCENT_REGEX.test(width) && height === 'auto') || containPercentSymbol,
|
|
78
|
+
// 是否开启原始宽度的计算
|
|
79
|
+
needImageSize: typeof width === 'string' && /^cover|contain$/.test(width) || style.sizeList.includes('auto')
|
|
80
|
+
}
|
|
83
81
|
}
|
|
84
82
|
|
|
85
83
|
/**
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
function calculateSize(h: number,
|
|
91
|
-
let height, width
|
|
92
|
-
|
|
84
|
+
* h - 用户设置的高度
|
|
85
|
+
* lh - 容器的高度
|
|
86
|
+
* ratio - 原始图片的宽高比
|
|
87
|
+
* **/
|
|
88
|
+
function calculateSize(h: number, ratio: number, lh?: number | boolean, reverse: boolean = false): Size | null {
|
|
89
|
+
let height = 0, width = 0
|
|
90
|
+
|
|
91
|
+
if (typeof lh === 'boolean') {
|
|
92
|
+
reverse = lh
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if (typeof h === 'string' && PERCENT_REGEX.test(h)) { // auto px/rpx
|
|
93
96
|
if (!lh) return null
|
|
94
|
-
height = (parseFloat(
|
|
97
|
+
height = (parseFloat(h) / 100) * (lh as number)
|
|
95
98
|
width = height * ratio
|
|
96
99
|
} else { // 2. auto px/rpx - 根据比例计算
|
|
97
100
|
height = h
|
|
98
101
|
width = height * ratio
|
|
99
102
|
}
|
|
100
|
-
|
|
101
103
|
return {
|
|
102
|
-
width,
|
|
103
|
-
height
|
|
104
|
+
width: reverse ? height : width,
|
|
105
|
+
height: reverse ? width : height
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* 用户设置百分比后,转换为偏移量
|
|
111
|
+
* h - 用户设置图片的高度
|
|
112
|
+
* ch - 容器的高度
|
|
113
|
+
* val - 用户设置的百分比
|
|
114
|
+
* **/
|
|
115
|
+
function calculateSizePosition(h: number, ch: number, val: string): number {
|
|
116
|
+
if (!h || !ch) return 0
|
|
117
|
+
|
|
118
|
+
// 百分比需要单独的计算
|
|
119
|
+
if (typeof h === 'string' && PERCENT_REGEX.test(h)) {
|
|
120
|
+
h = ch * parseFloat(h) / 100
|
|
104
121
|
}
|
|
122
|
+
|
|
123
|
+
// (container width - image width) * (position x%) = (x offset value)
|
|
124
|
+
return (ch - h) * parseFloat(val) / 100
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
function backgroundPosition(imageProps: ImageProps, preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) {
|
|
128
|
+
const bps = preImageInfo.backgroundPosition
|
|
129
|
+
if (bps.length === 0) return
|
|
130
|
+
let style: Position = {}
|
|
131
|
+
let imageStyle: ImageStyle = imageProps.style || {}
|
|
132
|
+
|
|
133
|
+
for (let i = 0; i < bps.length; i += 2) {
|
|
134
|
+
let key = bps[i] as PositionKey, val = bps[i + 1]
|
|
135
|
+
// 需要获取 图片宽度 和 容器的宽度 进行计算
|
|
136
|
+
if (typeof val === 'string' && PERCENT_REGEX.test(val)) {
|
|
137
|
+
if (i === 0) {
|
|
138
|
+
style[key] = calculateSizePosition(imageStyle.width as number, layoutInfo?.width, val)
|
|
139
|
+
} else {
|
|
140
|
+
style[key] = calculateSizePosition(imageStyle.height as number, layoutInfo?.height, val)
|
|
141
|
+
}
|
|
142
|
+
} else {
|
|
143
|
+
style[key] = val as number
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
imageProps.style = {
|
|
148
|
+
...imageProps.style as ImageStyle,
|
|
149
|
+
...style
|
|
150
|
+
}
|
|
151
|
+
|
|
105
152
|
}
|
|
106
153
|
|
|
107
154
|
// background-size 转换
|
|
108
|
-
function backgroundSize
|
|
155
|
+
function backgroundSize(imageProps: ImageProps, preImageInfo: PreImageInfo, imageSize: Size, layoutInfo: Size) {
|
|
109
156
|
let sizeList = preImageInfo.sizeList
|
|
110
157
|
if (!sizeList) return
|
|
158
|
+
const { width: layoutWidth, height: layoutHeight } = layoutInfo || {}
|
|
159
|
+
const { width: imageSizeWidth, height: imageSizeHeight } = imageSize || {}
|
|
160
|
+
const [width, height] = sizeList
|
|
161
|
+
let dimensions: {
|
|
162
|
+
width: NumberVal,
|
|
163
|
+
height: NumberVal
|
|
164
|
+
} | null = { width: 0, height: 0 }
|
|
165
|
+
|
|
111
166
|
// 枚举值
|
|
112
|
-
if (['cover', 'contain'].includes(
|
|
113
|
-
|
|
167
|
+
if (typeof width === 'string' && ['cover', 'contain'].includes(width)) {
|
|
168
|
+
if (layoutInfo && imageSize) {
|
|
169
|
+
let layoutRatio = layoutWidth / imageSizeWidth
|
|
170
|
+
let eleRatio = imageSizeWidth / imageSizeHeight
|
|
171
|
+
// 容器宽高比 大于 图片的宽高比,依据宽度作为基准,否则以高度为基准
|
|
172
|
+
if (layoutRatio <= eleRatio && (width as string) === 'contain' || layoutRatio >= eleRatio && (width as string) === 'cover') {
|
|
173
|
+
dimensions = calculateSize(layoutWidth as number, imageSizeHeight / imageSizeWidth, true) as Size
|
|
174
|
+
} else if (layoutRatio > eleRatio && (width as string) === 'contain' || layoutRatio < eleRatio && (width as string) === 'cover') {
|
|
175
|
+
dimensions = calculateSize(layoutHeight as number, imageSizeWidth / imageSizeHeight) as Size
|
|
176
|
+
}
|
|
177
|
+
}
|
|
114
178
|
} 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
179
|
if (width === 'auto' && height === 'auto') { // 均为auto
|
|
121
180
|
if (!imageSize) return
|
|
122
|
-
|
|
123
|
-
|
|
181
|
+
dimensions = {
|
|
182
|
+
width: imageSizeWidth,
|
|
183
|
+
height: imageSizeHeight
|
|
184
|
+
}
|
|
124
185
|
} else if (width === 'auto') { // auto px/rpx/%
|
|
125
186
|
if (!imageSize) return
|
|
126
|
-
|
|
187
|
+
dimensions = calculateSize(height as number, imageSizeWidth / imageSizeHeight, layoutInfo?.height)
|
|
127
188
|
if (!dimensions) return
|
|
128
|
-
|
|
129
|
-
newHeight = dimensions.height
|
|
130
|
-
}else if (height === 'auto') { // auto px/rpx/%
|
|
189
|
+
} else if (height === 'auto') { // auto px/rpx/%
|
|
131
190
|
if (!imageSize) return
|
|
132
|
-
|
|
191
|
+
dimensions = calculateSize(width as number, imageSizeHeight / imageSizeWidth, layoutInfo?.width, true)
|
|
133
192
|
if (!dimensions) return
|
|
134
|
-
newHeight = dimensions.width
|
|
135
|
-
newWidth = dimensions.height
|
|
136
193
|
} else { // 数值类型 ImageStyle
|
|
137
194
|
// 数值类型设置为 stretch
|
|
138
195
|
(imageProps.style as ImageStyle).resizeMode = 'stretch'
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
imageProps.style = {
|
|
144
|
-
...imageProps.style as ImageStyle,
|
|
145
|
-
width: newWidth,
|
|
146
|
-
height: newHeight
|
|
196
|
+
dimensions = {
|
|
197
|
+
width: typeof width === 'string' && PERCENT_REGEX.test(width) ? width : +width! as number,
|
|
198
|
+
height: typeof height === 'string' && PERCENT_REGEX.test(height) ? height : +height! as number
|
|
199
|
+
}
|
|
147
200
|
}
|
|
148
201
|
}
|
|
202
|
+
// 样式合并
|
|
203
|
+
imageProps.style = {
|
|
204
|
+
...imageProps.style as ImageStyle,
|
|
205
|
+
...dimensions
|
|
206
|
+
}
|
|
149
207
|
}
|
|
150
208
|
|
|
151
209
|
// background-image转换为source
|
|
@@ -158,28 +216,102 @@ const imageStyleToProps = (preImageInfo: PreImageInfo, imageSize: Size, layoutIn
|
|
|
158
216
|
const imageProps: ImageProps = {
|
|
159
217
|
style: {
|
|
160
218
|
resizeMode: 'cover' as ImageResizeMode,
|
|
161
|
-
|
|
219
|
+
position: 'absolute'
|
|
220
|
+
// ...StyleSheet.absoluteFillObject
|
|
162
221
|
}
|
|
163
222
|
}
|
|
164
|
-
|
|
165
|
-
applyHandlers([ backgroundSize, backgroundImage ],[imageProps, preImageInfo, imageSize, layoutInfo])
|
|
223
|
+
applyHandlers([backgroundSize, backgroundImage, backgroundPosition], [imageProps, preImageInfo, imageSize, layoutInfo])
|
|
166
224
|
if (!imageProps?.src) return null
|
|
167
225
|
return imageProps
|
|
168
226
|
}
|
|
169
227
|
|
|
228
|
+
function isHorizontal(val: PositionVal): val is 'left' | 'right' {
|
|
229
|
+
return typeof val === 'string' && /^(left|right)$/.test(val)
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
function isVertical(val: PositionVal): val is 'top' | 'bottom' {
|
|
233
|
+
return typeof val === 'string' && /^(top|bottom)$/.test(val)
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
function normalizeBackgroundPosition(parts: PositionVal[]): backgroundPositionList {
|
|
237
|
+
|
|
238
|
+
if (parts.length === 0) return []
|
|
239
|
+
|
|
240
|
+
// 定义默认值
|
|
241
|
+
let hStart: 'left' | 'right' = 'left'
|
|
242
|
+
let hOffset: PositionVal = 0
|
|
243
|
+
let vStart: 'top' | 'bottom' = 'top'
|
|
244
|
+
let vOffset: PositionVal = 0
|
|
245
|
+
|
|
246
|
+
if (parts.length === 4) return parts as backgroundPositionList
|
|
247
|
+
|
|
248
|
+
// 归一化
|
|
249
|
+
if (parts.length === 1) {
|
|
250
|
+
// 1. center
|
|
251
|
+
// 2. 2px - hOffset, vOffset(center) - center为50%
|
|
252
|
+
// 3. 10% - hOffset, vOffset(center) - center为50%
|
|
253
|
+
// 4. left - hStart, vOffset(center) - center为50%
|
|
254
|
+
// 5. top - hOffset(center), vStart - center为50%
|
|
255
|
+
|
|
256
|
+
if (isHorizontal(parts[0])) {
|
|
257
|
+
hStart = parts[0]
|
|
258
|
+
vOffset = '50%'
|
|
259
|
+
} else if (isVertical(parts[0])) {
|
|
260
|
+
vStart = parts[0]
|
|
261
|
+
hOffset = '50%'
|
|
262
|
+
} else {
|
|
263
|
+
hOffset = parts[0]
|
|
264
|
+
vOffset = '50%'
|
|
265
|
+
}
|
|
266
|
+
} else if (parts.length === 2) {
|
|
267
|
+
// 1. center center - hOffset, vOffset
|
|
268
|
+
// 2. 10px center - hOffset, vStart
|
|
269
|
+
// 3. left center - hStart, vOffset
|
|
270
|
+
// 4. right center - hStart, vOffset
|
|
271
|
+
// 5. 第一位是 left right 覆盖的是 hStart
|
|
272
|
+
// center, 100% 正常的px 覆盖的是 hOffset
|
|
273
|
+
// 第二位是 top bottom 覆盖的是 vStart
|
|
274
|
+
// center, 100% 覆盖的是 vOffset
|
|
275
|
+
//
|
|
276
|
+
// 水平方向
|
|
277
|
+
if (isHorizontal(parts[0])) {
|
|
278
|
+
hStart = parts[0]
|
|
279
|
+
} else { // center, 100% 正常的px 覆盖的是 hOffset
|
|
280
|
+
hOffset = parts[0]
|
|
281
|
+
}
|
|
282
|
+
// 垂直方向
|
|
283
|
+
if (isVertical(parts[1])) {
|
|
284
|
+
vStart = parts[1]
|
|
285
|
+
} else { // center, 100% 正常的px 覆盖的是 hOffset
|
|
286
|
+
vOffset = parts[1]
|
|
287
|
+
}
|
|
288
|
+
} else if (parts.length === 3) {
|
|
289
|
+
// 1. center top 10px / top 10px center 等价 - center为50%
|
|
290
|
+
// 2. right 10px center / center right 10px 等价 - center为50%
|
|
291
|
+
// 2. bottom 50px right
|
|
292
|
+
if (typeof parts[0] === 'string' && typeof parts[1] === 'string' && /^left|bottom|right|top$/.test(parts[0]) && /^left|bottom|right|top$/.test(parts[1])) {
|
|
293
|
+
[hStart, vStart, vOffset] = parts as ['left' | 'right', 'top' | 'bottom', number]
|
|
294
|
+
} else {
|
|
295
|
+
[hStart, hOffset, vStart] = parts as ['left' | 'right', number, 'top' | 'bottom']
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
return [hStart, hOffset, vStart, vOffset] as backgroundPositionList
|
|
300
|
+
}
|
|
170
301
|
|
|
171
302
|
function preParseImage(imageStyle?: ExtendedViewStyle) {
|
|
172
303
|
|
|
173
|
-
const { backgroundImage, backgroundSize = [
|
|
304
|
+
const { backgroundImage, backgroundSize = ['auto'], backgroundPosition = [0, 0] } = imageStyle || {}
|
|
174
305
|
const src = parseUrl(backgroundImage)
|
|
175
306
|
|
|
176
|
-
let sizeList = backgroundSize.slice() as DimensionValue
|
|
307
|
+
let sizeList = backgroundSize.slice() as DimensionValue[]
|
|
177
308
|
|
|
178
|
-
sizeList.length === 1 &&
|
|
309
|
+
sizeList.length === 1 && sizeList.push('auto')
|
|
179
310
|
|
|
180
311
|
return {
|
|
181
312
|
src,
|
|
182
|
-
sizeList
|
|
313
|
+
sizeList,
|
|
314
|
+
backgroundPosition: normalizeBackgroundPosition(backgroundPosition)
|
|
183
315
|
}
|
|
184
316
|
}
|
|
185
317
|
|
|
@@ -195,10 +327,9 @@ function wrapImage(imageStyle?: ExtendedViewStyle) {
|
|
|
195
327
|
// 预解析
|
|
196
328
|
const preImageInfo: PreImageInfo = preParseImage(imageStyle)
|
|
197
329
|
|
|
198
|
-
|
|
199
330
|
// 判断是否可挂载onLayout
|
|
200
|
-
const needLayout = checkNeedLayout(preImageInfo)
|
|
201
|
-
const { src
|
|
331
|
+
const { needLayout, needImageSize } = checkNeedLayout(preImageInfo)
|
|
332
|
+
const { src } = preImageInfo
|
|
202
333
|
|
|
203
334
|
useEffect(() => {
|
|
204
335
|
if(!src) {
|
|
@@ -207,8 +338,8 @@ function wrapImage(imageStyle?: ExtendedViewStyle) {
|
|
|
207
338
|
layoutInfo.current = null
|
|
208
339
|
return
|
|
209
340
|
}
|
|
210
|
-
|
|
211
|
-
if (!
|
|
341
|
+
|
|
342
|
+
if (!needImageSize) {
|
|
212
343
|
setShow(true)
|
|
213
344
|
return
|
|
214
345
|
}
|
|
@@ -232,71 +363,97 @@ function wrapImage(imageStyle?: ExtendedViewStyle) {
|
|
|
232
363
|
|
|
233
364
|
if (!preImageInfo?.src) return null
|
|
234
365
|
|
|
235
|
-
const onLayout = (res: LayoutChangeEvent) => {
|
|
366
|
+
const onLayout = (res: LayoutChangeEvent ) => {
|
|
236
367
|
const { width, height } = res?.nativeEvent?.layout || {}
|
|
237
368
|
layoutInfo.current = {
|
|
238
369
|
width,
|
|
239
370
|
height
|
|
240
371
|
}
|
|
241
|
-
if (
|
|
242
|
-
setImageSizeWidth(sizeInfo.current.width)
|
|
243
|
-
setImageSizeHeight(sizeInfo.current.height)
|
|
372
|
+
if (!needImageSize) {
|
|
244
373
|
setLayoutInfoWidth(width)
|
|
245
|
-
setLayoutInfoHeight(height)
|
|
374
|
+
setLayoutInfoHeight(height)
|
|
375
|
+
} else if (sizeInfo.current) {
|
|
376
|
+
setLayoutInfoWidth(width)
|
|
377
|
+
setLayoutInfoHeight(height)
|
|
378
|
+
setImageSizeWidth(sizeInfo.current.width)
|
|
379
|
+
setImageSizeHeight(sizeInfo.current.height)
|
|
246
380
|
setShow(true)
|
|
247
381
|
}
|
|
248
382
|
}
|
|
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
383
|
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
return 'textStyle'
|
|
259
|
-
else if (IMAGE_STYLE_REGEX.test(key)) return 'imageStyle'
|
|
260
|
-
return 'innerStyle'
|
|
261
|
-
}, {})
|
|
384
|
+
return <View key='viewBgImg' {...needLayout ? { onLayout } : null } style={{ ...StyleSheet.absoluteFillObject, width: '100%', height: '100%', overflow: 'hidden' }}>
|
|
385
|
+
{show && <Image {...imageStyleToProps(preImageInfo, sizeInfo.current as Size, layoutInfo.current as Size)} />}
|
|
386
|
+
</View>
|
|
262
387
|
}
|
|
263
388
|
|
|
264
|
-
function
|
|
265
|
-
|
|
266
|
-
}
|
|
389
|
+
function wrapChildren(children: ReactNode | ReactNode[], props: _ViewProps, textStyle?: StyleProp<TextStyle>, imageStyle?: ExtendedViewStyle) {
|
|
390
|
+
const { textProps } = splitProps(props)
|
|
391
|
+
const { 'enable-background-image': enableBackgroundImage } = props
|
|
267
392
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
393
|
+
if (every(children as ReactNode[], (child) => isText(child))) {
|
|
394
|
+
if (textStyle || textProps) {
|
|
395
|
+
transformTextStyle(textStyle as TextStyle)
|
|
396
|
+
children = <Text key='viewTextWrap' style={textStyle} {...(textProps || {})}>{children}</Text>
|
|
397
|
+
}
|
|
272
398
|
} else {
|
|
273
|
-
if(textStyle)
|
|
399
|
+
if (textStyle) throwReactWarning('[Mpx runtime warn]: Text style will be ignored unless every child of the view is Text node!')
|
|
274
400
|
}
|
|
275
401
|
|
|
276
402
|
return [
|
|
277
|
-
wrapImage(imageStyle),
|
|
278
|
-
|
|
403
|
+
enableBackgroundImage ? wrapImage(imageStyle) : null,
|
|
404
|
+
children
|
|
279
405
|
]
|
|
280
406
|
}
|
|
281
407
|
|
|
282
408
|
const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref): JSX.Element => {
|
|
409
|
+
const combinationStyleProps = [{
|
|
410
|
+
key: 'transform',
|
|
411
|
+
rules: {
|
|
412
|
+
width: 'translateX',
|
|
413
|
+
height: 'translateY'
|
|
414
|
+
}
|
|
415
|
+
}, {
|
|
416
|
+
key: 'borderTopLeftRadius',
|
|
417
|
+
rules: {
|
|
418
|
+
width: 'borderTopLeftRadius'
|
|
419
|
+
}
|
|
420
|
+
}, {
|
|
421
|
+
key: 'borderBottomLeftRadius',
|
|
422
|
+
rules: {
|
|
423
|
+
width: 'borderBottomLeftRadius'
|
|
424
|
+
}
|
|
425
|
+
}, {
|
|
426
|
+
key: 'borderBottomRightRadius',
|
|
427
|
+
rules: {
|
|
428
|
+
height: 'borderBottomRightRadius'
|
|
429
|
+
}
|
|
430
|
+
}, {
|
|
431
|
+
key: 'borderTopRightRadius',
|
|
432
|
+
rules: {
|
|
433
|
+
height: 'borderTopRightRadius'
|
|
434
|
+
}
|
|
435
|
+
}]
|
|
283
436
|
const {
|
|
284
|
-
style =
|
|
437
|
+
style = {},
|
|
285
438
|
children,
|
|
286
439
|
hoverStyle,
|
|
287
440
|
'hover-start-time': hoverStartTime = 50,
|
|
288
441
|
'hover-stay-time': hoverStayTime = 400,
|
|
289
|
-
'enable-offset': enableOffset
|
|
442
|
+
'enable-offset': enableOffset,
|
|
290
443
|
} = props
|
|
291
444
|
|
|
292
445
|
const [isHover, setIsHover] = useState(false)
|
|
446
|
+
let transformStyle = {}
|
|
447
|
+
|
|
448
|
+
const [containerWidth, setContainerWidth] = useState(0)
|
|
449
|
+
const [containerHeight, setContainerHeight] = useState(0)
|
|
293
450
|
|
|
294
451
|
const layoutRef = useRef({})
|
|
295
452
|
|
|
296
453
|
// 打平 style 数组
|
|
297
|
-
const styleObj:ExtendedViewStyle =
|
|
454
|
+
const styleObj: ExtendedViewStyle = normalizeStyle(style)
|
|
298
455
|
// 默认样式
|
|
299
|
-
const defaultStyle:ExtendedViewStyle = {
|
|
456
|
+
const defaultStyle: ExtendedViewStyle = {
|
|
300
457
|
// flex 布局相关的默认样式
|
|
301
458
|
...styleObj.display === 'flex' && {
|
|
302
459
|
flexDirection: 'row',
|
|
@@ -306,6 +463,24 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
306
463
|
}
|
|
307
464
|
}
|
|
308
465
|
|
|
466
|
+
const hasPercentStyle = combinationStyleProps.some(({ key, rules }) => {
|
|
467
|
+
return Object.entries(rules).some(([dimension, transformKey]) => {
|
|
468
|
+
const transformItemValue = styleObj[key]
|
|
469
|
+
if (transformItemValue) {
|
|
470
|
+
if (Array.isArray(transformItemValue)) {
|
|
471
|
+
const transformValue = transformItemValue.find((item: Record<string, any>) => item.hasOwnProperty(transformKey))
|
|
472
|
+
return transformValue && PERCENT_REGEX.test(transformValue[transformKey])
|
|
473
|
+
} else if (typeof transformItemValue === 'string') {
|
|
474
|
+
return PERCENT_REGEX.test(transformItemValue)
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
})
|
|
478
|
+
})
|
|
479
|
+
|
|
480
|
+
if (hasPercentStyle) {
|
|
481
|
+
transformStyle = percentTransform(combinationStyleProps, { width: containerWidth, height: containerHeight })
|
|
482
|
+
}
|
|
483
|
+
|
|
309
484
|
const { nodeRef } = useNodesRef<View, _ViewProps>(props, ref, {
|
|
310
485
|
defaultStyle
|
|
311
486
|
})
|
|
@@ -325,7 +500,7 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
325
500
|
const setStartTimer = () => {
|
|
326
501
|
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
|
|
327
502
|
dataRef.current.startTimer = setTimeout(() => {
|
|
328
|
-
setIsHover(
|
|
503
|
+
setIsHover(true)
|
|
329
504
|
}, +hoverStartTime)
|
|
330
505
|
}
|
|
331
506
|
|
|
@@ -333,38 +508,95 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
333
508
|
dataRef.current.stayTimer && clearTimeout(dataRef.current.stayTimer)
|
|
334
509
|
dataRef.current.startTimer && clearTimeout(dataRef.current.startTimer)
|
|
335
510
|
dataRef.current.stayTimer = setTimeout(() => {
|
|
336
|
-
setIsHover(
|
|
511
|
+
setIsHover(false)
|
|
337
512
|
}, +hoverStayTime)
|
|
338
513
|
}
|
|
339
514
|
|
|
340
|
-
function onTouchStart(e: NativeSyntheticEvent<TouchEvent>){
|
|
515
|
+
function onTouchStart(e: NativeSyntheticEvent<TouchEvent>) {
|
|
341
516
|
const { bindtouchstart } = props;
|
|
342
517
|
bindtouchstart && bindtouchstart(e)
|
|
343
518
|
setStartTimer()
|
|
344
519
|
}
|
|
345
520
|
|
|
346
|
-
function onTouchEnd(e: NativeSyntheticEvent<TouchEvent>){
|
|
521
|
+
function onTouchEnd(e: NativeSyntheticEvent<TouchEvent>) {
|
|
347
522
|
const { bindtouchend } = props;
|
|
348
523
|
bindtouchend && bindtouchend(e)
|
|
349
524
|
setStayTimer()
|
|
350
525
|
}
|
|
351
526
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
527
|
+
|
|
528
|
+
function percentTransform(style: string[] | Record<string, any>, { width, height }: { width?: number, height?: number }) {
|
|
529
|
+
const styleMap: Record<string, any> = {}
|
|
530
|
+
style.forEach((styleItem: Record<string, any>) => {
|
|
531
|
+
const transformItemValue = styleObj[styleItem.key]
|
|
532
|
+
if (Array.isArray(transformItemValue)) {
|
|
533
|
+
const transformStyle: Record<string, any>[] = []
|
|
534
|
+
styleObj[styleItem.key].forEach((transformItem: Record<string, any>) => {
|
|
535
|
+
const rules = styleItem.rules
|
|
536
|
+
for (const type in rules) {
|
|
537
|
+
const value = transformItem[rules[type]]
|
|
538
|
+
if (value !== undefined) {
|
|
539
|
+
if (PERCENT_REGEX.test(value)) {
|
|
540
|
+
const percentage = parseFloat(value) / 100;
|
|
541
|
+
if (type === 'height' && height) {
|
|
542
|
+
transformStyle.push({ [rules[type]]: percentage * height });
|
|
543
|
+
} else if (type === 'width' && width) {
|
|
544
|
+
transformStyle.push({ [rules[type]]: percentage * width });
|
|
545
|
+
} else {
|
|
546
|
+
transformStyle.push({ [rules[type]]: 0 });
|
|
547
|
+
}
|
|
548
|
+
} else {
|
|
549
|
+
transformStyle.push(transformItem);
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
})
|
|
554
|
+
styleMap[styleItem.key] = transformStyle
|
|
555
|
+
} else if (typeof transformItemValue === 'string') {
|
|
556
|
+
const rules = styleItem.rules
|
|
557
|
+
for (const type in rules) {
|
|
558
|
+
if (transformItemValue) {
|
|
559
|
+
if (PERCENT_REGEX.test(transformItemValue)) {
|
|
560
|
+
const percentage = parseFloat(transformItemValue) / 100;
|
|
561
|
+
if (type === 'height' && height) {
|
|
562
|
+
styleMap[styleItem.key] = percentage * height
|
|
563
|
+
} else if (type === 'width' && width) {
|
|
564
|
+
styleMap[styleItem.key] = percentage * width
|
|
565
|
+
} else {
|
|
566
|
+
styleMap[styleItem.key] = 0
|
|
567
|
+
}
|
|
568
|
+
} else {
|
|
569
|
+
styleMap[styleItem.key] = transformItemValue
|
|
570
|
+
}
|
|
571
|
+
}
|
|
572
|
+
}
|
|
573
|
+
}
|
|
356
574
|
})
|
|
575
|
+
return styleMap
|
|
357
576
|
}
|
|
577
|
+
const onLayout = (res: LayoutChangeEvent) => {
|
|
578
|
+
if (hasPercentStyle) {
|
|
579
|
+
const { width, height } = res?.nativeEvent?.layout || {}
|
|
580
|
+
setContainerWidth(width || 0)
|
|
581
|
+
setContainerHeight(height || 0)
|
|
582
|
+
}
|
|
583
|
+
if (enableOffset) {
|
|
584
|
+
nodeRef.current?.measure((x: number, y: number, width: number, height: number, offsetLeft: number, offsetTop: number) => {
|
|
585
|
+
layoutRef.current = { x, y, width, height, offsetLeft, offsetTop }
|
|
586
|
+
})
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
const { textStyle, imageStyle, innerStyle } = splitStyle({
|
|
590
|
+
...defaultStyle,
|
|
591
|
+
...styleObj,
|
|
592
|
+
...(isHover ? hoverStyle : null)
|
|
593
|
+
})
|
|
358
594
|
|
|
359
|
-
const
|
|
360
|
-
defaultStyle,
|
|
361
|
-
styleObj,
|
|
362
|
-
...(isHover ? hoverStyle : [])]
|
|
363
|
-
))
|
|
595
|
+
const needLayout = enableOffset || hasPercentStyle
|
|
364
596
|
|
|
365
597
|
const innerProps = useInnerProps(props, {
|
|
366
598
|
ref: nodeRef,
|
|
367
|
-
...
|
|
599
|
+
...needLayout ? { onLayout } : {},
|
|
368
600
|
...(hoverStyle && {
|
|
369
601
|
bindtouchstart: onTouchStart,
|
|
370
602
|
bindtouchend: onTouchEnd
|
|
@@ -376,7 +608,8 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
376
608
|
'hover-stay-time',
|
|
377
609
|
'hoverStyle',
|
|
378
610
|
'hover-class',
|
|
379
|
-
'enable-offset'
|
|
611
|
+
'enable-offset',
|
|
612
|
+
'enable-background-image'
|
|
380
613
|
], {
|
|
381
614
|
layoutRef
|
|
382
615
|
})
|
|
@@ -384,9 +617,9 @@ const _View = forwardRef<HandlerRef<View, _ViewProps>, _ViewProps>((props, ref):
|
|
|
384
617
|
return (
|
|
385
618
|
<View
|
|
386
619
|
{...innerProps}
|
|
387
|
-
style={innerStyle}
|
|
620
|
+
style={{ ...innerStyle, ...transformStyle }}
|
|
388
621
|
>
|
|
389
|
-
{wrapChildren(children, textStyle, imageStyle)}
|
|
622
|
+
{wrapChildren(children, props, textStyle, imageStyle)}
|
|
390
623
|
</View>
|
|
391
624
|
)
|
|
392
625
|
})
|