@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,145 @@
1
+ import { cls } from '@arco-design/mobile-utils';
2
+ import React, {
3
+ useContext,
4
+ useMemo,
5
+ useState,
6
+ useRef,
7
+ forwardRef,
8
+ useImperativeHandle,
9
+ Ref,
10
+ } from 'react';
11
+ import { GlobalContext } from '../context-provider';
12
+ import { PopoverMenuItem, PopoverMenuProps, PopoverProps, PopoverRef } from './type';
13
+ import { useUpdateEffect } from '../_helpers';
14
+
15
+ export function componentGenerator<
16
+ P extends PopoverProps = PopoverProps,
17
+ R extends PopoverRef = PopoverRef,
18
+ >(Comp: React.ForwardRefExoticComponent<P & React.RefAttributes<R>>) {
19
+ return forwardRef((props: PopoverMenuProps, ref: Ref<R | null>) => {
20
+ const {
21
+ menu,
22
+ menuLayout = 'vertical',
23
+ onSelect,
24
+ onClickMenuItem,
25
+ className = '',
26
+ useClickStatus = false,
27
+ clickStatusDuration = 300,
28
+ clickSelfToClose = true,
29
+ touchSelfToClose = props.touchToClose === void 0 ? false : props.touchToClose,
30
+ defaultVisible = false,
31
+ visible,
32
+ onChange,
33
+ ...restProps
34
+ } = props;
35
+ const { prefixCls } = useContext(GlobalContext);
36
+ const [activeIndex, setActiveIndex] = useState(-1);
37
+ const activeTimer = useRef(0);
38
+ const formattedMenu: PopoverMenuItem[] = useMemo(() => {
39
+ return menu.map(item => {
40
+ if (typeof item === 'string') {
41
+ return {
42
+ text: item,
43
+ };
44
+ }
45
+ return item;
46
+ });
47
+ }, [menu]);
48
+
49
+ const [visibleState, setVisibleState] = useState(
50
+ visible === void 0 ? defaultVisible : visible,
51
+ );
52
+ useUpdateEffect(() => {
53
+ setVisibleState(Boolean(visible));
54
+ }, [visible]);
55
+
56
+ const popoverRef = useRef<R | null>(null);
57
+
58
+ useImperativeHandle(ref, () => popoverRef.current!);
59
+
60
+ const onVisibleChange = newVisible => {
61
+ const handleVisibleChange = () => {
62
+ if (onChange && typeof onChange === 'function') {
63
+ onChange(newVisible);
64
+ }
65
+ if (visible === void 0) {
66
+ setVisibleState(newVisible);
67
+ }
68
+ };
69
+
70
+ // 如果设置了点击效果则延时回调onChange函数,留出点击效果的时间
71
+ // @en If the click effect is set, the onChange function is delayed and called back, leaving time for the click effect
72
+ if (!newVisible && useClickStatus) {
73
+ window.setTimeout(handleVisibleChange, Math.max(0, clickStatusDuration - 300));
74
+ } else {
75
+ handleVisibleChange();
76
+ }
77
+ };
78
+
79
+ const content = useMemo(
80
+ () => (
81
+ <div className={cls(`${prefixCls}-popover-menu-content`, `${menuLayout}-menu`)}>
82
+ {formattedMenu.map((item, index) => {
83
+ const defaultValue =
84
+ typeof item.text === 'string' ? item.text : `menu_item_${index}`;
85
+ const { text, value = defaultValue, disabled = false, icon } = item;
86
+ return (
87
+ <div
88
+ className={cls(`${prefixCls}-popover-menu-item`, {
89
+ disabled,
90
+ active: activeIndex === index,
91
+ })}
92
+ key={value}
93
+ onTouchStart={() => {
94
+ if (useClickStatus && !disabled) {
95
+ clearTimeout(activeTimer.current);
96
+ setActiveIndex(index);
97
+ activeTimer.current = window.setTimeout(() => {
98
+ setActiveIndex(-1);
99
+ activeTimer.current = 0;
100
+ }, clickStatusDuration);
101
+ }
102
+ }}
103
+ onClick={() => {
104
+ onClickMenuItem && onClickMenuItem(value, menu[index]);
105
+ if (disabled) return;
106
+ onSelect && onSelect(value, menu[index]);
107
+ }}
108
+ >
109
+ {icon && (
110
+ <div className={cls(`${prefixCls}-popover-menu-icon`)}>
111
+ {icon}
112
+ </div>
113
+ )}
114
+ <div className={cls(`${prefixCls}-popover-menu-text`)}>{text}</div>
115
+ </div>
116
+ );
117
+ })}
118
+ </div>
119
+ ),
120
+ [
121
+ prefixCls,
122
+ menuLayout,
123
+ formattedMenu,
124
+ activeIndex,
125
+ useClickStatus,
126
+ clickStatusDuration,
127
+ onClickMenuItem,
128
+ onSelect,
129
+ ],
130
+ );
131
+
132
+ return (
133
+ <Comp
134
+ ref={popoverRef}
135
+ visible={visibleState}
136
+ clickSelfToClose={clickSelfToClose}
137
+ touchSelfToClose={touchSelfToClose}
138
+ onChange={onVisibleChange}
139
+ {...(restProps as P)}
140
+ content={content}
141
+ className={cls(className, `${prefixCls}-popover-menu`)}
142
+ />
143
+ );
144
+ });
145
+ }
@@ -0,0 +1,147 @@
1
+ import React, { forwardRef, Ref, useImperativeHandle, useRef, useContext, useEffect } from 'react';
2
+ import { cls } from '@arco-design/mobile-utils';
3
+ import IconClose from '../icon/IconClose';
4
+ import { getStyleWithVendor, useMountedState } from '../_helpers';
5
+ import { PopoverInnerProps, PopoverInnerRef } from './type';
6
+ import { GlobalContext } from '../context-provider';
7
+
8
+ export const PopoverInner = forwardRef((props: PopoverInnerProps, ref: Ref<PopoverInnerRef>) => {
9
+ const { prefixCls } = useContext(GlobalContext);
10
+ const {
11
+ className,
12
+ needShadow,
13
+ content,
14
+ direction,
15
+ position,
16
+ minWidth,
17
+ maxWidth,
18
+ arrowWidth,
19
+ transformOrigin,
20
+ mode,
21
+ showCloseIcon = false,
22
+ textSuffix = null,
23
+ renderArrow,
24
+ onClickCloseIcon,
25
+ onClickTextSuffix,
26
+ } = props;
27
+ const domRef = useRef<HTMLDivElement>(null);
28
+ const contentRef = useRef<HTMLDivElement>(null);
29
+ const [show, setShow] = useMountedState(false);
30
+
31
+ useImperativeHandle(ref, () => ({
32
+ dom: domRef.current,
33
+ content: contentRef.current,
34
+ }));
35
+
36
+ useEffect(() => {
37
+ const { top, bottom, height, left, width } = position;
38
+ if (left || width || top || height || bottom) {
39
+ if (!show) {
40
+ setTimeout(() => {
41
+ setShow(() => {
42
+ // bugfix:
43
+ // 外层CSSTransition使用dom API而非通过react className属性修改class
44
+ // 如果内部通过react className属性动态修改class会覆盖CSSTransition的设置,导致CSSTransition enter相关的class无法应用到组件
45
+ domRef.current?.classList.add('show');
46
+ return true;
47
+ });
48
+ }, 0);
49
+ }
50
+ }
51
+ }, [position, show]);
52
+
53
+ /**
54
+ * 计算容器的样式
55
+ * @en Calculate the stylesheet of the container
56
+ */
57
+ const getWrapperStyle = () => {
58
+ const { top, bottom, height, left } = position;
59
+
60
+ const obj: React.CSSProperties = {
61
+ height: `${height}px`,
62
+ left: `${left}px`,
63
+ minWidth,
64
+ maxWidth,
65
+ };
66
+
67
+ if (top) {
68
+ obj.top = `${top}px`;
69
+ } else if (bottom) {
70
+ obj.bottom = `${bottom}px`;
71
+ }
72
+ // 用于执行缩放动画
73
+ // @en Used to perform zoom animations
74
+ obj.transformOrigin = `${transformOrigin.x} ${transformOrigin.y}`;
75
+ return getStyleWithVendor(obj);
76
+ };
77
+
78
+ /**
79
+ * 计算icon的样式
80
+ * @en Calculate the stylesheet of the icon
81
+ */
82
+ const getArrowStyle = () => {
83
+ const { arrowLeft } = position;
84
+ return {
85
+ width: arrowWidth,
86
+ height: arrowWidth,
87
+ marginLeft: arrowLeft ? `${arrowLeft}px` : null,
88
+ marginRight: arrowLeft ? `${arrowLeft}px` : null,
89
+ } as React.CSSProperties;
90
+ };
91
+
92
+ return (
93
+ <div
94
+ ref={domRef}
95
+ className={cls(
96
+ `${prefixCls}-popover-inner`,
97
+ 'popover-inner',
98
+ 'all-border-box',
99
+ `${mode}-mode`,
100
+ className,
101
+ {
102
+ 'with-shadow': needShadow,
103
+ 'with-suffix': showCloseIcon || textSuffix,
104
+ 'custom-content': typeof content !== 'string',
105
+ },
106
+ )}
107
+ style={getWrapperStyle()}
108
+ >
109
+ <div className="popover-bg">
110
+ {renderArrow ? (
111
+ renderArrow({ arrowWidth, arrowLeft: position.arrowLeft, direction })
112
+ ) : (
113
+ <div className={`popover-arrow ${direction}`} style={getArrowStyle()}>
114
+ <div className="popover-arrow-content" />
115
+ </div>
116
+ )}
117
+ </div>
118
+ <div
119
+ className={cls('popover-content', direction, {
120
+ 'show-close-icon': showCloseIcon,
121
+ })}
122
+ ref={contentRef}
123
+ >
124
+ {typeof content === 'string' ? (
125
+ <>
126
+ <div className="content-text">{content}</div>
127
+ {showCloseIcon && (
128
+ <>
129
+ <div className="icon-divider" />
130
+ <div className="text-close-icon" onClick={onClickCloseIcon}>
131
+ <IconClose />
132
+ </div>
133
+ </>
134
+ )}
135
+ {textSuffix && (
136
+ <div className="text-suffix" onClick={onClickTextSuffix}>
137
+ {textSuffix}
138
+ </div>
139
+ )}
140
+ </>
141
+ ) : (
142
+ content
143
+ )}
144
+ </div>
145
+ </div>
146
+ );
147
+ });
@@ -0,0 +1,268 @@
1
+ import React, {
2
+ forwardRef,
3
+ Ref,
4
+ useImperativeHandle,
5
+ useRef,
6
+ useState,
7
+ useContext,
8
+ useEffect,
9
+ } from 'react';
10
+ import { cls } from '@arco-design/mobile-utils';
11
+ import { GlobalContext } from '../context-provider';
12
+ import { PopoverInner } from './popover-inner';
13
+ import Transition from '../transition';
14
+ import { PopoverRef, PopoverProps, PopoverInnerRef } from './type';
15
+ import { useEvent, usePosition } from './hooks';
16
+ import Portal from '../portal';
17
+
18
+ export const Popover = forwardRef((props: PopoverProps, ref: Ref<PopoverRef>) => {
19
+ const {
20
+ className = '',
21
+ innerPopoverClassName = '',
22
+ style = {},
23
+ theme = 'black',
24
+ needShadow = false,
25
+ content = '',
26
+ transitionTimeout = 300,
27
+ minWidth = '10px',
28
+ maxWidth = '90vw',
29
+ transitionName = 'fade',
30
+ clickSelfToClose = true,
31
+ touchSelfToClose = props.touchToClose === void 0 ? false : props.touchToClose,
32
+ defaultVisible = false,
33
+ visible,
34
+ children,
35
+ bordered = props.theme === 'white',
36
+ showCloseIcon = false,
37
+ textSuffix = null,
38
+ mode = 'follow',
39
+ showMask = false,
40
+ maskTransitionTimeout = { enter: 450, exit: 240 },
41
+ renderArrow,
42
+ onChange,
43
+ onClickCloseIcon,
44
+ onClickTextSuffix,
45
+ onClickMask,
46
+ } = props;
47
+ const { prefixCls } = useContext(GlobalContext);
48
+ const [visibleState, setVisibleState] = useState(false);
49
+ const visibleRef = useRef(visibleState);
50
+ const wrapperRef = useRef<HTMLDivElement | null>(null);
51
+ const childRef = useRef<HTMLDivElement | null>(null);
52
+ const popoverRef = useRef<PopoverInnerRef | null>(null);
53
+ const transitionNodeRef = useRef<HTMLDivElement | null>(null);
54
+ const maskRef = useRef<HTMLDivElement | null>(null);
55
+ const {
56
+ direction,
57
+ position,
58
+ isCalcPosition,
59
+ transformOrigin,
60
+ computedChildAndPopoverOffset,
61
+ arrowWidth,
62
+ resetPosition,
63
+ adjustVerticalDirection,
64
+ } = usePosition(props, popoverRef, childRef, wrapperRef);
65
+
66
+ /**
67
+ * 气泡状态切换
68
+ * @en Bubble state toggle
69
+ */
70
+ const onVisibleChange = (newVisible = true) => {
71
+ // 为了防止退出中有缩放动画影响气泡位置计算,在退出动画结束前不可切换到展示气泡状态
72
+ // @en In order to prevent the zoom animation in the exit from affecting the calculation of the bubble position, it is not possible to switch to the display bubble state before the exit animation ends.
73
+ if (newVisible && !isCalcPosition) {
74
+ return;
75
+ }
76
+ onChange?.(newVisible);
77
+ if (visible === void 0) {
78
+ setVisibleState(newVisible);
79
+ }
80
+ };
81
+
82
+ const { popoverDisappear, mayAddEventOnBody, startCloseTimer, mayRemoveEventListenerOnBody } =
83
+ useEvent(
84
+ props,
85
+ wrapperRef,
86
+ popoverRef,
87
+ visibleRef,
88
+ onVisibleChange,
89
+ adjustVerticalDirection,
90
+ );
91
+
92
+ useImperativeHandle(ref, () => ({
93
+ dom: wrapperRef.current,
94
+ child: childRef.current,
95
+ innerPopover: popoverRef.current,
96
+ innerPopoverDom: popoverRef.current?.dom || null,
97
+ updatePosition,
98
+ }));
99
+
100
+ useEffect(() => {
101
+ if (defaultVisible || visible) {
102
+ setVisibleState(true);
103
+ }
104
+
105
+ return () => {
106
+ mayRemoveEventListenerOnBody();
107
+ };
108
+ }, []);
109
+
110
+ useEffect(() => {
111
+ if (visible !== void 0) {
112
+ setVisibleState(Boolean(visible));
113
+ }
114
+ }, [visible]);
115
+
116
+ useEffect(() => {
117
+ // 非 visibleState 变化引起的回调,仅用于更新位置
118
+ // @en Callbacks not caused by visibleState changes, only used to update the position
119
+ if (visibleRef.current) {
120
+ computedChildAndPopoverOffset();
121
+ }
122
+ }, [children, content, direction, mode]);
123
+
124
+ useEffect(() => {
125
+ visibleState && showPopover();
126
+ visibleRef.current = visibleState;
127
+ if (!visibleState) {
128
+ mayRemoveEventListenerOnBody();
129
+ setTimeout(() => {
130
+ !visibleRef.current && resetPosition();
131
+ }, (typeof transitionTimeout === 'object' ? transitionTimeout.exit : transitionTimeout) || 300);
132
+ }
133
+ }, [visibleState]);
134
+
135
+ function showPopover() {
136
+ startCloseTimer();
137
+ setTimeout(mayAddEventOnBody, 0);
138
+
139
+ // 为了防止缩放动画影响气泡位置计算,气泡漏出阶段不重新计算位置
140
+ // @en In order to prevent the zoom animation from affecting the bubble position calculation, the bubble leakage stage does not recalculate the position
141
+ if (!isCalcPosition) {
142
+ return;
143
+ }
144
+
145
+ // 异步计算气泡位置,等待气泡渲染
146
+ // @en Calculate the bubble position asynchronously and wait for the bubble to render
147
+ setTimeout(() => {
148
+ computedChildAndPopoverOffset();
149
+ }, 0);
150
+ }
151
+
152
+ function updatePosition() {
153
+ if (!visibleState) return;
154
+ computedChildAndPopoverOffset();
155
+ }
156
+
157
+ function onClickWrapper() {
158
+ const visibleRefValue = visibleRef.current;
159
+ if (!visibleRefValue) {
160
+ onVisibleChange(true);
161
+ return;
162
+ }
163
+ if (visibleRefValue && clickSelfToClose && !touchSelfToClose) {
164
+ popoverDisappear();
165
+ }
166
+ }
167
+
168
+ function onTouchWrapper() {
169
+ // 仅处理气泡消失,气泡出现交给onClick来处理
170
+ // @en Only the disappearance of the bubble is processed, and the appearance of the bubble is handed over to onClick for processing
171
+ if (touchSelfToClose && visibleRef.current) {
172
+ popoverDisappear();
173
+ }
174
+ }
175
+
176
+ const renderInnerPopover = () => (
177
+ <PopoverInner
178
+ className={cls(`${theme}-theme`, innerPopoverClassName, {
179
+ bordered,
180
+ })}
181
+ ref={ele => {
182
+ popoverRef.current = ele;
183
+ transitionNodeRef.current = ele?.dom!;
184
+ }}
185
+ direction={direction}
186
+ minWidth={minWidth}
187
+ maxWidth={maxWidth}
188
+ position={position}
189
+ arrowWidth={arrowWidth}
190
+ transformOrigin={transformOrigin}
191
+ needShadow={needShadow}
192
+ content={content}
193
+ mode={mode}
194
+ showCloseIcon={showCloseIcon}
195
+ textSuffix={textSuffix}
196
+ renderArrow={renderArrow}
197
+ onClickCloseIcon={onClickCloseIcon}
198
+ onClickTextSuffix={onClickTextSuffix}
199
+ />
200
+ );
201
+
202
+ const renderPopover = () => {
203
+ return (
204
+ <Portal
205
+ getContainer={() => {
206
+ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion
207
+ return mode === 'global' ? document.body : wrapperRef.current!;
208
+ }}
209
+ >
210
+ {visibleState && isCalcPosition && renderInnerPopover()}
211
+ <Transition
212
+ in={visibleState && !isCalcPosition}
213
+ timeout={transitionTimeout}
214
+ type={transitionName}
215
+ nodeRef={transitionNodeRef}
216
+ mountOnEnter
217
+ unmountOnExit
218
+ >
219
+ {renderInnerPopover()}
220
+ </Transition>
221
+ </Portal>
222
+ );
223
+ };
224
+
225
+ return (
226
+ <>
227
+ {showMask && (
228
+ <Portal>
229
+ <Transition
230
+ in={visibleState && !isCalcPosition}
231
+ timeout={maskTransitionTimeout}
232
+ nodeRef={maskRef}
233
+ type="fade"
234
+ mountOnEnter
235
+ unmountOnExit
236
+ >
237
+ <div
238
+ className={`${prefixCls}-popover-mask`}
239
+ onClick={onClickMask}
240
+ ref={maskRef}
241
+ />
242
+ </Transition>
243
+ </Portal>
244
+ )}
245
+ <div
246
+ className={cls(
247
+ `${prefixCls}-popover`,
248
+ className,
249
+ `${theme}-theme`,
250
+ `${mode}-mode`,
251
+ {
252
+ bordered,
253
+ 'custom-content': typeof content !== 'string',
254
+ },
255
+ )}
256
+ style={style}
257
+ ref={wrapperRef}
258
+ onClick={onClickWrapper}
259
+ onTouchStart={onTouchWrapper}
260
+ >
261
+ {renderPopover()}
262
+ <div ref={childRef} className="popover-child-inner">
263
+ {children}
264
+ </div>
265
+ </div>
266
+ </>
267
+ );
268
+ });
@@ -0,0 +1,101 @@
1
+ ### 反馈
2
+
3
+ # 弹出层 Popup
4
+
5
+ 基于模态弹窗的的全屏菜单,支持各个方向。默认做了防滚动穿透处理,如果弹层内容中需要滚动,则需将滚动容器传入`getScrollContainer`属性以在未滚动到顶部或底部时释放滚动。
6
+
7
+ ======
8
+
9
+ > 属性/Props
10
+
11
+ |参数|描述|类型|默认值|
12
+ |----------|-------------|------|------|
13
+ |direction|菜单滑出方向|"left" \| "right" \| "top" \| "bottom"|"bottom"|
14
+ |needBottomOffset|从底部滑出的菜单内容是否适配ipx底部|boolean|false|
15
+ |translateZ|\[即将废弃\] 开启translateZ强制提升|boolean|false|
16
+ |maskTransitionTimeout|菜单蒙层动画时长|number \| \{ appear?: number; enter?: number; exit?: number; \}|{ enter: 450, exit: 240 }|
17
+ |contentTransitionTimeout|菜单内容动画时长|number \| \{ appear?: number; enter?: number; exit?: number; \}|{ enter: 450, exit: 240 }|
18
+ |contentTransitionType|内容过渡动画类名|string|\`slide-from-${props.direction}\`|
19
+ |className|自定义类名|string|-|
20
+ |maskClass|自定义蒙层类名|string|-|
21
+ |maskStyle|自定义蒙层样式|CSSProperties|-|
22
+ |contentClass|自定义内容类名|string|-|
23
+ |contentStyle|自定义内容样式|CSSProperties|-|
24
+ |visible|是否展示菜单(受控)|boolean|必填|
25
+ |close|关闭菜单方法|(e: MouseEvent\<HTMLElement, MouseEvent\>) =\> void|必填|
26
+ |maskTransitionType|蒙层过渡动画类名|string|"fade"|
27
+ |contentTransitionVarType|内容过渡动画类名变量标识|string|-|
28
+ |children|菜单内部内容|ReactNode|-|
29
+ |maskClosable|点击蒙层是否关闭菜单|boolean|true|
30
+ |animatingClosable|执行进场动画时点击蒙层是否可关闭菜单|boolean|false|
31
+ |mountOnEnter|是否在打开菜单时再加载内容|boolean|true|
32
+ |unmountOnExit|是否在退出时卸载内容|boolean|true|
33
+ |orientationDirection|transform方向,用于通过transform模拟横屏的情况|"left" \| "right" \| "top" \| "bottom"|"top"|
34
+ |preventBodyScroll|弹窗打开时是否禁止body的滚动|boolean|true|
35
+ |initialBodyOverflow|页面初始 overflow 状态,即关闭弹窗时 overflow 应该还原的状态|string|第一个全屏组件(弹窗、toast等)打开时页面overflow值|
36
+ |gestureOutOfControl|是否禁用滚动容器手势判断,禁用后交给业务方自己判断|boolean|false|
37
+ |onClose|关闭后回调(动画执行完毕)|(scene?: string) =\> void|-|
38
+ |onOpen|打开后回调(动画执行完毕)|() =\> void|-|
39
+ |onMaskClick|点击蒙层回调,maskClosable=false时也会触发|() =\> void|-|
40
+ |onTouchMove|弹窗的touchmove回调|(e: TouchEvent, prevented: boolean, direction: "x" \| "y") =\> void|-|
41
+ |onPreventTouchMove|非滚动区域或滚动到顶部及底部时的触摸事件回调|(e: TouchEvent, direction: "x" \| "y") =\> void|-|
42
+ |getContainer|获取挂载容器|() =\> HTMLElement|-|
43
+ |getScrollContainer|内容内部滚动区域容器,在该容器中未滚动到顶部或底部时会释放滚动|() =\> HTMLElement \| HTMLElement\[\]|-|
44
+
45
+ > 引用/Refs
46
+
47
+ |参数|描述|类型|
48
+ |----------|-------------|------|
49
+ |dom|最外层元素 DOM|HTMLDivElement|
50
+ |mask|蒙层 DOM|HTMLDivElement|
51
+ |content|内容 DOM|HTMLDivElement|
52
+ |setCloseScene|在关闭弹窗前修改 onClose 的 scene 参数值|(scene: string) =\> void|
53
+
54
+ > 方法/Methods
55
+
56
+ |方法名|描述|类型|
57
+ |----------|-------------|------|
58
+ |open|打开弹出层|(config: PopupProps) =\> \{ close: () =\> void; update: (newConfig: PopupProps) =\> void; \}|
59
+
60
+ > DirectionType
61
+
62
+ ```
63
+ "left" | "right" | "top" | "bottom"
64
+ ```
65
+
66
+ > GlobalContextParams
67
+
68
+ |参数|描述|类型|默认值|
69
+ |----------|-------------|------|------|
70
+ |prefixCls|组件类名前缀|string|"arco"|
71
+ |system|手动控制当前所在系统,传入后将直接使用传入的值,ssr场景需指定系统初始值时适用|"" \| "pc" \| "android" \| "ios"|""|
72
+ |useDarkMode|是否监听系统原生的暗黑模式变化(prefers\-color\-scheme: dark)以判断是否切为暗黑模式|boolean|false|
73
+ |isDarkMode|是否处于暗黑模式,指定后以指定的值为准|boolean|false|
74
+ |darkModeSelector|当处于暗黑模式时,body上挂载的类名,为空值时不挂载类名|string|"arco-theme-dark"|
75
+ |theme|主题变量,传入后将在线替换css变量,需设置less变量 @use\-css\-vars: 1|Record\<string, string\>|-|
76
+ |locale|国际化语言包配置|ILocale|-|
77
+ |useRtl|是否使用Rtl模式|boolean|false|
78
+ |onDarkModeChange|当系统原生暗黑模式发生变化时触发,useDarkMode=true 时有效|(isDark: boolean) =\> void|-|
79
+ |createRoot|React19 修改了 createRoot 的引入路径,导致组件内部无法直接引入(低react版本会找不到模块)。因此使用 react 19 的用户需从外部传入 createRoot 方法|CreateRootFnType|-|
80
+
81
+ > ILocale
82
+
83
+ |参数|描述|类型|
84
+ |----------|-------------|------|
85
+ |locale|语言类型|string|
86
+ |LoadMore|-|\{ loadMoreText: string; loadingText: string; noDataText: string; failLoadText: string; prepareScrollText: string; prepareClickText: string; \}|
87
+ |Picker|-|\{ okText: string; cancelText: string; \}|
88
+ |Tag|-|\{ addTag: string; \}|
89
+ |Dialog|-|\{ okText: string; cancelText: string; \}|
90
+ |SwipeLoad|-|\{ normalText: string; activeText: string; \}|
91
+ |PullRefresh|-|\{ loadingText: string; pullingText: string; finishText: string; loosingText: string; \}|
92
+ |DropdownMenu|-|\{ select: string; \}|
93
+ |Pagination|-|\{ previousPage: string; nextPage: string; \}|
94
+ |Image|-|\{ loadError: string; \}|
95
+ |ImagePicker|-|\{ loadError: string; \}|
96
+ |SearchBar|-|\{ placeholder: string; cancelBtn: string; \}|
97
+ |Stepper|-|\{ minusButtonName: string; addButtonName: string; \}|
98
+ |Keyboard|-|\{ confirm: string; \}|
99
+ |Form|-|\{ required: string; type: \{ email: string; url: string; string: string; number: string; array: string; object: string; boolean: string; \}; number: \{ min: string; max: string; equal: string; range: string; positive: string; negative: string; \}; \.\.\. 4 more \.\.\.; pickerDefaultHint: string; \}|
100
+ |NavBar|-|\{ backBtnAriaLabel: string; \}|
101
+ |Uploader|-|\{ uploadBtn: string; retryUpload: string; \}|