@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.
Files changed (191) hide show
  1. package/README.md +85 -0
  2. package/dist/index.d.ts +1 -0
  3. package/dist/index.js +244 -0
  4. package/metaData/components/action-sheet/doc.md +102 -0
  5. package/metaData/components/action-sheet/example/index.tsx +199 -0
  6. package/metaData/components/action-sheet/example/methods.tsx +6 -0
  7. package/metaData/components/avatar/doc.md +57 -0
  8. package/metaData/components/avatar/example/group.tsx +69 -0
  9. package/metaData/components/avatar/example/index.tsx +196 -0
  10. package/metaData/components/badge/doc.md +28 -0
  11. package/metaData/components/badge/example/index.tsx +128 -0
  12. package/metaData/components/button/doc.md +45 -0
  13. package/metaData/components/button/example/index.tsx +264 -0
  14. package/metaData/components/carousel/doc.md +89 -0
  15. package/metaData/components/carousel/example/index.tsx +1481 -0
  16. package/metaData/components/cell/doc.md +68 -0
  17. package/metaData/components/cell/example/arrow.tsx +13 -0
  18. package/metaData/components/cell/example/cell.tsx +71 -0
  19. package/metaData/components/cell/example/group.tsx +63 -0
  20. package/metaData/components/cell/example/index.tsx +19 -0
  21. package/metaData/components/checkbox/doc.md +91 -0
  22. package/metaData/components/checkbox/example/checkbox.tsx +158 -0
  23. package/metaData/components/checkbox/example/group.tsx +103 -0
  24. package/metaData/components/checkbox/example/index.tsx +25 -0
  25. package/metaData/components/circle-progress/doc.md +40 -0
  26. package/metaData/components/circle-progress/example/index.tsx +323 -0
  27. package/metaData/components/collapse/doc.md +74 -0
  28. package/metaData/components/collapse/example/collapse.tsx +183 -0
  29. package/metaData/components/collapse/example/group.tsx +136 -0
  30. package/metaData/components/collapse/example/index.tsx +16 -0
  31. package/metaData/components/collapse/example/utils.tsx +20 -0
  32. package/metaData/components/context-provider/doc.md +44 -0
  33. package/metaData/components/context-provider/example/index.tsx +208 -0
  34. package/metaData/components/count-down/doc.md +40 -0
  35. package/metaData/components/count-down/example/hooks.tsx +118 -0
  36. package/metaData/components/count-down/example/index.tsx +63 -0
  37. package/metaData/components/date-picker/doc.md +102 -0
  38. package/metaData/components/date-picker/example/index.tsx +545 -0
  39. package/metaData/components/dialog/doc.md +200 -0
  40. package/metaData/components/dialog/example/index.tsx +328 -0
  41. package/metaData/components/dialog/example/methods.tsx +56 -0
  42. package/metaData/components/divider/doc.md +25 -0
  43. package/metaData/components/divider/example/index.tsx +87 -0
  44. package/metaData/components/dropdown/doc.md +80 -0
  45. package/metaData/components/dropdown/example/dropdown.tsx +308 -0
  46. package/metaData/components/dropdown/example/index.tsx +19 -0
  47. package/metaData/components/dropdown/example/options.tsx +103 -0
  48. package/metaData/components/dropdown-menu/doc.md +91 -0
  49. package/metaData/components/dropdown-menu/example/dropdown-menu.tsx +270 -0
  50. package/metaData/components/dropdown-menu/example/index.tsx +16 -0
  51. package/metaData/components/ellipsis/doc.md +33 -0
  52. package/metaData/components/ellipsis/example/index.tsx +93 -0
  53. package/metaData/components/ellipsis/example/js-ellipsis.tsx +229 -0
  54. package/metaData/components/ellipsis/example/native-ellipsis.tsx +48 -0
  55. package/metaData/components/form/doc.md +90 -0
  56. package/metaData/components/form/example/form-item-context.tsx +8 -0
  57. package/metaData/components/form/example/form-item.tsx +378 -0
  58. package/metaData/components/form/example/index.tsx +87 -0
  59. package/metaData/components/form/example/linked-container.tsx +66 -0
  60. package/metaData/components/grid/doc.md +39 -0
  61. package/metaData/components/grid/example/index.tsx +252 -0
  62. package/metaData/components/icon/doc.md +15 -0
  63. package/metaData/components/icon/example/index.tsx +32 -0
  64. package/metaData/components/image/doc.md +62 -0
  65. package/metaData/components/image/example/index.tsx +528 -0
  66. package/metaData/components/image-picker/doc.md +116 -0
  67. package/metaData/components/image-picker/example/add-icon.tsx +14 -0
  68. package/metaData/components/image-picker/example/index.tsx +175 -0
  69. package/metaData/components/image-preview/doc.md +119 -0
  70. package/metaData/components/image-preview/example/index.tsx +1290 -0
  71. package/metaData/components/image-preview/example/methods.tsx +72 -0
  72. package/metaData/components/index-bar/doc.md +83 -0
  73. package/metaData/components/index-bar/example/group.tsx +93 -0
  74. package/metaData/components/index-bar/example/index.tsx +271 -0
  75. package/metaData/components/index-bar/example/side-bar.tsx +82 -0
  76. package/metaData/components/input/doc.md +60 -0
  77. package/metaData/components/input/example/hooks.tsx +259 -0
  78. package/metaData/components/input/example/index.tsx +134 -0
  79. package/metaData/components/input/example/props.tsx +183 -0
  80. package/metaData/components/keyboard/doc.md +73 -0
  81. package/metaData/components/keyboard/example/index.tsx +238 -0
  82. package/metaData/components/load-more/doc.md +48 -0
  83. package/metaData/components/load-more/example/index.tsx +395 -0
  84. package/metaData/components/loading/doc.md +34 -0
  85. package/metaData/components/loading/example/index.tsx +312 -0
  86. package/metaData/components/masking/doc.md +93 -0
  87. package/metaData/components/masking/example/index.tsx +410 -0
  88. package/metaData/components/masking/example/methods.tsx +88 -0
  89. package/metaData/components/nav-bar/doc.md +40 -0
  90. package/metaData/components/nav-bar/example/back-icon.tsx +28 -0
  91. package/metaData/components/nav-bar/example/index.tsx +305 -0
  92. package/metaData/components/notice-bar/doc.md +34 -0
  93. package/metaData/components/notice-bar/example/index.tsx +294 -0
  94. package/metaData/components/notify/doc.md +81 -0
  95. package/metaData/components/notify/example/index.tsx +171 -0
  96. package/metaData/components/notify/example/methods.tsx +83 -0
  97. package/metaData/components/pagination/doc.md +41 -0
  98. package/metaData/components/pagination/example/arrow.tsx +14 -0
  99. package/metaData/components/pagination/example/index.tsx +292 -0
  100. package/metaData/components/picker/doc.md +89 -0
  101. package/metaData/components/picker/example/index.tsx +217 -0
  102. package/metaData/components/picker-view/doc.md +57 -0
  103. package/metaData/components/picker-view/example/cascader.tsx +141 -0
  104. package/metaData/components/picker-view/example/index.tsx +297 -0
  105. package/metaData/components/picker-view/example/multi-picker.tsx +66 -0
  106. package/metaData/components/picker-view/example/picker-cell.tsx +416 -0
  107. package/metaData/components/popover/doc.md +144 -0
  108. package/metaData/components/popover/example/index.tsx +23 -0
  109. package/metaData/components/popover/example/menu.tsx +145 -0
  110. package/metaData/components/popover/example/popover-inner.tsx +147 -0
  111. package/metaData/components/popover/example/popover.tsx +268 -0
  112. package/metaData/components/popup/doc.md +101 -0
  113. package/metaData/components/popup/example/index.tsx +125 -0
  114. package/metaData/components/popup/example/methods.tsx +6 -0
  115. package/metaData/components/popup-swiper/doc.md +108 -0
  116. package/metaData/components/popup-swiper/example/index.tsx +332 -0
  117. package/metaData/components/popup-swiper/example/methods.tsx +6 -0
  118. package/metaData/components/portal/doc.md +14 -0
  119. package/metaData/components/portal/example/index.tsx +35 -0
  120. package/metaData/components/progress/doc.md +42 -0
  121. package/metaData/components/progress/example/index.tsx +256 -0
  122. package/metaData/components/pull-refresh/doc.md +37 -0
  123. package/metaData/components/pull-refresh/example/android-pull-refresh.tsx +260 -0
  124. package/metaData/components/pull-refresh/example/index.tsx +44 -0
  125. package/metaData/components/pull-refresh/example/ios-pull-refresh.tsx +216 -0
  126. package/metaData/components/radio/doc.md +89 -0
  127. package/metaData/components/radio/example/group.tsx +92 -0
  128. package/metaData/components/radio/example/index.tsx +25 -0
  129. package/metaData/components/radio/example/radio.tsx +22 -0
  130. package/metaData/components/rate/doc.md +33 -0
  131. package/metaData/components/rate/example/index.tsx +281 -0
  132. package/metaData/components/search-bar/doc.md +97 -0
  133. package/metaData/components/search-bar/example/association.tsx +89 -0
  134. package/metaData/components/search-bar/example/cancel-button.tsx +34 -0
  135. package/metaData/components/search-bar/example/highlight.tsx +66 -0
  136. package/metaData/components/search-bar/example/index.tsx +251 -0
  137. package/metaData/components/show-monitor/doc.md +34 -0
  138. package/metaData/components/show-monitor/example/index.tsx +646 -0
  139. package/metaData/components/skeleton/doc.md +101 -0
  140. package/metaData/components/skeleton/example/elements.tsx +290 -0
  141. package/metaData/components/skeleton/example/index.tsx +96 -0
  142. package/metaData/components/skeleton/example/skeleton-context.tsx +7 -0
  143. package/metaData/components/slider/doc.md +42 -0
  144. package/metaData/components/slider/example/index.tsx +326 -0
  145. package/metaData/components/slider/example/marks.tsx +50 -0
  146. package/metaData/components/slider/example/popover.tsx +38 -0
  147. package/metaData/components/slider/example/thumb.tsx +48 -0
  148. package/metaData/components/slider/example/useSliderIcon.tsx +38 -0
  149. package/metaData/components/slider/example/useSliderInit.tsx +170 -0
  150. package/metaData/components/stepper/doc.md +46 -0
  151. package/metaData/components/stepper/example/index.tsx +166 -0
  152. package/metaData/components/stepper/example/useButtonClick.tsx +74 -0
  153. package/metaData/components/stepper/example/useInputEvent.tsx +65 -0
  154. package/metaData/components/stepper/example/useValue.tsx +43 -0
  155. package/metaData/components/steps/doc.md +57 -0
  156. package/metaData/components/steps/example/index.tsx +123 -0
  157. package/metaData/components/steps/example/step.tsx +126 -0
  158. package/metaData/components/sticky/doc.md +45 -0
  159. package/metaData/components/sticky/example/index.tsx +430 -0
  160. package/metaData/components/swipe-action/doc.md +44 -0
  161. package/metaData/components/swipe-action/example/index.tsx +338 -0
  162. package/metaData/components/swipe-action/example/item.tsx +40 -0
  163. package/metaData/components/swipe-load/doc.md +43 -0
  164. package/metaData/components/swipe-load/example/index.tsx +339 -0
  165. package/metaData/components/swipe-load/example/type.tsx +153 -0
  166. package/metaData/components/switch/doc.md +38 -0
  167. package/metaData/components/switch/example/index.tsx +237 -0
  168. package/metaData/components/tab-bar/doc.md +57 -0
  169. package/metaData/components/tab-bar/example/index.tsx +18 -0
  170. package/metaData/components/tab-bar/example/item.tsx +74 -0
  171. package/metaData/components/tab-bar/example/tab-bar.tsx +105 -0
  172. package/metaData/components/tabs/doc.md +187 -0
  173. package/metaData/components/tabs/example/index.tsx +514 -0
  174. package/metaData/components/tabs/example/tab-cell-underline.tsx +320 -0
  175. package/metaData/components/tabs/example/tab-cell.tsx +433 -0
  176. package/metaData/components/tabs/example/tab-pane.tsx +349 -0
  177. package/metaData/components/tag/doc.md +80 -0
  178. package/metaData/components/tag/example/index.tsx +23 -0
  179. package/metaData/components/tag/example/list.tsx +97 -0
  180. package/metaData/components/tag/example/tag.tsx +85 -0
  181. package/metaData/components/textarea/doc.md +67 -0
  182. package/metaData/components/textarea/example/index.tsx +258 -0
  183. package/metaData/components/toast/doc.md +90 -0
  184. package/metaData/components/toast/example/index.tsx +335 -0
  185. package/metaData/components/toast/example/methods.tsx +87 -0
  186. package/metaData/components/transition/doc.md +19 -0
  187. package/metaData/components/transition/example/index.tsx +113 -0
  188. package/metaData/components/uploader/doc.md +82 -0
  189. package/metaData/components/uploader/example/index.tsx +208 -0
  190. package/metaData/components-index.json +242 -0
  191. package/package.json +56 -0
@@ -0,0 +1,326 @@
1
+ import React, {
2
+ useRef,
3
+ forwardRef,
4
+ Ref,
5
+ useImperativeHandle,
6
+ useContext,
7
+ useState,
8
+ useMemo,
9
+ useCallback,
10
+ ReactNode,
11
+ } from 'react';
12
+ import { cls, componentWrapper } from '@arco-design/mobile-utils';
13
+ import { GlobalContext } from '../context-provider';
14
+ import {
15
+ useSliderStyle,
16
+ useSliderIcon,
17
+ SliderContext,
18
+ baseRenderThumb,
19
+ useSliderInit,
20
+ useSliderEvents,
21
+ } from './hooks';
22
+ import Thumb from './thumb';
23
+ import Marks from './marks';
24
+
25
+ export interface SliderProps {
26
+ /**
27
+ * 自定义类名
28
+ * @en Custom classname
29
+ * @default ""
30
+ */
31
+ className?: string;
32
+ /**
33
+ * 自定义样式
34
+ * @en Custom stylesheet
35
+ * @default {}
36
+ */
37
+ style?: React.CSSProperties;
38
+ /**
39
+ * 是否禁用
40
+ * @en Disabled
41
+ * @default false
42
+ */
43
+ disabled?: boolean;
44
+ /**
45
+ * 使用范围选择
46
+ * @en Use range selection
47
+ * @default 根据 传入初始参数判断,没有则为 false
48
+ * @default_en Judging by the incoming initial parameters, false if not
49
+ */
50
+ useRange?: boolean;
51
+ /**
52
+ * 非点击状态使用动画
53
+ * @en Use animation for non-click state
54
+ * @default true
55
+ */
56
+ useAnimation?: boolean;
57
+ /**
58
+ * 最小值
59
+ * @en Minimum value
60
+ * @default 0
61
+ */
62
+ min?: number;
63
+ /**
64
+ * 最大值
65
+ * @en Maximum value
66
+ * @default 100
67
+ */
68
+ max?: number;
69
+ /**
70
+ * 默认初始值
71
+ * @en Default initial value
72
+ */
73
+ defaultValue?: number | [number, number];
74
+ /**
75
+ * 基础值,组件受控
76
+ * @en Value, component will be controlled
77
+ */
78
+ value?: number | [number, number];
79
+ /**
80
+ * 最小单位
81
+ * @en Step
82
+ * @default 1
83
+ */
84
+ step?: number;
85
+ /**
86
+ * 组件方向
87
+ * @en Component direction
88
+ * @default "horizontal"
89
+ */
90
+ type?: 'horizontal' | 'vertical';
91
+ /**
92
+ * 是否展示气泡
93
+ * @en Whether to show tooltips
94
+ * @default "auto"
95
+ */
96
+ showTooltip?: 'auto' | 'always' | 'never';
97
+ /**
98
+ * 滑动条节点配置
99
+ * @en Slider node configuration
100
+ */
101
+ marks?: number | number[] | Record<string, ReactNode>;
102
+ /**
103
+ * 是否展示标签底部文案
104
+ * @en Whether to display the bottom mark text
105
+ * @default false
106
+ */
107
+ showMarks?: boolean;
108
+ /**
109
+ * 是否只可用标志的值,覆盖 step
110
+ * @en Whether only the value of the mark is available, overriding step
111
+ * @default false
112
+ */
113
+ useMarkOnly?: boolean;
114
+ /**
115
+ * 前缀 icon 或者 文案
116
+ * @en prefix icon or label
117
+ */
118
+ prefixLabel?: boolean | ((value: number | [number, number]) => ReactNode) | ReactNode;
119
+ /**
120
+ * 后缀 icon 或者 文案
121
+ * @en Suffix icon or label
122
+ */
123
+ suffixLabel?: boolean | ((value: number | [number, number]) => ReactNode) | ReactNode;
124
+ /**
125
+ * 组件横条粗细,单位 px
126
+ * @en Slider bar thickness (unit: px)
127
+ * @default 2
128
+ */
129
+ size?: number | string;
130
+ /**
131
+ * 只允许拖动滑块 默认 false
132
+ * @en Only allow dragging of sliders, the default is false
133
+ * @default false
134
+ */
135
+ draggableTrackOnly?: boolean;
136
+ /**
137
+ * 自定义气泡内容
138
+ * @en Custom tooltip content
139
+ */
140
+ formatTooltip?: (value: number) => string | ReactNode;
141
+ /**
142
+ * 修改后事件,时机同 touchend
143
+ * @en Callback after value changes, the timing is the same as touchend
144
+ */
145
+ onAfterChange?: (value: number | [number, number]) => void;
146
+ /**
147
+ * 实时修改事件
148
+ * @en Callback when value changes in real time
149
+ */
150
+ onChange?: (value: number | [number, number]) => void;
151
+ /**
152
+ * 自定义滑块
153
+ * @en Custom slider
154
+ */
155
+ renderThumb?: (value: number) => ReactNode;
156
+ /**
157
+ * 自定义滑块的Popover,优先级高于formatTooltip。value表示当前滑动进度,visible表示气泡的可见性,index表示当前滑块索引,thumbEl表示当前滑块元素。
158
+ * @en Custom slider popover,priority is higher than formatTooltip. value - current sliding progress, visible - visibility of the bubble, index - current slider index, thumbEl - current slider element.
159
+ */
160
+ renderThumbPopover?: (config: {
161
+ value: number;
162
+ visible: boolean;
163
+ index: number;
164
+ thumbEl: React.ReactNode;
165
+ }) => ReactNode;
166
+ }
167
+
168
+ export interface SliderRef {
169
+ /**
170
+ * 最外层元素 DOM
171
+ * @en The outermost element DOM
172
+ */
173
+ dom: HTMLDivElement | null;
174
+ }
175
+
176
+ const Slider = forwardRef((_, ref: Ref<SliderRef>) => {
177
+ const { prefixCls = '', useRtl } = useContext(GlobalContext);
178
+ const { className, style, disabled, min, max, type, showTooltip, showMarks } =
179
+ useContext(SliderContext);
180
+ const domRef = useRef<HTMLDivElement>(null);
181
+ const lineRef = useRef<HTMLDivElement>(null);
182
+ // 拖动滑块的 index 为当前的 isTouching
183
+ // @en The index of the slider is the current isTouching
184
+ const [commonIsTouching, setCommonIsTouching] = useState<number>(-1);
185
+ const isHorizontal = /^horizontal/g.test(type);
186
+
187
+ useImperativeHandle(ref, () => ({
188
+ dom: domRef.current,
189
+ }));
190
+
191
+ const { firstRender, valueGroup, setValueGroup, runTimeConfig, isMultiThumb } = useSliderInit({
192
+ commonIsTouching,
193
+ });
194
+
195
+ // 最长线 div 位置
196
+ const getLinePosition = useCallback(() => {
197
+ const { width, left, top, height } = lineRef.current?.getBoundingClientRect() ?? {
198
+ width: 0,
199
+ left: 0,
200
+ top: 0,
201
+ height: 0,
202
+ };
203
+ const leftValue = useRtl ? left + width : left;
204
+ return {
205
+ length: isHorizontal ? width : height,
206
+ start: isHorizontal ? leftValue : top,
207
+ };
208
+ }, [isHorizontal, firstRender]);
209
+
210
+ const { heightStyle, transitionClass, activeLineStyle } = useSliderStyle({
211
+ getLinePosition,
212
+ commonIsTouching,
213
+ valueGroup,
214
+ });
215
+
216
+ useSliderEvents({
217
+ lineRef,
218
+ valueGroup,
219
+ setValueGroup,
220
+ getLinePosition,
221
+ setCommonIsTouching,
222
+ });
223
+ const { renderPrefixLabel, renderSuffixLabel } = useSliderIcon({ valueGroup });
224
+
225
+ /**
226
+ * 为了减少 dom 元素计算,只改变激活 line 的样式,让对应的 thumb 附着在两边,所以需要实时调整 className
227
+ * @en In order to reduce the calculation of dom elements, only the style of the active line is changed, so that the corresponding thumb is attached to both sides, so the className needs to be adjusted in real time
228
+ */
229
+ const thumbConfig = useMemo(() => {
230
+ if (isMultiThumb) {
231
+ const classNames = ['is-end', 'is-start'];
232
+ return Array(2)
233
+ .fill('')
234
+ .map((_, index) => {
235
+ let childClassName = classNames[index];
236
+ if (valueGroup[index] > valueGroup[1 - index]) {
237
+ [childClassName] = classNames;
238
+ } else if (valueGroup[index] < valueGroup[1 - index]) {
239
+ [, childClassName] = classNames;
240
+ }
241
+ return {
242
+ className: childClassName,
243
+ };
244
+ });
245
+ }
246
+ return [
247
+ {
248
+ className: 'is-end',
249
+ },
250
+ ];
251
+ /**
252
+ * 只有 range 状态才监听 valueGroup
253
+ * @en Only listen to valueGroup in the range state
254
+ */
255
+ }, [isMultiThumb && valueGroup]);
256
+
257
+ return (
258
+ <div
259
+ className={cls(`${prefixCls}-slider ${className}`, `is-${type}`, {
260
+ 'is-disabled': disabled,
261
+ 'show-tooltip': showTooltip !== 'never' && !disabled,
262
+ 'show-marks': showMarks,
263
+ })}
264
+ style={style}
265
+ ref={domRef}
266
+ role="slider"
267
+ aria-valuemin={min}
268
+ aria-valuemax={max}
269
+ aria-valuenow={Array.isArray(valueGroup) ? valueGroup[0] : valueGroup}
270
+ aria-disabled={disabled}
271
+ >
272
+ {isHorizontal ? renderPrefixLabel : renderSuffixLabel}
273
+ <div className={`${prefixCls}-slider-wrapper`}>
274
+ <Marks runTimeConfig={runTimeConfig} className={transitionClass} />
275
+ <div className={`${prefixCls}-slider-line`} style={heightStyle} ref={lineRef}>
276
+ <div
277
+ className={`${prefixCls}-slider-line is-activated ${transitionClass}`}
278
+ style={{ ...heightStyle, ...activeLineStyle }}
279
+ >
280
+ {thumbConfig.map((cfg, idx) => (
281
+ <Thumb
282
+ key={idx}
283
+ {...{
284
+ value: Array.isArray(valueGroup) ? valueGroup[idx] : valueGroup,
285
+ idx,
286
+ min,
287
+ max,
288
+ isTouching: commonIsTouching === idx,
289
+ ...cfg,
290
+ }}
291
+ />
292
+ ))}
293
+ </div>
294
+ </div>
295
+ </div>
296
+ {isHorizontal ? renderSuffixLabel : renderPrefixLabel}
297
+ </div>
298
+ );
299
+ });
300
+
301
+ const SliderWrapper = forwardRef((props: SliderProps, ref: Ref<SliderRef>) => {
302
+ const { prefixCls = '' } = useContext(GlobalContext);
303
+ const defaultProps = useContext(SliderContext);
304
+ const newProps = {
305
+ ...defaultProps,
306
+ renderThumb: baseRenderThumb(prefixCls),
307
+ ...props,
308
+ };
309
+
310
+ return (
311
+ <SliderContext.Provider value={newProps}>
312
+ <Slider ref={ref} />
313
+ </SliderContext.Provider>
314
+ );
315
+ });
316
+
317
+ /**
318
+ * 滑动型输入器,展示当前值和可选范围。
319
+ * @en Slide input component, displays the current value and optional range.
320
+ * @name 滑动输入条
321
+ * @name_en Slider
322
+ * @type 数据录入
323
+ * @type_en Data Entry
324
+ * @displayName Slider
325
+ */
326
+ export default componentWrapper(SliderWrapper, 'Slider');
@@ -0,0 +1,50 @@
1
+ import React, { useContext, CSSProperties, useCallback, ReactNode } from 'react';
2
+ import { cls } from '@arco-design/mobile-utils';
3
+ import { GlobalContext } from '../context-provider';
4
+ import { SliderContext } from './hooks';
5
+
6
+ function Marks({
7
+ runTimeConfig,
8
+ className = '',
9
+ style = {},
10
+ }: {
11
+ runTimeConfig: Array<{ value: number; activated: boolean; label: ReactNode }>;
12
+ className?: string;
13
+ style?: CSSProperties;
14
+ }) {
15
+ const { prefixCls = '', useRtl } = useContext(GlobalContext);
16
+ const { type, showMarks, max, min } = useContext(SliderContext);
17
+ const isHorizontal = /^horizontal/g.test(type);
18
+
19
+ const genMarkStyle = useCallback(
20
+ (value: number) => {
21
+ const leftStyle = useRtl ? 'right' : 'left';
22
+ return {
23
+ [isHorizontal ? leftStyle : 'bottom']: `${((value - min) / (max - min)) * 100}%`,
24
+ };
25
+ },
26
+ [isHorizontal, min, max],
27
+ );
28
+
29
+ return (
30
+ <div className={`${prefixCls}-slider-marks`}>
31
+ {runTimeConfig.map(({ value, label, activated }) => (
32
+ <div
33
+ key={value}
34
+ className={cls(
35
+ `${prefixCls}-slider-marks-item`,
36
+ { 'is-activated': activated },
37
+ className,
38
+ )}
39
+ style={{ ...genMarkStyle(value), ...style }}
40
+ >
41
+ {showMarks && (
42
+ <div className={`${prefixCls}-slider-marks-item-label`}>{label}</div>
43
+ )}
44
+ </div>
45
+ ))}
46
+ </div>
47
+ );
48
+ }
49
+
50
+ export default Marks;
@@ -0,0 +1,38 @@
1
+ import React, { useContext, ReactNode, useRef } from 'react';
2
+ import Transition from '../transition';
3
+ import { GlobalContext } from '../context-provider';
4
+
5
+ export function Popover({
6
+ visible,
7
+ content,
8
+ children,
9
+ }: {
10
+ visible: boolean;
11
+ content: ReactNode;
12
+ children: ReactNode;
13
+ }) {
14
+ const { prefixCls = '' } = useContext(GlobalContext);
15
+ const domRef = useRef<HTMLDivElement | null>(null);
16
+
17
+ return (
18
+ <div className={`${prefixCls}-slider-popover-wrapper`}>
19
+ <Transition
20
+ in={visible}
21
+ timeout={300}
22
+ type="fade"
23
+ mountOnEnter
24
+ unmountOnExit
25
+ nodeRef={domRef}
26
+ >
27
+ <div
28
+ className={`${prefixCls}-slider-popover${content ? '' : ' no-content'}`}
29
+ ref={domRef}
30
+ >
31
+ <div className={`${prefixCls}-slider-popover-content`}>{content}</div>
32
+ <div className={`${prefixCls}-slider-popover-arrow`} />
33
+ </div>
34
+ </Transition>
35
+ {children}
36
+ </div>
37
+ );
38
+ }
@@ -0,0 +1,48 @@
1
+ import React, { useMemo, CSSProperties, useContext } from 'react';
2
+ import { Popover } from './popover';
3
+ import { SliderContext } from './hooks';
4
+ import { GlobalContext } from '../context-provider';
5
+
6
+ function Thumb({
7
+ className = '',
8
+ value,
9
+ style,
10
+ isTouching,
11
+ idx,
12
+ }: {
13
+ className?: string;
14
+ value: number;
15
+ isTouching: boolean;
16
+ style?: CSSProperties;
17
+ idx: number;
18
+ }) {
19
+ const { prefixCls = '' } = useContext(GlobalContext);
20
+ const { showTooltip, renderThumb, formatTooltip, renderThumbPopover } =
21
+ useContext(SliderContext);
22
+ const isHidden = showTooltip === 'never';
23
+
24
+ const renderValue = useMemo(() => formatTooltip(value), [formatTooltip, value]);
25
+ const isTooltipVisible = useMemo(() => {
26
+ if (isHidden) return false;
27
+ if (showTooltip === 'always') return true;
28
+ return isTouching;
29
+ }, [showTooltip, isTouching]);
30
+
31
+ const thumbEl = typeof renderThumb === 'function' ? renderThumb(value) : renderThumb;
32
+ const popoverEl =
33
+ typeof renderThumbPopover === 'function' ? (
34
+ renderThumbPopover({ value, visible: isTooltipVisible, thumbEl, index: idx })
35
+ ) : (
36
+ <Popover visible={isTooltipVisible} content={renderValue}>
37
+ {thumbEl}
38
+ </Popover>
39
+ );
40
+
41
+ return (
42
+ <div className={`${prefixCls}-slider-thumb-wrapper ${className}`} style={style}>
43
+ {isHidden ? thumbEl : popoverEl}
44
+ </div>
45
+ );
46
+ }
47
+
48
+ export default Thumb;
@@ -0,0 +1,38 @@
1
+ import React, { useMemo, useContext, ReactNode } from 'react';
2
+ import { GlobalContext } from '../../context-provider';
3
+ import { SliderContext } from '.';
4
+
5
+ export const useSliderIcon = ({ valueGroup }: { valueGroup: number | [number, number] }) => {
6
+ const { prefixCls = '' } = useContext(GlobalContext);
7
+
8
+ const { max, suffixLabel, min, prefixLabel } = useContext(SliderContext);
9
+ const renderPrefixLabel = useMemo(() => {
10
+ if (!prefixLabel) return null;
11
+ let inner: ReactNode;
12
+ if (typeof prefixLabel === 'boolean' && prefixLabel) {
13
+ inner = min;
14
+ } else if (typeof prefixLabel === 'function') {
15
+ inner = prefixLabel(valueGroup);
16
+ } else {
17
+ inner = prefixLabel;
18
+ }
19
+ return <div className={`${prefixCls}-slider-label is-prefix`}>{inner}</div>;
20
+ }, [min, prefixLabel, valueGroup]);
21
+
22
+ const renderSuffixLabel = useMemo(() => {
23
+ if (!suffixLabel) return null;
24
+ let inner: ReactNode;
25
+ if (typeof suffixLabel === 'boolean' && suffixLabel) {
26
+ inner = max;
27
+ } else if (typeof suffixLabel === 'function') {
28
+ inner = suffixLabel(valueGroup);
29
+ } else {
30
+ inner = suffixLabel;
31
+ }
32
+ return <div className={`${prefixCls}-slider-label is-suffix`}>{inner}</div>;
33
+ }, [max, suffixLabel, valueGroup]);
34
+ return {
35
+ renderPrefixLabel,
36
+ renderSuffixLabel,
37
+ };
38
+ };
@@ -0,0 +1,170 @@
1
+ import React, { useState, useEffect, useMemo, useContext, useCallback } from 'react';
2
+ import { SliderContext } from '.';
3
+
4
+ export const useSliderInit = ({ commonIsTouching }: { commonIsTouching: number }) => {
5
+ const ctx = useContext(SliderContext);
6
+ const { value, min, max, onAfterChange, onChange, useMarkOnly, marks, useRange } = ctx;
7
+ const baseValue = ctx?.value ?? ctx?.defaultValue ?? min;
8
+ const [valueGroup, setValueGroup] = useState<number | [number, number]>(baseValue);
9
+ const [firstRender, setFirstRender] = useState(false);
10
+ const [firstTouch, setFirstTouch] = useState(false);
11
+
12
+ // 基础标签数组
13
+ // @en Base mark list
14
+ const baseConfig = useMemo(() => {
15
+ if (marks === void 0) return [];
16
+ let res: number[] = [];
17
+ if (typeof marks === 'number') {
18
+ res = Array((max - min) / marks + 1)
19
+ .fill('')
20
+ .map((_, idx) => idx * marks);
21
+ } else if (Array.isArray(marks)) {
22
+ res = marks;
23
+ } else {
24
+ res = Object.keys(marks).map(e => parseInt(e));
25
+ }
26
+ return [...res].filter(e => e <= max && e >= min).sort((a, b) => (a > b ? 1 : -1));
27
+ }, [marks, max, min]);
28
+
29
+ const validate = useCallback(
30
+ (newValue: number) => {
31
+ if (typeof valueGroup === 'number') return newValue <= valueGroup;
32
+ const [small, large] = [...valueGroup].sort((a, b) => (a > b ? 1 : -1));
33
+ return newValue >= small && newValue <= large;
34
+ },
35
+ [valueGroup],
36
+ );
37
+
38
+ // 实际 mark 标签
39
+ // @en Actual mark tags
40
+ const runTimeConfig = useMemo(() => {
41
+ return baseConfig.map(e => {
42
+ const label =
43
+ marks && !Array.isArray(marks) && marks[String(e)] && typeof marks !== 'number' ? (
44
+ marks[String(e)]
45
+ ) : (
46
+ <p>{e}</p>
47
+ );
48
+ return {
49
+ activated: validate(e),
50
+ value: e,
51
+ label,
52
+ };
53
+ });
54
+ }, [baseConfig, valueGroup, validate, marks]);
55
+
56
+ // 当前值最近的标签值
57
+ // @en The mark value closest to the current value
58
+ const formatMarksValue = useCallback(
59
+ (newValue: number | [number, number]) => {
60
+ if (!useMarkOnly || marks === void 0) return newValue;
61
+ const format = (v: number) => {
62
+ let idx: number | undefined;
63
+ baseConfig.forEach((e, i) => {
64
+ if (v >= e) {
65
+ idx = i;
66
+ }
67
+ });
68
+ if (idx !== void 0) {
69
+ const largerIdx = idx + 1;
70
+ if (
71
+ largerIdx < baseConfig.length &&
72
+ Math.abs(baseConfig[largerIdx] - v) < Math.abs(baseConfig[idx] - v)
73
+ ) {
74
+ return baseConfig[largerIdx];
75
+ }
76
+ return baseConfig[idx];
77
+ }
78
+ return baseConfig[0];
79
+ };
80
+ if (typeof newValue === 'number') return format(newValue);
81
+ return newValue.map(v => format(v)) as [number, number];
82
+ },
83
+ [useMarkOnly, marks, baseConfig],
84
+ );
85
+
86
+ /**
87
+ * 标记第一次渲染,方便获取位置
88
+ * @en Mark the first render for easy location
89
+ */
90
+ useEffect(() => {
91
+ if (commonIsTouching) setFirstTouch(true);
92
+ }, [commonIsTouching]);
93
+
94
+ /**
95
+ * 是否为 range,多个游标
96
+ * @en Whether it is range, multiple cursors
97
+ */
98
+ const isMultiThumb = useMemo(
99
+ () => useRange || Array.isArray(baseValue),
100
+ [useRange, typeof baseValue === 'number'],
101
+ );
102
+
103
+ /**
104
+ * 为 range 组件初始化数据
105
+ * @en Initialize data for the range component
106
+ */
107
+ useEffect(() => {
108
+ setFirstRender(true);
109
+ /**
110
+ * 初始化数据
111
+ * @en Initialize data
112
+ */
113
+ const newValue =
114
+ isMultiThumb && typeof valueGroup === 'number'
115
+ ? formatMarksValue([valueGroup, valueGroup])
116
+ : formatMarksValue(valueGroup);
117
+ setValueGroup(newValue);
118
+ }, [isMultiThumb]);
119
+
120
+ /**
121
+ * 监听数据 value 变化
122
+ * @en Monitor data value changes
123
+ */
124
+ useEffect(() => {
125
+ if (value === void 0 || !firstRender || commonIsTouching !== -1) return;
126
+ const newValue =
127
+ isMultiThumb && typeof value === 'number'
128
+ ? formatMarksValue([value, value])
129
+ : formatMarksValue(value);
130
+ setValueGroup(newValue);
131
+ // 如果受控需要还原
132
+ // @en If controlled, it needs to restore
133
+ }, [firstRender && value, commonIsTouching]);
134
+
135
+ /**
136
+ * 上报排序后的值
137
+ * @en report sorted value
138
+ */
139
+ const formatValueGroup = useMemo(
140
+ () =>
141
+ typeof valueGroup === 'number'
142
+ ? valueGroup
143
+ : ([...valueGroup].sort((a, b) => (a > b ? 1 : -1)) as [number, number]),
144
+ [valueGroup],
145
+ );
146
+
147
+ useEffect(() => {
148
+ if (!firstTouch) return;
149
+ if (commonIsTouching > -1) onChange(formatValueGroup);
150
+ }, [valueGroup]);
151
+
152
+ useEffect(() => {
153
+ if (!firstTouch) return;
154
+ if (commonIsTouching === -1) {
155
+ onAfterChange(formatMarksValue(formatValueGroup));
156
+ if (value === void 0) {
157
+ const newValue = formatMarksValue(valueGroup);
158
+ setValueGroup(newValue);
159
+ }
160
+ }
161
+ }, [commonIsTouching, formatMarksValue]);
162
+
163
+ return {
164
+ valueGroup,
165
+ setValueGroup,
166
+ firstRender,
167
+ runTimeConfig,
168
+ isMultiThumb,
169
+ };
170
+ };