@fjyueke/arco-mcp 1.0.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.
- package/README.md +85 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +244 -0
- package/metaData/components/action-sheet/doc.md +102 -0
- package/metaData/components/action-sheet/example/index.tsx +199 -0
- package/metaData/components/action-sheet/example/methods.tsx +6 -0
- package/metaData/components/avatar/doc.md +57 -0
- package/metaData/components/avatar/example/group.tsx +69 -0
- package/metaData/components/avatar/example/index.tsx +196 -0
- package/metaData/components/badge/doc.md +28 -0
- package/metaData/components/badge/example/index.tsx +128 -0
- package/metaData/components/button/doc.md +45 -0
- package/metaData/components/button/example/index.tsx +264 -0
- package/metaData/components/carousel/doc.md +89 -0
- package/metaData/components/carousel/example/index.tsx +1481 -0
- package/metaData/components/cell/doc.md +68 -0
- package/metaData/components/cell/example/arrow.tsx +13 -0
- package/metaData/components/cell/example/cell.tsx +71 -0
- package/metaData/components/cell/example/group.tsx +63 -0
- package/metaData/components/cell/example/index.tsx +19 -0
- package/metaData/components/checkbox/doc.md +91 -0
- package/metaData/components/checkbox/example/checkbox.tsx +158 -0
- package/metaData/components/checkbox/example/group.tsx +103 -0
- package/metaData/components/checkbox/example/index.tsx +25 -0
- package/metaData/components/circle-progress/doc.md +40 -0
- package/metaData/components/circle-progress/example/index.tsx +323 -0
- package/metaData/components/collapse/doc.md +74 -0
- package/metaData/components/collapse/example/collapse.tsx +183 -0
- package/metaData/components/collapse/example/group.tsx +136 -0
- package/metaData/components/collapse/example/index.tsx +16 -0
- package/metaData/components/collapse/example/utils.tsx +20 -0
- package/metaData/components/context-provider/doc.md +44 -0
- package/metaData/components/context-provider/example/index.tsx +208 -0
- package/metaData/components/count-down/doc.md +40 -0
- package/metaData/components/count-down/example/hooks.tsx +118 -0
- package/metaData/components/count-down/example/index.tsx +63 -0
- package/metaData/components/date-picker/doc.md +102 -0
- package/metaData/components/date-picker/example/index.tsx +545 -0
- package/metaData/components/dialog/doc.md +200 -0
- package/metaData/components/dialog/example/index.tsx +328 -0
- package/metaData/components/dialog/example/methods.tsx +56 -0
- package/metaData/components/divider/doc.md +25 -0
- package/metaData/components/divider/example/index.tsx +87 -0
- package/metaData/components/dropdown/doc.md +80 -0
- package/metaData/components/dropdown/example/dropdown.tsx +308 -0
- package/metaData/components/dropdown/example/index.tsx +19 -0
- package/metaData/components/dropdown/example/options.tsx +103 -0
- package/metaData/components/dropdown-menu/doc.md +91 -0
- package/metaData/components/dropdown-menu/example/dropdown-menu.tsx +270 -0
- package/metaData/components/dropdown-menu/example/index.tsx +16 -0
- package/metaData/components/ellipsis/doc.md +33 -0
- package/metaData/components/ellipsis/example/index.tsx +93 -0
- package/metaData/components/ellipsis/example/js-ellipsis.tsx +229 -0
- package/metaData/components/ellipsis/example/native-ellipsis.tsx +48 -0
- package/metaData/components/form/doc.md +90 -0
- package/metaData/components/form/example/form-item-context.tsx +8 -0
- package/metaData/components/form/example/form-item.tsx +378 -0
- package/metaData/components/form/example/index.tsx +87 -0
- package/metaData/components/form/example/linked-container.tsx +66 -0
- package/metaData/components/grid/doc.md +39 -0
- package/metaData/components/grid/example/index.tsx +252 -0
- package/metaData/components/icon/doc.md +15 -0
- package/metaData/components/icon/example/index.tsx +32 -0
- package/metaData/components/image/doc.md +62 -0
- package/metaData/components/image/example/index.tsx +528 -0
- package/metaData/components/image-picker/doc.md +116 -0
- package/metaData/components/image-picker/example/add-icon.tsx +14 -0
- package/metaData/components/image-picker/example/index.tsx +175 -0
- package/metaData/components/image-preview/doc.md +119 -0
- package/metaData/components/image-preview/example/index.tsx +1290 -0
- package/metaData/components/image-preview/example/methods.tsx +72 -0
- package/metaData/components/index-bar/doc.md +83 -0
- package/metaData/components/index-bar/example/group.tsx +93 -0
- package/metaData/components/index-bar/example/index.tsx +271 -0
- package/metaData/components/index-bar/example/side-bar.tsx +82 -0
- package/metaData/components/input/doc.md +60 -0
- package/metaData/components/input/example/hooks.tsx +259 -0
- package/metaData/components/input/example/index.tsx +134 -0
- package/metaData/components/input/example/props.tsx +183 -0
- package/metaData/components/keyboard/doc.md +73 -0
- package/metaData/components/keyboard/example/index.tsx +238 -0
- package/metaData/components/load-more/doc.md +48 -0
- package/metaData/components/load-more/example/index.tsx +395 -0
- package/metaData/components/loading/doc.md +34 -0
- package/metaData/components/loading/example/index.tsx +312 -0
- package/metaData/components/masking/doc.md +93 -0
- package/metaData/components/masking/example/index.tsx +410 -0
- package/metaData/components/masking/example/methods.tsx +88 -0
- package/metaData/components/nav-bar/doc.md +40 -0
- package/metaData/components/nav-bar/example/back-icon.tsx +28 -0
- package/metaData/components/nav-bar/example/index.tsx +305 -0
- package/metaData/components/notice-bar/doc.md +34 -0
- package/metaData/components/notice-bar/example/index.tsx +294 -0
- package/metaData/components/notify/doc.md +81 -0
- package/metaData/components/notify/example/index.tsx +171 -0
- package/metaData/components/notify/example/methods.tsx +83 -0
- package/metaData/components/pagination/doc.md +41 -0
- package/metaData/components/pagination/example/arrow.tsx +14 -0
- package/metaData/components/pagination/example/index.tsx +292 -0
- package/metaData/components/picker/doc.md +89 -0
- package/metaData/components/picker/example/index.tsx +217 -0
- package/metaData/components/picker-view/doc.md +57 -0
- package/metaData/components/picker-view/example/cascader.tsx +141 -0
- package/metaData/components/picker-view/example/index.tsx +297 -0
- package/metaData/components/picker-view/example/multi-picker.tsx +66 -0
- package/metaData/components/picker-view/example/picker-cell.tsx +416 -0
- package/metaData/components/popover/doc.md +144 -0
- package/metaData/components/popover/example/index.tsx +23 -0
- package/metaData/components/popover/example/menu.tsx +145 -0
- package/metaData/components/popover/example/popover-inner.tsx +147 -0
- package/metaData/components/popover/example/popover.tsx +268 -0
- package/metaData/components/popup/doc.md +101 -0
- package/metaData/components/popup/example/index.tsx +125 -0
- package/metaData/components/popup/example/methods.tsx +6 -0
- package/metaData/components/popup-swiper/doc.md +108 -0
- package/metaData/components/popup-swiper/example/index.tsx +332 -0
- package/metaData/components/popup-swiper/example/methods.tsx +6 -0
- package/metaData/components/portal/doc.md +14 -0
- package/metaData/components/portal/example/index.tsx +35 -0
- package/metaData/components/progress/doc.md +42 -0
- package/metaData/components/progress/example/index.tsx +256 -0
- package/metaData/components/pull-refresh/doc.md +37 -0
- package/metaData/components/pull-refresh/example/android-pull-refresh.tsx +260 -0
- package/metaData/components/pull-refresh/example/index.tsx +44 -0
- package/metaData/components/pull-refresh/example/ios-pull-refresh.tsx +216 -0
- package/metaData/components/radio/doc.md +89 -0
- package/metaData/components/radio/example/group.tsx +92 -0
- package/metaData/components/radio/example/index.tsx +25 -0
- package/metaData/components/radio/example/radio.tsx +22 -0
- package/metaData/components/rate/doc.md +33 -0
- package/metaData/components/rate/example/index.tsx +281 -0
- package/metaData/components/search-bar/doc.md +97 -0
- package/metaData/components/search-bar/example/association.tsx +89 -0
- package/metaData/components/search-bar/example/cancel-button.tsx +34 -0
- package/metaData/components/search-bar/example/highlight.tsx +66 -0
- package/metaData/components/search-bar/example/index.tsx +251 -0
- package/metaData/components/show-monitor/doc.md +34 -0
- package/metaData/components/show-monitor/example/index.tsx +646 -0
- package/metaData/components/skeleton/doc.md +101 -0
- package/metaData/components/skeleton/example/elements.tsx +290 -0
- package/metaData/components/skeleton/example/index.tsx +96 -0
- package/metaData/components/skeleton/example/skeleton-context.tsx +7 -0
- package/metaData/components/slider/doc.md +42 -0
- package/metaData/components/slider/example/index.tsx +326 -0
- package/metaData/components/slider/example/marks.tsx +50 -0
- package/metaData/components/slider/example/popover.tsx +38 -0
- package/metaData/components/slider/example/thumb.tsx +48 -0
- package/metaData/components/slider/example/useSliderIcon.tsx +38 -0
- package/metaData/components/slider/example/useSliderInit.tsx +170 -0
- package/metaData/components/stepper/doc.md +46 -0
- package/metaData/components/stepper/example/index.tsx +166 -0
- package/metaData/components/stepper/example/useButtonClick.tsx +74 -0
- package/metaData/components/stepper/example/useInputEvent.tsx +65 -0
- package/metaData/components/stepper/example/useValue.tsx +43 -0
- package/metaData/components/steps/doc.md +57 -0
- package/metaData/components/steps/example/index.tsx +123 -0
- package/metaData/components/steps/example/step.tsx +126 -0
- package/metaData/components/sticky/doc.md +45 -0
- package/metaData/components/sticky/example/index.tsx +430 -0
- package/metaData/components/swipe-action/doc.md +44 -0
- package/metaData/components/swipe-action/example/index.tsx +338 -0
- package/metaData/components/swipe-action/example/item.tsx +40 -0
- package/metaData/components/swipe-load/doc.md +43 -0
- package/metaData/components/swipe-load/example/index.tsx +339 -0
- package/metaData/components/swipe-load/example/type.tsx +153 -0
- package/metaData/components/switch/doc.md +38 -0
- package/metaData/components/switch/example/index.tsx +237 -0
- package/metaData/components/tab-bar/doc.md +57 -0
- package/metaData/components/tab-bar/example/index.tsx +18 -0
- package/metaData/components/tab-bar/example/item.tsx +74 -0
- package/metaData/components/tab-bar/example/tab-bar.tsx +105 -0
- package/metaData/components/tabs/doc.md +187 -0
- package/metaData/components/tabs/example/index.tsx +514 -0
- package/metaData/components/tabs/example/tab-cell-underline.tsx +320 -0
- package/metaData/components/tabs/example/tab-cell.tsx +433 -0
- package/metaData/components/tabs/example/tab-pane.tsx +349 -0
- package/metaData/components/tag/doc.md +80 -0
- package/metaData/components/tag/example/index.tsx +23 -0
- package/metaData/components/tag/example/list.tsx +97 -0
- package/metaData/components/tag/example/tag.tsx +85 -0
- package/metaData/components/textarea/doc.md +67 -0
- package/metaData/components/textarea/example/index.tsx +258 -0
- package/metaData/components/toast/doc.md +90 -0
- package/metaData/components/toast/example/index.tsx +335 -0
- package/metaData/components/toast/example/methods.tsx +87 -0
- package/metaData/components/transition/doc.md +19 -0
- package/metaData/components/transition/example/index.tsx +113 -0
- package/metaData/components/uploader/doc.md +82 -0
- package/metaData/components/uploader/example/index.tsx +208 -0
- package/metaData/components-index.json +242 -0
- package/package.json +56 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
import { cls } from '@arco-design/mobile-utils';
|
|
2
|
+
import React, { useRef, forwardRef, Ref, useImperativeHandle } from 'react';
|
|
3
|
+
import { ContextLayout } from '../context-provider';
|
|
4
|
+
import { getStyleWithVendor, useProgress } from '../_helpers';
|
|
5
|
+
|
|
6
|
+
type PercentPosition = 'left' | 'innerLeft' | 'right' | 'follow';
|
|
7
|
+
export type BezierType = [number, number, number, number];
|
|
8
|
+
export interface ProgressProps {
|
|
9
|
+
/**
|
|
10
|
+
* 自定义类名
|
|
11
|
+
* @en Custom classname
|
|
12
|
+
*/
|
|
13
|
+
className?: string;
|
|
14
|
+
/**
|
|
15
|
+
* 自定义样式
|
|
16
|
+
* @en Custom stylesheet
|
|
17
|
+
*/
|
|
18
|
+
style?: React.CSSProperties;
|
|
19
|
+
/**
|
|
20
|
+
* 文字显示位置
|
|
21
|
+
* @en Text display position
|
|
22
|
+
* @default "center"
|
|
23
|
+
*/
|
|
24
|
+
percentPosition?: PercentPosition;
|
|
25
|
+
/**
|
|
26
|
+
* 是否显示进度条内部文字
|
|
27
|
+
* @en Whether to display the text inside the progress bar
|
|
28
|
+
* @default true
|
|
29
|
+
*/
|
|
30
|
+
showPercent?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* 进度环百分比
|
|
33
|
+
* @en Progress percentage
|
|
34
|
+
*/
|
|
35
|
+
percentage: number;
|
|
36
|
+
/**
|
|
37
|
+
* 进度条内部文字显示(一个函数,返回ReactNode类型,回调参数为当前进度百分比)
|
|
38
|
+
* @en The text display inside the progress bar (a function that returns the ReactNode type, and the callback parameter is the current progress percentage)
|
|
39
|
+
*/
|
|
40
|
+
renderPercent?: (percentage: number) => React.ReactNode;
|
|
41
|
+
/**
|
|
42
|
+
* 轨道颜色
|
|
43
|
+
* @en Track color
|
|
44
|
+
*/
|
|
45
|
+
trackColor?: string;
|
|
46
|
+
/**
|
|
47
|
+
* 进度条颜色
|
|
48
|
+
* @en Progress bar color
|
|
49
|
+
*/
|
|
50
|
+
progressColor?: string;
|
|
51
|
+
/**
|
|
52
|
+
* 是否置灰
|
|
53
|
+
* @en Whether to be disabled
|
|
54
|
+
* @default false
|
|
55
|
+
*/
|
|
56
|
+
disabled?: boolean;
|
|
57
|
+
/**
|
|
58
|
+
* 轨道粗细
|
|
59
|
+
* @en Track thickness
|
|
60
|
+
* @default 一般默认为4,percentPosition=innerLeft 时为18,mode=nav时为2
|
|
61
|
+
* @default_en Generally the default is 4, when percentPosition=innerLeft is 18, when mode=nav is 2
|
|
62
|
+
*/
|
|
63
|
+
trackStroke?: number;
|
|
64
|
+
/**
|
|
65
|
+
* 进度条粗细
|
|
66
|
+
* @en progress bar thickness
|
|
67
|
+
* @default 继承 trackStroke 值
|
|
68
|
+
* @default_en Inherit trackStroke value
|
|
69
|
+
*/
|
|
70
|
+
progressStroke?: number;
|
|
71
|
+
/**
|
|
72
|
+
* 每增加step步长所需的毫秒数
|
|
73
|
+
* @en The number of milliseconds required to increase the step size
|
|
74
|
+
* @default 300
|
|
75
|
+
*/
|
|
76
|
+
duration?: number;
|
|
77
|
+
/**
|
|
78
|
+
* 步长(增加步长,以step增长)
|
|
79
|
+
* @en Step size (increase the step size, grow by step)
|
|
80
|
+
* @default 1
|
|
81
|
+
*/
|
|
82
|
+
step?: number;
|
|
83
|
+
/**
|
|
84
|
+
* 进度条是否两端圆角
|
|
85
|
+
* @en Whether the progress bar has rounded corners at both ends
|
|
86
|
+
* @default true
|
|
87
|
+
*/
|
|
88
|
+
filleted?: boolean;
|
|
89
|
+
/**
|
|
90
|
+
* 初始化percentage时是否以动画形式过渡到目的值
|
|
91
|
+
* @en Whether to animate the transition to the destination value when initializing percentage
|
|
92
|
+
* @default true
|
|
93
|
+
*/
|
|
94
|
+
mountedTransition?: boolean;
|
|
95
|
+
/**
|
|
96
|
+
* 初始化时动画的贝塞尔曲线
|
|
97
|
+
* @en Animated bezier curves at initialization
|
|
98
|
+
* @default [0.34, 0.69, 0.1, 1]
|
|
99
|
+
*/
|
|
100
|
+
mountedBezier?: BezierType;
|
|
101
|
+
/**
|
|
102
|
+
* 模式可选为nav或者base模式
|
|
103
|
+
* @en The mode can be selected as nav or base mode
|
|
104
|
+
* @default "base"
|
|
105
|
+
*/
|
|
106
|
+
mode?: 'nav' | 'base';
|
|
107
|
+
/**
|
|
108
|
+
* 距离屏幕顶部的距离(只有当mode为"nav"才有效)
|
|
109
|
+
* @en The distance from the top of the screen (only valid when mode is "nav")
|
|
110
|
+
* @default 0
|
|
111
|
+
*/
|
|
112
|
+
top?: number;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export interface ProgressRef {
|
|
116
|
+
/**
|
|
117
|
+
* 最外层元素 DOM
|
|
118
|
+
* @en The outermost element DOM
|
|
119
|
+
*/
|
|
120
|
+
dom: HTMLDivElement | null;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* 进度条组件,可根据外界传递进来的百分比进行进度展示
|
|
125
|
+
* @en Progress bar, which can display progress according to the percentage passed in from the outside
|
|
126
|
+
* @type 反馈
|
|
127
|
+
* @type_en Feedback
|
|
128
|
+
* @name 进度条
|
|
129
|
+
* @name_en Progress
|
|
130
|
+
*/
|
|
131
|
+
const Progress = forwardRef((props: ProgressProps, ref: Ref<ProgressRef>) => {
|
|
132
|
+
const { mode = 'base' } = props;
|
|
133
|
+
const percentage = Math.min(100, Math.max(props.percentage, 0));
|
|
134
|
+
const {
|
|
135
|
+
top,
|
|
136
|
+
percentPosition = 'right',
|
|
137
|
+
className = '',
|
|
138
|
+
style,
|
|
139
|
+
showPercent = mode === 'base',
|
|
140
|
+
renderPercent,
|
|
141
|
+
trackColor,
|
|
142
|
+
progressColor,
|
|
143
|
+
disabled = false,
|
|
144
|
+
trackStroke,
|
|
145
|
+
progressStroke,
|
|
146
|
+
duration = 300,
|
|
147
|
+
step = 1,
|
|
148
|
+
filleted = true,
|
|
149
|
+
mountedTransition = true,
|
|
150
|
+
mountedBezier = [0.34, 0.69, 0.1, 1],
|
|
151
|
+
} = props;
|
|
152
|
+
const domRef = useRef<HTMLDivElement | null>(null);
|
|
153
|
+
const [currentPercentage, transitionControl] = useProgress(
|
|
154
|
+
mountedTransition,
|
|
155
|
+
percentage,
|
|
156
|
+
duration,
|
|
157
|
+
mountedBezier,
|
|
158
|
+
step,
|
|
159
|
+
);
|
|
160
|
+
useImperativeHandle(ref, () => ({
|
|
161
|
+
dom: domRef.current,
|
|
162
|
+
}));
|
|
163
|
+
function renderText(position?: PercentPosition) {
|
|
164
|
+
if (!showPercent) {
|
|
165
|
+
return null;
|
|
166
|
+
}
|
|
167
|
+
if (position === 'follow') {
|
|
168
|
+
return renderPercent !== void 0 ? (
|
|
169
|
+
renderPercent(currentPercentage)
|
|
170
|
+
) : (
|
|
171
|
+
<div
|
|
172
|
+
className={cls('text-follow', {
|
|
173
|
+
'inner-disabled inner-block-disabled': disabled,
|
|
174
|
+
})}
|
|
175
|
+
style={{ background: progressColor }}
|
|
176
|
+
>
|
|
177
|
+
{currentPercentage}%
|
|
178
|
+
</div>
|
|
179
|
+
);
|
|
180
|
+
}
|
|
181
|
+
if (position === percentPosition) {
|
|
182
|
+
return (
|
|
183
|
+
<div
|
|
184
|
+
style={{ color: progressColor }}
|
|
185
|
+
className={cls('text', `text-${percentPosition}`, {
|
|
186
|
+
'text-disabled':
|
|
187
|
+
disabled && (percentPosition === 'left' || percentPosition === 'right'),
|
|
188
|
+
})}
|
|
189
|
+
>
|
|
190
|
+
{renderPercent !== void 0
|
|
191
|
+
? renderPercent(currentPercentage)
|
|
192
|
+
: `${currentPercentage}%`}
|
|
193
|
+
</div>
|
|
194
|
+
);
|
|
195
|
+
}
|
|
196
|
+
return null;
|
|
197
|
+
}
|
|
198
|
+
function renderBarProgress({ prefixCls }) {
|
|
199
|
+
return (
|
|
200
|
+
<div
|
|
201
|
+
role="progressbar"
|
|
202
|
+
aria-valuenow={percentage}
|
|
203
|
+
aria-valuemax={100}
|
|
204
|
+
aria-valuemin={0}
|
|
205
|
+
className={cls(
|
|
206
|
+
`${prefixCls}-progress`,
|
|
207
|
+
{ 'progress-fixed': mode === 'nav' },
|
|
208
|
+
{ 'progress-disabled': disabled },
|
|
209
|
+
className,
|
|
210
|
+
)}
|
|
211
|
+
style={{
|
|
212
|
+
top,
|
|
213
|
+
...style,
|
|
214
|
+
}}
|
|
215
|
+
ref={domRef}
|
|
216
|
+
>
|
|
217
|
+
<div className="progress-wrapper">
|
|
218
|
+
{renderText('left')}
|
|
219
|
+
<div
|
|
220
|
+
style={{
|
|
221
|
+
background: trackColor,
|
|
222
|
+
height: trackStroke,
|
|
223
|
+
}}
|
|
224
|
+
className={cls(
|
|
225
|
+
'progress-track',
|
|
226
|
+
`position-${percentPosition}`,
|
|
227
|
+
{ filleted },
|
|
228
|
+
{ 'nav-mode': mode === 'nav' },
|
|
229
|
+
)}
|
|
230
|
+
>
|
|
231
|
+
<div
|
|
232
|
+
style={getStyleWithVendor({
|
|
233
|
+
background: progressColor,
|
|
234
|
+
width: `${currentPercentage}%`,
|
|
235
|
+
height: progressStroke,
|
|
236
|
+
transition: transitionControl
|
|
237
|
+
? `width linear ${duration / 1000}s`
|
|
238
|
+
: '',
|
|
239
|
+
})}
|
|
240
|
+
className={cls('progress-bar', { 'bar-disabled': disabled, filleted })}
|
|
241
|
+
>
|
|
242
|
+
{percentPosition === 'follow' ? (
|
|
243
|
+
<div className="wrapper">{renderText('follow')}</div>
|
|
244
|
+
) : null}
|
|
245
|
+
</div>
|
|
246
|
+
</div>
|
|
247
|
+
{renderText('right')}
|
|
248
|
+
{renderText('innerLeft')}
|
|
249
|
+
</div>
|
|
250
|
+
</div>
|
|
251
|
+
);
|
|
252
|
+
}
|
|
253
|
+
return <ContextLayout>{renderBarProgress}</ContextLayout>;
|
|
254
|
+
});
|
|
255
|
+
|
|
256
|
+
export default Progress;
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
### 其他
|
|
2
|
+
|
|
3
|
+
# 下拉刷新 PullRefresh
|
|
4
|
+
|
|
5
|
+
下拉刷新数据组件。
|
|
6
|
+
|
|
7
|
+
======
|
|
8
|
+
|
|
9
|
+
> 属性/Props
|
|
10
|
+
|
|
11
|
+
|参数|描述|类型|默认值|
|
|
12
|
+
|----------|-------------|------|------|
|
|
13
|
+
|type|下拉刷新组件不同的实现方式,android \- 常规的外层容器 transform,ios \- 利用 ios scrollTop 负值实现下拉及回弹(性能优于transform),仅ios可用。指定该属性值后优先级高于 useIosOptimize|"ios" \| "android"|跟随系统|
|
|
14
|
+
|useIosOptimize|在 ios 上是否使用 scrollTop 负值实现下拉及回弹,而不是 transform,关闭后所有机型都使用 transform 的方式|boolean|false|
|
|
15
|
+
|children|子元素|ReactNode|必填|
|
|
16
|
+
|className|样式类名|string|-|
|
|
17
|
+
|style|自定义样式|CSSProperties|-|
|
|
18
|
+
|disabled|是否禁用|boolean|false|
|
|
19
|
+
|finishDelay|加载完成后,展示加载完成的时间(ms)|number|300|
|
|
20
|
+
|loosingText|下拉到可释放时的展示元素(type 为 ios 失效)|ReactNode|-|
|
|
21
|
+
|loadingText|加载中的展示元素|ReactNode|-|
|
|
22
|
+
|pullingText|下拉时的展示元素|ReactNode|-|
|
|
23
|
+
|finishText|加载完成的展示元素|ReactNode|-|
|
|
24
|
+
|initialText|初始状态还未下拉时的展示元素|ReactNode|pullingText属性值|
|
|
25
|
+
|dampRate|阻尼系数(type 为 ios 失效)|number|4|
|
|
26
|
+
|onRefresh|刷新触发事件|() =\> Promise\<void\>|-|
|
|
27
|
+
|useHideAsNestedScroll|惯性滑动时隐藏展示元素|boolean|true|
|
|
28
|
+
|loosingMinHeight|释放可刷线的最小距离(px)|number|loosingText 的高度|
|
|
29
|
+
|allowPullWhenNotTop|未滚到顶部时向下滑动也允许触发下拉刷新,可能影响ios回弹动画效果|boolean|false|
|
|
30
|
+
|
|
31
|
+
> 引用/Refs
|
|
32
|
+
|
|
33
|
+
|参数|描述|类型|
|
|
34
|
+
|----------|-------------|------|
|
|
35
|
+
|dom|最外层元素 DOM|HTMLDivElement|
|
|
36
|
+
|refresh|主动触发刷新,执行完成动画后异步返回|() =\> Promise\<void\>|
|
|
37
|
+
|updateIOSHeight|手动更新 IOS 容器自动高度|() =\> void|
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import React, {
|
|
2
|
+
useRef,
|
|
3
|
+
forwardRef,
|
|
4
|
+
Ref,
|
|
5
|
+
useCallback,
|
|
6
|
+
useMemo,
|
|
7
|
+
useContext,
|
|
8
|
+
useEffect,
|
|
9
|
+
useImperativeHandle,
|
|
10
|
+
} from 'react';
|
|
11
|
+
import { cls, nextTick, defaultLocale } from '@arco-design/mobile-utils';
|
|
12
|
+
import { Promise } from 'es6-promise';
|
|
13
|
+
import Loading from '../loading';
|
|
14
|
+
import { GlobalContext } from '../context-provider';
|
|
15
|
+
import { PullRefreshRef, PullRefreshStatus, PullRefreshBasicProps } from './model';
|
|
16
|
+
import { useCommonState, useAddScrollEvents, useCheckAsStart } from './hooks';
|
|
17
|
+
import { setStyleWithVendor } from '../_helpers';
|
|
18
|
+
|
|
19
|
+
const dampRateCalculate = (val: number, tipsHeight: number, dampRate: number) =>
|
|
20
|
+
val > tipsHeight ? tipsHeight + (val - tipsHeight) / dampRate : val;
|
|
21
|
+
|
|
22
|
+
export const PullRefresh = forwardRef((props: PullRefreshBasicProps, ref: Ref<PullRefreshRef>) => {
|
|
23
|
+
const { prefixCls, locale = defaultLocale } = useContext(GlobalContext);
|
|
24
|
+
|
|
25
|
+
const {
|
|
26
|
+
className,
|
|
27
|
+
style,
|
|
28
|
+
children,
|
|
29
|
+
loosingText = (
|
|
30
|
+
<div className={cls(`${prefixCls}-pull-refresh-label-text`)}>
|
|
31
|
+
<span>{locale.PullRefresh.loosingText}</span>
|
|
32
|
+
</div>
|
|
33
|
+
),
|
|
34
|
+
loadingText = (
|
|
35
|
+
<div className={cls(`${prefixCls}-pull-refresh-label-text`)}>
|
|
36
|
+
<Loading type="circle" radius={4} />
|
|
37
|
+
<span>{locale.PullRefresh.loadingText}</span>
|
|
38
|
+
</div>
|
|
39
|
+
),
|
|
40
|
+
pullingText = (
|
|
41
|
+
<div className={cls(`${prefixCls}-pull-refresh-label-text`)}>
|
|
42
|
+
<span>{locale.PullRefresh.pullingText}</span>
|
|
43
|
+
</div>
|
|
44
|
+
),
|
|
45
|
+
finishText = (
|
|
46
|
+
<div className={cls(`${prefixCls}-pull-refresh-label-text`)}>
|
|
47
|
+
<span>{locale.PullRefresh.finishText}</span>
|
|
48
|
+
</div>
|
|
49
|
+
),
|
|
50
|
+
initialText,
|
|
51
|
+
finishDelay = 300,
|
|
52
|
+
loosingMinHeight,
|
|
53
|
+
dampRate = 4,
|
|
54
|
+
disabled = false,
|
|
55
|
+
useHideAsNestedScroll = true,
|
|
56
|
+
onRefresh,
|
|
57
|
+
allowPullWhenNotTop = false,
|
|
58
|
+
} = props;
|
|
59
|
+
const placeRef = useRef<HTMLDivElement>(null);
|
|
60
|
+
const touchRef = useRef<{ start: number; x: number; y: number } | null>(null);
|
|
61
|
+
const currentTranslateYRef = useRef(0);
|
|
62
|
+
const onTouching = useRef(false);
|
|
63
|
+
const {
|
|
64
|
+
loadingRef,
|
|
65
|
+
status,
|
|
66
|
+
setStatus,
|
|
67
|
+
labelRef,
|
|
68
|
+
domRef,
|
|
69
|
+
touching,
|
|
70
|
+
setTouching,
|
|
71
|
+
loosingHeight,
|
|
72
|
+
handleRefresh,
|
|
73
|
+
tipsHeight,
|
|
74
|
+
} = useCommonState({ loosingMinHeight, onRefresh });
|
|
75
|
+
|
|
76
|
+
const { ifShouldHandle } = useCheckAsStart({ domRef, allowPullWhenNotTop });
|
|
77
|
+
|
|
78
|
+
const currentLabelStyle = useMemo(() => {
|
|
79
|
+
return useHideAsNestedScroll &&
|
|
80
|
+
!touching &&
|
|
81
|
+
status === PullRefreshStatus.Pulling &&
|
|
82
|
+
(domRef?.current?.scrollTop ?? 0) > 0
|
|
83
|
+
? { opacity: 0 }
|
|
84
|
+
: {};
|
|
85
|
+
}, [useHideAsNestedScroll, touching]);
|
|
86
|
+
|
|
87
|
+
const pullTextConfig = {
|
|
88
|
+
[PullRefreshStatus.Static]: initialText === void 0 ? pullingText : initialText,
|
|
89
|
+
[PullRefreshStatus.Pulling]: pullingText,
|
|
90
|
+
[PullRefreshStatus.Loosing]: loosingText || pullingText,
|
|
91
|
+
[PullRefreshStatus.Loading]: loadingText,
|
|
92
|
+
[PullRefreshStatus.Finish]: finishText,
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const scroll = (y: number, ms: number, callback?: () => void) => {
|
|
96
|
+
if (y < 5) {
|
|
97
|
+
if (y < 0 || ms === 0) {
|
|
98
|
+
currentTranslateYRef.current = 0;
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
const translateY = dampRateCalculate(y, loosingHeight, dampRate);
|
|
103
|
+
currentTranslateYRef.current = translateY;
|
|
104
|
+
placeRef.current &&
|
|
105
|
+
setStyleWithVendor(placeRef.current, {
|
|
106
|
+
transform: translateY ? `translateY(${translateY}px) translateZ(0)` : '',
|
|
107
|
+
...(ms ? { transition: `all ${ms / 1000}s` } : {}),
|
|
108
|
+
});
|
|
109
|
+
callback &&
|
|
110
|
+
setTimeout(() => {
|
|
111
|
+
callback();
|
|
112
|
+
}, ms);
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const reset = (callback = () => {}) => {
|
|
116
|
+
scroll(0, 300, () => {
|
|
117
|
+
if (domRef.current && domRef.current.scrollTop < 0) {
|
|
118
|
+
domRef.current.scrollTop = 0;
|
|
119
|
+
}
|
|
120
|
+
loadingRef.current = false;
|
|
121
|
+
setStatus(PullRefreshStatus.Static);
|
|
122
|
+
placeRef.current && setStyleWithVendor(placeRef.current, { transition: '' });
|
|
123
|
+
callback();
|
|
124
|
+
});
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
const handleTouchStart = useCallback(
|
|
128
|
+
(e: HTMLElementEventMap['touchstart']) => {
|
|
129
|
+
if (disabled || touchRef.current || loadingRef.current || !domRef.current) return;
|
|
130
|
+
if (!ifShouldHandle()) return;
|
|
131
|
+
setTouching(true);
|
|
132
|
+
const { pageX, pageY } = e.touches[0];
|
|
133
|
+
if (pageX && pageY) {
|
|
134
|
+
touchRef.current = { start: domRef.current?.scrollTop, x: pageX, y: pageY };
|
|
135
|
+
}
|
|
136
|
+
setStatus(PullRefreshStatus.Pulling);
|
|
137
|
+
},
|
|
138
|
+
[disabled, ifShouldHandle],
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
const refresh = () =>
|
|
142
|
+
new Promise<void>(resolve => {
|
|
143
|
+
setStatus(PullRefreshStatus.Loading);
|
|
144
|
+
nextTick(() => {
|
|
145
|
+
scroll(tipsHeight, 300);
|
|
146
|
+
handleRefresh().then(() => {
|
|
147
|
+
if (pullTextConfig[PullRefreshStatus.Finish]) {
|
|
148
|
+
setStatus(PullRefreshStatus.Finish);
|
|
149
|
+
setTimeout(() => {
|
|
150
|
+
reset(resolve);
|
|
151
|
+
}, finishDelay);
|
|
152
|
+
} else {
|
|
153
|
+
reset(resolve);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
});
|
|
158
|
+
const handleTouchEnd = useCallback(() => {
|
|
159
|
+
if (currentTranslateYRef.current === 0 && !ifShouldHandle()) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
onTouching.current = false;
|
|
163
|
+
setTouching(false);
|
|
164
|
+
|
|
165
|
+
if (disabled || !touchRef.current || loadingRef.current) return;
|
|
166
|
+
touchRef.current = null;
|
|
167
|
+
if (status === PullRefreshStatus.Loosing) {
|
|
168
|
+
refresh();
|
|
169
|
+
} else {
|
|
170
|
+
reset();
|
|
171
|
+
}
|
|
172
|
+
}, [disabled, status, tipsHeight, ifShouldHandle]);
|
|
173
|
+
|
|
174
|
+
const handleTouchMove = useCallback(
|
|
175
|
+
(e: HTMLElementEventMap['touchmove']) => {
|
|
176
|
+
onTouching.current = true;
|
|
177
|
+
|
|
178
|
+
if (disabled || loadingRef.current || !domRef.current) return;
|
|
179
|
+
|
|
180
|
+
if (!touchRef.current) return;
|
|
181
|
+
const { pageY } = e.touches[0];
|
|
182
|
+
const pullY = pageY - touchRef.current.y - touchRef.current.start;
|
|
183
|
+
|
|
184
|
+
if (currentTranslateYRef.current === 0 && domRef.current.scrollTop > 0) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
if (currentTranslateYRef.current === 0 && pullY < 0) {
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
setStatus(() =>
|
|
192
|
+
pullY > loosingHeight ? PullRefreshStatus.Loosing : PullRefreshStatus.Pulling,
|
|
193
|
+
);
|
|
194
|
+
scroll(pullY, 0);
|
|
195
|
+
|
|
196
|
+
e.stopPropagation();
|
|
197
|
+
e.cancelable && e.preventDefault();
|
|
198
|
+
},
|
|
199
|
+
[disabled, loosingHeight],
|
|
200
|
+
);
|
|
201
|
+
|
|
202
|
+
useEffect(() => {
|
|
203
|
+
const onScroll = () => {
|
|
204
|
+
if (
|
|
205
|
+
onTouching.current &&
|
|
206
|
+
domRef.current &&
|
|
207
|
+
(domRef.current.scrollTop < 0 || currentTranslateYRef.current)
|
|
208
|
+
) {
|
|
209
|
+
// 禁止 ios 负 scrollTop 和双层滚动
|
|
210
|
+
domRef.current.scrollTop = 0;
|
|
211
|
+
}
|
|
212
|
+
};
|
|
213
|
+
domRef.current?.addEventListener('scroll', onScroll);
|
|
214
|
+
return () => {
|
|
215
|
+
domRef.current?.removeEventListener('scroll', onScroll);
|
|
216
|
+
};
|
|
217
|
+
}, []);
|
|
218
|
+
|
|
219
|
+
useImperativeHandle(ref, () => ({
|
|
220
|
+
dom: domRef.current,
|
|
221
|
+
refresh,
|
|
222
|
+
updateIOSHeight() {
|
|
223
|
+
console.warn('updateIOSHeight 仅在 type="ios" 时可用');
|
|
224
|
+
},
|
|
225
|
+
}));
|
|
226
|
+
|
|
227
|
+
useAddScrollEvents({ domRef, handleTouchStart, handleTouchMove, handleTouchEnd });
|
|
228
|
+
|
|
229
|
+
return (
|
|
230
|
+
<div
|
|
231
|
+
className={cls(`${prefixCls}-pull-refresh all-border-box is-android`, className, {
|
|
232
|
+
'is-disabled':
|
|
233
|
+
(disabled || (!touching && useHideAsNestedScroll)) &&
|
|
234
|
+
status !== PullRefreshStatus.Loading,
|
|
235
|
+
})}
|
|
236
|
+
style={style}
|
|
237
|
+
ref={domRef}
|
|
238
|
+
>
|
|
239
|
+
<div className={cls(`${prefixCls}-pull-refresh-place`)} ref={placeRef}>
|
|
240
|
+
<div
|
|
241
|
+
className={cls(`${prefixCls}-pull-refresh-label`)}
|
|
242
|
+
ref={labelRef}
|
|
243
|
+
style={currentLabelStyle}
|
|
244
|
+
>
|
|
245
|
+
{pullTextConfig[status]}
|
|
246
|
+
</div>
|
|
247
|
+
<div
|
|
248
|
+
className={cls(`${prefixCls}-pull-refresh-content`, {
|
|
249
|
+
'is-loading': [
|
|
250
|
+
PullRefreshStatus.Loading,
|
|
251
|
+
PullRefreshStatus.Finish,
|
|
252
|
+
].includes(status),
|
|
253
|
+
})}
|
|
254
|
+
>
|
|
255
|
+
{children}
|
|
256
|
+
</div>
|
|
257
|
+
</div>
|
|
258
|
+
</div>
|
|
259
|
+
);
|
|
260
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import React, { forwardRef, Ref } from 'react';
|
|
2
|
+
import { PullRefresh as IOSPullRefresh } from './ios-pull-refresh';
|
|
3
|
+
import { PullRefresh as AndroidPullRefresh } from './android-pull-refresh';
|
|
4
|
+
import { PullRefreshBasicProps, PullRefreshRef } from './model';
|
|
5
|
+
import { useSystem } from '../_helpers';
|
|
6
|
+
|
|
7
|
+
export type { PullRefreshRef } from './model';
|
|
8
|
+
|
|
9
|
+
export interface PullRefreshProps extends PullRefreshBasicProps {
|
|
10
|
+
/**
|
|
11
|
+
* 下拉刷新组件不同的实现方式,android - 常规的外层容器 transform,ios - 利用 ios scrollTop 负值实现下拉及回弹(性能优于transform),仅ios可用。指定该属性值后优先级高于 useIosOptimize
|
|
12
|
+
* @en Different implementation methods of PullRefresh, android - conventional outer container transform, ios - use ios scrollTop negative value to achieve pull-down and rebound (performance is better than transform), only available for ios. After specifying value, the priority is higher than useIosOptimize
|
|
13
|
+
* @default 跟随系统
|
|
14
|
+
* @default_en Follow the system
|
|
15
|
+
*/
|
|
16
|
+
type?: 'ios' | 'android';
|
|
17
|
+
/**
|
|
18
|
+
* 在 ios 上是否使用 scrollTop 负值实现下拉及回弹,而不是 transform,关闭后所有机型都使用 transform 的方式
|
|
19
|
+
* @en Whether to use the negative value of scrollTop on ios to achieve pull-down and rebound instead of transform. After closing, all models use transform
|
|
20
|
+
* @default false
|
|
21
|
+
*/
|
|
22
|
+
useIosOptimize?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* 下拉刷新数据组件。
|
|
27
|
+
* @en PullRefresh component that pulls down to refresh data.
|
|
28
|
+
* @name 下拉刷新
|
|
29
|
+
* @name_en PullRefresh
|
|
30
|
+
* @type 其他
|
|
31
|
+
* @type_en Others
|
|
32
|
+
*/
|
|
33
|
+
const PullRefresh = forwardRef((props: PullRefreshProps, ref: Ref<PullRefreshRef>) => {
|
|
34
|
+
const { type, useIosOptimize, children, ...rest } = props;
|
|
35
|
+
const system = useSystem();
|
|
36
|
+
|
|
37
|
+
const Container =
|
|
38
|
+
type === 'ios' || (useIosOptimize && (type || system) === 'ios')
|
|
39
|
+
? IOSPullRefresh
|
|
40
|
+
: AndroidPullRefresh;
|
|
41
|
+
return <Container {...{ ...rest, ref }}>{children}</Container>;
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
export default PullRefresh;
|