@arco-design/mobile-react 2.35.2 → 2.36.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 (73) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.en-US.md +2 -2
  3. package/README.md +2 -2
  4. package/cjs/_helpers/hooks.d.ts +10 -2
  5. package/cjs/_helpers/hooks.js +12 -5
  6. package/cjs/date-picker/index.js +218 -18
  7. package/cjs/date-picker/style/css/index.css +42 -0
  8. package/cjs/date-picker/style/index.less +38 -1
  9. package/cjs/date-picker/type.d.ts +22 -6
  10. package/cjs/form/linked-container.d.ts +2 -2
  11. package/cjs/form/linked-container.js +5 -1
  12. package/cjs/picker/index.js +3 -2
  13. package/cjs/picker/type.d.ts +5 -0
  14. package/cjs/search-bar/association.js +2 -2
  15. package/cjs/search-bar/type.d.ts +1 -1
  16. package/cjs/stepper/hooks/useValue.js +3 -1
  17. package/cjs/tabs/index.js +1 -1
  18. package/cjs/tabs/type.d.ts +2 -2
  19. package/dist/index.js +272 -38
  20. package/dist/index.min.js +4 -4
  21. package/dist/style.css +23 -0
  22. package/dist/style.min.css +1 -1
  23. package/esm/_helpers/hooks.d.ts +10 -2
  24. package/esm/_helpers/hooks.js +12 -5
  25. package/esm/date-picker/index.js +218 -18
  26. package/esm/date-picker/style/css/index.css +42 -0
  27. package/esm/date-picker/style/index.less +38 -1
  28. package/esm/date-picker/type.d.ts +22 -6
  29. package/esm/form/linked-container.d.ts +2 -2
  30. package/esm/form/linked-container.js +5 -1
  31. package/esm/picker/index.js +3 -2
  32. package/esm/picker/type.d.ts +5 -0
  33. package/esm/search-bar/association.js +2 -2
  34. package/esm/search-bar/type.d.ts +1 -1
  35. package/esm/stepper/hooks/useValue.js +1 -0
  36. package/esm/tabs/index.js +1 -1
  37. package/esm/tabs/type.d.ts +2 -2
  38. package/esnext/_helpers/hooks.d.ts +10 -2
  39. package/esnext/_helpers/hooks.js +12 -5
  40. package/esnext/date-picker/index.js +167 -10
  41. package/esnext/date-picker/style/css/index.css +42 -0
  42. package/esnext/date-picker/style/index.less +38 -1
  43. package/esnext/date-picker/type.d.ts +22 -6
  44. package/esnext/form/linked-container.d.ts +2 -2
  45. package/esnext/form/linked-container.js +7 -2
  46. package/esnext/picker/index.js +2 -1
  47. package/esnext/picker/type.d.ts +5 -0
  48. package/esnext/search-bar/association.js +1 -1
  49. package/esnext/search-bar/type.d.ts +1 -1
  50. package/esnext/stepper/hooks/useValue.js +1 -0
  51. package/esnext/tabs/index.js +1 -1
  52. package/esnext/tabs/type.d.ts +2 -2
  53. package/package.json +3 -3
  54. package/tokens/app/arcodesign/default/css-variables.less +10 -0
  55. package/tokens/app/arcodesign/default/index.d.ts +10 -0
  56. package/tokens/app/arcodesign/default/index.js +11 -1
  57. package/tokens/app/arcodesign/default/index.json +108 -0
  58. package/tokens/app/arcodesign/default/index.less +10 -0
  59. package/umd/_helpers/hooks.d.ts +10 -2
  60. package/umd/_helpers/hooks.js +12 -5
  61. package/umd/date-picker/index.js +218 -18
  62. package/umd/date-picker/style/css/index.css +42 -0
  63. package/umd/date-picker/style/index.less +38 -1
  64. package/umd/date-picker/type.d.ts +22 -6
  65. package/umd/form/linked-container.d.ts +2 -2
  66. package/umd/form/linked-container.js +5 -1
  67. package/umd/picker/index.js +3 -2
  68. package/umd/picker/type.d.ts +5 -0
  69. package/umd/search-bar/association.js +2 -2
  70. package/umd/search-bar/type.d.ts +1 -1
  71. package/umd/stepper/hooks/useValue.js +5 -5
  72. package/umd/tabs/index.js +1 -1
  73. package/umd/tabs/type.d.ts +2 -2
@@ -561,8 +561,8 @@ export interface TabCellRef {
561
561
  */
562
562
  setCaterpillarAnimate: (ratio?: number) => void;
563
563
  /**
564
- * 重新计算下划线样式
565
- * @en Recalculate underline style
564
+ * 重新计算下划线样式(仅重算位置,如果 tab cell DOM 被人为改变,请调用 updateLayout)
565
+ * @en Recalculate underline style (only recalculate position, if the tab cell DOM is changed manually, please call updateLayout)
566
566
  */
567
567
  resetUnderlineStyle: () => void;
568
568
  /**
@@ -4,6 +4,7 @@
4
4
  * @name_en General Hooks
5
5
  */
6
6
  import React from 'react';
7
+ import type { SystemOptions } from '@arco-design/mobile-utils';
7
8
  import { BezierType } from '../progress';
8
9
  /**
9
10
  * 监听页面resize事件的统一封装
@@ -130,15 +131,22 @@ export declare function useLatestRef<T>(variable: T): React.MutableRefObject<T>;
130
131
  /**
131
132
  * 从navigator.userAgent中获取当前操作系统,如果无法获取ua,则从ContextProvider传入的system中获取值
132
133
  * @desc {en} Get the current operating system from navigator.userAgent, if ua cannot be obtained, get the value from the system passed in by ContextProvider
133
- * @returns system 操作系统,"" | "pc" | "android" | "ios"
134
+ * @param options 配置选项
135
+ * @param {en} options Configuration options
136
+ * @param options.detectHarmony 是否识别鸿蒙系统,默认为 false,鸿蒙系统会被识别为 android
137
+ * @param {en} options.detectHarmony Whether to detect HarmonyOS separately, default is false, HarmonyOS will be recognized as android
138
+ * @returns 返回当前设备的操作系统,可能的值包括 'android'、'ios'、'harmony' 或 'pc',如果无法获取,则返回空字符串
139
+ * @returns {en} Returns the operating system of the current device, possible values are 'android', 'ios', 'harmony', or 'pc'. Returns an empty string if it cannot be obtained
134
140
  * @example
135
141
  * ```
136
142
  * import { useSystem } from '@arco-design/mobile-react/esm/_helpers/hooks';
137
143
  *
138
144
  * const system = useSystem();
145
+ * // Or with options
146
+ * const systemWithHarmony = useSystem({ detectHarmony: true });
139
147
  * ```
140
148
  */
141
- export declare function useSystem(): "" | "android" | "ios" | "pc";
149
+ export declare function useSystem(options?: SystemOptions): "" | "android" | "harmony" | "ios" | "pc";
142
150
  /**
143
151
  * 获取页面视口宽高大小,并在页面有resize时更新大小
144
152
  * @desc {en} Get the width and height of the page viewport, and update the size when the page is resized
@@ -206,20 +206,27 @@ export function useLatestRef(variable) {
206
206
  /**
207
207
  * 从navigator.userAgent中获取当前操作系统,如果无法获取ua,则从ContextProvider传入的system中获取值
208
208
  * @desc {en} Get the current operating system from navigator.userAgent, if ua cannot be obtained, get the value from the system passed in by ContextProvider
209
- * @returns system 操作系统,"" | "pc" | "android" | "ios"
209
+ * @param options 配置选项
210
+ * @param {en} options Configuration options
211
+ * @param options.detectHarmony 是否识别鸿蒙系统,默认为 false,鸿蒙系统会被识别为 android
212
+ * @param {en} options.detectHarmony Whether to detect HarmonyOS separately, default is false, HarmonyOS will be recognized as android
213
+ * @returns 返回当前设备的操作系统,可能的值包括 'android'、'ios'、'harmony' 或 'pc',如果无法获取,则返回空字符串
214
+ * @returns {en} Returns the operating system of the current device, possible values are 'android', 'ios', 'harmony', or 'pc'. Returns an empty string if it cannot be obtained
210
215
  * @example
211
216
  * ```
212
217
  * import { useSystem } from '@arco-design/mobile-react/esm/_helpers/hooks';
213
218
  *
214
219
  * const system = useSystem();
220
+ * // Or with options
221
+ * const systemWithHarmony = useSystem({ detectHarmony: true });
215
222
  * ```
216
223
  */
217
- export function useSystem() {
224
+ export function useSystem(options) {
218
225
  const { system: currentSystem } = useContext(GlobalContext);
219
- const [system, setSystem] = useState(() => currentSystem || getSystem());
226
+ const [system, setSystem] = useState(() => currentSystem || getSystem(options));
220
227
  useEffect(() => {
221
- setSystem(currentSystem || getSystem());
222
- }, [currentSystem]);
228
+ setSystem(currentSystem || getSystem(options));
229
+ }, [currentSystem, options]);
223
230
  return system;
224
231
  }
225
232
  /**
@@ -11,15 +11,45 @@ const initMinDate = Date.now() - 10 * YEAR;
11
11
  const initMaxDate = Date.now() + 10 * YEAR;
12
12
  const initDate = Date.now();
13
13
  const DatePicker = forwardRef((props, ref) => {
14
- const { currentTs: userSetCurrentTs = initDate, className = '', visible = false, onOk, onChange, onValueChange, mode = 'datetime', typeArr = [], minTs = initMinDate, maxTs = initMaxDate, formatter = defaultFormatter, valueFilter = () => true, columnsProcessor, touchToStop, useUTC = false, renderLinkedContainer, ...otherProps } = props;
15
- const currentTs = Math.min(maxTs, Math.max(minTs, userSetCurrentTs));
14
+ const { currentTs: userSetCurrentTs = initDate, className = '', visible = false, onOk, onChange, onValueChange, mode = 'datetime', typeArr = [], minTs: userSetMinTs = initMinDate, maxTs: userSetMaxTs = initMaxDate, rangeItemFormat, formatter = defaultFormatter, valueFilter = () => true, columnsProcessor, touchToStop, useUTC = false, renderSeparator, renderLinkedContainer, ...otherProps } = props;
15
+ const isRange = typeof userSetCurrentTs !== 'number';
16
+ const [leftTimeValue, setLeftTimeValue] = useState(userSetCurrentTs[0]);
17
+ const [rightTimeValue, setRightTimeValue] = useState(userSetCurrentTs[1]);
18
+ const [activeTabIndex, setActiveTabIndex] = useState(0);
19
+ const [minTs, maxTs] = useMemo(() => {
20
+ return _updateTimeScope();
21
+ }, [userSetMinTs, userSetMaxTs, activeTabIndex]);
22
+ const [currentTs, setCurrentTs] = useState(isRange
23
+ ? Math.min(maxTs, Math.max(minTs, userSetCurrentTs[0]))
24
+ : Math.min(maxTs, Math.max(minTs, userSetCurrentTs)));
16
25
  const [data, setData] = useState([[]]);
17
26
  const [value, setValue] = useState([]);
18
27
  const currentDateObjRef = useRef(_convertTsToDateObj(currentTs));
19
28
  const minDateObjRef = useRef(_convertTsToDateObj(minTs));
20
29
  const maxDateObjRef = useRef(_convertTsToDateObj(maxTs));
21
30
  const keyOptions = useMemo(() => _getKeyOptions(), [mode, typeArr]);
31
+ const leftTimeString = useMemo(() => _getRangeItemValue(leftTimeValue), [leftTimeValue]);
32
+ const rightTimeString = useMemo(() => _getRangeItemValue(rightTimeValue), [rightTimeValue]);
22
33
  const pickerRef = useRef(null);
34
+ function _updateRangeValue(nowCurrentTs) {
35
+ const leftMinTs = typeof userSetMinTs !== 'number' ? userSetMinTs.startTs : userSetMinTs;
36
+ const rightMinTs = typeof userSetMinTs !== 'number' ? userSetMinTs.endTs : userSetMinTs;
37
+ const leftMaxTs = typeof userSetMaxTs !== 'number' ? userSetMaxTs.startTs : userSetMaxTs;
38
+ const rightMaxTs = typeof userSetMaxTs !== 'number' ? userSetMaxTs.endTs : userSetMaxTs;
39
+ if (isRange) {
40
+ let leftTime, rightTime;
41
+ if (activeTabIndex === 0) {
42
+ leftTime = nowCurrentTs;
43
+ rightTime = Math.min(rightMaxTs, Math.max(Math.max(leftTime, rightMinTs), rightTimeValue));
44
+ }
45
+ else {
46
+ rightTime = nowCurrentTs;
47
+ leftTime = Math.min(leftMaxTs, Math.max(leftMinTs, leftTimeValue));
48
+ }
49
+ setLeftTimeValue(leftTime);
50
+ setRightTimeValue(rightTime);
51
+ }
52
+ }
23
53
  useImperativeHandle(ref, () => ({
24
54
  dom: pickerRef.current ? pickerRef.current.dom : null,
25
55
  }));
@@ -34,6 +64,61 @@ const DatePicker = forwardRef((props, ref) => {
34
64
  dateObj,
35
65
  };
36
66
  }
67
+ function _parseFormat(format, timeValue) {
68
+ const { year, month, date, hour, minute, second } = timeValue;
69
+ const padZero = (num, targetLength = 2) => {
70
+ let str = `${num}`;
71
+ while (str.length < targetLength) {
72
+ str = `0${str}`;
73
+ }
74
+ return str;
75
+ };
76
+ const replace = (formatArg, str, num) => {
77
+ if (formatArg.includes(str)) {
78
+ return str !== 'Y'
79
+ ? formatArg.replace(str.repeat(2), padZero(num)).replace(str, padZero(num))
80
+ : formatArg
81
+ .replace(str.repeat(4), padZero(num))
82
+ .replace(str.repeat(2), padZero(num))
83
+ .replace(str, padZero(num));
84
+ }
85
+ return formatArg;
86
+ };
87
+ return [
88
+ ['Y', year],
89
+ ['M', month],
90
+ ['D', date],
91
+ ['H', hour],
92
+ ['m', minute],
93
+ ['s', second],
94
+ ].reduce((current, item) => {
95
+ return replace(current, item[0], item[1]);
96
+ }, format);
97
+ }
98
+ function _getRangeItemValue(time) {
99
+ const timeValue = _convertTsToDateObj(time);
100
+ if (!isRange) {
101
+ return;
102
+ }
103
+ if (rangeItemFormat) {
104
+ return _parseFormat(rangeItemFormat, timeValue);
105
+ }
106
+ const format = (options, joinString) => {
107
+ return options
108
+ .filter(option => {
109
+ return keyOptions.includes(option);
110
+ })
111
+ .map(option => {
112
+ return timeValue[option] < 10
113
+ ? `0${timeValue[option]}`
114
+ : `${timeValue[option]}`;
115
+ })
116
+ .join(joinString);
117
+ };
118
+ const datePart = format(['year', 'month', 'date'], '/');
119
+ const timePart = format(['hour', 'minute', 'second'], ':');
120
+ return datePart + (datePart && timePart && ' ') + timePart;
121
+ }
37
122
  function _getSelectValue(columns) {
38
123
  const val = keyOptions.map((opt, index) => {
39
124
  const curCol = columns[index] || [];
@@ -137,7 +222,7 @@ const DatePicker = forwardRef((props, ref) => {
137
222
  }
138
223
  function _handlePickerChange(values, index) {
139
224
  const type = keyOptions[index];
140
- const nowDateObj = {};
225
+ const nowDateObj = currentDateObjRef.current;
141
226
  values.forEach((i, keyIndex) => {
142
227
  nowDateObj[keyOptions[keyIndex]] = i;
143
228
  });
@@ -155,16 +240,34 @@ const DatePicker = forwardRef((props, ref) => {
155
240
  setData(columns);
156
241
  setValue(val);
157
242
  }
243
+ setCurrentTs(_convertObjToTs(nowDateObj, currentTs));
158
244
  if (onValueChange) {
159
245
  onValueChange(_convertObjToTs(nowDateObj, currentTs), nowDateObj, index);
160
246
  }
161
247
  }
162
248
  function _handlePickerConfirm(values) {
163
- const nowDateObj = {};
164
- values.forEach((index, keyIndex) => {
165
- nowDateObj[keyOptions[keyIndex]] = index;
166
- });
167
- const newTs = _convertObjToTs(nowDateObj, currentTs);
249
+ let nowDateObj;
250
+ let newTs;
251
+ if (isRange) {
252
+ const leftTimeObj = _convertTsToDateObj(leftTimeValue);
253
+ const rightTimeObj = _convertTsToDateObj(rightTimeValue);
254
+ nowDateObj = keyOptions.reduce((arr, key) => {
255
+ arr[0][key] = leftTimeObj[key];
256
+ arr[1][key] = rightTimeObj[key];
257
+ return arr;
258
+ }, [{}, {}]);
259
+ newTs = [
260
+ _convertObjToTs(nowDateObj[0], currentTs),
261
+ _convertObjToTs(nowDateObj[1], currentTs),
262
+ ];
263
+ }
264
+ else {
265
+ nowDateObj = {};
266
+ values.forEach((index, keyIndex) => {
267
+ nowDateObj[keyOptions[keyIndex]] = index;
268
+ });
269
+ newTs = _convertObjToTs(nowDateObj, currentTs);
270
+ }
168
271
  if (onOk) {
169
272
  onOk(newTs, nowDateObj);
170
273
  }
@@ -189,19 +292,73 @@ const DatePicker = forwardRef((props, ref) => {
189
292
  }
190
293
  return options;
191
294
  }
295
+ function _updateTimeScope(isLeft) {
296
+ let nowMaxTs, nowMinTs;
297
+ if (isLeft || activeTabIndex === 0) {
298
+ nowMaxTs = typeof userSetMaxTs === 'number' ? userSetMaxTs : userSetMaxTs.startTs;
299
+ nowMinTs = Math.min(nowMaxTs, typeof userSetMinTs === 'number' ? userSetMinTs : userSetMinTs.startTs);
300
+ }
301
+ else {
302
+ nowMinTs = Math.max(Math.min(typeof userSetMaxTs === 'number' ? userSetMaxTs : userSetMaxTs.startTs, leftTimeValue), typeof userSetMinTs === 'number' ? userSetMinTs : userSetMinTs.endTs);
303
+ nowMaxTs = Math.max(nowMinTs, typeof userSetMaxTs === 'number' ? userSetMaxTs : userSetMaxTs.endTs);
304
+ }
305
+ return [nowMinTs, nowMaxTs];
306
+ }
307
+ function _chooseTimeActive(index) {
308
+ setActiveTabIndex(index);
309
+ }
192
310
  useEffect(() => {
193
311
  minDateObjRef.current = _convertTsToDateObj(minTs);
194
312
  currentDateObjRef.current = _convertTsToDateObj(currentTs);
195
313
  maxDateObjRef.current = _convertTsToDateObj(maxTs);
196
314
  _initData();
197
315
  }, [currentTs, minTs, maxTs, useUTC]);
316
+ useEffect(() => {
317
+ let nowCurrentTs;
318
+ if (isRange) {
319
+ nowCurrentTs = Math.min(maxTs, Math.max(minTs, activeTabIndex === 0 ? leftTimeValue : rightTimeValue));
320
+ if (currentTs === nowCurrentTs) {
321
+ _updateRangeValue(currentTs);
322
+ }
323
+ }
324
+ else {
325
+ nowCurrentTs = Math.min(maxTs, Math.max(minTs, currentTs));
326
+ }
327
+ setCurrentTs(nowCurrentTs);
328
+ }, [minTs, maxTs]);
329
+ useEffect(() => {
330
+ _updateRangeValue(currentTs);
331
+ }, [currentTs]);
198
332
  useEffect(() => {
199
333
  if (visible) {
200
- currentDateObjRef.current = _convertTsToDateObj(currentTs);
334
+ // 初始化当前时间
335
+ if (isRange) {
336
+ setActiveTabIndex(0);
337
+ setLeftTimeValue(userSetCurrentTs[0]);
338
+ setRightTimeValue(userSetCurrentTs[1]);
339
+ const [nowMinTs, nowMaxTs] = _updateTimeScope(true);
340
+ const nowCurrentTs = Math.min(nowMaxTs, Math.max(nowMinTs, userSetCurrentTs[0]));
341
+ setCurrentTs(nowCurrentTs);
342
+ if (currentTs === nowCurrentTs) {
343
+ _updateRangeValue(currentTs);
344
+ }
345
+ }
346
+ else {
347
+ setCurrentTs(Math.min(maxTs, Math.max(minTs, userSetCurrentTs)));
348
+ }
201
349
  _initData();
202
350
  }
203
351
  }, [visible]);
204
- return (React.createElement(ContextLayout, null, ({ prefixCls }) => (React.createElement(Picker, Object.assign({}, otherProps, { ref: pickerRef, visible: visible, className: cls(className, `${prefixCls}-date-picker`), cascade: false, data: data, value: value, onPickerChange: _handlePickerChange, onOk: _handlePickerConfirm, touchToStop: touchToStop, renderLinkedContainer: renderLinkedContainer
352
+ return (React.createElement(ContextLayout, null, ({ prefixCls }) => (React.createElement(Picker, Object.assign({}, otherProps, { ref: pickerRef, visible: visible, className: cls(className, `${prefixCls}-date-picker`), cascade: false, data: data, value: value, onPickerChange: _handlePickerChange, onOk: _handlePickerConfirm, touchToStop: touchToStop, renderExtraHeader: isRange
353
+ ? () => (React.createElement("div", { className: `${prefixCls}-date-picker-show` },
354
+ React.createElement("span", { className: cls(`${activeTabIndex === 0
355
+ ? `${prefixCls}-date-picker-range-item-active`
356
+ : ''}`, `${prefixCls}-date-picker-range-item`), onClick: () => _chooseTimeActive(0) }, leftTimeString),
357
+ renderSeparator ? (renderSeparator()) : (React.createElement("span", { className: `${prefixCls}-date-picker-show-separate` }, "~")),
358
+ React.createElement("span", { className: cls(`${activeTabIndex === 1
359
+ ? `${prefixCls}-date-picker-range-item-active`
360
+ : ''}`, `${prefixCls}-date-picker-range-item`), onClick: () => _chooseTimeActive(1) }, rightTimeString)))
361
+ : undefined, renderLinkedContainer: renderLinkedContainer
205
362
  ? () => renderLinkedContainer(isEmptyValue(props.currentTs) ? undefined : currentTs, keyOptions)
206
363
  : undefined })))));
207
364
  });
@@ -510,6 +510,41 @@
510
510
  * }
511
511
  * ```
512
512
  */
513
+ .arco-date-picker-show {
514
+ display: -webkit-box;
515
+ display: -webkit-flex;
516
+ display: flex;
517
+ font-size: 0.32rem ;
518
+ padding: 0 0.32rem ;
519
+ color: #c9cdd4 ;
520
+ min-height: 0.96rem ;
521
+ background-color: #FBFCFC ;
522
+ }
523
+ .arco-date-picker-show > span {
524
+ display: -webkit-box;
525
+ display: -webkit-flex;
526
+ display: flex;
527
+ -webkit-box-align: center;
528
+ -webkit-align-items: center;
529
+ align-items: center;
530
+ -webkit-box-pack: center;
531
+ -webkit-justify-content: center;
532
+ justify-content: center;
533
+ }
534
+ .arco-date-picker-show-separate {
535
+ -webkit-box-flex: 0;
536
+ -webkit-flex: 0 1 auto;
537
+ flex: 0 1 auto;
538
+ min-width: 0.96rem ;
539
+ }
540
+ .arco-date-picker-range-item {
541
+ -webkit-box-flex: 1;
542
+ -webkit-flex: 1 0 auto;
543
+ flex: 1 0 auto;
544
+ }
545
+ .arco-date-picker-range-item-active {
546
+ color: #1d2129 ;
547
+ }
513
548
  /***************************************************
514
549
  * *
515
550
  * Arco Theme Style *
@@ -523,4 +558,11 @@
523
558
  background: #2e2e30 ;
524
559
  color: #929293 ;
525
560
  }
561
+ .arco-theme-dark .arco-date-picker-show {
562
+ color: #5f5f60 ;
563
+ background-color: #1E1E1E ;
564
+ }
565
+ .arco-theme-dark .arco-date-picker-range-item-active {
566
+ color: #f6f6f6 ;
567
+ }
526
568
  /********************* End *************************/
@@ -1,7 +1,29 @@
1
1
  @import '../../../style/mixin.less';
2
2
 
3
3
  .@{prefix}-date-picker {
4
-
4
+ &-show {
5
+ display: flex;
6
+ .use-var(font-size, date-picker-range-font-size);
7
+ .use-var(padding, date-picker-range-show-padding);
8
+ .use-var(color, date-picker-range-disabled-font-color);
9
+ .use-var(min-height, date-picker-range-show-min-height);
10
+ .use-var(background-color, date-picker-range-background-color);
11
+ & > span {
12
+ display: flex;
13
+ align-items: center;
14
+ justify-content: center;
15
+ }
16
+ &-separate {
17
+ flex: 0 1 auto;
18
+ .use-var(min-width, date-picker-range-separate-min-width);
19
+ }
20
+ }
21
+ &-range-item {
22
+ flex: 1 0 auto;
23
+ &-active {
24
+ .use-var(color, date-picker-range-font-color);
25
+ }
26
+ }
5
27
  }
6
28
 
7
29
  /***************************************************
@@ -26,5 +48,20 @@
26
48
  .use-var(color, dark-sub-info-font-color);
27
49
  }
28
50
  }
51
+ .@{prefix}-date-picker {
52
+ &-show {
53
+ @{arco-dark-mode-selector} & {
54
+ .use-var(color, dark-date-picker-range-disabled-font-color);
55
+ .use-var(background-color, dark-date-picker-range-background-color);
56
+ }
57
+ }
58
+ &-range-item {
59
+ &-active {
60
+ @{arco-dark-mode-selector} & {
61
+ .use-var(color, dark-date-picker-range-font-color);
62
+ }
63
+ }
64
+ }
65
+ }
29
66
  }
30
67
  /********************* End *************************/
@@ -40,18 +40,18 @@ export interface DatePickerProps extends Omit<PickerProps, 'data' | 'cascade' |
40
40
  * 点击选中时执行的回调
41
41
  * @en Callback when clicking OK
42
42
  */
43
- onOk?: (timestamp: number, obj: IDateObj) => void;
43
+ onOk?: (timestamp: number | [number, number], obj: IDateObj | [IDateObj, IDateObj]) => void;
44
44
  /**
45
45
  * 当前选中的时间,timestamp
46
46
  * @en The currently selected time, timestamp
47
47
  * @default Date.now()
48
48
  */
49
- currentTs?: number;
49
+ currentTs?: number | [number, number];
50
50
  /**
51
51
  * 选中后的回调
52
52
  * @en Callback when value is changed
53
53
  */
54
- onChange?: (timestamp: number, obj: IDateObj) => void;
54
+ onChange?: (timestamp: number | [number, number], obj: IDateObj | [IDateObj, IDateObj]) => void;
55
55
  /**
56
56
  * 每列数据选择变化后的回调函数
57
57
  * @en The callback function after each column data selection changes
@@ -75,20 +75,31 @@ export interface DatePickerProps extends Omit<PickerProps, 'data' | 'cascade' |
75
75
  * @default 当前时间的前十年
76
76
  * @default_en 10 years ago from the current time
77
77
  */
78
- minTs?: number;
78
+ minTs?: number | {
79
+ startTs: number;
80
+ endTs: number;
81
+ };
79
82
  /**
80
83
  * 最大可选日期,timestamp
81
84
  * @en Maximum selectable date, timestamp
82
85
  * @default 当前时间的后十年
83
86
  * @default_en Next decade from current time
84
87
  */
85
- maxTs?: number;
88
+ maxTs?: number | {
89
+ startTs: number;
90
+ endTs: number;
91
+ };
86
92
  /**
87
93
  * 是否使用 UTC 时间
88
94
  * @en Whether to use UTC
89
95
  * @default false
90
96
  */
91
97
  useUTC?: boolean;
98
+ /**
99
+ * 日期时间范围选择展示格式
100
+ * @en Time range picker display format
101
+ */
102
+ rangeItemFormat?: string;
92
103
  /**
93
104
  * 各可选项展示的格式化方法,参数type为ItemTypes,参数value为当前行的值,返回展示的文字
94
105
  * @en The formatting method of each optional item, the parameter type is ItemTypes, the parameter value is the value of the current row, and the displayed text is returned.
@@ -106,9 +117,14 @@ export interface DatePickerProps extends Omit<PickerProps, 'data' | 'cascade' |
106
117
  * @en Selector list item intervention to insert custom options.
107
118
  */
108
119
  columnsProcessor?: (columns: PickerData[][], currentDateObj: IDateObj) => PickerData[][];
120
+ /**
121
+ * 自定义分隔符
122
+ * @en Defined separator area
123
+ */
124
+ renderSeparator?: () => React.ReactNode;
109
125
  /**
110
126
  * 将选择器的展现隐藏状态及选中值的展示与某个容器关联,传入后将同时渲染该容器和选择器组件,此时选择器组件的 visible 和 onHide 属性可不传,点击该容器会唤起选择器
111
127
  * @en Associate the hidden state of the picker and the display of the selected value with a container. After passing it in, the container and the picker component will be rendered at the same time. At this time, the visible and onHide attributes of the picker component are optional values. Clicking the container will evoke the picker
112
128
  */
113
- renderLinkedContainer?: (currentTs: number | undefined, itemTypes: ItemType[]) => ReactNode;
129
+ renderLinkedContainer?: (currentTs: number | [number, number] | undefined, itemTypes: ItemType[]) => ReactNode;
114
130
  }
@@ -2,7 +2,7 @@
2
2
  export declare function DefaultPickerLinkedContainer({ value }: {
3
3
  value: (string | number)[];
4
4
  }): JSX.Element;
5
- export declare function DefaultDatePickerLinkedContainer({ ts, types }: {
6
- ts: number;
5
+ export declare function DefaultDatePickerLinkedContainer({ ts, types, }: {
6
+ ts: number | [number, number];
7
7
  types: string[];
8
8
  }): JSX.Element;
@@ -7,10 +7,15 @@ export function DefaultPickerLinkedContainer({ value }) {
7
7
  const className = `${prefixCls}-form-picker-link-container`;
8
8
  return (React.createElement("div", { className: className }, value && value.length ? (value.join('-')) : (React.createElement("span", { className: `${className}-placeholder` }, locale?.Form.pickerDefaultHint))));
9
9
  }
10
- export function DefaultDatePickerLinkedContainer({ ts, types }) {
10
+ export function DefaultDatePickerLinkedContainer({ ts, types, }) {
11
11
  const { prefixCls, locale } = useContext(GlobalContext);
12
12
  const className = `${prefixCls}-form-picker-link-container`;
13
- const dateTimeStr = useMemo(() => formatDateTimeStr(ts, types), [ts, types]);
13
+ const dateTimeStr = useMemo(() => {
14
+ if (typeof ts === 'number') {
15
+ return formatDateTimeStr(ts, types);
16
+ }
17
+ return `${formatDateTimeStr(ts[0], types)} ~ ${formatDateTimeStr(ts[1], types)}`;
18
+ }, [ts, types]);
14
19
  function formatDateTimeStr(timestamp, itemTypes) {
15
20
  const dateObj = convertTsToDateObj(timestamp);
16
21
  const validDateObj = Object.keys(dateObj).reduce((acc, key) => ({
@@ -7,7 +7,7 @@ import { useLatestRef, useListenResize } from '../_helpers';
7
7
  export * from './type';
8
8
  export { MultiPicker, PickerCell, Cascader } from '../picker-view';
9
9
  const Picker = forwardRef((props, ref) => {
10
- const { className, itemStyle, cascade = true, cols = 3, rows = 5, data, okText, dismissText, disabled = false, clickable = true, hideEmptyCols = false, title = '', visible: userSetVisible, value, needBottomOffset = false, onDismiss, onOk, onChange, maskClosable = false, onHide, onPickerChange, touchToStop, gestureOutOfControl = true, renderLinkedContainer, ...otherProps } = props;
10
+ const { className, itemStyle, cascade = true, cols = 3, rows = 5, data, okText, dismissText, disabled = false, clickable = true, hideEmptyCols = false, title = '', visible: userSetVisible, value, needBottomOffset = false, onDismiss, onOk, onChange, maskClosable = false, onHide, onPickerChange, touchToStop, gestureOutOfControl = true, renderLinkedContainer, renderExtraHeader, ...otherProps } = props;
11
11
  const scrollValueRef = useLatestRef(value);
12
12
  const domRef = useRef(null);
13
13
  const pickerViewRef = useRef(null);
@@ -79,6 +79,7 @@ const Picker = forwardRef((props, ref) => {
79
79
  React.createElement("div", { className: `${prefixCls}-picker-header-btn left`, onClick: handleDismiss }, dismissText || locale?.Picker.cancelText),
80
80
  React.createElement("div", { className: `${prefixCls}-picker-header-title` }, title),
81
81
  React.createElement("div", { className: `${prefixCls}-picker-header-btn right`, onClick: handleConfirm }, okText || locale?.Picker.okText)),
82
+ renderExtraHeader && renderExtraHeader(),
82
83
  React.createElement(PickerView, { ref: pickerViewRef, data: data, cascade: cascade, cols: cols, rows: rows, disabled: disabled, value: value, onPickerChange: onPickerChange, itemStyle: itemStyle, clickable: clickable, hideEmptyCols: hideEmptyCols, touchToStop: touchToStop })))))));
83
84
  });
84
85
  /**
@@ -128,4 +128,9 @@ export interface PickerProps extends Omit<PopupProps, 'visible' | 'close' | 'chi
128
128
  * @en Associate the hidden state of the picker and the display of the selected value with a container. After passing it in, the container and the picker component will be rendered at the same time. At this time, the visible and onHide attributes of the picker component are optional values. Clicking the container will evoke the picker
129
129
  */
130
130
  renderLinkedContainer?: (value: ValueType[], data: PickerData[]) => ReactNode;
131
+ /**
132
+ * 自定义头部扩展区域
133
+ * @en Define the area of extra header
134
+ */
135
+ renderExtraHeader?: () => ReactNode;
131
136
  }
@@ -36,7 +36,7 @@ export function SearchBarAssociation(props) {
36
36
  if (renderAssociationItem) {
37
37
  node = renderAssociationItem(item, index, node);
38
38
  }
39
- return (React.createElement("div", { key: index, className: `${searchBarAssociationPrefixCls}-item`, onClick: () => onAssociationItemClick?.(item, index) }, node));
39
+ return (React.createElement("div", { key: index, className: `${searchBarAssociationPrefixCls}-item`, onClick: e => onAssociationItemClick?.(item, index, e) }, node));
40
40
  };
41
41
  const renderContent = () => {
42
42
  const associationContent = associationItems.map(renderItem);
@@ -57,7 +57,7 @@ export interface SearchBarAssociationProps<Data = Record<string, any>> {
57
57
  * 每行搜索结果的点击回调
58
58
  * @en Click callback for each row of search results
59
59
  */
60
- onAssociationItemClick?: (item: SearchAssociationItem<Data>, index: number) => void;
60
+ onAssociationItemClick?: (item: SearchAssociationItem<Data>, index: number, event: React.MouseEvent<HTMLDivElement, MouseEvent>) => void;
61
61
  /**
62
62
  * 搜索联想框整体被点击的回调
63
63
  * @en The callback for the overall click of the search association box
@@ -1,4 +1,5 @@
1
1
  import { useState } from 'react';
2
+ import { Promise } from 'es6-promise';
2
3
  export default function useValue(params) {
3
4
  const { defaultValue, formatter, max, min, value, digits } = params;
4
5
  const [innerValue, setInnerValue] = useState(defaultValue);
@@ -247,7 +247,7 @@ const Tabs = forwardRef((props, ref) => {
247
247
  }
248
248
  function updateLayout() {
249
249
  const { width, height } = getOffset(domRef.current);
250
- cellRef.current && cellRef.current.resetUnderlineStyle();
250
+ cellRef.current && cellRef.current.updateLayout();
251
251
  setWrapWidth(width || domRef.current?.offsetWidth || 0);
252
252
  setWrapHeight(height || domRef.current?.offsetHeight || 0);
253
253
  paneRef.current && paneRef.current.setCurrentHeight();
@@ -561,8 +561,8 @@ export interface TabCellRef {
561
561
  */
562
562
  setCaterpillarAnimate: (ratio?: number) => void;
563
563
  /**
564
- * 重新计算下划线样式
565
- * @en Recalculate underline style
564
+ * 重新计算下划线样式(仅重算位置,如果 tab cell DOM 被人为改变,请调用 updateLayout)
565
+ * @en Recalculate underline style (only recalculate position, if the tab cell DOM is changed manually, please call updateLayout)
566
566
  */
567
567
  resetUnderlineStyle: () => void;
568
568
  /**
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@arco-design/mobile-react",
3
- "version": "2.35.2",
3
+ "version": "2.36.0",
4
4
  "description": "",
5
5
  "main": "cjs/index.js",
6
6
  "module": "esm/index.js",
@@ -15,7 +15,7 @@
15
15
  "author": "taoyiyue@bytedance.com",
16
16
  "license": "ISC",
17
17
  "dependencies": {
18
- "@arco-design/mobile-utils": "2.20.4",
18
+ "@arco-design/mobile-utils": "2.21.0",
19
19
  "@arco-design/transformable": "^1.0.0",
20
20
  "@babel/runtime": "^7",
21
21
  "lodash.throttle": "^4.1.1",
@@ -47,5 +47,5 @@
47
47
  "publishConfig": {
48
48
  "access": "public"
49
49
  },
50
- "gitHead": "a60bba95c16b19816c23b4e59b4db57d16137589"
50
+ "gitHead": "e61b011d31905626ef7082a4a29faf2a03db93cf"
51
51
  }
@@ -1093,4 +1093,14 @@
1093
1093
  --uploader-disabled-delete-icon-color: var(--disabled-color);
1094
1094
  --dark-uploader-item-text-error-color: var(--dark-danger-color);
1095
1095
  --uploader-item-text-error-color: var(--danger-color);
1096
+ --date-picker-range-font-size: ~`pxtorem(16)`;
1097
+ --date-picker-range-background-color: #FBFCFC;
1098
+ --dark-date-picker-range-background-color: #1E1E1E;
1099
+ --dark-date-picker-range-font-color: var(--dark-font-color);
1100
+ --date-picker-range-font-color: var(--font-color);
1101
+ --dark-date-picker-range-disabled-font-color: var(--dark-disabled-color);
1102
+ --date-picker-range-disabled-font-color: var(--disabled-color);
1103
+ --date-picker-range-show-padding: 0 ~`pxtorem(16)`;
1104
+ --date-picker-range-show-min-height: ~`pxtorem(48)`;
1105
+ --date-picker-range-separate-min-width: ~`pxtorem(48)`;
1096
1106
  }
@@ -1092,6 +1092,16 @@ export interface ArcodesignToken extends Record<string, string> {
1092
1092
  'uploader-disabled-delete-icon-color': string;
1093
1093
  'dark-uploader-item-text-error-color': string;
1094
1094
  'uploader-item-text-error-color': string;
1095
+ 'date-picker-range-font-size': string;
1096
+ 'date-picker-range-background-color': string;
1097
+ 'dark-date-picker-range-background-color': string;
1098
+ 'dark-date-picker-range-font-color': string;
1099
+ 'date-picker-range-font-color': string;
1100
+ 'dark-date-picker-range-disabled-font-color': string;
1101
+ 'date-picker-range-disabled-font-color': string;
1102
+ 'date-picker-range-show-padding': string;
1103
+ 'date-picker-range-show-min-height': string;
1104
+ 'date-picker-range-separate-min-width': string;
1095
1105
  }
1096
1106
  declare const tokens: ArcodesignToken;
1097
1107
  export default tokens;