@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.
Files changed (106) hide show
  1. package/lib/platform/style/wx/index.js +314 -254
  2. package/lib/platform/template/wx/component-config/checkbox-group.js +8 -0
  3. package/lib/platform/template/wx/component-config/checkbox.js +8 -0
  4. package/lib/platform/template/wx/component-config/cover-image.js +15 -0
  5. package/lib/platform/template/wx/component-config/cover-view.js +9 -0
  6. package/lib/platform/template/wx/component-config/form.js +13 -1
  7. package/lib/platform/template/wx/component-config/icon.js +8 -0
  8. package/lib/platform/template/wx/component-config/index.js +5 -1
  9. package/lib/platform/template/wx/component-config/label.js +15 -0
  10. package/lib/platform/template/wx/component-config/movable-area.js +18 -1
  11. package/lib/platform/template/wx/component-config/movable-view.js +18 -1
  12. package/lib/platform/template/wx/component-config/navigator.js +8 -0
  13. package/lib/platform/template/wx/component-config/picker-view-column.js +8 -0
  14. package/lib/platform/template/wx/component-config/picker-view.js +18 -2
  15. package/lib/platform/template/wx/component-config/picker.js +14 -1
  16. package/lib/platform/template/wx/component-config/radio-group.js +8 -0
  17. package/lib/platform/template/wx/component-config/radio.js +8 -0
  18. package/lib/platform/template/wx/component-config/root-portal.js +15 -0
  19. package/lib/platform/template/wx/component-config/switch.js +8 -0
  20. package/lib/platform/template/wx/component-config/unsupported.js +1 -3
  21. package/lib/react/processScript.js +2 -0
  22. package/lib/runtime/components/react/context.ts +38 -0
  23. package/lib/runtime/components/react/dist/context.js +7 -0
  24. package/lib/runtime/components/react/dist/getInnerListeners.js +22 -11
  25. package/lib/runtime/components/react/dist/mpx-button.jsx +67 -45
  26. package/lib/runtime/components/react/dist/mpx-checkbox-group.jsx +81 -0
  27. package/lib/runtime/components/react/dist/mpx-checkbox.jsx +152 -0
  28. package/lib/runtime/components/react/dist/mpx-form.jsx +59 -0
  29. package/lib/runtime/components/react/dist/mpx-icon.jsx +51 -0
  30. package/lib/runtime/components/react/dist/mpx-image/index.jsx +17 -22
  31. package/lib/runtime/components/react/dist/mpx-image/svg.jsx +0 -1
  32. package/lib/runtime/components/react/dist/mpx-input.jsx +38 -16
  33. package/lib/runtime/components/react/dist/mpx-label.jsx +63 -0
  34. package/lib/runtime/components/react/dist/mpx-movable-area.jsx +46 -0
  35. package/lib/runtime/components/react/dist/mpx-movable-view.jsx +346 -0
  36. package/lib/runtime/components/react/dist/mpx-navigator.jsx +35 -0
  37. package/lib/runtime/components/react/dist/mpx-picker/date.jsx +69 -0
  38. package/lib/runtime/components/react/dist/mpx-picker/index.jsx +138 -0
  39. package/lib/runtime/components/react/dist/mpx-picker/multiSelector.jsx +139 -0
  40. package/lib/runtime/components/react/dist/mpx-picker/region.jsx +90 -0
  41. package/lib/runtime/components/react/dist/mpx-picker/regionData.js +6099 -0
  42. package/lib/runtime/components/react/dist/mpx-picker/selector.jsx +76 -0
  43. package/lib/runtime/components/react/dist/mpx-picker/time.jsx +244 -0
  44. package/lib/runtime/components/react/dist/mpx-picker/type.js +1 -0
  45. package/lib/runtime/components/react/dist/mpx-picker-view-column.jsx +15 -0
  46. package/lib/runtime/components/react/dist/mpx-picker-view.jsx +68 -0
  47. package/lib/runtime/components/react/dist/mpx-radio-group.jsx +79 -0
  48. package/lib/runtime/components/react/dist/mpx-radio.jsx +169 -0
  49. package/lib/runtime/components/react/dist/mpx-root-portal.jsx +11 -0
  50. package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +66 -50
  51. package/lib/runtime/components/react/dist/mpx-swiper/carouse.jsx +206 -147
  52. package/lib/runtime/components/react/dist/mpx-swiper/index.jsx +9 -7
  53. package/lib/runtime/components/react/dist/mpx-swiper-item.jsx +3 -3
  54. package/lib/runtime/components/react/dist/mpx-switch.jsx +76 -0
  55. package/lib/runtime/components/react/dist/mpx-text.jsx +7 -19
  56. package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -1
  57. package/lib/runtime/components/react/dist/mpx-view.jsx +326 -96
  58. package/lib/runtime/components/react/dist/mpx-web-view.jsx +9 -15
  59. package/lib/runtime/components/react/dist/types/common.js +1 -0
  60. package/lib/runtime/components/react/dist/useNodesRef.js +3 -8
  61. package/lib/runtime/components/react/dist/utils.js +82 -14
  62. package/lib/runtime/components/react/getInnerListeners.ts +25 -13
  63. package/lib/runtime/components/react/mpx-button.tsx +87 -67
  64. package/lib/runtime/components/react/mpx-checkbox-group.tsx +147 -0
  65. package/lib/runtime/components/react/mpx-checkbox.tsx +245 -0
  66. package/lib/runtime/components/react/mpx-form.tsx +89 -0
  67. package/lib/runtime/components/react/mpx-icon.tsx +103 -0
  68. package/lib/runtime/components/react/mpx-image/index.tsx +20 -32
  69. package/lib/runtime/components/react/mpx-image/svg.tsx +2 -2
  70. package/lib/runtime/components/react/mpx-input.tsx +54 -26
  71. package/lib/runtime/components/react/mpx-label.tsx +115 -0
  72. package/lib/runtime/components/react/mpx-movable-area.tsx +67 -0
  73. package/lib/runtime/components/react/mpx-movable-view.tsx +425 -0
  74. package/lib/runtime/components/react/mpx-navigator.tsx +67 -0
  75. package/lib/runtime/components/react/mpx-picker/date.tsx +83 -0
  76. package/lib/runtime/components/react/mpx-picker/index.tsx +155 -0
  77. package/lib/runtime/components/react/mpx-picker/multiSelector.tsx +153 -0
  78. package/lib/runtime/components/react/mpx-picker/region.tsx +104 -0
  79. package/lib/runtime/components/react/mpx-picker/regionData.ts +6101 -0
  80. package/lib/runtime/components/react/mpx-picker/selector.tsx +92 -0
  81. package/lib/runtime/components/react/mpx-picker/time.tsx +274 -0
  82. package/lib/runtime/components/react/mpx-picker/type.ts +107 -0
  83. package/lib/runtime/components/react/mpx-picker-view-column.tsx +28 -0
  84. package/lib/runtime/components/react/mpx-picker-view.tsx +104 -0
  85. package/lib/runtime/components/react/mpx-radio-group.tsx +147 -0
  86. package/lib/runtime/components/react/mpx-radio.tsx +246 -0
  87. package/lib/runtime/components/react/mpx-root-portal.tsx +25 -0
  88. package/lib/runtime/components/react/mpx-scroll-view.tsx +82 -58
  89. package/lib/runtime/components/react/mpx-swiper/carouse.tsx +203 -156
  90. package/lib/runtime/components/react/mpx-swiper/index.tsx +12 -13
  91. package/lib/runtime/components/react/mpx-swiper/type.ts +11 -4
  92. package/lib/runtime/components/react/mpx-swiper-item.tsx +5 -3
  93. package/lib/runtime/components/react/mpx-switch.tsx +127 -0
  94. package/lib/runtime/components/react/mpx-text.tsx +52 -68
  95. package/lib/runtime/components/react/mpx-textarea.tsx +2 -2
  96. package/lib/runtime/components/react/mpx-view.tsx +373 -140
  97. package/lib/runtime/components/react/mpx-web-view.tsx +24 -28
  98. package/lib/runtime/components/react/types/common.ts +12 -0
  99. package/lib/runtime/components/react/types/getInnerListeners.ts +2 -1
  100. package/lib/runtime/components/react/types/global.d.ts +4 -0
  101. package/lib/runtime/components/react/useNodesRef.ts +3 -8
  102. package/lib/runtime/components/react/utils.ts +93 -15
  103. package/lib/runtime/optionProcessor.js +19 -17
  104. package/lib/template-compiler/compiler.js +56 -41
  105. package/lib/template-compiler/gen-node-react.js +7 -7
  106. package/package.json +6 -3
@@ -0,0 +1,76 @@
1
+ /**
2
+ * 普通选择器,range可以是Array<Obj> 也可以是Array
3
+ */
4
+ import { View, TouchableWithoutFeedback } from 'react-native';
5
+ import React, { forwardRef, useState, useRef, useEffect } from 'react';
6
+ import { Picker } from '@ant-design/react-native';
7
+ import useNodesRef from '../useNodesRef'; // 引入辅助函数
8
+ const formatRangeFun = (range, rangeKey = '') => {
9
+ let newRange = [];
10
+ newRange = (range || []).map((item, index) => {
11
+ if (typeof item === 'object') {
12
+ return { value: index, label: item[rangeKey] };
13
+ }
14
+ else {
15
+ return { value: index, label: item };
16
+ }
17
+ });
18
+ return newRange;
19
+ };
20
+ const _SelectorPicker = forwardRef((props, ref) => {
21
+ const { range, children, value, disabled, bindchange, bindcancel } = props;
22
+ // 格式化数据为Array<*>
23
+ let formatRange = formatRangeFun(range, props['range-key']);
24
+ // 选中的索引值
25
+ const [selected, setSelected] = useState(value || 0);
26
+ // range数据源
27
+ const [data, setData] = useState(formatRange || []);
28
+ // 存储layout布局信息
29
+ const layoutRef = useRef({});
30
+ const { nodeRef: viewRef } = useNodesRef(props, ref, {});
31
+ useEffect(() => {
32
+ if (range) {
33
+ const newFormatRange = formatRangeFun(range, props['range-key']);
34
+ setData(newFormatRange);
35
+ }
36
+ setSelected(() => {
37
+ return value;
38
+ });
39
+ }, [range, value]);
40
+ const defaultValue = [value];
41
+ const onChange = (value) => {
42
+ bindchange && bindchange({
43
+ detail: {
44
+ value: value && value[0]
45
+ }
46
+ });
47
+ };
48
+ const onElementLayout = (layout) => {
49
+ viewRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
50
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
51
+ props.getInnerLayout && props.getInnerLayout(layoutRef);
52
+ });
53
+ };
54
+ const antPickerProps = {
55
+ data,
56
+ value: [selected],
57
+ cols: 1,
58
+ defaultValue,
59
+ itemHeight: 40,
60
+ onChange,
61
+ onDismiss: bindcancel && bindcancel
62
+ };
63
+ const touchProps = {
64
+ onLayout: onElementLayout,
65
+ ref: viewRef
66
+ };
67
+ return (<Picker {...antPickerProps}>
68
+ <TouchableWithoutFeedback>
69
+ <View {...touchProps}>
70
+ {children}
71
+ </View>
72
+ </TouchableWithoutFeedback>
73
+ </Picker>);
74
+ });
75
+ _SelectorPicker.displayName = 'mpx-picker-selector';
76
+ export default _SelectorPicker;
@@ -0,0 +1,244 @@
1
+ import { View, Text, Modal, TouchableWithoutFeedback } from 'react-native';
2
+ import { PickerView } from '@ant-design/react-native';
3
+ import React, { forwardRef, useState, useRef, useEffect } from 'react';
4
+ import useNodesRef from '../useNodesRef'; // 引入辅助函数
5
+ // 可见应用窗口的大小。
6
+ // const { height: dHeight, width: dWidth } = Dimensions.get('window');
7
+ // modal属性: {"height": 298.33331298828125, "offsetLeft": 0, "offsetTop": 513.6666870117188, "width": 375, "x": 0, "y": 513.6666870117188}
8
+ // const { height: sHeight, width: sWidth } = Dimensions.get('screen');
9
+ // 设备屏幕的大小。 screen
10
+ const styles = {
11
+ showModal: {
12
+ backgroundColor: "black",
13
+ opacity: 0.5,
14
+ position: "absolute",
15
+ width: "100%"
16
+ },
17
+ hideModal: {
18
+ opacity: 1,
19
+ height: 0
20
+ },
21
+ modal: {
22
+ backgroundColor: "black",
23
+ opacity: 0.5
24
+ },
25
+ centeredView: {
26
+ position: 'absolute',
27
+ bottom: 0,
28
+ width: "100%",
29
+ overflow: 'scroll'
30
+ },
31
+ btnLine: {
32
+ width: "100%",
33
+ flex: 1,
34
+ flexDirection: "row",
35
+ justifyContent: "space-between",
36
+ borderColor: 20,
37
+ borderBottomWidth: 1,
38
+ backgroundColor: "white",
39
+ paddingLeft: 40,
40
+ paddingRight: 40
41
+ },
42
+ cancel: {
43
+ height: 50,
44
+ display: "flex",
45
+ justifyContent: 'center'
46
+ },
47
+ ok: {
48
+ height: 50,
49
+ display: "flex",
50
+ justifyContent: 'center'
51
+ },
52
+ btntext: {
53
+ color: '#0ae',
54
+ fontSize: 18
55
+ }
56
+ };
57
+ function formatStrToInt(timestr) {
58
+ let [start, end] = timestr.split(':');
59
+ return [parseInt(start), parseInt(end)];
60
+ }
61
+ // [9, 59] to 09:59
62
+ function formatStr(arr) {
63
+ let [hour, minute] = arr;
64
+ if (hour < 10) {
65
+ hour = '0' + hour;
66
+ }
67
+ if (minute < 10) {
68
+ minute = '0' + minute;
69
+ }
70
+ return hour + ':' + minute;
71
+ }
72
+ function generateMinute() {
73
+ let arrMinute = [];
74
+ for (let i = 0; i <= 59; i++) {
75
+ let obj = {
76
+ label: toSingleStr(i),
77
+ value: i,
78
+ children: []
79
+ };
80
+ arrMinute.push(obj);
81
+ }
82
+ return arrMinute;
83
+ }
84
+ function generateColumns() {
85
+ let pickData = [];
86
+ for (let i = 0; i <= 23; i++) {
87
+ let obj = {
88
+ label: toSingleStr(i),
89
+ value: i,
90
+ children: generateMinute()
91
+ };
92
+ pickData.push(obj);
93
+ }
94
+ return pickData;
95
+ }
96
+ function toSingleStr(str) {
97
+ return str < 10 ? '0' + str : str;
98
+ }
99
+ function toStr(time) {
100
+ const [hour, minute] = formatStrToInt(time);
101
+ const newHour = toSingleStr(hour);
102
+ const newMinute = toSingleStr(minute);
103
+ return '' + newHour + newMinute;
104
+ }
105
+ function checkSelectedIsValid(strStart, strEnd, selected) {
106
+ const strSel = '' + toSingleStr(selected[0]) + toSingleStr(selected[1]);
107
+ if (strSel < strStart || strSel > strEnd)
108
+ return false;
109
+ return true;
110
+ }
111
+ /**
112
+ * [{label:'', value: '', key: '', children: []}]
113
+ label: string | ReactNode
114
+ value: string | number
115
+ key?: string | number
116
+ children?: PickerColumnItem[]
117
+ */
118
+ // start="02:10" end = 23:01
119
+ const _TimePicker = forwardRef((props, ref) => {
120
+ const { children, start, end, value, bindchange, bindcancel, disabled } = props;
121
+ const defaultProps = {
122
+ start: '00:10',
123
+ end: '23:59'
124
+ };
125
+ const defaultValue = formatStrToInt(value);
126
+ const [timevalue, setTimeValue] = useState(defaultValue);
127
+ // 存储layout布局信息
128
+ const layoutRef = useRef({});
129
+ const { nodeRef: viewRef } = useNodesRef(props, ref, {});
130
+ // 存储modal的布局信息
131
+ const modalLayoutRef = useRef({});
132
+ const { nodeRef: modalRef } = useNodesRef(props, ref, {});
133
+ const [visible, setVisible] = useState(false);
134
+ const columnData = generateColumns();
135
+ const [data, setData] = useState(columnData);
136
+ const [offsetTop, setOffsetTop] = useState(0);
137
+ const strStart = toStr(start);
138
+ const strEnd = toStr(end);
139
+ useEffect(() => {
140
+ const newColumnData = generateColumns();
141
+ setData(newColumnData);
142
+ }, [start, end]);
143
+ useEffect(() => {
144
+ if (value) {
145
+ const nValue = formatStrToInt(value);
146
+ nValue && setTimeValue(nValue);
147
+ }
148
+ }, [value]);
149
+ // console.log('---------------visible---', visible, JSON.stringify(columnData))
150
+ const handleModalStatus = (status) => {
151
+ setVisible(status);
152
+ };
153
+ const handleConfirm = () => {
154
+ handleModalStatus(false);
155
+ bindchange && bindchange({
156
+ detail: {
157
+ value: formatStr(timevalue)
158
+ }
159
+ });
160
+ };
161
+ const handleCancel = () => {
162
+ handleModalStatus(false);
163
+ bindcancel && bindcancel();
164
+ };
165
+ const handleChildClick = () => {
166
+ handleModalStatus(true);
167
+ };
168
+ const handlePickChange = (date) => {
169
+ // 不是有效的值
170
+ if (!checkSelectedIsValid(strStart, strEnd, date)) {
171
+ setTimeValue(timevalue);
172
+ }
173
+ else {
174
+ // [9, 13]
175
+ setTimeValue(date);
176
+ const strDate = formatStr(date);
177
+ bindchange && bindchange({
178
+ detail: {
179
+ value: strDate
180
+ }
181
+ });
182
+ }
183
+ };
184
+ const onElementLayout = () => {
185
+ viewRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
186
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
187
+ props.getInnerLayout && props.getInnerLayout(layoutRef);
188
+ });
189
+ };
190
+ const onModalLayout = () => {
191
+ modalRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
192
+ modalLayoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
193
+ setOffsetTop(offsetTop);
194
+ });
195
+ };
196
+ const renderModalChildren = () => {
197
+ const pickerProps = {
198
+ data,
199
+ value: timevalue,
200
+ defaultValue: timevalue,
201
+ cols: 2,
202
+ onChange: handlePickChange
203
+ };
204
+ return (<View style={styles.centeredView} ref={modalRef} onLayout={onModalLayout}>
205
+ <View style={styles.btnLine}>
206
+ <View style={styles.cancel}>
207
+ <TouchableWithoutFeedback onPress={handleCancel}>
208
+ <Text style={styles.btntext}>取消</Text>
209
+ </TouchableWithoutFeedback>
210
+ </View>
211
+ <View style={styles.ok}>
212
+ <TouchableWithoutFeedback onPress={handleConfirm}>
213
+ <Text style={styles.btntext}>确定</Text>
214
+ </TouchableWithoutFeedback>
215
+ </View>
216
+ </View>
217
+ <PickerView {...pickerProps}></PickerView>
218
+ </View>);
219
+ };
220
+ const renderChildren = () => {
221
+ const touchProps = {
222
+ onLayout: onElementLayout,
223
+ ref: viewRef
224
+ };
225
+ return <View>
226
+ <TouchableWithoutFeedback onPress={handleChildClick}>
227
+ <View {...touchProps}>{children}</View>
228
+ </TouchableWithoutFeedback>
229
+ </View>;
230
+ };
231
+ const strStyle = visible ? styles['showModal'] : styles['hideModal'];
232
+ const mheight = Math.floor(offsetTop);
233
+ // Animated.View
234
+ return (<>
235
+ <View style={{ ...strStyle, height: visible ? mheight : 0, bottom: 0 }}>
236
+ <Modal animationType="slide" transparent={true} visible={visible}>
237
+ {renderModalChildren()}
238
+ </Modal>
239
+ </View>
240
+ {renderChildren()}
241
+ </>);
242
+ });
243
+ _TimePicker.displayName = 'mpx-picker-time';
244
+ export default _TimePicker;
@@ -0,0 +1,15 @@
1
+ import { View } from 'react-native';
2
+ import React, { forwardRef, useRef } from 'react';
3
+ import useInnerProps from './getInnerListeners';
4
+ import useNodesRef from './useNodesRef'; // 引入辅助函数
5
+ const _PickerViewColumn = forwardRef((props, ref) => {
6
+ const { children } = props;
7
+ const layoutRef = useRef({});
8
+ const { nodeRef } = useNodesRef(props, ref, {});
9
+ const innerProps = useInnerProps(props, {}, [], { layoutRef });
10
+ return (<View ref={nodeRef} {...innerProps}>
11
+ {children}
12
+ </View>);
13
+ });
14
+ _PickerViewColumn.displayName = 'mpx-picker-view-column';
15
+ export default _PickerViewColumn;
@@ -0,0 +1,68 @@
1
+ import React, { forwardRef, useState, useRef, useEffect } from 'react';
2
+ import { PickerView } from '@ant-design/react-native';
3
+ import useInnerProps from './getInnerListeners';
4
+ import { getCustomEvent } from './getInnerListeners';
5
+ import useNodesRef from './useNodesRef'; // 引入辅助函数
6
+ const _PickerView = forwardRef((props, ref) => {
7
+ const { children, ...restProps } = props;
8
+ const layoutRef = useRef({});
9
+ const { nodeRef } = useNodesRef(props, ref, {});
10
+ const [value, setValue] = useState(props.value);
11
+ useEffect(() => {
12
+ // 确认这个是变化的props变化的时候才执行,还是初始化的时候就执行
13
+ setValue(props.value);
14
+ }, [props.value]);
15
+ const onLayout = () => {
16
+ nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
17
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
18
+ });
19
+ };
20
+ const innerProps = useInnerProps(props, {}, [], { layoutRef });
21
+ const onChange = (val) => {
22
+ const eventData = getCustomEvent('change', {}, { detail: { value: val, source: 'touch' }, layoutRef: layoutRef });
23
+ setValue(val);
24
+ props.bindchange && props.bindchange(eventData);
25
+ };
26
+ const joinString = (data) => {
27
+ return (Array.isArray(data) ? data : [data]).join('');
28
+ };
29
+ const getLabelFromChildren = (child) => {
30
+ return child.props && child.props.children ? getLabelFromChildren(child.props.children) : joinString(child);
31
+ };
32
+ const handleChildren = (children) => {
33
+ return children.map((child, index) => {
34
+ return {
35
+ label: getLabelFromChildren(child),
36
+ value: index
37
+ };
38
+ });
39
+ };
40
+ const getDataFromChildren = (children) => {
41
+ return (Array.isArray(children) ? children : [children]).map((child) => {
42
+ return handleChildren(child.props && child.props.children ? child.props.children : [child]);
43
+ });
44
+ };
45
+ const columns = Array.isArray(children) ? children.length : 1;
46
+ const originData = getDataFromChildren(children);
47
+ // 子节点默认的序号,这里是更新默认值的
48
+ const subChildLength = originData.map((item) => {
49
+ return item.length;
50
+ });
51
+ const defaultValue = (props.value || []).map((item, index) => {
52
+ if (item > subChildLength[index]) {
53
+ return subChildLength[index] - 1;
54
+ }
55
+ else {
56
+ return item;
57
+ }
58
+ });
59
+ return (<PickerView {...restProps} cols={columns}
60
+ // 默认选中项
61
+ defaultValue={defaultValue}
62
+ // 内部维护选中项
63
+ value={value}
64
+ // data数据源column
65
+ data={originData} onChange={onChange} cascade={false}/>);
66
+ });
67
+ _PickerView.displayName = 'mpx-picker-view';
68
+ export default _PickerView;
@@ -0,0 +1,79 @@
1
+ /**
2
+ * ✔ bindchange
3
+ */
4
+ import { useRef, forwardRef, useContext } from 'react';
5
+ import { View } from 'react-native';
6
+ import { FormContext, RadioGroupContext } from './context';
7
+ import useInnerProps, { getCustomEvent } from './getInnerListeners';
8
+ import useNodesRef from './useNodesRef';
9
+ import { throwReactWarning } from './utils';
10
+ const radioGroup = forwardRef((props, ref) => {
11
+ const { style = {}, 'enable-offset': enableOffset, children, bindchange, } = props;
12
+ const layoutRef = useRef({});
13
+ const formContext = useContext(FormContext);
14
+ let formValuesMap;
15
+ if (formContext) {
16
+ formValuesMap = formContext.formValuesMap;
17
+ }
18
+ const groupValue = useRef({}).current;
19
+ const defaultStyle = {
20
+ flexDirection: 'row',
21
+ flexWrap: 'wrap',
22
+ ...style
23
+ };
24
+ const { nodeRef } = useNodesRef(props, ref, {
25
+ defaultStyle
26
+ });
27
+ const onLayout = () => {
28
+ nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
29
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
30
+ });
31
+ };
32
+ const getSelectionValue = () => {
33
+ for (let key in groupValue) {
34
+ if (groupValue[key].checked) {
35
+ return key;
36
+ }
37
+ }
38
+ };
39
+ const getValue = () => {
40
+ return getSelectionValue();
41
+ };
42
+ const resetValue = () => {
43
+ Object.keys(groupValue).forEach((key) => {
44
+ groupValue[key].checked = false;
45
+ groupValue[key].setValue(false);
46
+ });
47
+ };
48
+ if (formValuesMap) {
49
+ if (!props.name) {
50
+ throwReactWarning('[Mpx runtime warn]: If a form component is used, the name attribute is required.');
51
+ }
52
+ else {
53
+ formValuesMap.set(props.name, { getValue, resetValue });
54
+ }
55
+ }
56
+ const notifyChange = (evt) => {
57
+ bindchange &&
58
+ bindchange(getCustomEvent('tap', evt, {
59
+ layoutRef,
60
+ detail: {
61
+ value: getSelectionValue()
62
+ }
63
+ }, props));
64
+ };
65
+ const innerProps = useInnerProps(props, {
66
+ ref: nodeRef,
67
+ style: defaultStyle,
68
+ ...(enableOffset ? { onLayout } : {})
69
+ }, ['enable-offset'], {
70
+ layoutRef
71
+ });
72
+ return (<View {...innerProps}>
73
+ <RadioGroupContext.Provider value={{ groupValue, notifyChange }}>
74
+ {children}
75
+ </RadioGroupContext.Provider>
76
+ </View>);
77
+ });
78
+ radioGroup.displayName = 'mpx-radio-group';
79
+ export default radioGroup;
@@ -0,0 +1,169 @@
1
+ /**
2
+ * ✔ value
3
+ * ✔ disabled
4
+ * ✔ checked
5
+ * ✔ color
6
+ */
7
+ import { useRef, useState, forwardRef, useEffect, useContext } from 'react';
8
+ import { View, Text, StyleSheet } from 'react-native';
9
+ import { LabelContext, RadioGroupContext } from './context';
10
+ import useInnerProps, { getCustomEvent } from './getInnerListeners';
11
+ import useNodesRef from './useNodesRef';
12
+ import { every, splitStyle, splitProps, isText, throwReactWarning } from './utils';
13
+ import Icon from './mpx-icon';
14
+ const styles = StyleSheet.create({
15
+ container: {
16
+ flexDirection: 'row',
17
+ alignItems: 'center'
18
+ },
19
+ wrapper: {
20
+ alignItems: 'center',
21
+ justifyContent: 'center',
22
+ width: 24,
23
+ height: 24,
24
+ borderColor: '#D1D1D1',
25
+ borderWidth: 1,
26
+ borderRadius: 12,
27
+ backgroundColor: '#ffffff',
28
+ marginRight: 5,
29
+ overflow: 'hidden'
30
+ },
31
+ wrapperChecked: {
32
+ borderWidth: 0
33
+ },
34
+ wrapperDisabled: {
35
+ backgroundColor: '#E1E1E1'
36
+ },
37
+ icon: {
38
+ opacity: 0
39
+ },
40
+ iconDisabled: {
41
+ backgroundColor: '#ADADAD'
42
+ },
43
+ iconChecked: {
44
+ opacity: 1
45
+ }
46
+ });
47
+ const Radio = forwardRef((props, ref) => {
48
+ const { value = '', disabled = false, checked = false, color = '#09BB07', style = [], 'enable-offset': enableOffset, children, bindtap, catchtap, } = props;
49
+ const layoutRef = useRef({});
50
+ const [isChecked, setIsChecked] = useState(!!checked);
51
+ const groupContext = useContext(RadioGroupContext);
52
+ let groupValue;
53
+ let notifyChange;
54
+ const labelContext = useContext(LabelContext);
55
+ const { textStyle, imageStyle, innerStyle } = splitStyle(style);
56
+ if (imageStyle) {
57
+ throwReactWarning('[Mpx runtime warn]: Radio does not support background image-related styles!');
58
+ }
59
+ const defaultStyle = {
60
+ ...styles.wrapper,
61
+ ...(isChecked && styles.wrapperChecked),
62
+ ...(disabled && styles.wrapperDisabled),
63
+ };
64
+ const viewStyle = {
65
+ ...defaultStyle,
66
+ ...innerStyle
67
+ };
68
+ const onChange = (evt) => {
69
+ if (disabled || isChecked)
70
+ return;
71
+ setIsChecked(!isChecked);
72
+ if (groupValue) {
73
+ for (const [key, radio] of Object.entries(groupValue)) {
74
+ if (!radio)
75
+ continue;
76
+ radio.setValue(key === value);
77
+ radio.checked = key === value;
78
+ }
79
+ }
80
+ notifyChange && notifyChange(evt);
81
+ };
82
+ const onTap = (evt) => {
83
+ if (disabled)
84
+ return;
85
+ bindtap && bindtap(getCustomEvent('tap', evt, { layoutRef }, props));
86
+ onChange(evt);
87
+ };
88
+ const catchTap = (evt) => {
89
+ if (disabled)
90
+ return;
91
+ catchtap && catchtap(getCustomEvent('tap', evt, { layoutRef }, props));
92
+ };
93
+ const { nodeRef } = useNodesRef(props, ref, {
94
+ defaultStyle,
95
+ change: onChange
96
+ });
97
+ const onLayout = () => {
98
+ nodeRef.current?.measure((x, y, width, height, offsetLeft, offsetTop) => {
99
+ layoutRef.current = { x, y, width, height, offsetLeft, offsetTop };
100
+ });
101
+ };
102
+ const wrapChildren = (children, textStyle) => {
103
+ if (!children)
104
+ return children;
105
+ const { textProps } = splitProps(props);
106
+ if (every(children, (child) => isText(child))) {
107
+ if (textStyle || textProps) {
108
+ children = <Text key='radioTextWrap' style={textStyle || {}} {...(textProps || {})}>
109
+ {children}
110
+ </Text>;
111
+ }
112
+ }
113
+ else {
114
+ if (textStyle) {
115
+ throwReactWarning('[Mpx runtime warn]: Text style will be ignored unless every child of the Radio is Text node!');
116
+ }
117
+ }
118
+ return children;
119
+ };
120
+ if (groupContext) {
121
+ groupValue = groupContext.groupValue;
122
+ notifyChange = groupContext.notifyChange;
123
+ }
124
+ if (labelContext) {
125
+ labelContext.current.triggerChange = onChange;
126
+ }
127
+ const innerProps = useInnerProps(props, {
128
+ ref: nodeRef,
129
+ style: styles.container,
130
+ bindtap: onTap,
131
+ catchtap: catchTap,
132
+ ...(enableOffset ? { onLayout } : {})
133
+ }, ['enable-offset'], {
134
+ layoutRef
135
+ });
136
+ useEffect(() => {
137
+ if (groupValue) {
138
+ groupValue[value] = {
139
+ checked: checked,
140
+ setValue: setIsChecked
141
+ };
142
+ }
143
+ return () => {
144
+ if (groupValue) {
145
+ delete groupValue[value];
146
+ }
147
+ };
148
+ }, []);
149
+ useEffect(() => {
150
+ if (checked !== isChecked) {
151
+ setIsChecked(checked);
152
+ if (groupValue) {
153
+ groupValue[value].checked = checked;
154
+ }
155
+ }
156
+ }, [checked]);
157
+ return (<View {...innerProps}>
158
+ <View style={viewStyle}>
159
+ <Icon type='success' size={24} color={disabled ? '#E1E1E1' : color} style={{
160
+ ...styles.icon,
161
+ ...(isChecked && styles.iconChecked),
162
+ ...(disabled && styles.iconDisabled)
163
+ }}/>
164
+ </View>
165
+ {wrapChildren(children, textStyle)}
166
+ </View>);
167
+ });
168
+ Radio.displayName = 'mpx-radio';
169
+ export default Radio;
@@ -0,0 +1,11 @@
1
+ import { Portal } from '@ant-design/react-native';
2
+ const _RootPortal = (props) => {
3
+ const { children, enable = true } = props;
4
+ return enable ? (
5
+ // @ts-ignore
6
+ <Portal>
7
+ {children}
8
+ </Portal>) : (<>{children}</>);
9
+ };
10
+ _RootPortal.displayName = 'mpx-root-portal';
11
+ export default _RootPortal;