@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,281 @@
1
+ import React, {
2
+ useState,
3
+ useRef,
4
+ forwardRef,
5
+ Ref,
6
+ useImperativeHandle,
7
+ useMemo,
8
+ ReactNode,
9
+ } from 'react';
10
+ import { cls, componentWrapper } from '@arco-design/mobile-utils';
11
+ import { ContextLayout } from '../context-provider';
12
+ import IconStarFill from '../icon/IconStarFill';
13
+ import IconStarHalf from '../icon/IconStarHalf';
14
+ import { useUpdateEffect } from '../_helpers';
15
+
16
+ export type RateIconType = ReactNode | ((index: number) => ReactNode);
17
+
18
+ export interface RateProps {
19
+ /**
20
+ * 自定义类名
21
+ * @en Custom classname
22
+ */
23
+ className?: string;
24
+ /**
25
+ * 自定义样式
26
+ * @en Custom stylesheet
27
+ */
28
+ style?: React.CSSProperties;
29
+ /**
30
+ * 默认评分
31
+ * @en Default value
32
+ * @default 0
33
+ */
34
+ defaultValue?: number;
35
+ /**
36
+ * 当前评分(受控)
37
+ * @en Current value (Controlled)
38
+ */
39
+ value?: number;
40
+ /**
41
+ * 图标数量
42
+ * @en Number of icons
43
+ * @default 5
44
+ */
45
+ count?: number;
46
+ /**
47
+ * 每个图标的分值
48
+ * @en Points for each icon
49
+ * @default 1
50
+ */
51
+ step?: number;
52
+ /**
53
+ * 选中时颜色
54
+ * @en Color when selected
55
+ */
56
+ color?: string;
57
+ /**
58
+ * 未选中时颜色
59
+ * @en Color when unselected
60
+ */
61
+ normalColor?: string;
62
+ /**
63
+ * 禁用时颜色
64
+ * @en Color when disabled
65
+ */
66
+ disabledColor?: string;
67
+ /**
68
+ * 是否允许半选
69
+ * @en Whether to allow semi-selection
70
+ * @default false
71
+ */
72
+ allowHalf?: boolean;
73
+ /**
74
+ * 是否为禁用状态
75
+ * @en Whether to be disable
76
+ * @default false
77
+ */
78
+ disabled?: boolean;
79
+ /**
80
+ * 自定义图标大小
81
+ * @en Custom icon size
82
+ */
83
+ size?: number | string;
84
+ /**
85
+ * 自定义图标间距(点击热区包含间距)
86
+ * @en Custom icon spacing (click hotspot includes spacing)
87
+ */
88
+ offset?: number | string;
89
+ /**
90
+ * 自定义图标
91
+ * @en Custom icons
92
+ */
93
+ icons?: {
94
+ normal: RateIconType;
95
+ active: RateIconType;
96
+ halfActive?: RateIconType;
97
+ };
98
+ /**
99
+ * 当前分值变化触发的事件
100
+ * @en Callback when the current value changes
101
+ * @default (value) => void
102
+ */
103
+ onChange?: (value: number) => void;
104
+ }
105
+
106
+ export interface RateRef {
107
+ /**
108
+ * 最外层元素 DOM
109
+ * @en The outermost element DOM
110
+ */
111
+ dom: HTMLDivElement | null;
112
+ }
113
+
114
+ const Rate = forwardRef((props: RateProps, ref: Ref<RateRef>) => {
115
+ const {
116
+ className,
117
+ style,
118
+ defaultValue = 0,
119
+ value,
120
+ count = 5,
121
+ step = 1,
122
+ color,
123
+ normalColor,
124
+ disabledColor,
125
+ allowHalf = false,
126
+ disabled = false,
127
+ size,
128
+ offset,
129
+ icons,
130
+ onChange,
131
+ } = props;
132
+ const [innerValue, setInnerValue] = useState(defaultValue);
133
+ const starIndex = useMemo(() => {
134
+ const actualValue = value !== void 0 ? value : innerValue;
135
+ return actualValue / step || 0;
136
+ }, [value, innerValue, step]);
137
+ const domRef = useRef<HTMLDivElement | null>(null);
138
+ const helpArray = useMemo(() => Array(count).fill(''), [count]);
139
+
140
+ useUpdateEffect(() => {
141
+ handleStarIndexChange(starIndex);
142
+ }, [step]);
143
+
144
+ useImperativeHandle(ref, () => ({
145
+ dom: domRef.current,
146
+ }));
147
+
148
+ function handleStarIndexChange(newIndex: number) {
149
+ if (disabled) {
150
+ return;
151
+ }
152
+ const newValue = newIndex * step;
153
+ setInnerValue(newValue);
154
+ onChange && onChange(newValue);
155
+ }
156
+
157
+ function renderIconByAttr(defaultNode: ReactNode, index: number, attr?: RateIconType) {
158
+ if (!attr) {
159
+ return defaultNode;
160
+ }
161
+ if (typeof attr === 'function') {
162
+ // 对外的index从0开始
163
+ // @en External index starts from 0
164
+ return attr(index - 1);
165
+ }
166
+ return attr;
167
+ }
168
+
169
+ function getIconStatus(index: number) {
170
+ if (starIndex >= index) {
171
+ return 'active';
172
+ }
173
+ if (starIndex >= index - 0.5 && allowHalf) {
174
+ return 'half-active';
175
+ }
176
+ return 'normal';
177
+ }
178
+
179
+ function renderRateIcon(
180
+ prefix: string,
181
+ status: 'active' | 'half-active' | 'normal',
182
+ index: number,
183
+ ) {
184
+ if (status === 'active') {
185
+ return renderIconByAttr(
186
+ <IconStarFill
187
+ className={cls(`${prefix}-icon active`, { disabled })}
188
+ style={{ fontSize: size, color: disabled ? disabledColor : color }}
189
+ />,
190
+ index,
191
+ icons?.active,
192
+ );
193
+ }
194
+ if (status === 'half-active') {
195
+ const { active, halfActive } = icons || {};
196
+ const customIcon = halfActive || active;
197
+ return renderIconByAttr(
198
+ <>
199
+ <IconStarFill
200
+ className={cls(`${prefix}-icon normal`, { disabled })}
201
+ style={{ fontSize: size, color: normalColor }}
202
+ />
203
+ <IconStarHalf
204
+ className={cls(`${prefix}-icon half-active`, { disabled })}
205
+ style={{
206
+ fontSize: size,
207
+ color: disabled ? disabledColor : color,
208
+ }}
209
+ />
210
+ </>,
211
+ index,
212
+ customIcon,
213
+ );
214
+ }
215
+ return renderIconByAttr(
216
+ <IconStarFill
217
+ className={cls(`${prefix}-icon normal`, { disabled })}
218
+ style={{ fontSize: size, color: normalColor }}
219
+ />,
220
+ index,
221
+ icons?.normal,
222
+ );
223
+ }
224
+
225
+ return (
226
+ <ContextLayout>
227
+ {({ prefixCls, useRtl }) => (
228
+ <div
229
+ role="slider"
230
+ aria-valuemin={0}
231
+ aria-valuemax={count}
232
+ aria-valuenow={innerValue}
233
+ aria-disabled={disabled}
234
+ className={cls(`${prefixCls}-rate`, className, { disabled })}
235
+ style={style}
236
+ ref={domRef}
237
+ >
238
+ {helpArray.map((_, i) => {
239
+ // 对内的index从1开始,方便计算
240
+ // @en The index of the pair starts from 1, which is convenient for calculation
241
+ const index = i + 1;
242
+ const halfIndex = allowHalf ? index - 0.5 : index;
243
+ const status = getIconStatus(index);
244
+ return (
245
+ <div
246
+ key={index}
247
+ style={{ padding: offset }}
248
+ className={`${prefixCls}-rate-icon-wrap ${status}`}
249
+ >
250
+ {renderRateIcon(`${prefixCls}-rate`, status, index)}
251
+ <div
252
+ className={`${prefixCls}-rate-icon-click-half left`}
253
+ onClick={() =>
254
+ handleStarIndexChange(useRtl ? index : halfIndex)
255
+ }
256
+ />
257
+ <div
258
+ className={`${prefixCls}-rate-icon-click-half right`}
259
+ onClick={() =>
260
+ handleStarIndexChange(useRtl ? halfIndex : index)
261
+ }
262
+ />
263
+ </div>
264
+ );
265
+ })}
266
+ </div>
267
+ )}
268
+ </ContextLayout>
269
+ );
270
+ });
271
+
272
+ /**
273
+ * 评分组件,支持受控模式
274
+ * @en Rate component, supports controlled mode
275
+ * @type 数据录入
276
+ * @type_en Data Entry
277
+ * @name 评分
278
+ * @name_en Rate
279
+ * @displayName Rate
280
+ */
281
+ export default componentWrapper(Rate, 'Rate');
@@ -0,0 +1,97 @@
1
+ ### 数据录入
2
+
3
+ # 搜索栏 SearchBar
4
+
5
+ 搜索栏组件
6
+
7
+ ======
8
+
9
+ > 属性/Props
10
+
11
+ |参数|描述|类型|默认值|
12
+ |----------|-------------|------|------|
13
+ |shape|输入框形状|"square" \| "round"|"square"|
14
+ |textAlign|搜索栏内容位置|"left" \| "center" \| "right"|"left"|
15
+ |prepend|搜索栏头部插入的内容|ReactNode \| ((focusing: boolean, value: string) =\> ReactNode)|-|
16
+ |append|搜索栏尾部要插入的内容, 默认在搜索栏激活态时会插入一个按钮|ReactNode \| ((focusing: boolean, value: string) =\> ReactNode)|(focusing) => focusing ? (<span>取消</span>) : null|
17
+ |actionButton|搜索栏最右侧要插入的按钮,默认情况下插入一个取消按钮|ReactNode|<CancelButton />|
18
+ |enableAssociation|是否开启搜索联想框功能|boolean|false|
19
+ |associationVisible|(受控模式)搜索联想框的可见态|boolean|-|
20
+ |associationShowType|非受控模式下,搜索联想框的展示时机 \- focus 仅聚焦时 \- value 搜索词不为空 \- default 搜索栏被聚焦或者搜索词不为空 \- always 一直展示|"value" \| "focus" \| "default" \| "always"|"default"|
21
+ |associationItems|每一项搜索内容|SearchAssociationBaseItem\[\]|-|
22
+ |highlightMode|搜索结果高亮模式,可以是内置的两种模式,或者一个自定义的高亮函数(接受选项内容content、搜索关键字keyword、默认的高亮class,返回一个ReactNode) \- prefix 高亮最长前缀匹配字符串 \- contain 高亮所有搜索关键字 \- none 关闭高亮|SearchAssociationHighlightMode|"none"|
23
+ |highlightStyle|要为高亮结果添加的样式,仅非自定高亮模式下生效|CSSProperties|-|
24
+ |highlightClassName|要为高亮结果添加的class,仅非自定义高亮模式下生效|string|-|
25
+ |onCancel|右侧取消按钮的点击回调|() =\> void|-|
26
+ |onAssociationItemClick|每行搜索结果的点击回调|(item: SearchAssociationBaseItem, index: number, event: MouseEvent\<HTMLDivElement, MouseEvent\>) =\> void|-|
27
+ |onAssociationClick|搜索联想框整体被点击的回调|(event: MouseEvent\<HTMLDivElement, MouseEvent\>) =\> void|-|
28
+ |renderAssociationItem|自定义渲染每行搜索结果|(item: SearchAssociationBaseItem, index: number, node: ReactNode) =\> ReactNode|-|
29
+ |renderAssociation|自定义渲染搜索联想框整体内容|(Content: ReactNode) =\> ReactNode|-|
30
+ |type|输入框类型|string|"text"|
31
+ |pattern|检查控件值的正则表达式|string|-|
32
+ |inputClass|输入框dom自定义类名|string|-|
33
+ |inputStyle|输入框dom自定义样式|CSSProperties|-|
34
+ |nativeProps|其他未列出的原生属性,优先级低于已列出的组件属性|InputHTMLAttributes\<HTMLInputElement\>|-|
35
+ |ariaLabel|无障碍label|string|-|
36
+ |id|输入框的id|string|-|
37
+ |name|输入框的name|string|-|
38
+ |className|自定义类名|string|-|
39
+ |style|自定义样式|CSSProperties|-|
40
+ |value|绑定值,传入即受控|string|-|
41
+ |defaultValue|默认值|string|-|
42
+ |maxLength|最大输入长度|number|-|
43
+ |placeholder|占位文本|string|-|
44
+ |disabled|输入框是否禁用|boolean|-|
45
+ |readOnly|是否只读|boolean|-|
46
+ |autoFocus|是否自动获取焦点,开启后会触发一次onClick事件|boolean|-|
47
+ |blockChangeWhenCompositing|当 ios 输入中文时,输拼音的过程不触发onChange,仅确认选择后触发|boolean|false|
48
+ |validator|正则验证,不符合验证的不允许输入|RegExp \| ((value: string) =\> boolean)|-|
49
+ |blurBeforeFocus|在聚焦之前blur掉,即切换不同input时会重新弹起键盘,常用于input type切换时重新加载键盘,安卓上有效|boolean|-|
50
+ |clearable|是否有清除按钮|boolean|-|
51
+ |clearShowType|清除按钮展示时机:focus \- 聚焦时展示 value \- 有值则展示 always \- 始终展示|"value" \| "focus" \| "always"|"focus"|
52
+ |preventEventWhenClearing|在聚焦模式下点击清除按钮时,是否要屏蔽对应产生的onBlur和onFocus事件|boolean|true|
53
+ |clearIcon|清除按钮类型,也可自定义|ReactNode|\<IconClear className="clear-icon" /\>|
54
+ |onClear|按下清除按钮回调|(e: TouchEvent\<HTMLElement\>) =\> void|-|
55
+ |prefix|输入框前置内容,在输入框内部,也可自定义|ReactNode|-|
56
+ |suffix|输入框后置内容,在输入框内部,也可自定义|ReactNode|-|
57
+ |onChange|数据改变时触发(失去焦点时)|(e: ChangeEvent\<HTMLInputElement\>, value: string) =\> void|-|
58
+ |onInput|数据改变时触发|(e: ChangeEvent\<HTMLInputElement\>, value: string) =\> void|-|
59
+ |onFocus|输入框聚焦时触发|(e: FocusEvent\<HTMLInputElement, Element\>) =\> void|-|
60
+ |onBlur|输入框失去焦点时触发|(e: FocusEvent\<HTMLInputElement, Element\>) =\> void|-|
61
+ |onClick|点击输入框事件|(e: MouseEvent\<HTMLInputElement, MouseEvent\>) =\> void|-|
62
+ |onKeyUp|原生的keyup事件|(e: KeyboardEvent\<HTMLInputElement\>) =\> void|-|
63
+ |onKeyDown|原生的keydown事件|(e: KeyboardEvent\<HTMLInputElement\>) =\> void|-|
64
+ |onKeyPress|原生的keypress事件|(e: KeyboardEvent\<HTMLInputElement\>) =\> void|-|
65
+ |onPressEnter|按下回车键时触发|(e: KeyboardEvent\<HTMLInputElement\>) =\> void|-|
66
+
67
+ > 引用/Refs
68
+
69
+ |参数|描述|类型|
70
+ |----------|-------------|------|
71
+ |dom|最外层元素 DOM|HTMLDivElement|
72
+ |input|原生输入框 DOM|HTMLInputElement|
73
+ |toggleAssociation|仅非受控模式下生效,手动控制搜索联想框的显隐,如果没有传入值则默认将显隐状态反转|(newVisible?: boolean) =\> void|
74
+
75
+ > SearchBarShape
76
+
77
+ ```
78
+ "square" | "round"
79
+ ```
80
+
81
+ > SearchAssociationShowType
82
+
83
+ ```
84
+ "value" | "focus" | "default" | "always"
85
+ ```
86
+
87
+ > SearchAssociationBaseItem
88
+
89
+ |参数|描述|类型|
90
+ |----------|-------------|------|
91
+ |content|基础内容|string|
92
+
93
+ > SearchAssociationHighlightMode
94
+
95
+ ```
96
+ "prefix" | "contain" | "none" | (content: string, keyword: string, defaultHighlightClassName: string) => ReactNode
97
+ ```
@@ -0,0 +1,89 @@
1
+ import { cls } from '@arco-design/mobile-utils';
2
+ import React, { ReactNode } from 'react';
3
+ import {
4
+ SearchAssociationItem,
5
+ SearchBarAssociationHighlightConfig,
6
+ SearchBarAssociationProps,
7
+ } from './type';
8
+ import { highlightWithContainMode, highlightWithPrefixMode } from './highlight';
9
+
10
+ export function SearchBarAssociation<Data>(props: SearchBarAssociationProps<Data>) {
11
+ const {
12
+ prefixCls,
13
+ associationItems = [],
14
+ highlightClassName,
15
+ highlightMode = 'none',
16
+ highlightStyle,
17
+ onAssociationClick,
18
+ onAssociationItemClick,
19
+ renderAssociation,
20
+ renderAssociationItem,
21
+ keyword,
22
+ visible,
23
+ } = props;
24
+ const searchBarAssociationPrefixCls = `${prefixCls}-association`;
25
+ const defaultHighlightClassName = `${searchBarAssociationPrefixCls}-item-highlight`;
26
+
27
+ const renderHighlightNode = (content: string) => {
28
+ if (!content || !keyword || highlightMode === 'none') {
29
+ return content;
30
+ }
31
+ const config: SearchBarAssociationHighlightConfig = {
32
+ keyword,
33
+ content,
34
+ highlightClassName: highlightClassName || defaultHighlightClassName,
35
+ highlightStyle,
36
+ };
37
+
38
+ if (highlightMode === 'contain') {
39
+ return highlightWithContainMode(config);
40
+ }
41
+ if (highlightMode === 'prefix') {
42
+ return highlightWithPrefixMode(config);
43
+ }
44
+ return typeof highlightMode === 'function'
45
+ ? highlightMode(content, keyword, defaultHighlightClassName)
46
+ : content;
47
+ };
48
+
49
+ const renderItem = (item: SearchAssociationItem<Data>, index: number) => {
50
+ const itemContent = item.content;
51
+ let node: ReactNode = itemContent;
52
+ // itemContent为string类型,并且开启高亮模式才去走渲染高亮内容的逻辑
53
+ // @en When `itemContent` is a string, and the highlight mode is turned on, the logic of rendering the highlighted content is performed
54
+ if (typeof itemContent === 'string' && highlightMode !== 'none') {
55
+ node = renderHighlightNode(itemContent);
56
+ }
57
+ if (renderAssociationItem) {
58
+ node = renderAssociationItem(item, index, node);
59
+ }
60
+ return (
61
+ <div
62
+ key={index}
63
+ className={`${searchBarAssociationPrefixCls}-item`}
64
+ onClick={e => onAssociationItemClick?.(item, index, e)}
65
+ >
66
+ {node}
67
+ </div>
68
+ );
69
+ };
70
+
71
+ const renderContent = () => {
72
+ const associationContent = associationItems.map(renderItem);
73
+ if (renderAssociation) {
74
+ return renderAssociation(associationContent);
75
+ }
76
+ return associationContent;
77
+ };
78
+
79
+ return (
80
+ <div
81
+ className={cls(searchBarAssociationPrefixCls, {
82
+ [`${searchBarAssociationPrefixCls}-visible`]: visible,
83
+ })}
84
+ onClick={onAssociationClick}
85
+ >
86
+ {renderContent()}
87
+ </div>
88
+ );
89
+ }
@@ -0,0 +1,34 @@
1
+ import { nextTick } from '@arco-design/mobile-utils';
2
+ import React, { useEffect, useState } from 'react';
3
+
4
+ interface CancelButtonProps {
5
+ className: string;
6
+ onCancel?: () => void;
7
+ focusing: boolean;
8
+ currentInputValue: string;
9
+ text?: string;
10
+ }
11
+
12
+ export function CancelButton(props: CancelButtonProps) {
13
+ const { className, onCancel, focusing, currentInputValue, text } = props;
14
+ const [visible, setVisible] = useState(focusing || Boolean(currentInputValue));
15
+
16
+ const handleClick = () => {
17
+ onCancel?.();
18
+ // 如果不延迟,在聚焦切输入框有值的情况下,点击取消按钮会造成闪烁
19
+ // @en If there is no delay, when the focus cut input box has a value, clicking the cancel button will cause flickering
20
+ nextTick(() => {
21
+ setVisible(false);
22
+ });
23
+ };
24
+
25
+ useEffect(() => {
26
+ setVisible(focusing || Boolean(currentInputValue));
27
+ }, [focusing, currentInputValue]);
28
+
29
+ return visible ? (
30
+ <span className={className} onClick={handleClick}>
31
+ {text}
32
+ </span>
33
+ ) : null;
34
+ }
@@ -0,0 +1,66 @@
1
+ import React, { ReactNode } from 'react';
2
+ import { SearchBarAssociationHighlightConfig } from './type';
3
+
4
+ function createHighlightNode(
5
+ config: Omit<SearchBarAssociationHighlightConfig, 'content'>,
6
+ index: number,
7
+ ) {
8
+ const { keyword, highlightClassName, highlightStyle } = config;
9
+ return (
10
+ <span className={highlightClassName} style={highlightStyle} key={index}>
11
+ {keyword}
12
+ </span>
13
+ );
14
+ }
15
+
16
+ /**
17
+ * 高亮搜索候选项中,包含的关键字
18
+ *
19
+ */
20
+ export function highlightWithContainMode(config: SearchBarAssociationHighlightConfig) {
21
+ const { content = '', keyword = '' } = config;
22
+
23
+ // 具体实现思路就是将keyword作为split的分隔符,切割content得到数组
24
+ const splitContent = content.split(keyword);
25
+
26
+ // 再将高亮后的keyword节点,插空填入数组
27
+ const highlightResult = splitContent.reduce((prev, word, index) => {
28
+ prev.push(word);
29
+ if (index !== splitContent.length - 1) {
30
+ prev.push(createHighlightNode(config, index));
31
+ }
32
+ return prev;
33
+ }, [] as ReactNode[]);
34
+
35
+ return highlightResult;
36
+ }
37
+
38
+ /**
39
+ * 高亮搜索候选项和关键字的最长前缀公共字符串
40
+ *
41
+ */
42
+ export function highlightWithPrefixMode(config: SearchBarAssociationHighlightConfig) {
43
+ const { content = '', keyword = '', ...otherConfig } = config;
44
+
45
+ let splitIndex = -1;
46
+
47
+ for (let i = 0; i < keyword.length; i++) {
48
+ if (i >= content.length || content[i] !== keyword[i]) {
49
+ break;
50
+ }
51
+ splitIndex = i;
52
+ }
53
+
54
+ return splitIndex > -1
55
+ ? [
56
+ createHighlightNode(
57
+ {
58
+ ...otherConfig,
59
+ keyword: content.substring(0, splitIndex + 1),
60
+ },
61
+ 0,
62
+ ),
63
+ content.substring(splitIndex + 1),
64
+ ]
65
+ : content;
66
+ }