antd-mobile 5.41.1 → 5.42.0-alpha.1

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 (58) hide show
  1. package/2x/bundle/antd-mobile.cjs.development.js +80 -59
  2. package/2x/bundle/antd-mobile.cjs.js +6 -6
  3. package/2x/bundle/antd-mobile.es.development.js +80 -59
  4. package/2x/bundle/antd-mobile.es.js +1743 -1729
  5. package/2x/bundle/antd-mobile.umd.development.js +80 -59
  6. package/2x/bundle/antd-mobile.umd.js +6 -6
  7. package/2x/bundle/style.css +9 -2
  8. package/2x/cjs/components/dialog/dialog.d.ts +2 -2
  9. package/2x/cjs/components/dialog/dialog.js +3 -3
  10. package/2x/cjs/components/modal/modal.d.ts +2 -2
  11. package/2x/cjs/components/modal/modal.js +4 -4
  12. package/2x/cjs/components/number-keyboard/number-keyboard.d.ts +6 -1
  13. package/2x/cjs/components/number-keyboard/number-keyboard.js +33 -29
  14. package/2x/cjs/components/virtual-input/use-click-outside.d.ts +2 -0
  15. package/2x/cjs/components/virtual-input/use-click-outside.js +25 -0
  16. package/2x/cjs/components/virtual-input/virtual-input.css +9 -2
  17. package/2x/cjs/components/virtual-input/virtual-input.js +32 -30
  18. package/2x/es/components/dialog/dialog.d.ts +2 -2
  19. package/2x/es/components/dialog/dialog.js +3 -3
  20. package/2x/es/components/modal/modal.d.ts +2 -2
  21. package/2x/es/components/modal/modal.js +4 -4
  22. package/2x/es/components/number-keyboard/number-keyboard.d.ts +6 -1
  23. package/2x/es/components/number-keyboard/number-keyboard.js +33 -29
  24. package/2x/es/components/virtual-input/use-click-outside.d.ts +2 -0
  25. package/2x/es/components/virtual-input/use-click-outside.js +18 -0
  26. package/2x/es/components/virtual-input/virtual-input.css +9 -2
  27. package/2x/es/components/virtual-input/virtual-input.js +32 -30
  28. package/2x/package.json +1 -1
  29. package/bundle/antd-mobile.cjs.development.js +80 -59
  30. package/bundle/antd-mobile.cjs.js +6 -6
  31. package/bundle/antd-mobile.compatible.umd.js +1 -1
  32. package/bundle/antd-mobile.es.development.js +80 -59
  33. package/bundle/antd-mobile.es.js +1743 -1729
  34. package/bundle/antd-mobile.umd.development.js +80 -59
  35. package/bundle/antd-mobile.umd.js +6 -6
  36. package/bundle/style.css +1 -1
  37. package/cjs/components/dialog/dialog.d.ts +2 -2
  38. package/cjs/components/dialog/dialog.js +3 -3
  39. package/cjs/components/modal/modal.d.ts +2 -2
  40. package/cjs/components/modal/modal.js +4 -4
  41. package/cjs/components/number-keyboard/number-keyboard.d.ts +6 -1
  42. package/cjs/components/number-keyboard/number-keyboard.js +33 -29
  43. package/cjs/components/virtual-input/use-click-outside.d.ts +2 -0
  44. package/cjs/components/virtual-input/use-click-outside.js +25 -0
  45. package/cjs/components/virtual-input/virtual-input.css +8 -2
  46. package/cjs/components/virtual-input/virtual-input.js +32 -30
  47. package/es/components/dialog/dialog.d.ts +2 -2
  48. package/es/components/dialog/dialog.js +3 -3
  49. package/es/components/modal/modal.d.ts +2 -2
  50. package/es/components/modal/modal.js +4 -4
  51. package/es/components/number-keyboard/number-keyboard.d.ts +6 -1
  52. package/es/components/number-keyboard/number-keyboard.js +33 -29
  53. package/es/components/virtual-input/use-click-outside.d.ts +2 -0
  54. package/es/components/virtual-input/use-click-outside.js +18 -0
  55. package/es/components/virtual-input/virtual-input.css +8 -2
  56. package/es/components/virtual-input/virtual-input.js +32 -30
  57. package/package.json +1 -1
  58. package/umd/antd-mobile.js +1 -1
@@ -5718,6 +5718,13 @@ a.adm-list-item:active:not(.adm-list-item-disabled):after {
5718
5718
  display: none;
5719
5719
  }
5720
5720
 
5721
+ .adm-virtual-input-trap {
5722
+ width: 20px;
5723
+ height: 20px;
5724
+ position: absolute;
5725
+ opacity: 0;
5726
+ }
5727
+
5721
5728
  .adm-virtual-input-placeholder {
5722
5729
  display: block;
5723
5730
  position: absolute;
@@ -5751,11 +5758,11 @@ a.adm-list-item:active:not(.adm-list-item-disabled):after {
5751
5758
  z-index: 1;
5752
5759
  }
5753
5760
 
5754
- .adm-virtual-input:focus {
5761
+ .adm-virtual-input-focused {
5755
5762
  outline: none;
5756
5763
  }
5757
5764
 
5758
- .adm-virtual-input:focus .adm-virtual-input-caret {
5765
+ .adm-virtual-input-focused .adm-virtual-input-caret {
5759
5766
  animation-name: adm-caret-blink;
5760
5767
  animation-duration: 1s;
5761
5768
  animation-timing-function: linear;
@@ -1,7 +1,7 @@
1
1
  import type { FC, ReactNode } from 'react';
2
- import { Action } from './dialog-action-button';
3
2
  import { NativeProps } from '../../utils/native-props';
4
3
  import { CenterPopupProps } from '../center-popup';
4
+ import { Action } from './dialog-action-button';
5
5
  export declare type DialogProps = Pick<CenterPopupProps, 'afterClose' | 'afterShow' | 'bodyClassName' | 'bodyStyle' | 'destroyOnClose' | 'disableBodyScroll' | 'forceRender' | 'getContainer' | 'maskClassName' | 'maskStyle' | 'stopPropagation' | 'visible'> & {
6
6
  image?: string;
7
7
  header?: ReactNode;
@@ -12,5 +12,5 @@ export declare type DialogProps = Pick<CenterPopupProps, 'afterClose' | 'afterSh
12
12
  onClose?: () => void;
13
13
  closeOnAction?: boolean;
14
14
  closeOnMaskClick?: boolean;
15
- } & NativeProps;
15
+ } & NativeProps<'--background-color' | '--border-radius' | '--max-width' | '--min-width' | '--z-index'>;
16
16
  export declare const Dialog: FC<DialogProps>;
@@ -5,13 +5,13 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.Dialog = void 0;
7
7
  var _tslib = require("tslib");
8
+ var _classnames = _interopRequireDefault(require("classnames"));
8
9
  var _react = _interopRequireDefault(require("react"));
9
10
  var _withDefaultProps = require("../../utils/with-default-props");
10
- var _classnames = _interopRequireDefault(require("classnames"));
11
- var _dialogActionButton = require("./dialog-action-button");
12
- var _image = _interopRequireDefault(require("../image"));
13
11
  var _autoCenter = _interopRequireDefault(require("../auto-center"));
14
12
  var _centerPopup = _interopRequireDefault(require("../center-popup"));
13
+ var _image = _interopRequireDefault(require("../image"));
14
+ var _dialogActionButton = require("./dialog-action-button");
15
15
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
16
16
  const defaultProps = {
17
17
  actions: [],
@@ -1,7 +1,7 @@
1
1
  import type { FC, ReactNode } from 'react';
2
- import { Action } from './modal-action-button';
3
2
  import { NativeProps } from '../../utils/native-props';
4
3
  import { CenterPopupProps } from '../center-popup';
4
+ import { Action } from './modal-action-button';
5
5
  export declare type ModalProps = Pick<CenterPopupProps, 'afterClose' | 'afterShow' | 'bodyClassName' | 'bodyStyle' | 'destroyOnClose' | 'disableBodyScroll' | 'forceRender' | 'getContainer' | 'maskClassName' | 'maskStyle' | 'stopPropagation' | 'visible'> & {
6
6
  image?: string;
7
7
  header?: ReactNode;
@@ -13,5 +13,5 @@ export declare type ModalProps = Pick<CenterPopupProps, 'afterClose' | 'afterSho
13
13
  closeOnAction?: boolean;
14
14
  closeOnMaskClick?: boolean;
15
15
  showCloseButton?: boolean;
16
- } & NativeProps;
16
+ } & NativeProps<'--background-color' | '--border-radius' | '--max-width' | '--min-width' | '--z-index'>;
17
17
  export declare const Modal: FC<ModalProps>;
@@ -5,14 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.Modal = void 0;
7
7
  var _tslib = require("tslib");
8
+ var _classnames = _interopRequireDefault(require("classnames"));
8
9
  var _react = _interopRequireDefault(require("react"));
9
10
  var _withDefaultProps = require("../../utils/with-default-props");
10
- var _classnames = _interopRequireDefault(require("classnames"));
11
- var _modalActionButton = require("./modal-action-button");
12
- var _image = _interopRequireDefault(require("../image"));
13
- var _space = _interopRequireDefault(require("../space"));
14
11
  var _autoCenter = _interopRequireDefault(require("../auto-center"));
15
12
  var _centerPopup = _interopRequireDefault(require("../center-popup"));
13
+ var _image = _interopRequireDefault(require("../image"));
14
+ var _space = _interopRequireDefault(require("../space"));
15
+ var _modalActionButton = require("./modal-action-button");
16
16
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
17
17
  const defaultProps = {
18
18
  actions: [],
@@ -1,11 +1,15 @@
1
1
  import type { FC } from 'react';
2
2
  import { NativeProps } from '../../utils/native-props';
3
3
  import { PopupProps } from '../popup';
4
+ declare type CustomKeyType = string | {
5
+ key: string;
6
+ title: string;
7
+ };
4
8
  export declare type NumberKeyboardProps = {
5
9
  visible?: boolean;
6
10
  title?: string;
7
11
  confirmText?: string | null;
8
- customKey?: string | [string, string];
12
+ customKey?: CustomKeyType | CustomKeyType[];
9
13
  randomOrder?: boolean;
10
14
  showCloseButton?: boolean;
11
15
  onInput?: (v: string) => void;
@@ -16,3 +20,4 @@ export declare type NumberKeyboardProps = {
16
20
  safeArea?: boolean;
17
21
  } & Pick<PopupProps, 'afterClose' | 'afterShow' | 'getContainer' | 'destroyOnClose' | 'forceRender' | 'stopPropagation'> & NativeProps<'--adm-safe-area-multiple'>;
18
22
  export declare const NumberKeyboard: FC<NumberKeyboardProps>;
23
+ export {};
@@ -78,7 +78,6 @@ const NumberKeyboard = p => {
78
78
  };
79
79
  const onKeyPress = (e, key) => {
80
80
  var _a, _b;
81
- e.preventDefault();
82
81
  switch (key) {
83
82
  case 'BACKSPACE':
84
83
  onDelete === null || onDelete === void 0 ? void 0 : onDelete();
@@ -115,39 +114,51 @@ const NumberKeyboard = p => {
115
114
  tabIndex: -1
116
115
  }, _react.default.createElement(_antdMobileIcons.DownOutline, null)));
117
116
  };
117
+ const onBackspaceTouchStart = () => {
118
+ stopContinueClear();
119
+ startContinueClear();
120
+ };
121
+ const onBackspaceTouchEnd = e => {
122
+ e.preventDefault(); // 短按时,touchend 会阻止后续 click 事件触发,防止删除两次
123
+ stopContinueClear();
124
+ onKeyPress(e, 'BACKSPACE');
125
+ };
118
126
  const renderKey = (key, index) => {
119
- const isNumberKey = /^\d$/.test(key);
120
- const isBackspace = key === 'BACKSPACE';
127
+ const keyConfig = typeof key === 'string' ? {
128
+ key,
129
+ title: key
130
+ } : key;
131
+ const realKey = keyConfig.key;
132
+ const isNumberKey = /^\d$/.test(realKey);
133
+ const isBackspace = realKey === 'BACKSPACE';
134
+ const title = isBackspace ? locale.Input.clear : keyConfig.title;
121
135
  const className = (0, _classnames.default)(`${classPrefix}-key`, {
122
136
  [`${classPrefix}-key-number`]: isNumberKey,
123
- [`${classPrefix}-key-sign`]: !isNumberKey && key,
137
+ [`${classPrefix}-key-sign`]: !isNumberKey && realKey,
124
138
  [`${classPrefix}-key-mid`]: index === 9 && !!confirmText && keys.length < 12
125
139
  });
126
- const ariaProps = key ? {
140
+ const ariaProps = realKey ? {
127
141
  role: 'button',
128
- title: isBackspace ? locale.Input.clear : key,
142
+ title,
143
+ 'aria-label': title,
129
144
  tabIndex: -1
130
145
  } : undefined;
131
146
  return _react.default.createElement("div", Object.assign({
132
- key: key,
147
+ key: realKey,
133
148
  className: className,
134
149
  // 仅为 backspace 绑定,支持长按快速删除
135
- onTouchStart: isBackspace ? () => {
136
- stopContinueClear();
137
- startContinueClear();
138
- } : undefined,
139
- onTouchEnd: isBackspace ? e => {
140
- stopContinueClear();
141
- onKeyPress(e, key);
142
- } : undefined,
150
+ onTouchStart: isBackspace ? onBackspaceTouchStart : undefined,
151
+ onTouchEnd: isBackspace ? onBackspaceTouchEnd : undefined,
152
+ onTouchCancel: isBackspace ? stopContinueClear : undefined,
143
153
  // <div role="button" title="1" onTouchEnd={e => {}}>1</div> 安卓上 talback 可读不可点
144
154
  // see https://ua-gilded-eef7f9.netlify.app/grid-button-bug.html
145
- // 所以还是绑定 click,通过 touchEnd preventDefault 防重复触发
155
+ // 所以普通按钮绑定 click 事件,而 backspace 仍然额外绑定 touch 事件支持长按删除
156
+ // backspace touchend 时会 preventDefault 阻止其后续 click 事件
146
157
  onClick: e => {
147
158
  stopContinueClear();
148
- onKeyPress(e, key);
159
+ onKeyPress(e, realKey);
149
160
  }
150
- }, ariaProps), isBackspace ? _react.default.createElement(_antdMobileIcons.TextDeletionOutline, null) : key);
161
+ }, ariaProps), isBackspace ? _react.default.createElement(_antdMobileIcons.TextDeletionOutline, null) : realKey);
151
162
  };
152
163
  return _react.default.createElement(_popup.default, {
153
164
  visible: visible,
@@ -161,10 +172,7 @@ const NumberKeyboard = p => {
161
172
  forceRender: props.forceRender
162
173
  }, (0, _nativeProps.withNativeProps)(props, _react.default.createElement("div", {
163
174
  ref: keyboardRef,
164
- className: classPrefix,
165
- onMouseDown: e => {
166
- e.preventDefault();
167
- }
175
+ className: classPrefix
168
176
  }, renderHeader(), _react.default.createElement("div", {
169
177
  className: `${classPrefix}-wrapper`
170
178
  }, _react.default.createElement("div", {
@@ -175,13 +183,9 @@ const NumberKeyboard = p => {
175
183
  className: `${classPrefix}-confirm`
176
184
  }, _react.default.createElement("div", {
177
185
  className: `${classPrefix}-key ${classPrefix}-key-extra ${classPrefix}-key-bs`,
178
- onTouchStart: () => {
179
- startContinueClear();
180
- },
181
- onTouchEnd: e => {
182
- stopContinueClear();
183
- onKeyPress(e, 'BACKSPACE');
184
- },
186
+ onTouchStart: onBackspaceTouchStart,
187
+ onTouchEnd: onBackspaceTouchEnd,
188
+ onTouchCancel: stopContinueClear,
185
189
  onClick: e => {
186
190
  stopContinueClear();
187
191
  onKeyPress(e, 'BACKSPACE');
@@ -0,0 +1,2 @@
1
+ declare function useClickOutside(handler: (event: MouseEvent) => void, ref: React.RefObject<HTMLElement>): void;
2
+ export default useClickOutside;
@@ -0,0 +1,25 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _react = require("react");
8
+ // 监听点击组件外部的事件
9
+ function useClickOutside(handler, ref) {
10
+ (0, _react.useEffect)(() => {
11
+ function handleClick(event) {
12
+ if (!ref.current || ref.current.contains(event.target)) {
13
+ return;
14
+ }
15
+ handler(event);
16
+ }
17
+ // 在捕获阶段监听,以确保在事件被阻止传播之前触发
18
+ document.addEventListener('click', handleClick, true);
19
+ return () => {
20
+ document.removeEventListener('click', handleClick, true);
21
+ };
22
+ }, [handler, ref]);
23
+ }
24
+ var _default = useClickOutside;
25
+ exports.default = _default;
@@ -40,6 +40,13 @@
40
40
  display: none;
41
41
  }
42
42
 
43
+ .adm-virtual-input-trap {
44
+ width: 20px;
45
+ height: 20px;
46
+ position: absolute;
47
+ opacity: 0;
48
+ }
49
+
43
50
  .adm-virtual-input-placeholder {
44
51
  display: block;
45
52
  position: absolute;
@@ -73,11 +80,11 @@
73
80
  z-index: 1;
74
81
  }
75
82
 
76
- .adm-virtual-input:focus {
83
+ .adm-virtual-input-focused {
77
84
  outline: none;
78
85
  }
79
86
 
80
- .adm-virtual-input:focus .adm-virtual-input-caret {
87
+ .adm-virtual-input-focused .adm-virtual-input-caret {
81
88
  animation-name: adm-caret-blink;
82
89
  animation-duration: 1s;
83
90
  animation-timing-function: linear;
@@ -12,6 +12,7 @@ var _nativeProps = require("../../utils/native-props");
12
12
  var _usePropsValue = require("../../utils/use-props-value");
13
13
  var _withDefaultProps = require("../../utils/with-default-props");
14
14
  var _configProvider = require("../config-provider");
15
+ var _useClickOutside = _interopRequireDefault(require("./use-click-outside"));
15
16
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
16
17
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
17
18
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
@@ -42,13 +43,10 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
42
43
  const touchMoveTimeoutRef = (0, _react.useRef)();
43
44
  const clearIcon = (0, _withDefaultProps.mergeProp)(_react.default.createElement(_antdMobileIcons.CloseCircleFill, null), componentConfig.clearIcon, props.clearIcon);
44
45
  function scrollToEnd() {
45
- const root = rootRef.current;
46
- if (!root) return;
47
- if (document.activeElement !== root) {
46
+ const content = contentRef.current;
47
+ if (!content) {
48
48
  return;
49
49
  }
50
- const content = contentRef.current;
51
- if (!content) return;
52
50
  content.scrollLeft = content.clientWidth;
53
51
  }
54
52
  (0, _react.useEffect)(() => {
@@ -80,23 +78,29 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
80
78
  (0, _react.useImperativeHandle)(ref, () => ({
81
79
  focus: () => {
82
80
  var _a;
83
- (_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.focus();
81
+ (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.focus();
84
82
  },
85
83
  blur: () => {
86
84
  var _a;
87
- (_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.blur();
85
+ (_a = contentRef.current) === null || _a === void 0 ? void 0 : _a.blur();
86
+ setBlur();
88
87
  }
89
88
  }));
90
- function onFocus() {
89
+ function setFocus() {
91
90
  var _a;
91
+ if (hasFocus) return;
92
92
  setHasFocus(true);
93
93
  (_a = mergedProps.onFocus) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
94
94
  }
95
- function onBlur() {
95
+ function setBlur() {
96
96
  var _a;
97
+ if (!hasFocus) return;
97
98
  setHasFocus(false);
98
99
  (_a = mergedProps.onBlur) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
99
100
  }
101
+ (0, _useClickOutside.default)(() => {
102
+ setBlur();
103
+ }, rootRef);
100
104
  const keyboard = mergedProps.keyboard;
101
105
  const keyboardElement = keyboard && _react.default.cloneElement(keyboard, {
102
106
  onInput: v => {
@@ -124,26 +128,20 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
124
128
  },
125
129
  visible: hasFocus,
126
130
  onClose: () => {
127
- var _a, _b, _c, _d;
128
- const activeElement = document.activeElement;
129
- // Long press makes `activeElement` to be the child of rootRef
130
- // We will trigger blur on the child element instead
131
- if (activeElement && ((_a = rootRef.current) === null || _a === void 0 ? void 0 : _a.contains(activeElement))) {
132
- activeElement.blur();
133
- } else {
134
- (_b = rootRef.current) === null || _b === void 0 ? void 0 : _b.blur();
135
- }
136
- (_d = (_c = keyboard.props).onClose) === null || _d === void 0 ? void 0 : _d.call(_c);
131
+ var _a, _b;
132
+ setBlur();
133
+ (_b = (_a = keyboard.props).onClose) === null || _b === void 0 ? void 0 : _b.call(_a);
137
134
  },
138
135
  getContainer: null
139
136
  });
140
137
  // 点击输入框时,将光标置于最后
141
- const setCaretPositionToEnd = () => {
142
- var _a, _b;
138
+ const setCaretPositionToEnd = e => {
139
+ var _a, _b, _c;
143
140
  if (caretPosition !== value.length) {
144
141
  setCaretPosition(value.length);
145
142
  (_b = (_a = mergedProps.cursor) === null || _a === void 0 ? void 0 : _a.onMove) === null || _b === void 0 ? void 0 : _b.call(_a, value.length);
146
143
  }
144
+ (_c = mergedProps.onClick) === null || _c === void 0 ? void 0 : _c.call(mergedProps, e);
147
145
  };
148
146
  // 点击单个字符时,根据点击位置置于字符前或后
149
147
  const changeCaretPosition = index => e => {
@@ -212,23 +210,27 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
212
210
  ref: rootRef,
213
211
  className: (0, _classnames.default)(classPrefix, {
214
212
  [`${classPrefix}-disabled`]: mergedProps.disabled,
215
- [`${classPrefix}-caret-dragging`]: isCaretDragging
216
- }),
217
- tabIndex: mergedProps.disabled ? undefined : 0,
218
- role: 'textbox',
219
- onFocus: onFocus,
220
- onBlur: onBlur,
221
- onClick: mergedProps.onClick
213
+ [`${classPrefix}-caret-dragging`]: isCaretDragging,
214
+ [`${classPrefix}-focused`]: hasFocus
215
+ })
222
216
  }, _react.default.createElement("div", {
223
217
  className: `${classPrefix}-content`,
224
218
  ref: contentRef,
225
219
  "aria-disabled": mergedProps.disabled,
226
- "aria-label": mergedProps.placeholder,
220
+ "aria-label": value || mergedProps.placeholder,
221
+ role: 'textbox',
222
+ tabIndex: mergedProps.disabled ? undefined : 0,
223
+ // note: 这里增加 onFocus 有两个目的:
224
+ // 1. 在安卓 talkback 模式下,role=textbox 的元素双击后只会触发 focus 而非 click
225
+ // 2. 处理 content 框点击、单个字符点击时,不用再额外处理 focus 逻辑,因为 focus 事件会先触发
226
+ onFocus: setFocus,
227
227
  onClick: setCaretPositionToEnd,
228
228
  onTouchStart: handleTouchStart,
229
229
  onTouchMove: handleTouchMove,
230
230
  onTouchEnd: handleTouchEnd
231
- }, chars.slice(0, caretPosition).map((i, index) => _react.default.createElement("span", {
231
+ }, _react.default.createElement("span", {
232
+ className: `${classPrefix}-trap`
233
+ }), chars.slice(0, caretPosition).map((i, index) => _react.default.createElement("span", {
232
234
  ref: index === 0 ? charRef : undefined,
233
235
  key: index,
234
236
  onClick: changeCaretPosition(index)
@@ -1,7 +1,7 @@
1
1
  import type { FC, ReactNode } from 'react';
2
- import { Action } from './dialog-action-button';
3
2
  import { NativeProps } from '../../utils/native-props';
4
3
  import { CenterPopupProps } from '../center-popup';
4
+ import { Action } from './dialog-action-button';
5
5
  export declare type DialogProps = Pick<CenterPopupProps, 'afterClose' | 'afterShow' | 'bodyClassName' | 'bodyStyle' | 'destroyOnClose' | 'disableBodyScroll' | 'forceRender' | 'getContainer' | 'maskClassName' | 'maskStyle' | 'stopPropagation' | 'visible'> & {
6
6
  image?: string;
7
7
  header?: ReactNode;
@@ -12,5 +12,5 @@ export declare type DialogProps = Pick<CenterPopupProps, 'afterClose' | 'afterSh
12
12
  onClose?: () => void;
13
13
  closeOnAction?: boolean;
14
14
  closeOnMaskClick?: boolean;
15
- } & NativeProps;
15
+ } & NativeProps<'--background-color' | '--border-radius' | '--max-width' | '--min-width' | '--z-index'>;
16
16
  export declare const Dialog: FC<DialogProps>;
@@ -1,11 +1,11 @@
1
1
  import { __awaiter } from "tslib";
2
+ import classNames from 'classnames';
2
3
  import React from 'react';
3
4
  import { mergeProps } from '../../utils/with-default-props';
4
- import classNames from 'classnames';
5
- import { DialogActionButton } from './dialog-action-button';
6
- import Image from '../image';
7
5
  import AutoCenter from '../auto-center';
8
6
  import CenterPopup from '../center-popup';
7
+ import Image from '../image';
8
+ import { DialogActionButton } from './dialog-action-button';
9
9
  const defaultProps = {
10
10
  actions: [],
11
11
  closeOnAction: false,
@@ -1,7 +1,7 @@
1
1
  import type { FC, ReactNode } from 'react';
2
- import { Action } from './modal-action-button';
3
2
  import { NativeProps } from '../../utils/native-props';
4
3
  import { CenterPopupProps } from '../center-popup';
4
+ import { Action } from './modal-action-button';
5
5
  export declare type ModalProps = Pick<CenterPopupProps, 'afterClose' | 'afterShow' | 'bodyClassName' | 'bodyStyle' | 'destroyOnClose' | 'disableBodyScroll' | 'forceRender' | 'getContainer' | 'maskClassName' | 'maskStyle' | 'stopPropagation' | 'visible'> & {
6
6
  image?: string;
7
7
  header?: ReactNode;
@@ -13,5 +13,5 @@ export declare type ModalProps = Pick<CenterPopupProps, 'afterClose' | 'afterSho
13
13
  closeOnAction?: boolean;
14
14
  closeOnMaskClick?: boolean;
15
15
  showCloseButton?: boolean;
16
- } & NativeProps;
16
+ } & NativeProps<'--background-color' | '--border-radius' | '--max-width' | '--min-width' | '--z-index'>;
17
17
  export declare const Modal: FC<ModalProps>;
@@ -1,12 +1,12 @@
1
1
  import { __awaiter } from "tslib";
2
+ import classNames from 'classnames';
2
3
  import React from 'react';
3
4
  import { mergeProps } from '../../utils/with-default-props';
4
- import classNames from 'classnames';
5
- import { ModalActionButton } from './modal-action-button';
6
- import Image from '../image';
7
- import Space from '../space';
8
5
  import AutoCenter from '../auto-center';
9
6
  import CenterPopup from '../center-popup';
7
+ import Image from '../image';
8
+ import Space from '../space';
9
+ import { ModalActionButton } from './modal-action-button';
10
10
  const defaultProps = {
11
11
  actions: [],
12
12
  closeOnAction: false,
@@ -1,11 +1,15 @@
1
1
  import type { FC } from 'react';
2
2
  import { NativeProps } from '../../utils/native-props';
3
3
  import { PopupProps } from '../popup';
4
+ declare type CustomKeyType = string | {
5
+ key: string;
6
+ title: string;
7
+ };
4
8
  export declare type NumberKeyboardProps = {
5
9
  visible?: boolean;
6
10
  title?: string;
7
11
  confirmText?: string | null;
8
- customKey?: string | [string, string];
12
+ customKey?: CustomKeyType | CustomKeyType[];
9
13
  randomOrder?: boolean;
10
14
  showCloseButton?: boolean;
11
15
  onInput?: (v: string) => void;
@@ -16,3 +20,4 @@ export declare type NumberKeyboardProps = {
16
20
  safeArea?: boolean;
17
21
  } & Pick<PopupProps, 'afterClose' | 'afterShow' | 'getContainer' | 'destroyOnClose' | 'forceRender' | 'stopPropagation'> & NativeProps<'--adm-safe-area-multiple'>;
18
22
  export declare const NumberKeyboard: FC<NumberKeyboardProps>;
23
+ export {};
@@ -69,7 +69,6 @@ export const NumberKeyboard = p => {
69
69
  };
70
70
  const onKeyPress = (e, key) => {
71
71
  var _a, _b;
72
- e.preventDefault();
73
72
  switch (key) {
74
73
  case 'BACKSPACE':
75
74
  onDelete === null || onDelete === void 0 ? void 0 : onDelete();
@@ -106,39 +105,51 @@ export const NumberKeyboard = p => {
106
105
  tabIndex: -1
107
106
  }, React.createElement(DownOutline, null)));
108
107
  };
108
+ const onBackspaceTouchStart = () => {
109
+ stopContinueClear();
110
+ startContinueClear();
111
+ };
112
+ const onBackspaceTouchEnd = e => {
113
+ e.preventDefault(); // 短按时,touchend 会阻止后续 click 事件触发,防止删除两次
114
+ stopContinueClear();
115
+ onKeyPress(e, 'BACKSPACE');
116
+ };
109
117
  const renderKey = (key, index) => {
110
- const isNumberKey = /^\d$/.test(key);
111
- const isBackspace = key === 'BACKSPACE';
118
+ const keyConfig = typeof key === 'string' ? {
119
+ key,
120
+ title: key
121
+ } : key;
122
+ const realKey = keyConfig.key;
123
+ const isNumberKey = /^\d$/.test(realKey);
124
+ const isBackspace = realKey === 'BACKSPACE';
125
+ const title = isBackspace ? locale.Input.clear : keyConfig.title;
112
126
  const className = classNames(`${classPrefix}-key`, {
113
127
  [`${classPrefix}-key-number`]: isNumberKey,
114
- [`${classPrefix}-key-sign`]: !isNumberKey && key,
128
+ [`${classPrefix}-key-sign`]: !isNumberKey && realKey,
115
129
  [`${classPrefix}-key-mid`]: index === 9 && !!confirmText && keys.length < 12
116
130
  });
117
- const ariaProps = key ? {
131
+ const ariaProps = realKey ? {
118
132
  role: 'button',
119
- title: isBackspace ? locale.Input.clear : key,
133
+ title,
134
+ 'aria-label': title,
120
135
  tabIndex: -1
121
136
  } : undefined;
122
137
  return React.createElement("div", Object.assign({
123
- key: key,
138
+ key: realKey,
124
139
  className: className,
125
140
  // 仅为 backspace 绑定,支持长按快速删除
126
- onTouchStart: isBackspace ? () => {
127
- stopContinueClear();
128
- startContinueClear();
129
- } : undefined,
130
- onTouchEnd: isBackspace ? e => {
131
- stopContinueClear();
132
- onKeyPress(e, key);
133
- } : undefined,
141
+ onTouchStart: isBackspace ? onBackspaceTouchStart : undefined,
142
+ onTouchEnd: isBackspace ? onBackspaceTouchEnd : undefined,
143
+ onTouchCancel: isBackspace ? stopContinueClear : undefined,
134
144
  // <div role="button" title="1" onTouchEnd={e => {}}>1</div> 安卓上 talback 可读不可点
135
145
  // see https://ua-gilded-eef7f9.netlify.app/grid-button-bug.html
136
- // 所以还是绑定 click,通过 touchEnd preventDefault 防重复触发
146
+ // 所以普通按钮绑定 click 事件,而 backspace 仍然额外绑定 touch 事件支持长按删除
147
+ // backspace touchend 时会 preventDefault 阻止其后续 click 事件
137
148
  onClick: e => {
138
149
  stopContinueClear();
139
- onKeyPress(e, key);
150
+ onKeyPress(e, realKey);
140
151
  }
141
- }, ariaProps), isBackspace ? React.createElement(TextDeletionOutline, null) : key);
152
+ }, ariaProps), isBackspace ? React.createElement(TextDeletionOutline, null) : realKey);
142
153
  };
143
154
  return React.createElement(Popup, {
144
155
  visible: visible,
@@ -152,10 +163,7 @@ export const NumberKeyboard = p => {
152
163
  forceRender: props.forceRender
153
164
  }, withNativeProps(props, React.createElement("div", {
154
165
  ref: keyboardRef,
155
- className: classPrefix,
156
- onMouseDown: e => {
157
- e.preventDefault();
158
- }
166
+ className: classPrefix
159
167
  }, renderHeader(), React.createElement("div", {
160
168
  className: `${classPrefix}-wrapper`
161
169
  }, React.createElement("div", {
@@ -166,13 +174,9 @@ export const NumberKeyboard = p => {
166
174
  className: `${classPrefix}-confirm`
167
175
  }, React.createElement("div", {
168
176
  className: `${classPrefix}-key ${classPrefix}-key-extra ${classPrefix}-key-bs`,
169
- onTouchStart: () => {
170
- startContinueClear();
171
- },
172
- onTouchEnd: e => {
173
- stopContinueClear();
174
- onKeyPress(e, 'BACKSPACE');
175
- },
177
+ onTouchStart: onBackspaceTouchStart,
178
+ onTouchEnd: onBackspaceTouchEnd,
179
+ onTouchCancel: stopContinueClear,
176
180
  onClick: e => {
177
181
  stopContinueClear();
178
182
  onKeyPress(e, 'BACKSPACE');
@@ -0,0 +1,2 @@
1
+ declare function useClickOutside(handler: (event: MouseEvent) => void, ref: React.RefObject<HTMLElement>): void;
2
+ export default useClickOutside;
@@ -0,0 +1,18 @@
1
+ import { useEffect } from 'react';
2
+ // 监听点击组件外部的事件
3
+ function useClickOutside(handler, ref) {
4
+ useEffect(() => {
5
+ function handleClick(event) {
6
+ if (!ref.current || ref.current.contains(event.target)) {
7
+ return;
8
+ }
9
+ handler(event);
10
+ }
11
+ // 在捕获阶段监听,以确保在事件被阻止传播之前触发
12
+ document.addEventListener('click', handleClick, true);
13
+ return () => {
14
+ document.removeEventListener('click', handleClick, true);
15
+ };
16
+ }, [handler, ref]);
17
+ }
18
+ export default useClickOutside;