@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.
Files changed (115) hide show
  1. package/lib/index.js +1 -3
  2. package/lib/platform/style/wx/index.js +344 -270
  3. package/lib/platform/template/wx/component-config/checkbox-group.js +8 -0
  4. package/lib/platform/template/wx/component-config/checkbox.js +8 -0
  5. package/lib/platform/template/wx/component-config/cover-image.js +15 -0
  6. package/lib/platform/template/wx/component-config/cover-view.js +9 -0
  7. package/lib/platform/template/wx/component-config/form.js +13 -1
  8. package/lib/platform/template/wx/component-config/icon.js +8 -0
  9. package/lib/platform/template/wx/component-config/index.js +5 -1
  10. package/lib/platform/template/wx/component-config/label.js +15 -0
  11. package/lib/platform/template/wx/component-config/movable-area.js +18 -1
  12. package/lib/platform/template/wx/component-config/movable-view.js +18 -1
  13. package/lib/platform/template/wx/component-config/navigator.js +8 -0
  14. package/lib/platform/template/wx/component-config/picker-view-column.js +8 -0
  15. package/lib/platform/template/wx/component-config/picker-view.js +18 -2
  16. package/lib/platform/template/wx/component-config/picker.js +14 -1
  17. package/lib/platform/template/wx/component-config/radio-group.js +8 -0
  18. package/lib/platform/template/wx/component-config/radio.js +8 -0
  19. package/lib/platform/template/wx/component-config/root-portal.js +15 -0
  20. package/lib/platform/template/wx/component-config/switch.js +8 -0
  21. package/lib/platform/template/wx/component-config/unsupported.js +1 -3
  22. package/lib/react/processScript.js +2 -0
  23. package/lib/react/processStyles.js +1 -0
  24. package/lib/react/processTemplate.js +2 -3
  25. package/lib/react/style-helper.js +12 -7
  26. package/lib/runtime/components/react/context.ts +40 -0
  27. package/lib/runtime/components/react/dist/context.js +8 -0
  28. package/lib/runtime/components/react/dist/getInnerListeners.js +34 -12
  29. package/lib/runtime/components/react/dist/mpx-button.jsx +88 -88
  30. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +82 -0
  31. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +139 -0
  32. package/lib/runtime/components/react/dist/mpx-form.jsx +61 -0
  33. package/lib/runtime/components/react/dist/mpx-icon.jsx +48 -0
  34. package/lib/runtime/components/react/dist/mpx-image/index.jsx +39 -43
  35. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +3 -2
  36. package/lib/runtime/components/react/dist/mpx-input.jsx +63 -37
  37. package/lib/runtime/components/react/dist/mpx-label.jsx +55 -0
  38. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +41 -0
  39. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +346 -0
  40. package/lib/runtime/components/react/dist/mpx-navigator.jsx +35 -0
  41. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +69 -0
  42. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +138 -0
  43. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +142 -0
  44. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +94 -0
  45. package/lib/runtime/components/react/dist/mpx-picker/regionData.js +6099 -0
  46. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +76 -0
  47. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +244 -0
  48. package/lib/runtime/components/react/dist/mpx-picker/type.js +1 -0
  49. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +107 -0
  50. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +162 -0
  51. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +80 -0
  52. package/lib/runtime/components/react/dist/mpx-radio.jsx +154 -0
  53. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +15 -0
  54. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +93 -70
  55. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +281 -157
  56. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +21 -11
  57. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +19 -11
  58. package/lib/runtime/components/react/dist/mpx-switch.jsx +79 -0
  59. package/lib/runtime/components/react/dist/mpx-text.jsx +21 -49
  60. package/lib/runtime/components/react/dist/mpx-textarea.jsx +2 -2
  61. package/lib/runtime/components/react/dist/mpx-view.jsx +451 -146
  62. package/lib/runtime/components/react/dist/mpx-web-view.jsx +17 -20
  63. package/lib/runtime/components/react/dist/parser.js +218 -0
  64. package/lib/runtime/components/react/dist/types/common.js +1 -0
  65. package/lib/runtime/components/react/dist/useNodesRef.js +3 -8
  66. package/lib/runtime/components/react/dist/utils.jsx +433 -0
  67. package/lib/runtime/components/react/getInnerListeners.ts +43 -21
  68. package/lib/runtime/components/react/mpx-button.tsx +129 -119
  69. package/lib/runtime/components/react/mpx-checkbox-group.tsx +152 -0
  70. package/lib/runtime/components/react/mpx-checkbox.tsx +234 -0
  71. package/lib/runtime/components/react/mpx-form.tsx +117 -0
  72. package/lib/runtime/components/react/mpx-icon.tsx +106 -0
  73. package/lib/runtime/components/react/mpx-image/index.tsx +62 -68
  74. package/lib/runtime/components/react/mpx-image/svg.tsx +7 -5
  75. package/lib/runtime/components/react/mpx-input.tsx +90 -42
  76. package/lib/runtime/components/react/mpx-label.tsx +110 -0
  77. package/lib/runtime/components/react/mpx-movable-area.tsx +81 -0
  78. package/lib/runtime/components/react/mpx-movable-view.tsx +424 -0
  79. package/lib/runtime/components/react/mpx-navigator.tsx +67 -0
  80. package/lib/runtime/components/react/mpx-picker/date.tsx +82 -0
  81. package/lib/runtime/components/react/mpx-picker/index.tsx +155 -0
  82. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +156 -0
  83. package/lib/runtime/components/react/mpx-picker/region.tsx +107 -0
  84. package/lib/runtime/components/react/mpx-picker/regionData.ts +6101 -0
  85. package/lib/runtime/components/react/mpx-picker/selector.tsx +91 -0
  86. package/lib/runtime/components/react/mpx-picker/time.tsx +270 -0
  87. package/lib/runtime/components/react/mpx-picker/type.ts +107 -0
  88. package/lib/runtime/components/react/mpx-picker-view-column.tsx +156 -0
  89. package/lib/runtime/components/react/mpx-picker-view.tsx +220 -0
  90. package/lib/runtime/components/react/mpx-radio-group.tsx +150 -0
  91. package/lib/runtime/components/react/mpx-radio.tsx +230 -0
  92. package/lib/runtime/components/react/mpx-root-portal.tsx +27 -0
  93. package/lib/runtime/components/react/mpx-scroll-view.tsx +184 -130
  94. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +308 -183
  95. package/lib/runtime/components/react/mpx-swiper/index.tsx +27 -19
  96. package/lib/runtime/components/react/mpx-swiper/type.ts +23 -5
  97. package/lib/runtime/components/react/mpx-swiper-item.tsx +49 -14
  98. package/lib/runtime/components/react/mpx-switch.tsx +148 -0
  99. package/lib/runtime/components/react/mpx-text.tsx +53 -77
  100. package/lib/runtime/components/react/mpx-textarea.tsx +3 -3
  101. package/lib/runtime/components/react/mpx-view.tsx +576 -195
  102. package/lib/runtime/components/react/mpx-web-view.tsx +34 -39
  103. package/lib/runtime/components/react/parser.ts +245 -0
  104. package/lib/runtime/components/react/types/common.ts +12 -0
  105. package/lib/runtime/components/react/types/getInnerListeners.ts +2 -1
  106. package/lib/runtime/components/react/types/global.d.ts +17 -1
  107. package/lib/runtime/components/react/useNodesRef.ts +4 -10
  108. package/lib/runtime/components/react/utils.tsx +505 -0
  109. package/lib/runtime/optionProcessor.js +19 -17
  110. package/lib/template-compiler/compiler.js +84 -61
  111. package/lib/template-compiler/gen-node-react.js +7 -9
  112. package/lib/web/processStyles.js +2 -5
  113. package/package.json +8 -3
  114. package/lib/runtime/components/react/dist/utils.js +0 -80
  115. package/lib/runtime/components/react/utils.ts +0 -92
@@ -0,0 +1,346 @@
1
+ /**
2
+ * ✔ direction
3
+ * ✘ inertia
4
+ * ✘ out-of-bounds
5
+ * ✔ x
6
+ * ✔ y
7
+ * ✘ damping
8
+ * ✔ friction
9
+ * ✔ disabled
10
+ * ✔ scale
11
+ * ✔ scale-min
12
+ * ✔ scale-max
13
+ * ✔ scale-value
14
+ * ✘ animation
15
+ * ✔ bindchange
16
+ * ✔ bindscale
17
+ * ✔ htouchmove
18
+ * ✔ vtouchmove
19
+ */
20
+ import { useRef, useEffect, forwardRef, useContext, useState, useMemo } from 'react';
21
+ import { StyleSheet, Animated, PanResponder } from 'react-native';
22
+ import useInnerProps, { getCustomEvent } from './getInnerListeners';
23
+ import useNodesRef from './useNodesRef';
24
+ import { MovableAreaContext } from './context';
25
+ const styles = StyleSheet.create({
26
+ container: {
27
+ position: 'absolute',
28
+ left: 0,
29
+ top: 0
30
+ }
31
+ });
32
+ const _MovableView = forwardRef((props, ref) => {
33
+ const { children, friction = 7, scale = false, direction = 'none', x = 0, y = 0, style = {}, 'scale-min': scaleMin = 0.1, 'scale-max': scaleMax = 10, 'scale-value': originScaleValue = 1, bindscale, bindchange } = props;
34
+ const pan = useRef(new Animated.ValueXY());
35
+ const scaleValue = useRef(new Animated.Value(1));
36
+ const [transformOrigin, setTransformOrigin] = useState('0% 0%');
37
+ const propsRef = useRef({});
38
+ const layoutRef = useRef({});
39
+ const MovableAreaLayout = useContext(MovableAreaContext);
40
+ const movablePosition = useRef({
41
+ x: Number(x),
42
+ y: Number(y)
43
+ });
44
+ const { nodeRef } = useNodesRef(props, ref, {
45
+ defaultStyle: styles.container
46
+ });
47
+ let panResponder = {};
48
+ const isFirstTouch = useRef(true);
49
+ const touchEvent = useRef('');
50
+ const initialDistance = useRef(0);
51
+ propsRef.current = props;
52
+ useEffect(() => {
53
+ if (scale && (scaleValue.current._value !== originScaleValue)) {
54
+ const clampedScale = Math.min(scaleMax, Math.max(scaleMin, originScaleValue));
55
+ Animated.spring(scaleValue.current, {
56
+ toValue: clampedScale,
57
+ friction,
58
+ useNativeDriver: false
59
+ }).start(() => {
60
+ bindscale && bindscale(getCustomEvent('scale', {}, {
61
+ detail: {
62
+ x: pan.current.x._value,
63
+ y: pan.current.y._value,
64
+ scale: clampedScale
65
+ },
66
+ layoutRef
67
+ }, props));
68
+ });
69
+ }
70
+ }, [originScaleValue]);
71
+ useEffect(() => {
72
+ if (movablePosition.current.x !== Number(x) || movablePosition.current.y !== Number(y)) {
73
+ const { x: newX, y: newY } = checkBoundaryPosition({
74
+ clampedScale: scaleValue.current._value,
75
+ width: layoutRef.current.width,
76
+ height: layoutRef.current.height,
77
+ positionX: Number(x),
78
+ positionY: Number(y)
79
+ });
80
+ movablePosition.current = { x: newX, y: newY };
81
+ Animated.spring(pan.current, {
82
+ toValue: { x: newX, y: newY },
83
+ useNativeDriver: false,
84
+ friction
85
+ }).start(() => {
86
+ bindchange &&
87
+ bindchange(getCustomEvent('change', {}, {
88
+ detail: {
89
+ x: newX,
90
+ y: newY,
91
+ source: ''
92
+ },
93
+ layoutRef
94
+ }, props));
95
+ });
96
+ }
97
+ }, [x, y]);
98
+ const handlePanReleaseOrTerminate = () => {
99
+ pan.current.flattenOffset();
100
+ isFirstTouch.current = true;
101
+ initialDistance.current = 0;
102
+ const { x, y } = checkBoundaryPosition({
103
+ clampedScale: scaleValue.current._value,
104
+ width: layoutRef.current.width,
105
+ height: layoutRef.current.height,
106
+ positionX: pan.current.x._value,
107
+ positionY: pan.current.y._value
108
+ });
109
+ movablePosition.current = {
110
+ x,
111
+ y
112
+ };
113
+ const needChange = x !== pan.current.x._value || y !== pan.current.y._value;
114
+ Animated.spring(pan.current, {
115
+ toValue: { x, y },
116
+ friction: 7,
117
+ useNativeDriver: false
118
+ }).start(() => {
119
+ if (needChange) {
120
+ bindchange && bindchange(getCustomEvent('change', {}, {
121
+ detail: {
122
+ x,
123
+ y,
124
+ source: 'out-of-bounds'
125
+ },
126
+ layoutRef
127
+ }, propsRef.current));
128
+ }
129
+ });
130
+ };
131
+ panResponder = useMemo(() => {
132
+ return PanResponder.create({
133
+ onMoveShouldSetPanResponder: () => !propsRef.current.disabled,
134
+ onMoveShouldSetPanResponderCapture: () => !propsRef.current.disabled,
135
+ onPanResponderGrant: (e, gestureState) => {
136
+ if (gestureState.numberActiveTouches === 1) {
137
+ setTransformOrigin('0% 0%');
138
+ pan.current.setOffset({
139
+ x: direction === 'all' || direction === 'horizontal' ? pan.current.x._value : 0,
140
+ y: direction === 'all' || direction === 'vertical' ? pan.current.y._value : 0
141
+ });
142
+ pan.current.setValue({ x: 0, y: 0 });
143
+ }
144
+ else {
145
+ initialDistance.current = 0;
146
+ setTransformOrigin('50% 50%');
147
+ }
148
+ },
149
+ onPanResponderMove: (e, gestureState) => {
150
+ if (gestureState.numberActiveTouches === 2 && scale) {
151
+ setTransformOrigin('50% 50%');
152
+ const touch1 = e.nativeEvent.touches[0];
153
+ const touch2 = e.nativeEvent.touches[1];
154
+ const currentTouchDistance = Math.sqrt(Math.pow(touch1.pageX - touch2.pageX, 2) + Math.pow(touch1.pageY - touch2.pageY, 2));
155
+ if (!initialDistance.current) {
156
+ initialDistance.current = currentTouchDistance;
157
+ }
158
+ else {
159
+ const newScale = currentTouchDistance / initialDistance.current;
160
+ const clampedScale = Math.min(scaleMax, Math.max(scaleMin, newScale));
161
+ Animated.spring(scaleValue.current, {
162
+ toValue: clampedScale,
163
+ friction: 7,
164
+ useNativeDriver: false
165
+ }).start();
166
+ bindscale && bindscale(getCustomEvent('scale', e, {
167
+ detail: {
168
+ x: pan.current.x._value,
169
+ y: pan.current.y._value,
170
+ scale: clampedScale
171
+ },
172
+ layoutRef
173
+ }, propsRef.current));
174
+ }
175
+ }
176
+ else if (gestureState.numberActiveTouches === 1) {
177
+ if (initialDistance.current) {
178
+ return; // Skip processing if it's switching from a double touch
179
+ }
180
+ setTransformOrigin('0% 0%');
181
+ if (isFirstTouch.current) {
182
+ touchEvent.current = Math.abs(gestureState.dx) > Math.abs(gestureState.dy) ? 'htouchmove' : 'vtouchmove';
183
+ isFirstTouch.current = false;
184
+ }
185
+ Animated.event([
186
+ null,
187
+ {
188
+ dx: direction === 'all' || direction === 'horizontal' ? pan.current.x : new Animated.Value(0),
189
+ dy: direction === 'all' || direction === 'vertical' ? pan.current.y : new Animated.Value(0)
190
+ }
191
+ ], {
192
+ useNativeDriver: false
193
+ })(e, gestureState);
194
+ movablePosition.current = {
195
+ x: pan.current.x.__getValue(),
196
+ y: pan.current.y.__getValue()
197
+ };
198
+ bindchange && bindchange(getCustomEvent('change', e, {
199
+ detail: {
200
+ x: movablePosition.current.x,
201
+ y: movablePosition.current.y,
202
+ source: 'touch'
203
+ },
204
+ layoutRef
205
+ }, propsRef.current));
206
+ }
207
+ },
208
+ onPanResponderRelease: () => {
209
+ handlePanReleaseOrTerminate();
210
+ },
211
+ onPanResponderTerminate: () => {
212
+ handlePanReleaseOrTerminate();
213
+ }
214
+ });
215
+ }, [MovableAreaLayout.width, MovableAreaLayout.height]);
216
+ const onLayout = () => {
217
+ nodeRef.current?.measure((x, y, width, height) => {
218
+ layoutRef.current = { x, y, width, height, offsetLeft: 0, offsetTop: 0 };
219
+ const clampedScale = Math.min(scaleMax, Math.max(scaleMin, originScaleValue));
220
+ const { x: newX, y: nexY } = checkBoundaryPosition({
221
+ clampedScale,
222
+ width,
223
+ height,
224
+ positionX: movablePosition.current.x,
225
+ positionY: movablePosition.current.y
226
+ });
227
+ Animated.spring(pan.current, {
228
+ toValue: { x: newX, y: nexY },
229
+ useNativeDriver: false,
230
+ friction
231
+ }).start(() => {
232
+ movablePosition.current = { x: newX, y: nexY };
233
+ bindchange &&
234
+ bindchange(getCustomEvent('change', {}, {
235
+ detail: {
236
+ x: newX,
237
+ y: nexY,
238
+ source: ''
239
+ },
240
+ layoutRef
241
+ }, props));
242
+ });
243
+ });
244
+ };
245
+ const onTouchMove = (e) => {
246
+ const { bindhtouchmove, bindvtouchmove, bindtouchmove } = props;
247
+ if (touchEvent.current === 'htouchmove') {
248
+ bindhtouchmove && bindhtouchmove(e);
249
+ }
250
+ else if (touchEvent.current === 'vtouchmove') {
251
+ bindvtouchmove && bindvtouchmove(e);
252
+ }
253
+ bindtouchmove && bindtouchmove(e);
254
+ };
255
+ const onCatchTouchMove = (e) => {
256
+ const { catchhtouchmove, catchvtouchmove, catchtouchmove } = props;
257
+ if (touchEvent.current === 'htouchmove') {
258
+ catchhtouchmove && catchhtouchmove(e);
259
+ }
260
+ else if (touchEvent.current === 'vtouchmove') {
261
+ catchvtouchmove && catchvtouchmove(e);
262
+ }
263
+ catchtouchmove && catchtouchmove(e);
264
+ };
265
+ const checkBoundaryPosition = ({ clampedScale, width, height, positionX, positionY }) => {
266
+ // Calculate scaled element size
267
+ const scaledWidth = width * clampedScale;
268
+ const scaledHeight = height * clampedScale;
269
+ // Calculate the boundary limits
270
+ let x = positionX;
271
+ let y = positionY;
272
+ // Correct y coordinate
273
+ if (scaledHeight > MovableAreaLayout.height) {
274
+ if (y >= 0) {
275
+ y = 0;
276
+ }
277
+ else if (y < MovableAreaLayout.height - scaledHeight) {
278
+ y = MovableAreaLayout.height - scaledHeight;
279
+ }
280
+ }
281
+ else {
282
+ if (y < 0) {
283
+ y = 0;
284
+ }
285
+ else if (y > MovableAreaLayout.height - scaledHeight) {
286
+ y = MovableAreaLayout.height - scaledHeight;
287
+ }
288
+ }
289
+ // Correct x coordinate
290
+ if (scaledWidth > MovableAreaLayout.width) {
291
+ if (x >= 0) {
292
+ x = 0;
293
+ }
294
+ else if (x < MovableAreaLayout.width - scaledWidth) {
295
+ x = MovableAreaLayout.width - scaledWidth;
296
+ }
297
+ }
298
+ else {
299
+ if (x < 0) {
300
+ x = 0;
301
+ }
302
+ else if (x > MovableAreaLayout.width - scaledWidth) {
303
+ x = MovableAreaLayout.width - scaledWidth;
304
+ }
305
+ }
306
+ return {
307
+ x,
308
+ y
309
+ };
310
+ };
311
+ const [translateX, translateY] = [pan.current.x, pan.current.y];
312
+ const transformStyle = { transform: [{ translateX }, { translateY }, { scale: scaleValue.current }], transformOrigin: transformOrigin };
313
+ const hasTouchmove = () => !!props.bindhtouchmove || !!props.bindvtouchmove || !!props.bindtouchmove;
314
+ const hasCatchTouchmove = () => !!props.catchhtouchmove || !!props.catchvtouchmove || !!props.catchtouchmove;
315
+ const innerProps = useInnerProps(props, {
316
+ ref: nodeRef,
317
+ ...panResponder.panHandlers,
318
+ onLayout,
319
+ ...(hasTouchmove() ? { bindtouchmove: onTouchMove } : {}),
320
+ ...(hasCatchTouchmove() ? { catchtouchmove: onCatchTouchMove } : {})
321
+ }, [
322
+ 'children',
323
+ 'style',
324
+ 'direction',
325
+ 'x',
326
+ 'y',
327
+ 'scale',
328
+ 'disabled',
329
+ 'scale-value',
330
+ 'scale-min',
331
+ 'scale-max',
332
+ 'bindchange',
333
+ 'bindscale',
334
+ 'htouchmove',
335
+ 'vtouchmove'
336
+ ], { layoutRef });
337
+ return (<Animated.View {...innerProps} style={{
338
+ ...styles.container,
339
+ ...style,
340
+ ...transformStyle
341
+ }}>
342
+ {children}
343
+ </Animated.View>);
344
+ });
345
+ _MovableView.displayName = 'mpx-movable-view';
346
+ export default _MovableView;
@@ -0,0 +1,35 @@
1
+ import { useCallback, forwardRef } from 'react';
2
+ import useInnerProps from './getInnerListeners';
3
+ import { redirectTo, navigateTo, navigateBack, reLaunch, switchTab } from '@mpxjs/api-proxy';
4
+ import MpxView from './mpx-view';
5
+ const _Navigator = forwardRef((props, ref) => {
6
+ const { children, 'open-type': openType, url, delta } = props;
7
+ const handleClick = useCallback(() => {
8
+ switch (openType) {
9
+ case 'navigateBack':
10
+ navigateBack({ delta });
11
+ break;
12
+ case 'redirect':
13
+ redirectTo({ url });
14
+ break;
15
+ case 'switchTab':
16
+ switchTab({ url });
17
+ break;
18
+ case 'reLaunch':
19
+ reLaunch({ url });
20
+ break;
21
+ default:
22
+ navigateTo({ url });
23
+ break;
24
+ }
25
+ }, [openType, url, delta]);
26
+ const innerProps = useInnerProps(props, {
27
+ ref,
28
+ bindtap: handleClick
29
+ });
30
+ return (<MpxView {...innerProps}>
31
+ {children}
32
+ </MpxView>);
33
+ });
34
+ _Navigator.displayName = 'mpx-navigator';
35
+ export default _Navigator;
@@ -0,0 +1,69 @@
1
+ import { View, TouchableWithoutFeedback } from 'react-native';
2
+ import { DatePicker } from '@ant-design/react-native';
3
+ import React, { forwardRef, useState, useRef, useEffect } from 'react';
4
+ import useNodesRef from '../useNodesRef'; // 引入辅助函数
5
+ function formatTimeStr(time = '') {
6
+ let [year, month, day] = time.split('-');
7
+ year = ~~year || 2000;
8
+ month = ~~month || 1;
9
+ day = ~~day || 1;
10
+ return new Date(year, month - 1, day);
11
+ }
12
+ function dateToString(date, fields = 'day') {
13
+ const yyyy = date.getFullYear() + '';
14
+ const MM = ('0' + (date.getMonth() + 1)).slice(-2);
15
+ const dd = ('0' + date.getDate()).slice(-2);
16
+ let ret = yyyy;
17
+ if (fields === 'month' || fields === 'day') {
18
+ ret += `-${MM}`;
19
+ if (fields === 'day') {
20
+ ret += `-${dd}`;
21
+ }
22
+ }
23
+ return ret;
24
+ }
25
+ const _DatePicker = forwardRef((props, ref) => {
26
+ const { children, start = '1970-01-01', end = '2999-01-01', value, bindchange, bindcancel, disabled, fields } = props;
27
+ const [datevalue, setDateValue] = useState(value);
28
+ // 存储layout布局信息
29
+ const layoutRef = useRef({});
30
+ const { nodeRef: viewRef } = useNodesRef(props, ref, {});
31
+ useEffect(() => {
32
+ value && setDateValue(value);
33
+ }, [value]);
34
+ const onChange = (date) => {
35
+ const { fields = 'day' } = props;
36
+ const ret = dateToString(date, fields);
37
+ setDateValue(ret);
38
+ bindchange && bindchange({ detail: { value: ret } });
39
+ };
40
+ const onDismiss = () => {
41
+ bindcancel && bindcancel();
42
+ };
43
+ const onElementLayout = (layout) => {
44
+ viewRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
45
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
46
+ props.getInnerLayout && props.getInnerLayout(layoutRef);
47
+ });
48
+ };
49
+ const dateProps = {
50
+ precision: fields,
51
+ value: formatTimeStr(datevalue),
52
+ minDate: formatTimeStr(start),
53
+ maxDate: formatTimeStr(end),
54
+ onChange,
55
+ onDismiss,
56
+ disabled
57
+ };
58
+ const touchProps = {
59
+ onLayout: onElementLayout,
60
+ ref: viewRef
61
+ };
62
+ return (<DatePicker {...dateProps}>
63
+ <TouchableWithoutFeedback>
64
+ <View {...touchProps}>{children}</View>
65
+ </TouchableWithoutFeedback>
66
+ </DatePicker>);
67
+ });
68
+ _DatePicker.displayName = 'mpx-picker-date';
69
+ export default _DatePicker;
@@ -0,0 +1,138 @@
1
+ import { View } from 'react-native';
2
+ import React, { forwardRef, useRef, useContext, useState } from 'react';
3
+ import { warn } from '@mpxjs/utils';
4
+ import useInnerProps, { getCustomEvent } from '../getInnerListeners';
5
+ import useNodesRef from '../useNodesRef'; // 引入辅助函数
6
+ import Selector from './selector';
7
+ import TimeSelector from './time';
8
+ import DateSelector from './date';
9
+ import MultiSelector from './multiSelector';
10
+ import RegionSelector from './region';
11
+ import { FormContext } from '../context';
12
+ /**
13
+ * ✔ mode
14
+ * ✔ disabled
15
+ * ✔ bindcancel
16
+ * ✔ bindchange
17
+ * ✔ range
18
+ * ✔ range-key
19
+ * ✔ value
20
+ * ✔ start
21
+ * ✔ end
22
+ * ✔ fields 有效值 year,month,day,表示选择器的粒度
23
+ * ✔ end
24
+ * ✔ custom-item
25
+ * ✔ level 选择器层级 province,city,region,<sub-district不支持>
26
+ * ✔ level
27
+ * ✘ header-text
28
+ * ✘ bindcolumnchange
29
+ */
30
+ const _Picker = forwardRef((props, ref) => {
31
+ const { mode = 'selector', value, bindcancel, bindchange, children, bindcolumnchange } = props;
32
+ const innerLayout = useRef({});
33
+ const { nodeRef } = useNodesRef(props, ref, {});
34
+ const innerProps = useInnerProps(props, {
35
+ ref: nodeRef
36
+ }, [], { layoutRef: innerLayout });
37
+ const [pickerValue, setPickerValue] = useState(value);
38
+ const defaultValues = {
39
+ selector: 0,
40
+ multiSelector: [0],
41
+ time: props.start,
42
+ date: props.start,
43
+ region: undefined
44
+ };
45
+ const formContext = useContext(FormContext);
46
+ let formValuesMap;
47
+ // 判断 context 是否存在,存在的话读取 context 中存的 formValuesMap
48
+ if (formContext) {
49
+ formValuesMap = formContext.formValuesMap;
50
+ }
51
+ const resetValue = () => {
52
+ const defalutValue = (defaultValues[mode] !== undefined ? defaultValues[mode] : value);
53
+ setPickerValue(defalutValue);
54
+ };
55
+ const getValue = () => {
56
+ return pickerValue;
57
+ };
58
+ if (formValuesMap) {
59
+ if (!props.name) {
60
+ warn('If a form component is used, the name attribute is required.');
61
+ }
62
+ else {
63
+ formValuesMap.set(props.name, { getValue, resetValue });
64
+ }
65
+ }
66
+ const getInnerLayout = (layout) => {
67
+ innerLayout.current = layout.current;
68
+ };
69
+ const onChange = (event) => {
70
+ const eventData = getCustomEvent('change', {}, { detail: event.detail, layoutRef: innerLayout });
71
+ bindchange && bindchange(eventData);
72
+ setPickerValue(event.detail.value);
73
+ };
74
+ const columnChange = (value, index) => {
75
+ // type: "columnchange", detail: {column: 1, value: 2}
76
+ const eventData = getCustomEvent('columnchange', {}, { detail: { column: index, value }, layoutRef: innerLayout });
77
+ bindcolumnchange && bindcolumnchange(eventData);
78
+ };
79
+ const commonProps = {
80
+ ...{ innerProps },
81
+ mode,
82
+ children,
83
+ bindchange: onChange,
84
+ bindcolumnchange: columnChange,
85
+ bindcancel,
86
+ getInnerLayout
87
+ };
88
+ const selectorProps = {
89
+ ...commonProps,
90
+ value: pickerValue,
91
+ range: props.range,
92
+ 'range-key': props['range-key']
93
+ };
94
+ const multiProps = {
95
+ ...commonProps,
96
+ value: pickerValue,
97
+ range: props.range,
98
+ 'range-key': props['range-key']
99
+ };
100
+ const timeProps = {
101
+ ...commonProps,
102
+ value: pickerValue,
103
+ start: props.start,
104
+ end: props.end
105
+ };
106
+ const dateProps = {
107
+ ...commonProps,
108
+ value: pickerValue,
109
+ start: props.start,
110
+ end: props.end,
111
+ fileds: props.fields || 'day'
112
+ };
113
+ const regionProps = {
114
+ ...commonProps,
115
+ value: pickerValue,
116
+ level: props.level || 'sub-district'
117
+ };
118
+ if (mode === 'selector') {
119
+ return <Selector {...selectorProps}></Selector>;
120
+ }
121
+ else if (mode === 'multiSelector') {
122
+ return <MultiSelector {...multiProps}></MultiSelector>;
123
+ }
124
+ else if (mode === 'time') {
125
+ return <TimeSelector {...timeProps}></TimeSelector>;
126
+ }
127
+ else if (mode === 'date') {
128
+ return <DateSelector {...dateProps}></DateSelector>;
129
+ }
130
+ else if (mode === 'region') {
131
+ return <RegionSelector {...regionProps}></RegionSelector>;
132
+ }
133
+ else {
134
+ return <View>只支持selector, multiSelector, time, date, region 这些类型</View>;
135
+ }
136
+ });
137
+ _Picker.displayName = 'mpx-picker';
138
+ export default _Picker;