@mpxjs/webpack-plugin 2.10.17 → 2.10.18
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/config.js +60 -0
- package/lib/file-loader.js +4 -1
- package/lib/global.d.ts +231 -0
- package/lib/index.js +58 -73
- package/lib/init.js +3 -0
- package/lib/json-compiler/index.js +13 -4
- package/lib/loader.js +4 -0
- package/lib/platform/json/wx/index.js +6 -0
- package/lib/platform/style/wx/index.js +102 -72
- package/lib/platform/template/wx/component-config/ad.js +5 -0
- package/lib/platform/template/wx/component-config/button.js +10 -3
- package/lib/platform/template/wx/component-config/camera.js +13 -3
- package/lib/platform/template/wx/component-config/canvas.js +8 -1
- package/lib/platform/template/wx/component-config/cover-image.js +7 -2
- package/lib/platform/template/wx/component-config/cover-view.js +3 -1
- package/lib/platform/template/wx/component-config/form.js +27 -2
- package/lib/platform/template/wx/component-config/image.js +5 -0
- package/lib/platform/template/wx/component-config/input.js +10 -0
- package/lib/platform/template/wx/component-config/label.js +10 -2
- package/lib/platform/template/wx/component-config/map.js +11 -0
- package/lib/platform/template/wx/component-config/movable-area.js +4 -1
- package/lib/platform/template/wx/component-config/movable-view.js +17 -2
- package/lib/platform/template/wx/component-config/navigator.js +26 -0
- package/lib/platform/template/wx/component-config/picker-view.js +12 -0
- package/lib/platform/template/wx/component-config/picker.js +3 -1
- package/lib/platform/template/wx/component-config/progress.js +11 -1
- package/lib/platform/template/wx/component-config/rich-text.js +5 -0
- package/lib/platform/template/wx/component-config/scroll-view.js +12 -1
- package/lib/platform/template/wx/component-config/slider.js +8 -0
- package/lib/platform/template/wx/component-config/swiper-item.js +5 -2
- package/lib/platform/template/wx/component-config/swiper.js +10 -0
- package/lib/platform/template/wx/component-config/text.js +5 -0
- package/lib/platform/template/wx/component-config/textarea.js +19 -2
- package/lib/platform/template/wx/component-config/unsupported.js +9 -0
- package/lib/platform/template/wx/component-config/video.js +10 -0
- package/lib/platform/template/wx/index.js +21 -1
- package/lib/react/LoadAsyncChunkModule.js +1 -1
- package/lib/react/processStyles.js +21 -9
- package/lib/react/script-helper.js +2 -2
- package/lib/react/style-helper.js +76 -13
- package/lib/resolver/AddModePlugin.js +17 -7
- package/lib/runtime/components/react/animationHooks/index.ts +75 -0
- package/lib/runtime/components/react/animationHooks/useAnimationAPIHooks.ts +197 -0
- package/lib/runtime/components/react/animationHooks/useTransitionHooks.ts +301 -0
- package/lib/runtime/components/react/animationHooks/utils.ts +197 -0
- package/lib/runtime/components/react/context.ts +12 -3
- package/lib/runtime/components/react/dist/animationHooks/index.d.ts +15 -0
- package/lib/runtime/components/react/dist/animationHooks/index.js +67 -0
- package/lib/runtime/components/react/dist/animationHooks/useAnimationAPIHooks.d.ts +3 -0
- package/lib/runtime/components/react/dist/animationHooks/useAnimationAPIHooks.js +181 -0
- package/lib/runtime/components/react/dist/animationHooks/useTransitionHooks.d.ts +3 -0
- package/lib/runtime/components/react/dist/animationHooks/useTransitionHooks.js +279 -0
- package/lib/runtime/components/react/dist/animationHooks/utils.d.ts +109 -0
- package/lib/runtime/components/react/dist/animationHooks/utils.js +151 -0
- package/lib/runtime/components/react/dist/context.d.ts +10 -3
- package/lib/runtime/components/react/dist/context.js +1 -2
- package/lib/runtime/components/react/dist/event.config.d.ts +0 -1
- package/lib/runtime/components/react/dist/getInnerListeners.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.jsx +3 -1
- package/lib/runtime/components/react/dist/mpx-button.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/Bus.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/Image.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/ImageData.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/html.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/utils.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-checkbox-group.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-checkbox.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-form.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-icon/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-image.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-image.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-inline-text.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-input.d.ts +2 -1
- package/lib/runtime/components/react/dist/mpx-input.jsx +66 -50
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.jsx +35 -6
- package/lib/runtime/components/react/dist/mpx-label.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-movable-area.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-movable-view.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-nav.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-navigator.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/date.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/dateData.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/region.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/regionData.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/selector.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/time.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/type.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewFaces.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewIndicator.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewMask.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-popup/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-popup/popupBase.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-portal/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.jsx +2 -2
- package/lib/runtime/components/react/dist/mpx-progress.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-radio-group.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-radio.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-rich-text/html.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-rich-text/index.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-root-portal.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.jsx +84 -78
- package/lib/runtime/components/react/dist/mpx-simple-text.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-simple-view.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-slider.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-sticky-header.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-sticky-header.jsx +20 -20
- package/lib/runtime/components/react/dist/mpx-sticky-section.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-swiper-item.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-swiper.d.ts +10 -1
- package/lib/runtime/components/react/dist/mpx-swiper.jsx +95 -61
- package/lib/runtime/components/react/dist/mpx-switch.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-text.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-textarea.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-textarea.jsx +1 -0
- package/lib/runtime/components/react/dist/mpx-video.d.ts +0 -1
- package/lib/runtime/components/react/dist/mpx-view.d.ts +3 -3
- package/lib/runtime/components/react/dist/mpx-view.jsx +22 -8
- package/lib/runtime/components/react/dist/mpx-web-view.d.ts +0 -1
- package/lib/runtime/components/react/dist/parser.d.ts +0 -1
- package/lib/runtime/components/react/dist/useNodesRef.d.ts +0 -1
- package/lib/runtime/components/react/dist/utils.d.ts +10 -9
- package/lib/runtime/components/react/dist/utils.jsx +47 -24
- package/lib/runtime/components/react/mpx-async-suspense.tsx +3 -1
- package/lib/runtime/components/react/mpx-image.tsx +2 -2
- package/lib/runtime/components/react/mpx-input.tsx +77 -54
- package/lib/runtime/components/react/mpx-keyboard-avoiding-view.tsx +35 -6
- package/lib/runtime/components/react/mpx-portal/portal-manager.tsx +2 -2
- package/lib/runtime/components/react/mpx-scroll-view.tsx +110 -114
- package/lib/runtime/components/react/mpx-sticky-header.tsx +24 -24
- package/lib/runtime/components/react/mpx-swiper.tsx +115 -60
- package/lib/runtime/components/react/mpx-textarea.tsx +1 -0
- package/lib/runtime/components/react/mpx-view.tsx +27 -12
- package/lib/runtime/components/react/tsconfig.json +26 -0
- package/lib/runtime/components/react/types/global.d.ts +1 -0
- package/lib/runtime/components/react/utils.tsx +51 -27
- package/lib/runtime/optionProcessor.js +5 -0
- package/lib/runtime/optionProcessorReact.js +7 -0
- package/lib/runtime/stringify.wxs +2 -2
- package/lib/script-setup-compiler/index.js +1 -2
- package/lib/style-compiler/strip-conditional.js +243 -0
- package/lib/template-compiler/compiler.js +2 -5
- package/lib/utils/string.js +25 -1
- package/lib/wxss/loader.js +4 -1
- package/lib/wxss/utils.js +7 -2
- package/package.json +7 -14
- package/lib/runtime/components/react/dist/context.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/event.config.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/getInnerListeners.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-async-suspense.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-button.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/Bus.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasGradient.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/CanvasRenderingContext2D.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/Image.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/ImageData.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/constructorsRegistry.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/html.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-canvas/utils.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-checkbox-group.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-checkbox.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-form.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-icon/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-image.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-inline-text.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-input.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-keyboard-avoiding-view.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-label.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-movable-area.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-movable-view.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-nav.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-navigator.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/date.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/dateData.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/multiSelector.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/region.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/regionData.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/selector.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/time.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker/type.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view/pickerVIewContext.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItem.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewColumnItemLite.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewFaces.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewIndicator.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-picker-view-column/pickerViewMask.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-popup/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-popup/popupBase.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-portal/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-host.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-portal/portal-manager.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-progress.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-radio-group.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-radio.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-rich-text/html.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-rich-text/index.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-root-portal.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-scroll-view.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-simple-text.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-simple-view.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-slider.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-sticky-header.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-sticky-section.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-swiper-item.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-swiper.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-switch.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-text.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-textarea.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-video.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-view.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/mpx-web-view.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/parser.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/useAnimationHooks.d.ts +0 -33
- package/lib/runtime/components/react/dist/useAnimationHooks.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/useAnimationHooks.js +0 -289
- package/lib/runtime/components/react/dist/useNodesRef.d.ts.map +0 -1
- package/lib/runtime/components/react/dist/utils.d.ts.map +0 -1
- package/lib/runtime/components/react/useAnimationHooks.ts +0 -320
- package/lib/style-compiler/strip-conditional-loader.js +0 -289
|
@@ -4,7 +4,6 @@ import { isObject, isFunction, isNumber, hasOwn, diffAndCloneA, error, warn } fr
|
|
|
4
4
|
import { VarContext, ScrollViewContext, RouteContext } from './context';
|
|
5
5
|
import { ExpressionParser, parseFunc, ReplaceSource } from './parser';
|
|
6
6
|
import { initialWindowMetrics } from 'react-native-safe-area-context';
|
|
7
|
-
import FastImage from '@d11/react-native-fast-image';
|
|
8
7
|
import { Gesture } from 'react-native-gesture-handler';
|
|
9
8
|
export const TEXT_STYLE_REGEX = /color|font.*|text.*|letterSpacing|lineHeight|includeFontPadding|writingDirection/;
|
|
10
9
|
export const PERCENT_REGEX = /^\s*-?\d+(\.\d+)?%\s*$/;
|
|
@@ -24,6 +23,7 @@ const varUseRegExp = /var\(/;
|
|
|
24
23
|
const unoVarDecRegExp = /^--un-/;
|
|
25
24
|
const unoVarUseRegExp = /var\(--un-/;
|
|
26
25
|
const calcUseRegExp = /calc\(/;
|
|
26
|
+
const calcPercentExp = /^calc\(.*-?\d+(\.\d+)?%.*\)$/;
|
|
27
27
|
const envUseRegExp = /env\(/;
|
|
28
28
|
const filterRegExp = /(calc|env|%)/;
|
|
29
29
|
const safeAreaInsetMap = {
|
|
@@ -32,6 +32,7 @@ const safeAreaInsetMap = {
|
|
|
32
32
|
'safe-area-inset-bottom': 'bottom',
|
|
33
33
|
'safe-area-inset-left': 'left'
|
|
34
34
|
};
|
|
35
|
+
export const extendObject = Object.assign;
|
|
35
36
|
function getSafeAreaInset(name, navigation) {
|
|
36
37
|
const insets = extendObject({}, initialWindowMetrics?.insets, navigation?.insets);
|
|
37
38
|
return insets[safeAreaInsetMap[name]];
|
|
@@ -110,15 +111,17 @@ export function splitStyle(styleObj) {
|
|
|
110
111
|
}
|
|
111
112
|
});
|
|
112
113
|
}
|
|
113
|
-
const
|
|
114
|
-
translateX: 'width',
|
|
115
|
-
translateY: 'height',
|
|
114
|
+
const radiusPercentRule = {
|
|
116
115
|
borderTopLeftRadius: 'width',
|
|
117
116
|
borderBottomLeftRadius: 'width',
|
|
118
117
|
borderBottomRightRadius: 'width',
|
|
119
118
|
borderTopRightRadius: 'width',
|
|
120
119
|
borderRadius: 'width'
|
|
121
120
|
};
|
|
121
|
+
const selfPercentRule = extendObject({
|
|
122
|
+
translateX: 'width',
|
|
123
|
+
translateY: 'height'
|
|
124
|
+
}, radiusPercentRule);
|
|
122
125
|
const parentHeightPercentRule = {
|
|
123
126
|
height: true,
|
|
124
127
|
minHeight: true,
|
|
@@ -170,19 +173,22 @@ function resolveVar(input, varContext) {
|
|
|
170
173
|
const parsed = parseFunc(input, 'var');
|
|
171
174
|
const replaced = new ReplaceSource(input);
|
|
172
175
|
for (const { start, end, args } of parsed) {
|
|
176
|
+
// NOTE:
|
|
177
|
+
// - CSS var() fallback 允许包含空格、逗号等字符(如 font-family 的 fallback)
|
|
178
|
+
// - parseFunc 会按逗号分割 args,因此这里把 args[1..] 重新 join 回 fallback
|
|
173
179
|
const varName = args[0];
|
|
174
|
-
const fallback = args
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
varValue = resolveVar(varValue, varContext);
|
|
180
|
-
if (varValue === undefined)
|
|
181
|
-
return;
|
|
180
|
+
const fallback = args.length > 1 ? args.slice(1).join(',').trim() : undefined;
|
|
181
|
+
// 先处理 varValue
|
|
182
|
+
let varValue = hasOwn(varContext, varName) ? varContext[varName] : undefined;
|
|
183
|
+
if (varValue !== undefined) {
|
|
184
|
+
varValue = varUseRegExp.test(varValue) ? resolveVar(varValue, varContext) : global.__formatValue(varValue);
|
|
182
185
|
}
|
|
183
|
-
|
|
184
|
-
|
|
186
|
+
// 再处理 fallback
|
|
187
|
+
if (varValue === undefined && fallback !== undefined) {
|
|
188
|
+
varValue = varUseRegExp.test(fallback) ? resolveVar(fallback, varContext) : global.__formatValue(fallback);
|
|
185
189
|
}
|
|
190
|
+
if (varValue === undefined)
|
|
191
|
+
return;
|
|
186
192
|
replaced.replace(start, end - 1, varValue);
|
|
187
193
|
}
|
|
188
194
|
return global.__formatValue(replaced.source());
|
|
@@ -241,6 +247,10 @@ function transformStringify(styleObj) {
|
|
|
241
247
|
if (isNumber(styleObj.fontWeight)) {
|
|
242
248
|
styleObj.fontWeight = '' + styleObj.fontWeight;
|
|
243
249
|
}
|
|
250
|
+
// transformOrigin 20px 需要转换为 transformOrigin '20'
|
|
251
|
+
if (isNumber(styleObj.transformOrigin)) {
|
|
252
|
+
styleObj.transformOrigin = '' + styleObj.transformOrigin;
|
|
253
|
+
}
|
|
244
254
|
}
|
|
245
255
|
function transformPosition(styleObj, meta) {
|
|
246
256
|
if (styleObj.position === 'fixed') {
|
|
@@ -249,7 +259,7 @@ function transformPosition(styleObj, meta) {
|
|
|
249
259
|
}
|
|
250
260
|
}
|
|
251
261
|
// 多value解析
|
|
252
|
-
function parseValues(str, char = ' ') {
|
|
262
|
+
export function parseValues(str, char = ' ') {
|
|
253
263
|
let stack = 0;
|
|
254
264
|
let temp = '';
|
|
255
265
|
const result = [];
|
|
@@ -261,11 +271,11 @@ function parseValues(str, char = ' ') {
|
|
|
261
271
|
stack--;
|
|
262
272
|
}
|
|
263
273
|
// 非括号内 或者 非分隔字符且非空
|
|
264
|
-
if (stack !== 0 ||
|
|
274
|
+
if (stack !== 0 || str[i] !== char) {
|
|
265
275
|
temp += str[i];
|
|
266
276
|
}
|
|
267
277
|
if ((stack === 0 && str[i] === char) || i === str.length - 1) {
|
|
268
|
-
result.push(temp);
|
|
278
|
+
result.push(temp.trim());
|
|
269
279
|
temp = '';
|
|
270
280
|
}
|
|
271
281
|
}
|
|
@@ -274,6 +284,8 @@ function parseValues(str, char = ' ') {
|
|
|
274
284
|
// parse string transform, eg: transform: 'rotateX(45deg) rotateZ(0.785398rad)'
|
|
275
285
|
function parseTransform(transformStr) {
|
|
276
286
|
const values = parseValues(transformStr);
|
|
287
|
+
// Todo transform 排序不一致时,transform动画会闪烁,故这里同样的排序输出 transform
|
|
288
|
+
values.sort();
|
|
277
289
|
const transform = [];
|
|
278
290
|
values.forEach(item => {
|
|
279
291
|
const match = item.match(/([/\w]+)\((.+)\)/);
|
|
@@ -337,7 +349,7 @@ function transformBoxShadow(styleObj) {
|
|
|
337
349
|
return `${res}${idx === 0 ? '' : ' '}${global.__formatValue(i)}`;
|
|
338
350
|
}, '');
|
|
339
351
|
}
|
|
340
|
-
export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight }) {
|
|
352
|
+
export function useTransformStyle(styleObj = {}, { enableVar, transformRadiusPercent, externalVarContext, parentFontSize, parentWidth, parentHeight }) {
|
|
341
353
|
const varStyle = {};
|
|
342
354
|
const unoVarStyle = {};
|
|
343
355
|
const normalStyle = {};
|
|
@@ -386,13 +398,20 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
386
398
|
envKeyPaths.push(keyPath.slice());
|
|
387
399
|
}
|
|
388
400
|
}
|
|
389
|
-
function calcVisitor({ value, keyPath }) {
|
|
401
|
+
function calcVisitor({ key, value, keyPath }) {
|
|
390
402
|
if (calcUseRegExp.test(value)) {
|
|
403
|
+
// calc translate & border-radius 的百分比计算
|
|
404
|
+
if (hasOwn(selfPercentRule, key) && calcPercentExp.test(value)) {
|
|
405
|
+
hasSelfPercent = true;
|
|
406
|
+
percentKeyPaths.push(keyPath.slice());
|
|
407
|
+
}
|
|
391
408
|
calcKeyPaths.push(keyPath.slice());
|
|
392
409
|
}
|
|
393
410
|
}
|
|
394
411
|
function percentVisitor({ key, value, keyPath }) {
|
|
395
|
-
|
|
412
|
+
// fixme 去掉 translate & border-radius 的百分比计算
|
|
413
|
+
// fixme Image 组件 borderRadius 仅支持 number
|
|
414
|
+
if (transformRadiusPercent && hasOwn(radiusPercentRule, key) && PERCENT_REGEX.test(value)) {
|
|
396
415
|
hasSelfPercent = true;
|
|
397
416
|
percentKeyPaths.push(keyPath.slice());
|
|
398
417
|
}
|
|
@@ -467,7 +486,7 @@ export function useTransformStyle(styleObj = {}, { enableVar, externalVarContext
|
|
|
467
486
|
transformStringify(normalStyle);
|
|
468
487
|
// transform rpx to px
|
|
469
488
|
transformBoxShadow(normalStyle);
|
|
470
|
-
// transform 字符串格式转化数组格式
|
|
489
|
+
// transform 字符串格式转化数组格式(先转数组再处理css var)
|
|
471
490
|
transformTransform(normalStyle);
|
|
472
491
|
return {
|
|
473
492
|
hasVarDec,
|
|
@@ -612,15 +631,19 @@ export function flatGesture(gestures = []) {
|
|
|
612
631
|
return gesture?.current ? [gesture] : [];
|
|
613
632
|
})) || [];
|
|
614
633
|
}
|
|
615
|
-
export const extendObject = Object.assign;
|
|
616
634
|
export function getCurrentPage(pageId) {
|
|
617
635
|
if (!global.getCurrentPages)
|
|
618
636
|
return;
|
|
619
637
|
const pages = global.getCurrentPages();
|
|
620
638
|
return pages.find((page) => isFunction(page.getPageId) && page.getPageId() === pageId);
|
|
621
639
|
}
|
|
622
|
-
export function renderImage(imageProps, enableFastImage =
|
|
623
|
-
|
|
640
|
+
export function renderImage(imageProps, enableFastImage = true) {
|
|
641
|
+
let Component = Image;
|
|
642
|
+
if (enableFastImage) {
|
|
643
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
644
|
+
const fastImageModule = require('@d11/react-native-fast-image');
|
|
645
|
+
Component = fastImageModule.default || fastImageModule;
|
|
646
|
+
}
|
|
624
647
|
return createElement(Component, imageProps);
|
|
625
648
|
}
|
|
626
649
|
export function pickStyle(styleObj = {}, pickedKeys, callback) {
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useState, ComponentType, useEffect, useCallback, useRef, ReactNode, createElement } from 'react'
|
|
2
2
|
import { View, Image, StyleSheet, Text, TouchableOpacity } from 'react-native'
|
|
3
|
-
import FastImage from '@d11/react-native-fast-image'
|
|
4
3
|
import { AnyFunc } from './types/common'
|
|
5
4
|
|
|
6
5
|
const asyncChunkMap = new Map()
|
|
@@ -82,6 +81,9 @@ const DefaultFallback = ({ onReload }: DefaultFallbackProps) => {
|
|
|
82
81
|
}
|
|
83
82
|
|
|
84
83
|
const DefaultLoading = () => {
|
|
84
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
85
|
+
const FastImageModule = require('@d11/react-native-fast-image')
|
|
86
|
+
const FastImage = FastImageModule.default || FastImageModule
|
|
85
87
|
return (
|
|
86
88
|
<View style={styles.container}>
|
|
87
89
|
<FastImage
|
|
@@ -26,7 +26,7 @@ import { noop } from '@mpxjs/utils'
|
|
|
26
26
|
import { SvgCssUri } from 'react-native-svg/css'
|
|
27
27
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
28
28
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
29
|
-
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject } from './utils'
|
|
29
|
+
import { SVG_REGEXP, useLayout, useTransformStyle, renderImage, extendObject, isAndroid } from './utils'
|
|
30
30
|
import Portal from './mpx-portal'
|
|
31
31
|
|
|
32
32
|
export type Mode =
|
|
@@ -190,7 +190,7 @@ const Image = forwardRef<HandlerRef<RNImage, ImageProps>, ImageProps>((props, re
|
|
|
190
190
|
normalStyle,
|
|
191
191
|
setWidth,
|
|
192
192
|
setHeight
|
|
193
|
-
} = useTransformStyle(styleObj, { enableVar, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
193
|
+
} = useTransformStyle(styleObj, { enableVar, transformRadiusPercent: isAndroid && !isSvg && !isLayoutMode, externalVarContext, parentFontSize, parentWidth, parentHeight })
|
|
194
194
|
|
|
195
195
|
const { layoutRef, layoutStyle, layoutProps } = useLayout({
|
|
196
196
|
props,
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
* ✔ selection-start
|
|
19
19
|
* ✔ selection-end
|
|
20
20
|
* ✔ adjust-position
|
|
21
|
-
*
|
|
21
|
+
* ✔ hold-keyboard
|
|
22
22
|
* ✘ safe-password-cert-path
|
|
23
23
|
* ✘ safe-password-length
|
|
24
24
|
* ✘ safe-password-time-stamp
|
|
@@ -54,7 +54,7 @@ import {
|
|
|
54
54
|
NativeTouchEvent
|
|
55
55
|
} from 'react-native'
|
|
56
56
|
import { warn } from '@mpxjs/utils'
|
|
57
|
-
import { useUpdateEffect, useTransformStyle, useLayout, extendObject,
|
|
57
|
+
import { useUpdateEffect, useTransformStyle, useLayout, extendObject, isAndroid } from './utils'
|
|
58
58
|
import useInnerProps, { getCustomEvent } from './getInnerListeners'
|
|
59
59
|
import useNodesRef, { HandlerRef } from './useNodesRef'
|
|
60
60
|
import { FormContext, FormFieldValue, KeyboardAvoidContext } from './context'
|
|
@@ -95,13 +95,16 @@ export interface InputProps {
|
|
|
95
95
|
'selection-start'?: number
|
|
96
96
|
'selection-end'?: number
|
|
97
97
|
'placeholder-style'?: { color?: string }
|
|
98
|
-
'enable-offset'?: boolean
|
|
98
|
+
'enable-offset'?: boolean
|
|
99
99
|
'enable-var'?: boolean
|
|
100
100
|
'external-var-context'?: Record<string, any>
|
|
101
101
|
'parent-font-size'?: number
|
|
102
102
|
'parent-width'?: number
|
|
103
103
|
'parent-height'?: number
|
|
104
|
-
|
|
104
|
+
// 只有 RN 环境读取
|
|
105
|
+
'keyboard-type'?: string
|
|
106
|
+
'adjust-position': boolean
|
|
107
|
+
'hold-keyboard'?: boolean
|
|
105
108
|
bindinput?: (evt: NativeSyntheticEvent<TextInputTextInputEventData> | unknown) => void
|
|
106
109
|
bindfocus?: (evt: NativeSyntheticEvent<TextInputFocusEventData> | unknown) => void
|
|
107
110
|
bindblur?: (evt: NativeSyntheticEvent<TextInputFocusEventData> | unknown) => void
|
|
@@ -118,11 +121,11 @@ export interface PrivateInputProps {
|
|
|
118
121
|
|
|
119
122
|
type FinalInputProps = InputProps & PrivateInputProps
|
|
120
123
|
|
|
121
|
-
const
|
|
122
|
-
text: '
|
|
124
|
+
const inputModeMap: Record<Type, string> = {
|
|
125
|
+
text: 'text',
|
|
123
126
|
number: 'numeric',
|
|
124
|
-
idcard: '
|
|
125
|
-
digit:
|
|
127
|
+
idcard: 'text',
|
|
128
|
+
digit: 'decimal'
|
|
126
129
|
}
|
|
127
130
|
|
|
128
131
|
const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps>((props: FinalInputProps, ref): JSX.Element => {
|
|
@@ -150,6 +153,8 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
150
153
|
'parent-width': parentWidth,
|
|
151
154
|
'parent-height': parentHeight,
|
|
152
155
|
'adjust-position': adjustPosition = true,
|
|
156
|
+
'keyboard-type': originalKeyboardType,
|
|
157
|
+
'hold-keyboard': holdKeyboard = false,
|
|
153
158
|
bindinput,
|
|
154
159
|
bindfocus,
|
|
155
160
|
bindblur,
|
|
@@ -182,9 +187,11 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
182
187
|
return ''
|
|
183
188
|
}
|
|
184
189
|
|
|
185
|
-
const keyboardType = keyboardTypeMap[type]
|
|
186
190
|
const defaultValue = parseValue(value)
|
|
191
|
+
// 微信小程序的 input 永远是单行,textAlignVertical 固定为 auto
|
|
192
|
+
// multiline 为 true 时表示是 textarea 组件复用此逻辑
|
|
187
193
|
const textAlignVertical = multiline ? 'top' : 'auto'
|
|
194
|
+
const isAutoFocus = !!autoFocus || !!focus
|
|
188
195
|
|
|
189
196
|
const tmpValue = useRef<string>(defaultValue)
|
|
190
197
|
const cursorIndex = useRef<number>(0)
|
|
@@ -193,13 +200,10 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
193
200
|
const [inputValue, setInputValue] = useState(defaultValue)
|
|
194
201
|
const [contentHeight, setContentHeight] = useState(0)
|
|
195
202
|
const [selection, setSelection] = useState({ start: -1, end: tmpValue.current.length })
|
|
196
|
-
|
|
197
203
|
const styleObj = extendObject(
|
|
198
204
|
{ padding: 0, backgroundColor: '#fff' },
|
|
199
205
|
style,
|
|
200
|
-
multiline && autoHeight
|
|
201
|
-
? { height: 'auto', minHeight: Math.max((style as any)?.minHeight || 35, contentHeight) }
|
|
202
|
-
: {}
|
|
206
|
+
multiline && autoHeight ? { height: 'auto' } : {}
|
|
203
207
|
)
|
|
204
208
|
|
|
205
209
|
const {
|
|
@@ -281,12 +285,13 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
281
285
|
|
|
282
286
|
const setKeyboardAvoidContext = () => {
|
|
283
287
|
if (keyboardAvoid) {
|
|
284
|
-
keyboardAvoid.current = { cursorSpacing, ref: nodeRef, adjustPosition }
|
|
288
|
+
keyboardAvoid.current = { cursorSpacing, ref: nodeRef, adjustPosition, holdKeyboard, readyToShow: true }
|
|
285
289
|
}
|
|
286
290
|
}
|
|
287
291
|
|
|
288
292
|
const onTouchStart = () => {
|
|
289
|
-
//
|
|
293
|
+
// 手动聚焦时初始化 keyboardAvoid 上下文
|
|
294
|
+
// auto-focus/focus 不会触发而是在 useEffect 中初始化
|
|
290
295
|
setKeyboardAvoidContext()
|
|
291
296
|
}
|
|
292
297
|
|
|
@@ -295,42 +300,49 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
295
300
|
}
|
|
296
301
|
|
|
297
302
|
const onFocus = (evt: NativeSyntheticEvent<TextInputFocusEventData>) => {
|
|
298
|
-
|
|
303
|
+
if (!keyboardAvoid?.current) {
|
|
304
|
+
// Android:从一个正聚焦状态 input,聚焦到另一个新的 input 时,正常会触发如下时序:
|
|
305
|
+
// 新的 Input `onTouchStart` -> 旧输入框键盘 `keyboardDidHide` -> 新的 Input `onFocus`
|
|
306
|
+
// 导致这里的 keyboardAvoid.current 为 null,所以需要判空重新初始化。
|
|
307
|
+
setKeyboardAvoidContext()
|
|
308
|
+
}
|
|
299
309
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
{
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
height: keyboardAvoid?.current?.keyboardHeight
|
|
310
|
-
},
|
|
311
|
-
layoutRef
|
|
310
|
+
const focusAction = () => {
|
|
311
|
+
bindfocus?.(
|
|
312
|
+
getCustomEvent(
|
|
313
|
+
'focus',
|
|
314
|
+
evt,
|
|
315
|
+
{
|
|
316
|
+
detail: {
|
|
317
|
+
value: tmpValue.current || '',
|
|
318
|
+
height: keyboardAvoid?.current?.keyboardHeight
|
|
312
319
|
},
|
|
313
|
-
|
|
314
|
-
|
|
320
|
+
layoutRef
|
|
321
|
+
},
|
|
322
|
+
props
|
|
315
323
|
)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
324
|
+
)
|
|
325
|
+
if (keyboardAvoid?.current?.onKeyboardShow) {
|
|
326
|
+
keyboardAvoid.current.onKeyboardShow = undefined
|
|
319
327
|
}
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
evt.persist()
|
|
328
|
-
keyboardAvoid.current.onKeyboardShow = focusAction
|
|
329
|
-
}
|
|
330
|
-
} else {
|
|
331
|
-
// 无 keyboardAvoiding,直接执行 focus 回调
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
if (keyboardAvoid?.current) {
|
|
331
|
+
// 有 keyboardAvoiding
|
|
332
|
+
if (keyboardAvoid.current.keyboardHeight) {
|
|
333
|
+
// 仅以下场景触发顺序:先 keyboardWillShow 获取高度 -> 后 onFocus,可以立即执行
|
|
334
|
+
// - iOS + 手动点击聚焦
|
|
332
335
|
focusAction()
|
|
336
|
+
} else {
|
|
337
|
+
// 其他场景触发顺序:先 onFocus -> 后 keyboardWillShow 获取高度 -> 执行回调
|
|
338
|
+
// - iOS + auto-focus/focus=true 自动聚焦
|
|
339
|
+
// - Android 手动点击聚焦/自动聚焦 都一样
|
|
340
|
+
evt.persist()
|
|
341
|
+
keyboardAvoid.current.onKeyboardShow = focusAction
|
|
333
342
|
}
|
|
343
|
+
} else {
|
|
344
|
+
// 兜底:无 keyboardAvoiding 直接执行 focus 回调
|
|
345
|
+
focusAction()
|
|
334
346
|
}
|
|
335
347
|
}
|
|
336
348
|
|
|
@@ -440,19 +452,28 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
440
452
|
}, [])
|
|
441
453
|
|
|
442
454
|
useEffect(() => {
|
|
443
|
-
if (
|
|
455
|
+
if (isAutoFocus) {
|
|
456
|
+
// auto-focus/focus=true 初始化 keyboardAvoidContext
|
|
444
457
|
setKeyboardAvoidContext()
|
|
445
458
|
}
|
|
446
|
-
}, [
|
|
459
|
+
}, [isAutoFocus])
|
|
447
460
|
|
|
448
461
|
useUpdateEffect(() => {
|
|
449
462
|
if (!nodeRef?.current) {
|
|
450
463
|
return
|
|
451
464
|
}
|
|
452
|
-
|
|
465
|
+
// RN autoFocus 属性仅在初次渲染时生效
|
|
466
|
+
// 后续更新需要手动调用 focus/blur 方法,和微信小程序对齐
|
|
467
|
+
isAutoFocus
|
|
453
468
|
? (nodeRef.current as TextInput)?.focus()
|
|
454
469
|
: (nodeRef.current as TextInput)?.blur()
|
|
455
|
-
}, [
|
|
470
|
+
}, [isAutoFocus])
|
|
471
|
+
|
|
472
|
+
// 使用 multiline 来修复光标位置问题
|
|
473
|
+
// React Native 的 TextInput 在 textAlign center + placeholder 时光标会跑到右边
|
|
474
|
+
// 这个问题只在 Android 上出现
|
|
475
|
+
// 参考:https://github.com/facebook/react-native/issues/28794 (Android only)
|
|
476
|
+
const needMultilineFix = isAndroid && !multiline
|
|
456
477
|
|
|
457
478
|
const innerProps = useInnerProps(
|
|
458
479
|
extendObject(
|
|
@@ -463,20 +484,21 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
463
484
|
ref: nodeRef,
|
|
464
485
|
style: extendObject({}, normalStyle, layoutStyle),
|
|
465
486
|
allowFontScaling,
|
|
466
|
-
|
|
487
|
+
inputMode: originalKeyboardType ? undefined : inputModeMap[type],
|
|
488
|
+
keyboardType: originalKeyboardType,
|
|
467
489
|
secureTextEntry: !!password,
|
|
468
490
|
defaultValue: defaultValue,
|
|
469
491
|
value: inputValue,
|
|
470
492
|
maxLength: maxlength === -1 ? undefined : maxlength,
|
|
471
493
|
editable: !disabled,
|
|
472
|
-
autoFocus:
|
|
494
|
+
autoFocus: isAutoFocus,
|
|
473
495
|
selection: selectionStart > -1 || typeof cursor === 'number' ? selection : undefined,
|
|
474
496
|
selectionColor: cursorColor,
|
|
475
|
-
blurOnSubmit:
|
|
497
|
+
blurOnSubmit: multiline ? confirmType !== 'return' : !confirmHold,
|
|
476
498
|
underlineColorAndroid: 'rgba(0,0,0,0)',
|
|
477
499
|
textAlignVertical: textAlignVertical,
|
|
478
500
|
placeholderTextColor: placeholderStyle?.color,
|
|
479
|
-
multiline:
|
|
501
|
+
multiline: multiline || needMultilineFix,
|
|
480
502
|
onTouchStart,
|
|
481
503
|
onTouchEnd,
|
|
482
504
|
onFocus,
|
|
@@ -484,8 +506,9 @@ const Input = forwardRef<HandlerRef<TextInput, FinalInputProps>, FinalInputProps
|
|
|
484
506
|
onChange,
|
|
485
507
|
onSelectionChange,
|
|
486
508
|
onContentSizeChange,
|
|
487
|
-
onSubmitEditing: bindconfirm &&
|
|
509
|
+
onSubmitEditing: bindconfirm && onSubmitEditing
|
|
488
510
|
},
|
|
511
|
+
needMultilineFix ? { numberOfLines: 1 } : {},
|
|
489
512
|
!!multiline && confirmType === 'return' ? {} : { enterKeyHint: confirmType }
|
|
490
513
|
),
|
|
491
514
|
[
|
|
@@ -23,10 +23,13 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
23
23
|
// 比如机型 iPhone 11 Pro,可能会导致显隐动画冲突
|
|
24
24
|
// 因此增加状态标记 + cancelAnimation 来优化
|
|
25
25
|
const isShow = useRef<boolean>(false)
|
|
26
|
+
const keybaordHandleTimerRef = useRef<NodeJS.Timeout | null>(null)
|
|
26
27
|
|
|
27
28
|
const animatedStyle = useAnimatedStyle(() => ({
|
|
28
|
-
// translate/position top
|
|
29
|
-
|
|
29
|
+
// translate/position top+ overflow hidden 在 android 上时因为键盘顶起让页面高度变小,同时元素位置上移
|
|
30
|
+
// 此时最底部的区域是超出了页面高度的,hidden生效就被隐藏掉,因此需要 android 配置聚焦时禁用高度缩小
|
|
31
|
+
// margin-top 因为在 react-native 上和 flex 1 同时存在时,负值只会让容器高度整体变高,不会让元素上移
|
|
32
|
+
transform: [{ translateY: -offset.value }],
|
|
30
33
|
flexBasis: basic.value as DimensionValue
|
|
31
34
|
}))
|
|
32
35
|
|
|
@@ -39,11 +42,20 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
39
42
|
|
|
40
43
|
if (keyboardAvoid?.current) {
|
|
41
44
|
const inputRef = keyboardAvoid.current.ref?.current
|
|
42
|
-
if (inputRef && inputRef.isFocused()) {
|
|
45
|
+
if (inputRef && inputRef.isFocused() && !keyboardAvoid.current.readyToShow) {
|
|
43
46
|
// 修复 Android 点击键盘收起按钮时当前 input 没触发失焦的问题
|
|
47
|
+
// keyboardAvoid.current.readyToShow = true 表示聚焦到了新的输入框,不需要手动触发失焦
|
|
44
48
|
inputRef.blur()
|
|
45
49
|
}
|
|
46
|
-
keyboardAvoid.current
|
|
50
|
+
if (!keyboardAvoid.current.onKeyboardShow) {
|
|
51
|
+
// 修复部分 Android 机型可能时序问题:当从 input 已聚焦状态,聚焦到另一个 input 时,可能时序:
|
|
52
|
+
// - 新的 Input `onTouchStart` -> 新的 Input `onFocus` -> 旧输入框键盘 `keyboardDidHide` -> 新输入框键盘 `keyboardDidShow`
|
|
53
|
+
// - 此时 keyboardAvoid.current 如果清空 null,会导致新输入框键盘 `keyboardDidShow` 回调 keybaordAvoding 执行失败。
|
|
54
|
+
// 修复方案:
|
|
55
|
+
// 如果出现时序问题,那么新的 Input `onFocus` 会更早执行,那么 `keyboardAvoid.current.onKeyboardShow` 存在,
|
|
56
|
+
// 那么不应该重置为 null,反之,说明时正常情况,应当重置为 null。
|
|
57
|
+
keyboardAvoid.current = null
|
|
58
|
+
}
|
|
47
59
|
}
|
|
48
60
|
|
|
49
61
|
cancelAnimation(offset)
|
|
@@ -53,6 +65,9 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
53
65
|
|
|
54
66
|
const onTouchEnd = ({ nativeEvent }: NativeSyntheticEvent<NativeTouchEvent & { origin?: string }>) => {
|
|
55
67
|
if (nativeEvent.origin !== 'input') {
|
|
68
|
+
if (keyboardAvoid?.current?.holdKeyboard) {
|
|
69
|
+
return
|
|
70
|
+
}
|
|
56
71
|
Keyboard.isVisible() && Keyboard.dismiss()
|
|
57
72
|
}
|
|
58
73
|
}
|
|
@@ -61,7 +76,11 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
61
76
|
let subscriptions: EmitterSubscription[] = []
|
|
62
77
|
|
|
63
78
|
function keybaordAvoding(evt: any) {
|
|
64
|
-
if (
|
|
79
|
+
if (keyboardAvoid?.current?.readyToShow) {
|
|
80
|
+
// 重置标记位
|
|
81
|
+
keyboardAvoid.current.readyToShow = false
|
|
82
|
+
}
|
|
83
|
+
if (!keyboardAvoid?.current) {
|
|
65
84
|
return
|
|
66
85
|
}
|
|
67
86
|
|
|
@@ -106,13 +125,23 @@ const KeyboardAvoidingView = ({ children, style, contentContainerStyle }: Keyboa
|
|
|
106
125
|
}
|
|
107
126
|
|
|
108
127
|
if (isIOS) {
|
|
109
|
-
subscriptions = [
|
|
128
|
+
subscriptions = [
|
|
129
|
+
Keyboard.addListener('keyboardWillShow', (evt: any) => {
|
|
130
|
+
if (keybaordHandleTimerRef.current) {
|
|
131
|
+
clearTimeout(keybaordHandleTimerRef.current)
|
|
132
|
+
}
|
|
133
|
+
// iphone 在input聚焦时长按滑动后会导致 show 事件先于 focus 事件发生,因此等一下,等 focus 先触发拿到 input,避免键盘出现但input没顶上去
|
|
134
|
+
keybaordHandleTimerRef.current = setTimeout(() => keybaordAvoding(evt), 32)
|
|
135
|
+
}),
|
|
136
|
+
Keyboard.addListener('keyboardWillHide', resetKeyboard)
|
|
137
|
+
]
|
|
110
138
|
} else {
|
|
111
139
|
subscriptions = [Keyboard.addListener('keyboardDidShow', keybaordAvoding), Keyboard.addListener('keyboardDidHide', resetKeyboard)]
|
|
112
140
|
}
|
|
113
141
|
|
|
114
142
|
return () => {
|
|
115
143
|
subscriptions.forEach(subscription => subscription.remove())
|
|
144
|
+
keybaordHandleTimerRef.current && clearTimeout(keybaordHandleTimerRef.current)
|
|
116
145
|
}
|
|
117
146
|
}, [keyboardAvoid])
|
|
118
147
|
|
|
@@ -19,7 +19,7 @@ const _PortalManager = forwardRef((props: PortalManagerProps, ref:ForwardedRef<u
|
|
|
19
19
|
setState((prevState) => ({
|
|
20
20
|
portals: [...prevState.portals, { key, children }]
|
|
21
21
|
}))
|
|
22
|
-
}, [
|
|
22
|
+
}, [])
|
|
23
23
|
|
|
24
24
|
const update = useCallback((key: number, children: ReactNode) => {
|
|
25
25
|
setState((prevState) => ({
|
|
@@ -30,7 +30,7 @@ const _PortalManager = forwardRef((props: PortalManagerProps, ref:ForwardedRef<u
|
|
|
30
30
|
return item
|
|
31
31
|
})
|
|
32
32
|
}))
|
|
33
|
-
}, [
|
|
33
|
+
}, [])
|
|
34
34
|
|
|
35
35
|
const unmount = useCallback((key: number) => {
|
|
36
36
|
setState((prevState) => ({
|