antd-mobile 5.40.0 → 5.41.0-alpha.0

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 +150 -16
  2. package/2x/bundle/antd-mobile.cjs.js +6 -6
  3. package/2x/bundle/antd-mobile.es.development.js +150 -16
  4. package/2x/bundle/antd-mobile.es.js +3983 -3914
  5. package/2x/bundle/antd-mobile.umd.development.js +150 -16
  6. package/2x/bundle/antd-mobile.umd.js +7 -7
  7. package/2x/bundle/style.css +4 -1
  8. package/2x/cjs/components/date-picker/date-picker-week-utils.js +2 -1
  9. package/2x/cjs/components/ellipsis/ellipsis.d.ts +3 -0
  10. package/2x/cjs/components/ellipsis/ellipsis.js +10 -2
  11. package/2x/cjs/components/swiper/swiper.js +1 -1
  12. package/2x/cjs/components/tabs/tabs.js +45 -13
  13. package/2x/cjs/components/virtual-input/virtual-input.css +4 -1
  14. package/2x/cjs/components/virtual-input/virtual-input.d.ts +6 -0
  15. package/2x/cjs/components/virtual-input/virtual-input.js +105 -8
  16. package/2x/es/components/date-picker/date-picker-week-utils.js +2 -1
  17. package/2x/es/components/ellipsis/ellipsis.d.ts +3 -0
  18. package/2x/es/components/ellipsis/ellipsis.js +10 -2
  19. package/2x/es/components/swiper/swiper.js +1 -1
  20. package/2x/es/components/tabs/tabs.js +44 -12
  21. package/2x/es/components/virtual-input/virtual-input.css +4 -1
  22. package/2x/es/components/virtual-input/virtual-input.d.ts +6 -0
  23. package/2x/es/components/virtual-input/virtual-input.js +105 -8
  24. package/2x/package.json +3 -3
  25. package/bundle/antd-mobile.cjs.development.js +150 -16
  26. package/bundle/antd-mobile.cjs.js +6 -6
  27. package/bundle/antd-mobile.compatible.umd.js +1 -1
  28. package/bundle/antd-mobile.es.development.js +150 -16
  29. package/bundle/antd-mobile.es.js +3983 -3914
  30. package/bundle/antd-mobile.umd.development.js +150 -16
  31. package/bundle/antd-mobile.umd.js +7 -7
  32. package/bundle/style.css +1 -1
  33. package/cjs/components/date-picker/date-picker-week-utils.js +2 -1
  34. package/cjs/components/ellipsis/ellipsis.d.ts +3 -0
  35. package/cjs/components/ellipsis/ellipsis.js +10 -2
  36. package/cjs/components/swiper/swiper.js +1 -1
  37. package/cjs/components/tabs/tabs.js +45 -13
  38. package/cjs/components/virtual-input/virtual-input.css +3 -1
  39. package/cjs/components/virtual-input/virtual-input.d.ts +6 -0
  40. package/cjs/components/virtual-input/virtual-input.js +105 -8
  41. package/es/components/date-picker/date-picker-week-utils.js +2 -1
  42. package/es/components/ellipsis/ellipsis.d.ts +3 -0
  43. package/es/components/ellipsis/ellipsis.js +10 -2
  44. package/es/components/swiper/swiper.js +1 -1
  45. package/es/components/tabs/tabs.js +44 -12
  46. package/es/components/virtual-input/virtual-input.css +3 -1
  47. package/es/components/virtual-input/virtual-input.d.ts +6 -0
  48. package/es/components/virtual-input/virtual-input.js +105 -8
  49. package/package.json +3 -3
  50. package/umd/antd-mobile.js +1 -1
  51. package/2x/cjs/components/ellipsis/~ellipsis.d.ts +0 -15
  52. package/2x/cjs/components/ellipsis/~ellipsis.js +0 -161
  53. package/2x/es/components/ellipsis/~ellipsis.d.ts +0 -15
  54. package/2x/es/components/ellipsis/~ellipsis.js +0 -151
  55. package/cjs/components/ellipsis/~ellipsis.d.ts +0 -15
  56. package/cjs/components/ellipsis/~ellipsis.js +0 -161
  57. package/es/components/ellipsis/~ellipsis.d.ts +0 -15
  58. package/es/components/ellipsis/~ellipsis.js +0 -151
@@ -5751,7 +5751,6 @@ a.adm-list-item:active:not(.adm-list-item-disabled):after {
5751
5751
  }
5752
5752
 
5753
5753
  .adm-virtual-input:focus .adm-virtual-input-caret {
5754
- display: block;
5755
5754
  animation-name: adm-caret-blink;
5756
5755
  animation-duration: 1s;
5757
5756
  animation-timing-function: linear;
@@ -5762,6 +5761,10 @@ a.adm-list-item:active:not(.adm-list-item-disabled):after {
5762
5761
  color: var(--disabled-color);
5763
5762
  }
5764
5763
 
5764
+ .adm-virtual-input-caret-dragging .adm-virtual-input-caret {
5765
+ animation: none!important;
5766
+ }
5767
+
5765
5768
  @keyframes adm-caret-blink {
5766
5769
  0% {
5767
5770
  opacity: 1;
@@ -100,6 +100,7 @@ function convertStringArrayToDate(value) {
100
100
  const yearString = (_a = value[0]) !== null && _a !== void 0 ? _a : '1900';
101
101
  const weekString = (_b = value[1]) !== null && _b !== void 0 ? _b : '1';
102
102
  const weekdayString = (_c = value[2]) !== null && _c !== void 0 ? _c : '1';
103
- const day = (0, _dayjs.default)(`${parseInt(yearString)}-01-01`).isoWeek(parseInt(weekString)).isoWeekday(parseInt(weekdayString)).hour(0).minute(0).second(0);
103
+ // See https://github.com/ant-design/ant-design-mobile/issues/6905
104
+ const day = (0, _dayjs.default)(`${parseInt(yearString)}-01-04`).isoWeek(parseInt(weekString)).isoWeekday(parseInt(weekdayString)).hour(0).minute(0).second(0);
104
105
  return day.toDate();
105
106
  }
@@ -11,5 +11,8 @@ export declare type EllipsisProps = {
11
11
  stopPropagationForActionButtons?: PropagationEvent[];
12
12
  onContentClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
13
13
  defaultExpanded?: boolean;
14
+ onExpand?: (expanded: boolean, info: {
15
+ event: React.MouseEvent<HTMLAnchorElement, MouseEvent>;
16
+ }) => void;
14
17
  } & NativeProps;
15
18
  export declare const Ellipsis: FC<EllipsisProps>;
@@ -39,13 +39,21 @@ const Ellipsis = p => {
39
39
  // ========================== Expanded ==========================
40
40
  const [expanded, setExpanded] = _react.default.useState(defaultExpanded);
41
41
  const expandNode = expandText ? (0, _withStopPropagation.withStopPropagation)(stopPropagationForActionButtons, _react.default.createElement("a", {
42
- onClick: () => {
42
+ onClick: e => {
43
+ var _a;
43
44
  setExpanded(true);
45
+ (_a = props.onExpand) === null || _a === void 0 ? void 0 : _a.call(props, true, {
46
+ event: e
47
+ });
44
48
  }
45
49
  }, expandText)) : null;
46
50
  const collapseNode = collapseText ? (0, _withStopPropagation.withStopPropagation)(stopPropagationForActionButtons, _react.default.createElement("a", {
47
- onClick: () => {
51
+ onClick: e => {
52
+ var _a;
48
53
  setExpanded(false);
54
+ (_a = props.onExpand) === null || _a === void 0 ? void 0 : _a.call(props, false, {
55
+ event: e
56
+ });
49
57
  }
50
58
  }, collapseText)) : null;
51
59
  // ========================== Ellipsis ==========================
@@ -279,7 +279,7 @@ const Swiper = (0, _react.forwardRef)((0, _stagedComponents.staged)((p, ref) =>
279
279
  return _react.default.createElement(_react.default.Fragment, null, _react.default.createElement("div", {
280
280
  className: `${classPrefix}-slide-placeholder`,
281
281
  style: {
282
- width: `${startIndex * 100}%`
282
+ [isVertical ? 'height' : 'width']: `${startIndex * 100}%`
283
283
  }
284
284
  }), items);
285
285
  }
@@ -4,22 +4,22 @@ Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
6
  exports.Tabs = exports.Tab = void 0;
7
- var _react = _interopRequireWildcard(require("react"));
8
- var _classnames = _interopRequireDefault(require("classnames"));
9
7
  var _web = require("@react-spring/web");
10
- var _nativeProps = require("../../utils/native-props");
11
- var _usePropsValue = require("../../utils/use-props-value");
12
- var _bound = require("../../utils/bound");
13
8
  var _ahooks = require("ahooks");
9
+ var _classnames = _interopRequireDefault(require("classnames"));
10
+ var _react = _interopRequireWildcard(require("react"));
11
+ var _bound = require("../../utils/bound");
12
+ var _nativeProps = require("../../utils/native-props");
13
+ var _shouldRender = require("../../utils/should-render");
14
+ var _traverseReactNode = require("../../utils/traverse-react-node");
15
+ var _useIsomorphicUpdateLayoutEffect = require("../../utils/use-isomorphic-update-layout-effect");
14
16
  var _useMutationEffect = require("../../utils/use-mutation-effect");
17
+ var _usePropsValue = require("../../utils/use-props-value");
15
18
  var _useResizeEffect = require("../../utils/use-resize-effect");
16
19
  var _withDefaultProps = require("../../utils/with-default-props");
17
- var _useIsomorphicUpdateLayoutEffect = require("../../utils/use-isomorphic-update-layout-effect");
18
- var _shouldRender = require("../../utils/should-render");
19
- var _traverseReactNode = require("../../utils/traverse-react-node");
20
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
21
20
  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); }
22
21
  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; }
22
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
23
23
  const classPrefix = `adm-tabs`;
24
24
  const Tab = () => {
25
25
  return null;
@@ -35,6 +35,7 @@ const Tabs = p => {
35
35
  const props = (0, _withDefaultProps.mergeProps)(defaultProps, p);
36
36
  const tabListContainerRef = (0, _react.useRef)(null);
37
37
  const activeLineRef = (0, _react.useRef)(null);
38
+ const tabRefs = (0, _react.useRef)({});
38
39
  const keyToIndexRecord = {};
39
40
  let firstActiveKey = null;
40
41
  const panes = [];
@@ -176,7 +177,7 @@ const Tabs = p => {
176
177
  });
177
178
  const {
178
179
  run: updateMask
179
- } = (0, _ahooks.useThrottleFn)((immediate = false) => {
180
+ } = (0, _ahooks.useThrottleFn)(immediate => {
180
181
  const container = tabListContainerRef.current;
181
182
  if (!container) return;
182
183
  const scrollLeft = container.scrollLeft;
@@ -207,6 +208,34 @@ const Tabs = p => {
207
208
  (0, _ahooks.useIsomorphicLayoutEffect)(() => {
208
209
  updateMask(true);
209
210
  }, []);
211
+ const handleKeyDown = e => {
212
+ const keys = Object.keys(keyToIndexRecord);
213
+ const currentIndex = keyToIndexRecord[activeKey];
214
+ const isNext = isRTL ? e.key === 'ArrowLeft' : e.key === 'ArrowRight';
215
+ const isPrev = isRTL ? e.key === 'ArrowRight' : e.key === 'ArrowLeft';
216
+ const offsetDirection = isNext ? 1 : -1;
217
+ const findNextEnabledTab = (startIndex, direction) => {
218
+ const length = keys.length;
219
+ for (let i = 0; i < length; i++) {
220
+ const index = (startIndex + direction * (i + 1) + length) % length;
221
+ const key = keys[index];
222
+ const pane = panes.find(p => p.key === key);
223
+ if (!(pane === null || pane === void 0 ? void 0 : pane.props.disabled)) return key;
224
+ }
225
+ return keys[startIndex];
226
+ };
227
+ const currentKey = findNextEnabledTab(currentIndex, offsetDirection);
228
+ if (isNext || isPrev) {
229
+ e.preventDefault();
230
+ setActiveKey(currentKey);
231
+ }
232
+ };
233
+ (0, _react.useEffect)(() => {
234
+ var _a;
235
+ if (activeKey && tabRefs.current[activeKey]) {
236
+ (_a = tabRefs.current[activeKey]) === null || _a === void 0 ? void 0 : _a.focus();
237
+ }
238
+ }, [activeKey]);
210
239
  return (0, _nativeProps.withNativeProps)(props, _react.default.createElement("div", {
211
240
  className: classPrefix,
212
241
  style: {
@@ -229,6 +258,7 @@ const Tabs = p => {
229
258
  ref: tabListContainerRef,
230
259
  scrollLeft: scrollLeft,
231
260
  onScroll: updateMask,
261
+ onKeyDown: handleKeyDown,
232
262
  role: 'tablist'
233
263
  }, _react.default.createElement(_web.animated.div, {
234
264
  ref: activeLineRef,
@@ -243,6 +273,10 @@ const Tabs = p => {
243
273
  [`${classPrefix}-tab-wrapper-stretch`]: props.stretch
244
274
  })
245
275
  }, _react.default.createElement("div", {
276
+ role: 'tab',
277
+ "aria-selected": pane.key === activeKey,
278
+ tabIndex: pane.key === activeKey ? 0 : -1,
279
+ ref: el => tabRefs.current[pane.key] = el,
246
280
  onClick: () => {
247
281
  const {
248
282
  key
@@ -256,9 +290,7 @@ const Tabs = p => {
256
290
  className: (0, _classnames.default)(`${classPrefix}-tab`, {
257
291
  [`${classPrefix}-tab-active`]: pane.key === activeKey,
258
292
  [`${classPrefix}-tab-disabled`]: pane.props.disabled
259
- }),
260
- role: 'tab',
261
- "aria-selected": pane.key === activeKey
293
+ })
262
294
  }, pane.props.title)))))), panes.map(pane => {
263
295
  if (pane.props.children === undefined) {
264
296
  return null;
@@ -73,7 +73,6 @@
73
73
  }
74
74
 
75
75
  .adm-virtual-input:focus .adm-virtual-input-caret {
76
- display: block;
77
76
  animation-name: adm-caret-blink;
78
77
  animation-duration: 1s;
79
78
  animation-timing-function: linear;
@@ -84,6 +83,10 @@
84
83
  color: var(--disabled-color);
85
84
  }
86
85
 
86
+ .adm-virtual-input-caret-dragging .adm-virtual-input-caret {
87
+ animation: none !important;
88
+ }
89
+
87
90
  @keyframes adm-caret-blink {
88
91
  from {
89
92
  opacity: 1;
@@ -3,6 +3,10 @@ import React from 'react';
3
3
  import { NativeProps } from '../../utils/native-props';
4
4
  import type { InputProps } from '../input';
5
5
  import { NumberKeyboardProps } from '../number-keyboard';
6
+ export declare type Cursor = {
7
+ movable?: boolean;
8
+ onMove?: (position: number) => void;
9
+ };
6
10
  export declare type VirtualInputProps = {
7
11
  onFocus?: () => void;
8
12
  onBlur?: () => void;
@@ -10,6 +14,7 @@ export declare type VirtualInputProps = {
10
14
  keyboard?: ReactElement<NumberKeyboardProps>;
11
15
  clearable?: boolean;
12
16
  onClear?: () => void;
17
+ cursor?: Cursor;
13
18
  } & Pick<InputProps, 'value' | 'onChange' | 'placeholder' | 'disabled' | 'clearIcon'> & NativeProps<'--font-size' | '--color' | '--placeholder-color' | '--disabled-color' | '--text-align' | '--caret-width' | '--caret-color'>;
14
19
  export declare type VirtualInputRef = {
15
20
  focus: () => void;
@@ -22,6 +27,7 @@ export declare const VirtualInput: React.ForwardRefExoticComponent<{
22
27
  keyboard?: ReactElement<NumberKeyboardProps, string | React.JSXElementConstructor<any>> | undefined;
23
28
  clearable?: boolean | undefined;
24
29
  onClear?: (() => void) | undefined;
30
+ cursor?: Cursor | undefined;
25
31
  } & Pick<InputProps, "value" | "onChange" | "disabled" | "placeholder" | "clearIcon"> & {
26
32
  className?: string | undefined;
27
33
  style?: (React.CSSProperties & Partial<Record<"--color" | "--font-size" | "--placeholder-color" | "--text-align" | "--disabled-color" | "--caret-width" | "--caret-color", string>>) | undefined;
@@ -17,7 +17,10 @@ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj &&
17
17
  function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
18
  const classPrefix = 'adm-virtual-input';
19
19
  const defaultProps = {
20
- defaultValue: ''
20
+ defaultValue: '',
21
+ cursor: {
22
+ movable: false
23
+ }
21
24
  };
22
25
  const VirtualInput = (0, _react.forwardRef)((props, ref) => {
23
26
  const {
@@ -30,6 +33,13 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
30
33
  const contentRef = (0, _react.useRef)(null);
31
34
  const [hasFocus, setHasFocus] = (0, _react.useState)(false);
32
35
  const [caretPosition, setCaretPosition] = (0, _react.useState)(value.length); // 光标位置,从 0 开始,如值是 2 则表示光标在顺序下标为 2 的数字之前
36
+ const keyboardDataRef = (0, _react.useRef)({}); // 临时记录虚拟键盘输入,在下次更新时用于判断光标位置如何调整
37
+ const touchDataRef = (0, _react.useRef)(); // 记录上一次 touch 时的坐标位置
38
+ const charRef = (0, _react.useRef)(null); // 第一个字符的 DOM
39
+ const charWidthRef = (0, _react.useRef)(0); // 单个字符宽度
40
+ const caretRef = (0, _react.useRef)(null); // 光标的 DOM
41
+ const [isCaretDragging, setIsCaretDragging] = (0, _react.useState)(false);
42
+ const touchMoveTimeoutRef = (0, _react.useRef)();
33
43
  const clearIcon = (0, _withDefaultProps.mergeProp)(_react.default.createElement(_antdMobileIcons.CloseCircleFill, null), componentConfig.clearIcon, props.clearIcon);
34
44
  function scrollToEnd() {
35
45
  const root = rootRef.current;
@@ -41,6 +51,24 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
41
51
  if (!content) return;
42
52
  content.scrollLeft = content.clientWidth;
43
53
  }
54
+ (0, _react.useEffect)(() => {
55
+ // 记录单个字符的宽度,用于光标移动时的计算
56
+ if (charRef.current) {
57
+ charWidthRef.current = charRef.current.getBoundingClientRect().width;
58
+ }
59
+ }, [value]);
60
+ (0, _react.useEffect)(() => {
61
+ // 经过外部受控逻辑后,再调整光标位置,如果受控逻辑改动了值则光标放到最后
62
+ if (value === keyboardDataRef.current.newValue) {
63
+ if (keyboardDataRef.current.mode === 'input') {
64
+ setCaretPosition(c => c + 1);
65
+ } else if (keyboardDataRef.current.mode === 'delete') {
66
+ setCaretPosition(c => c - 1);
67
+ }
68
+ } else {
69
+ setCaretPosition(value.length);
70
+ }
71
+ }, [value]);
44
72
  (0, _ahooks.useIsomorphicLayoutEffect)(() => {
45
73
  scrollToEnd();
46
74
  }, [value]);
@@ -74,16 +102,24 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
74
102
  onInput: v => {
75
103
  var _a, _b;
76
104
  const newValue = value.substring(0, caretPosition) + v + value.substring(caretPosition);
105
+ // 临时记录,用于后续光标位置
106
+ keyboardDataRef.current = {
107
+ newValue,
108
+ mode: 'input'
109
+ };
77
110
  setValue(newValue);
78
- setCaretPosition(c => c + 1);
79
111
  (_b = (_a = keyboard.props).onInput) === null || _b === void 0 ? void 0 : _b.call(_a, v);
80
112
  },
81
113
  onDelete: () => {
82
114
  var _a, _b;
83
115
  if (caretPosition === 0) return;
84
116
  const newValue = value.substring(0, caretPosition - 1) + value.substring(caretPosition);
117
+ // 临时记录,用于后续光标位置
118
+ keyboardDataRef.current = {
119
+ newValue,
120
+ mode: 'delete'
121
+ };
85
122
  setValue(newValue);
86
- setCaretPosition(caretPosition - 1);
87
123
  (_b = (_a = keyboard.props).onDelete) === null || _b === void 0 ? void 0 : _b.call(_a);
88
124
  },
89
125
  visible: hasFocus,
@@ -103,23 +139,80 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
103
139
  });
104
140
  // 点击输入框时,将光标置于最后
105
141
  const setCaretPositionToEnd = () => {
106
- setCaretPosition(value.length);
142
+ var _a, _b;
143
+ if (caretPosition !== value.length) {
144
+ setCaretPosition(value.length);
145
+ (_b = (_a = mergedProps.cursor) === null || _a === void 0 ? void 0 : _a.onMove) === null || _b === void 0 ? void 0 : _b.call(_a, value.length);
146
+ }
107
147
  };
108
148
  // 点击单个字符时,根据点击位置置于字符前或后
109
149
  const changeCaretPosition = index => e => {
150
+ var _a, _b, _c;
151
+ if (mergedProps.disabled || !((_a = mergedProps.cursor) === null || _a === void 0 ? void 0 : _a.movable)) return;
110
152
  e.stopPropagation();
111
153
  const rect = e.target.getBoundingClientRect();
112
154
  const midX = rect.left + rect.width / 2;
113
155
  const clickX = e.clientX;
114
156
  // 点击区域是否偏右
115
157
  const isRight = clickX > midX;
116
- setCaretPosition(isRight ? index + 1 : index);
158
+ const newCaretPosition = isRight ? index + 1 : index;
159
+ setCaretPosition(newCaretPosition);
160
+ (_c = (_b = mergedProps.cursor) === null || _b === void 0 ? void 0 : _b.onMove) === null || _c === void 0 ? void 0 : _c.call(_b, newCaretPosition);
161
+ };
162
+ // 在光标附近 touchmove 时也可以调整光标位置
163
+ const handleTouchStart = e => {
164
+ var _a;
165
+ if (mergedProps.disabled || !((_a = mergedProps.cursor) === null || _a === void 0 ? void 0 : _a.movable)) return;
166
+ if (!caretRef.current) return;
167
+ const touch = e.touches[0];
168
+ const caretRect = caretRef.current.getBoundingClientRect();
169
+ const distance = Math.abs(touch.clientX - (caretRect.left + caretRect.width / 2));
170
+ if (distance < 20) {
171
+ // 20px 阈值可调整
172
+ touchDataRef.current = {
173
+ startX: touch.clientX,
174
+ startCaretPosition: caretPosition
175
+ };
176
+ } else {
177
+ touchDataRef.current = null;
178
+ }
179
+ };
180
+ const handleTouchMove = e => {
181
+ var _a, _b, _c;
182
+ if (!touchDataRef.current || !((_a = mergedProps.cursor) === null || _a === void 0 ? void 0 : _a.movable)) return;
183
+ setIsCaretDragging(true);
184
+ const touch = e.touches[0];
185
+ const deltaX = touch.clientX - touchDataRef.current.startX;
186
+ const charWidth = charWidthRef.current;
187
+ const moveChars = Math.round(deltaX / charWidth);
188
+ let newCaretPosition = touchDataRef.current.startCaretPosition + moveChars;
189
+ // 边界处理
190
+ newCaretPosition = Math.max(0, Math.min(newCaretPosition, value.length));
191
+ setCaretPosition(newCaretPosition);
192
+ (_c = (_b = mergedProps.cursor) === null || _b === void 0 ? void 0 : _b.onMove) === null || _c === void 0 ? void 0 : _c.call(_b, newCaretPosition);
193
+ // 防止 touchend 不触发
194
+ if (touchMoveTimeoutRef.current) {
195
+ clearTimeout(touchMoveTimeoutRef.current);
196
+ }
197
+ touchMoveTimeoutRef.current = setTimeout(() => {
198
+ setIsCaretDragging(false);
199
+ touchMoveTimeoutRef.current = null;
200
+ }, 500);
201
+ };
202
+ const handleTouchEnd = () => {
203
+ touchDataRef.current = null;
204
+ setIsCaretDragging(false);
205
+ if (touchMoveTimeoutRef.current) {
206
+ clearTimeout(touchMoveTimeoutRef.current);
207
+ touchMoveTimeoutRef.current = null;
208
+ }
117
209
  };
118
210
  const chars = (value + '').split('');
119
211
  return (0, _nativeProps.withNativeProps)(mergedProps, _react.default.createElement("div", {
120
212
  ref: rootRef,
121
213
  className: (0, _classnames.default)(classPrefix, {
122
- [`${classPrefix}-disabled`]: mergedProps.disabled
214
+ [`${classPrefix}-disabled`]: mergedProps.disabled,
215
+ [`${classPrefix}-caret-dragging`]: isCaretDragging
123
216
  }),
124
217
  tabIndex: mergedProps.disabled ? undefined : 0,
125
218
  role: 'textbox',
@@ -131,13 +224,18 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
131
224
  ref: contentRef,
132
225
  "aria-disabled": mergedProps.disabled,
133
226
  "aria-label": mergedProps.placeholder,
134
- onClick: setCaretPositionToEnd
227
+ onClick: setCaretPositionToEnd,
228
+ onTouchStart: handleTouchStart,
229
+ onTouchMove: handleTouchMove,
230
+ onTouchEnd: handleTouchEnd
135
231
  }, chars.slice(0, caretPosition).map((i, index) => _react.default.createElement("span", {
232
+ ref: index === 0 ? charRef : undefined,
136
233
  key: index,
137
234
  onClick: changeCaretPosition(index)
138
235
  }, i)), _react.default.createElement("div", {
139
236
  className: `${classPrefix}-caret-container`
140
237
  }, hasFocus && _react.default.createElement("div", {
238
+ ref: caretRef,
141
239
  className: `${classPrefix}-caret`
142
240
  })), chars.slice(caretPosition).map((i, index) => _react.default.createElement("span", {
143
241
  key: index,
@@ -148,7 +246,6 @@ const VirtualInput = (0, _react.forwardRef)((props, ref) => {
148
246
  var _a;
149
247
  e.stopPropagation();
150
248
  setValue('');
151
- setCaretPosition(0);
152
249
  (_a = mergedProps.onClear) === null || _a === void 0 ? void 0 : _a.call(mergedProps);
153
250
  },
154
251
  role: 'button',
@@ -91,6 +91,7 @@ export function convertStringArrayToDate(value) {
91
91
  const yearString = (_a = value[0]) !== null && _a !== void 0 ? _a : '1900';
92
92
  const weekString = (_b = value[1]) !== null && _b !== void 0 ? _b : '1';
93
93
  const weekdayString = (_c = value[2]) !== null && _c !== void 0 ? _c : '1';
94
- const day = dayjs(`${parseInt(yearString)}-01-01`).isoWeek(parseInt(weekString)).isoWeekday(parseInt(weekdayString)).hour(0).minute(0).second(0);
94
+ // See https://github.com/ant-design/ant-design-mobile/issues/6905
95
+ const day = dayjs(`${parseInt(yearString)}-01-04`).isoWeek(parseInt(weekString)).isoWeekday(parseInt(weekdayString)).hour(0).minute(0).second(0);
95
96
  return day.toDate();
96
97
  }
@@ -11,5 +11,8 @@ export declare type EllipsisProps = {
11
11
  stopPropagationForActionButtons?: PropagationEvent[];
12
12
  onContentClick?: (e: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
13
13
  defaultExpanded?: boolean;
14
+ onExpand?: (expanded: boolean, info: {
15
+ event: React.MouseEvent<HTMLAnchorElement, MouseEvent>;
16
+ }) => void;
14
17
  } & NativeProps;
15
18
  export declare const Ellipsis: FC<EllipsisProps>;
@@ -32,13 +32,21 @@ export const Ellipsis = p => {
32
32
  // ========================== Expanded ==========================
33
33
  const [expanded, setExpanded] = React.useState(defaultExpanded);
34
34
  const expandNode = expandText ? withStopPropagation(stopPropagationForActionButtons, React.createElement("a", {
35
- onClick: () => {
35
+ onClick: e => {
36
+ var _a;
36
37
  setExpanded(true);
38
+ (_a = props.onExpand) === null || _a === void 0 ? void 0 : _a.call(props, true, {
39
+ event: e
40
+ });
37
41
  }
38
42
  }, expandText)) : null;
39
43
  const collapseNode = collapseText ? withStopPropagation(stopPropagationForActionButtons, React.createElement("a", {
40
- onClick: () => {
44
+ onClick: e => {
45
+ var _a;
41
46
  setExpanded(false);
47
+ (_a = props.onExpand) === null || _a === void 0 ? void 0 : _a.call(props, false, {
48
+ event: e
49
+ });
42
50
  }
43
51
  }, collapseText)) : null;
44
52
  // ========================== Ellipsis ==========================
@@ -270,7 +270,7 @@ export const Swiper = forwardRef(staged((p, ref) => {
270
270
  return React.createElement(React.Fragment, null, React.createElement("div", {
271
271
  className: `${classPrefix}-slide-placeholder`,
272
272
  style: {
273
- width: `${startIndex * 100}%`
273
+ [isVertical ? 'height' : 'width']: `${startIndex * 100}%`
274
274
  }
275
275
  }), items);
276
276
  }
@@ -1,16 +1,16 @@
1
- import React, { isValidElement, useRef } from 'react';
1
+ import { animated, useSpring } from '@react-spring/web';
2
+ import { useIsomorphicLayoutEffect, useThrottleFn } from 'ahooks';
2
3
  import classNames from 'classnames';
3
- import { useSpring, animated } from '@react-spring/web';
4
- import { withNativeProps } from '../../utils/native-props';
5
- import { usePropsValue } from '../../utils/use-props-value';
4
+ import React, { isValidElement, useEffect, useRef } from 'react';
6
5
  import { bound } from '../../utils/bound';
7
- import { useThrottleFn, useIsomorphicLayoutEffect } from 'ahooks';
6
+ import { withNativeProps } from '../../utils/native-props';
7
+ import { ShouldRender } from '../../utils/should-render';
8
+ import { traverseReactNode } from '../../utils/traverse-react-node';
9
+ import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect';
8
10
  import { useMutationEffect } from '../../utils/use-mutation-effect';
11
+ import { usePropsValue } from '../../utils/use-props-value';
9
12
  import { useResizeEffect } from '../../utils/use-resize-effect';
10
13
  import { mergeProps } from '../../utils/with-default-props';
11
- import { useIsomorphicUpdateLayoutEffect } from '../../utils/use-isomorphic-update-layout-effect';
12
- import { ShouldRender } from '../../utils/should-render';
13
- import { traverseReactNode } from '../../utils/traverse-react-node';
14
14
  const classPrefix = `adm-tabs`;
15
15
  export const Tab = () => {
16
16
  return null;
@@ -25,6 +25,7 @@ export const Tabs = p => {
25
25
  const props = mergeProps(defaultProps, p);
26
26
  const tabListContainerRef = useRef(null);
27
27
  const activeLineRef = useRef(null);
28
+ const tabRefs = useRef({});
28
29
  const keyToIndexRecord = {};
29
30
  let firstActiveKey = null;
30
31
  const panes = [];
@@ -166,7 +167,7 @@ export const Tabs = p => {
166
167
  });
167
168
  const {
168
169
  run: updateMask
169
- } = useThrottleFn((immediate = false) => {
170
+ } = useThrottleFn(immediate => {
170
171
  const container = tabListContainerRef.current;
171
172
  if (!container) return;
172
173
  const scrollLeft = container.scrollLeft;
@@ -197,6 +198,34 @@ export const Tabs = p => {
197
198
  useIsomorphicLayoutEffect(() => {
198
199
  updateMask(true);
199
200
  }, []);
201
+ const handleKeyDown = e => {
202
+ const keys = Object.keys(keyToIndexRecord);
203
+ const currentIndex = keyToIndexRecord[activeKey];
204
+ const isNext = isRTL ? e.key === 'ArrowLeft' : e.key === 'ArrowRight';
205
+ const isPrev = isRTL ? e.key === 'ArrowRight' : e.key === 'ArrowLeft';
206
+ const offsetDirection = isNext ? 1 : -1;
207
+ const findNextEnabledTab = (startIndex, direction) => {
208
+ const length = keys.length;
209
+ for (let i = 0; i < length; i++) {
210
+ const index = (startIndex + direction * (i + 1) + length) % length;
211
+ const key = keys[index];
212
+ const pane = panes.find(p => p.key === key);
213
+ if (!(pane === null || pane === void 0 ? void 0 : pane.props.disabled)) return key;
214
+ }
215
+ return keys[startIndex];
216
+ };
217
+ const currentKey = findNextEnabledTab(currentIndex, offsetDirection);
218
+ if (isNext || isPrev) {
219
+ e.preventDefault();
220
+ setActiveKey(currentKey);
221
+ }
222
+ };
223
+ useEffect(() => {
224
+ var _a;
225
+ if (activeKey && tabRefs.current[activeKey]) {
226
+ (_a = tabRefs.current[activeKey]) === null || _a === void 0 ? void 0 : _a.focus();
227
+ }
228
+ }, [activeKey]);
200
229
  return withNativeProps(props, React.createElement("div", {
201
230
  className: classPrefix,
202
231
  style: {
@@ -219,6 +248,7 @@ export const Tabs = p => {
219
248
  ref: tabListContainerRef,
220
249
  scrollLeft: scrollLeft,
221
250
  onScroll: updateMask,
251
+ onKeyDown: handleKeyDown,
222
252
  role: 'tablist'
223
253
  }, React.createElement(animated.div, {
224
254
  ref: activeLineRef,
@@ -233,6 +263,10 @@ export const Tabs = p => {
233
263
  [`${classPrefix}-tab-wrapper-stretch`]: props.stretch
234
264
  })
235
265
  }, React.createElement("div", {
266
+ role: 'tab',
267
+ "aria-selected": pane.key === activeKey,
268
+ tabIndex: pane.key === activeKey ? 0 : -1,
269
+ ref: el => tabRefs.current[pane.key] = el,
236
270
  onClick: () => {
237
271
  const {
238
272
  key
@@ -246,9 +280,7 @@ export const Tabs = p => {
246
280
  className: classNames(`${classPrefix}-tab`, {
247
281
  [`${classPrefix}-tab-active`]: pane.key === activeKey,
248
282
  [`${classPrefix}-tab-disabled`]: pane.props.disabled
249
- }),
250
- role: 'tab',
251
- "aria-selected": pane.key === activeKey
283
+ })
252
284
  }, pane.props.title)))))), panes.map(pane => {
253
285
  if (pane.props.children === undefined) {
254
286
  return null;
@@ -73,7 +73,6 @@
73
73
  }
74
74
 
75
75
  .adm-virtual-input:focus .adm-virtual-input-caret {
76
- display: block;
77
76
  animation-name: adm-caret-blink;
78
77
  animation-duration: 1s;
79
78
  animation-timing-function: linear;
@@ -84,6 +83,10 @@
84
83
  color: var(--disabled-color);
85
84
  }
86
85
 
86
+ .adm-virtual-input-caret-dragging .adm-virtual-input-caret {
87
+ animation: none !important;
88
+ }
89
+
87
90
  @keyframes adm-caret-blink {
88
91
  from {
89
92
  opacity: 1;
@@ -3,6 +3,10 @@ import React from 'react';
3
3
  import { NativeProps } from '../../utils/native-props';
4
4
  import type { InputProps } from '../input';
5
5
  import { NumberKeyboardProps } from '../number-keyboard';
6
+ export declare type Cursor = {
7
+ movable?: boolean;
8
+ onMove?: (position: number) => void;
9
+ };
6
10
  export declare type VirtualInputProps = {
7
11
  onFocus?: () => void;
8
12
  onBlur?: () => void;
@@ -10,6 +14,7 @@ export declare type VirtualInputProps = {
10
14
  keyboard?: ReactElement<NumberKeyboardProps>;
11
15
  clearable?: boolean;
12
16
  onClear?: () => void;
17
+ cursor?: Cursor;
13
18
  } & Pick<InputProps, 'value' | 'onChange' | 'placeholder' | 'disabled' | 'clearIcon'> & NativeProps<'--font-size' | '--color' | '--placeholder-color' | '--disabled-color' | '--text-align' | '--caret-width' | '--caret-color'>;
14
19
  export declare type VirtualInputRef = {
15
20
  focus: () => void;
@@ -22,6 +27,7 @@ export declare const VirtualInput: React.ForwardRefExoticComponent<{
22
27
  keyboard?: ReactElement<NumberKeyboardProps, string | React.JSXElementConstructor<any>> | undefined;
23
28
  clearable?: boolean | undefined;
24
29
  onClear?: (() => void) | undefined;
30
+ cursor?: Cursor | undefined;
25
31
  } & Pick<InputProps, "value" | "onChange" | "disabled" | "placeholder" | "clearIcon"> & {
26
32
  className?: string | undefined;
27
33
  style?: (React.CSSProperties & Partial<Record<"--color" | "--font-size" | "--placeholder-color" | "--text-align" | "--disabled-color" | "--caret-width" | "--caret-color", string>>) | undefined;