@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,126 @@
1
+ import React, { forwardRef, Ref, useContext, useImperativeHandle, useMemo, useRef } from 'react';
2
+ import { cls } from '@arco-design/mobile-utils';
3
+ import { IconCheckBold, IconCloseBold } from '../icon';
4
+ import { ContextLayout } from '../context-provider';
5
+ import { StepsContext } from './index';
6
+ import { StepProps, StepRef } from './type';
7
+
8
+ const Step = forwardRef((props: StepProps, ref: Ref<StepRef | null>) => {
9
+ const { title, description, icon } = props;
10
+
11
+ const {
12
+ iconType,
13
+ current,
14
+ direction,
15
+ index = 0,
16
+ status: contextStatus,
17
+ align: contextAlign,
18
+ changeIndex,
19
+ } = useContext(StepsContext);
20
+ const status = props.status || contextStatus;
21
+ const align = props.align || contextAlign;
22
+
23
+ const domRef = useRef<HTMLDivElement | null>(null);
24
+ useImperativeHandle(ref, () => ({
25
+ dom: domRef.current,
26
+ }));
27
+
28
+ const currentStatus = useMemo(() => {
29
+ if (status) return status;
30
+ if (current! < index) {
31
+ return 'wait';
32
+ }
33
+ if (current! === index) {
34
+ return 'process';
35
+ }
36
+ return 'finish';
37
+ }, [status, index, current]);
38
+
39
+ function renderNumIcon(prefixCls) {
40
+ let content;
41
+ if (currentStatus === 'finish') {
42
+ content = <IconCheckBold />;
43
+ } else if (currentStatus === 'error') {
44
+ content = <IconCloseBold />;
45
+ }
46
+ return (
47
+ content || <span className={cls(`${prefixCls}-steps-item-icon-num`)}>{index + 1}</span>
48
+ );
49
+ }
50
+
51
+ return (
52
+ <ContextLayout>
53
+ {({ prefixCls }) => (
54
+ <div
55
+ ref={domRef}
56
+ className={cls(
57
+ `${prefixCls}-steps-item`,
58
+ `${prefixCls}-steps-item-align-${align}`,
59
+ currentStatus,
60
+ direction,
61
+ iconType,
62
+ )}
63
+ onClick={() => changeIndex(index)}
64
+ >
65
+ <div
66
+ className={cls(
67
+ `${prefixCls}-steps-item-tail`,
68
+ `${prefixCls}-steps-item-tail-status-${currentStatus}`,
69
+ `${prefixCls}-steps-item-tail-align-${align}`,
70
+ `${currentStatus}-tail-color-with-config`,
71
+ )}
72
+ />
73
+ {icon ? (
74
+ <div
75
+ className={cls(
76
+ `${prefixCls}-steps-item-custom-icon`,
77
+ `${currentStatus}-custom-icon-bg-color-with-config`,
78
+ )}
79
+ >
80
+ {icon}
81
+ </div>
82
+ ) : (
83
+ <div
84
+ className={cls(
85
+ `${prefixCls}-steps-item-icon`,
86
+ `${currentStatus}-bg-color-with-config`,
87
+ )}
88
+ >
89
+ {iconType === 'number' ? (
90
+ renderNumIcon(prefixCls)
91
+ ) : (
92
+ <span className={cls(`${prefixCls}-steps-item-icon-dot`)} />
93
+ )}
94
+ </div>
95
+ )}
96
+ {title || description ? (
97
+ <div
98
+ className={cls(
99
+ `${prefixCls}-steps-item-content`,
100
+ `${prefixCls}-steps-item-content-align-${align}`,
101
+ )}
102
+ >
103
+ {title ? (
104
+ <div
105
+ className={cls(
106
+ `${prefixCls}-steps-item-title`,
107
+ `${currentStatus}-title-color-with-config`,
108
+ )}
109
+ >
110
+ {title}
111
+ </div>
112
+ ) : null}
113
+ {description ? (
114
+ <div className={cls(`${prefixCls}-steps-item-description`)}>
115
+ {description}
116
+ </div>
117
+ ) : null}
118
+ </div>
119
+ ) : null}
120
+ </div>
121
+ )}
122
+ </ContextLayout>
123
+ );
124
+ });
125
+
126
+ export default Step;
@@ -0,0 +1,45 @@
1
+ ### 布局
2
+
3
+ # 粘性布局 Sticky
4
+
5
+ 粘性布局组件,元素相对于窗口或指定容器的吸顶效果。
6
+
7
+ ======
8
+
9
+ > 属性/Props
10
+
11
+ |参数|描述|类型|默认值|
12
+ |----------|-------------|------|------|
13
+ |position|吸附位置,top 表示吸顶,bottom 表示吸底,both 表示既吸顶又吸底|"top" \| "bottom" \| "both"|"top"|
14
+ |topOffset|当距离容器顶部距离为该值时吸顶|number|0|
15
+ |bottomOffset|当距离容器底部距离为该值时吸底|number|0|
16
+ |followOffset|当sticky元素需要跟随依附容器离开视口时距离依附容器边缘的距离|number|0|
17
+ |className|自定义类名|string|-|
18
+ |style|自定义样式|CSSProperties|-|
19
+ |children|组件内部内容|ReactNode|-|
20
+ |zIndex|层级指数,z\-index的值|number|100|
21
+ |portalWhenSticky|在处于sticky状态时是否portal|boolean|false|
22
+ |stickyStyle|处于sticky状态时,元素固定样式。推荐用fixed,如果为absolute则需自行为滚动容器的父容器设置 position: relative|"fixed" \| "absolute"|"fixed"|
23
+ |stickyCssStyle|处于sticky状态时的自定义样式|CSSProperties|-|
24
+ |getPortalContainer|被portal时挂载的容器|() =\> HTMLElement|() => document.body|
25
+ |onStickyStateChange|吸顶状态切换时触发 payload\.isSticky: 当前是否为吸顶/吸底状态 payload\.wasSticky: 前一个状态是否为吸顶/吸底状态|(payload: StickyEventPayload) =\> void|-|
26
+ |onTopChange|滚动时top变化回调,参数为元素距离容器顶部减去topOffset的距离|(top: number) =\> void|-|
27
+ |getContainer|指定sticky元素的依附容器,sticky元素不会超出容器,在容器离开视口时会跟随 如果返回string则使用querySelector选取容器|() =\> string \| HTMLElement|-|
28
+ |getScrollContainer|指定滚动容器;如果返回string则使用querySelector选取容器|() =\> string \| HTMLElement \| Window|() => window|
29
+
30
+ > 引用/Refs
31
+
32
+ |参数|描述|类型|
33
+ |----------|-------------|------|
34
+ |dom|最外层元素 DOM|HTMLDivElement|
35
+ |recalculatePosition|局部滚动模式下,如果容器外部还有嵌套滚动,可主动调用此方法,让 sticky 的元素主动更新 fixed 位置|() =\> void|
36
+ |updatePlaceholderLayout|手动更新占位模块的高度|() =\> void|
37
+
38
+ > StickyEventPayload
39
+
40
+ |参数|描述|类型|
41
+ |----------|-------------|------|
42
+ |isSticky|当前是否为吸顶/吸底状态|boolean|
43
+ |wasSticky|前一个状态是否为吸顶/吸底状态|boolean|
44
+ |isTopSticky|当前是否为吸顶状态|boolean|
45
+ |isBottomSticky|当前是否为吸底状态|boolean|
@@ -0,0 +1,430 @@
1
+ import React, {
2
+ useRef,
3
+ forwardRef,
4
+ Ref,
5
+ useImperativeHandle,
6
+ useEffect,
7
+ useMemo,
8
+ useState,
9
+ CSSProperties,
10
+ useCallback,
11
+ ReactNode,
12
+ } from 'react';
13
+ import {
14
+ cls,
15
+ execRAF,
16
+ getActualContainer,
17
+ getScrollContainerRect,
18
+ safeGetComputedStyle,
19
+ convertCssPropertyToNumber,
20
+ } from '@arco-design/mobile-utils';
21
+ import { ContextLayout } from '../context-provider';
22
+ import { useRefState } from '../_helpers';
23
+ import Portal from '../portal';
24
+
25
+ export interface StickyRef {
26
+ /**
27
+ * 最外层元素 DOM
28
+ * @en The outermost element DOM
29
+ */
30
+ dom: HTMLDivElement | null;
31
+ /**
32
+ * 局部滚动模式下,如果容器外部还有嵌套滚动,可主动调用此方法,让 sticky 的元素主动更新 fixed 位置
33
+ * @en In the local scrolling mode, if there is nested scrolling outside the container, this method can be actively called to make the sticky element actively update the fixed position
34
+ */
35
+ recalculatePosition: () => void;
36
+ /**
37
+ * 手动更新占位模块的高度
38
+ * @en Manually update the height of the placeholder
39
+ */
40
+ updatePlaceholderLayout: () => void;
41
+ }
42
+
43
+ export interface StickyEventPayload {
44
+ /**
45
+ * 当前是否为吸顶/吸底状态
46
+ * @en Whether it is currently in the top/bottom suction state
47
+ */
48
+ isSticky: boolean;
49
+ /**
50
+ * 前一个状态是否为吸顶/吸底状态
51
+ * @en Whether the previous state is ceiling / bottom suction state
52
+ */
53
+ wasSticky: boolean;
54
+ /** 当前是否为吸顶状态 */
55
+ isTopSticky: boolean;
56
+ /** 当前是否为吸底状态 */
57
+ isBottomSticky: boolean;
58
+ }
59
+
60
+ export interface StickyProps {
61
+ /**
62
+ * 吸附位置,top 表示吸顶,bottom 表示吸底,both 表示既吸顶又吸底
63
+ * @en Adsorption position, top means fixed top, bottom means fixed bottom, both means both top and bottom
64
+ * @default "top"
65
+ */
66
+ position?: 'top' | 'bottom' | 'both';
67
+ /**
68
+ * 当距离容器顶部距离为该值时吸顶
69
+ * @en Fixed top when the distance from the top of the container is this value
70
+ * @default 0
71
+ */
72
+ topOffset?: number;
73
+ /**
74
+ * 当距离容器底部距离为该值时吸底
75
+ * @en Fixed bottom when the distance from the bottom of the container is this value
76
+ * @default 0
77
+ */
78
+ bottomOffset?: number;
79
+ /**
80
+ * 当sticky元素需要跟随依附容器离开视口时距离依附容器边缘的距离
81
+ * @en The distance from the edge of the attached container when the sticky element needs to follow the attached container to leave the viewport
82
+ * @default 0
83
+ */
84
+ followOffset?: number;
85
+ /**
86
+ * 自定义类名
87
+ * @en Custom classname
88
+ */
89
+ className?: string;
90
+ /**
91
+ * 自定义样式
92
+ * @en Custom stylesheet
93
+ */
94
+ style?: CSSProperties;
95
+ /**
96
+ * 组件内部内容
97
+ * @en Children elements of the component
98
+ */
99
+ children?: ReactNode;
100
+ /**
101
+ * 层级指数,z-index的值
102
+ * @en z-index
103
+ * @default 100
104
+ */
105
+ zIndex?: number;
106
+ /**
107
+ * 在处于sticky状态时是否portal
108
+ * @en Whether it is portal in sticky state
109
+ * @default false
110
+ */
111
+ portalWhenSticky?: boolean;
112
+ /**
113
+ * 处于sticky状态时,元素固定样式。推荐用fixed,如果为absolute则需自行为滚动容器的父容器设置 position: relative
114
+ * @en When in the sticky state, the fixed style of the element. Fixed is recommended. If absolute, need to set position: relative for the parent container of the scrolling container.
115
+ * @default "fixed"
116
+ */
117
+ stickyStyle?: 'fixed' | 'absolute';
118
+ /**
119
+ * 处于sticky状态时的自定义样式
120
+ * @en Custom style when in sticky state
121
+ */
122
+ stickyCssStyle?: CSSProperties;
123
+ /**
124
+ * 被portal时挂载的容器
125
+ * @en Container mounted when being portaled
126
+ * @default () => document.body
127
+ */
128
+ getPortalContainer?: () => HTMLElement;
129
+ /**
130
+ * 吸顶状态切换时触发
131
+ * payload.isSticky: 当前是否为吸顶/吸底状态
132
+ * payload.wasSticky: 前一个状态是否为吸顶/吸底状态
133
+ * @en Triggered when the sticky state is switched
134
+ * @en isSticky: Whether it is currently in the top/bottom state
135
+ * @en Whether the previous state is the top/bottom state
136
+ */
137
+ onStickyStateChange?: (payload: StickyEventPayload) => void;
138
+ /**
139
+ * 滚动时top变化回调,参数为元素距离容器顶部减去topOffset的距离
140
+ * @en The top change callback when scrolling, the parameter is the distance of the element from the top of the container minus topOffset
141
+ */
142
+ onTopChange?: (top: number) => void;
143
+ /**
144
+ * 指定sticky元素的依附容器,sticky元素不会超出容器,在容器离开视口时会跟随
145
+ * 如果返回string则使用querySelector选取容器
146
+ * @en Specifies the attachment container of the sticky element. The sticky element will not exceed the container and will follow when the container leaves the viewport
147
+ * @en If a string is returned, use querySelector to select the container
148
+ */
149
+ getContainer?: () => HTMLElement | string;
150
+ /**
151
+ * 指定滚动容器;如果返回string则使用querySelector选取容器
152
+ * @en Specifies the scrolling container. If this value is specified, the relative property is always regarded as false; if a string is input, use querySelector to select the container
153
+ * @default () => window
154
+ */
155
+ getScrollContainer?: () => HTMLElement | Window | string;
156
+ }
157
+
158
+ /**
159
+ * 粘性布局组件,元素相对于窗口或指定容器的吸顶效果。
160
+ * @en Sticky layout component, The sticky-to-top effect of the element relative to the window or specified container
161
+ * @type 布局
162
+ * @type_en Layout
163
+ * @name 粘性布局
164
+ * @name_en Sticky
165
+ */
166
+ const Sticky = forwardRef((props: StickyProps, ref: Ref<StickyRef>) => {
167
+ const {
168
+ position = 'top',
169
+ topOffset = 0,
170
+ bottomOffset = 0,
171
+ followOffset = 0,
172
+ children,
173
+ className,
174
+ style,
175
+ zIndex = 100,
176
+ portalWhenSticky = false,
177
+ stickyStyle = 'fixed',
178
+ stickyCssStyle: userSetStickyCssStyle,
179
+ getPortalContainer,
180
+ getContainer,
181
+ getScrollContainer,
182
+ onStickyStateChange,
183
+ onTopChange,
184
+ } = props;
185
+ const [isSticky, isStickyRef, setIsSticky] = useRefState(false);
186
+ const [wasSticky, wasStickyRef, setWasSticky] = useRefState(false);
187
+ const [stickyStateStyle, setStickyStateStyle] = useState<CSSProperties>({});
188
+ const contentRef = useRef<HTMLDivElement | null>(null);
189
+ const placeholderRef = useRef<HTMLDivElement | null>(null);
190
+ const contentCalculateHeightRef = useRef<number>(0);
191
+ const containerRef = useRef<HTMLElement | null>(null);
192
+ const scrollContainerRef = useRef<HTMLElement | null | Window>(null);
193
+ const framePendingRef = useRef(false);
194
+
195
+ const containerEventHandler = useCallback(
196
+ ({ followTop, followBottom }) => {
197
+ if (!contentRef.current) {
198
+ return;
199
+ }
200
+ const needTop = position === 'top' || position === 'both';
201
+ const needBottom = position === 'bottom' || position === 'both';
202
+
203
+ const placeholderClientRect = placeholderRef.current!.getBoundingClientRect();
204
+ const contentClientRect = contentRef.current.getBoundingClientRect();
205
+ const calculatedHeight = contentClientRect.height;
206
+ contentCalculateHeightRef.current = contentClientRect.height;
207
+ const { containerRect } = getScrollContainerRect(scrollContainerRef.current);
208
+ const { top: rectTop, bottom: rectBottom, height: containerHeight } = containerRect;
209
+ const scrollStyle = safeGetComputedStyle(scrollContainerRef.current as HTMLElement);
210
+ const borderTop = needTop
211
+ ? convertCssPropertyToNumber(scrollStyle, 'borderTopWidth')
212
+ : 0;
213
+ const borderBottom = needBottom
214
+ ? convertCssPropertyToNumber(scrollStyle, 'borderBottomWidth')
215
+ : 0;
216
+ const containerTop = rectTop + borderTop;
217
+ const containerBottom = rectBottom - borderBottom;
218
+
219
+ const disFromTop = Math.round(placeholderClientRect.top - containerTop);
220
+ const disFromBottom = Math.round(
221
+ placeholderClientRect.top + calculatedHeight - containerBottom,
222
+ );
223
+ const topFollowDifference =
224
+ followBottom - followOffset - calculatedHeight - topOffset - containerTop;
225
+ const bottomFollowDifference =
226
+ containerHeight - followTop - followOffset - calculatedHeight - bottomOffset;
227
+
228
+ setWasSticky(Boolean(isStickyRef.current));
229
+ const isTopSticky = needTop
230
+ ? disFromTop <= topOffset && followBottom > containerTop + followOffset
231
+ : false;
232
+ const isBottomSticky = needBottom
233
+ ? disFromBottom >= -bottomOffset && followTop < containerBottom - followOffset
234
+ : false;
235
+ const newStickyState = isTopSticky || isBottomSticky;
236
+
237
+ let stickyTop = containerTop;
238
+ let stickyBottom = window.innerHeight - containerBottom;
239
+ let stickyLeft = placeholderClientRect.left;
240
+
241
+ if (stickyStyle === 'absolute') {
242
+ const offsetParent = contentRef.current.offsetParent as HTMLElement;
243
+ if (offsetParent) {
244
+ const { containerRect: parentRect } = getScrollContainerRect(offsetParent);
245
+ const parentStyle = safeGetComputedStyle(offsetParent);
246
+ const parentBorderTop = needTop
247
+ ? convertCssPropertyToNumber(parentStyle, 'borderTopWidth')
248
+ : 0;
249
+ const parentBorderBottom = needBottom
250
+ ? convertCssPropertyToNumber(parentStyle, 'borderBottomWidth')
251
+ : 0;
252
+ const parentBorderLeft = convertCssPropertyToNumber(
253
+ parentStyle,
254
+ 'borderLeftWidth',
255
+ );
256
+ stickyTop = containerTop - parentRect.top - parentBorderTop;
257
+ stickyBottom = parentRect.bottom - containerBottom - parentBorderBottom;
258
+ stickyLeft = placeholderClientRect.left - parentRect.left - parentBorderLeft;
259
+ } else {
260
+ stickyTop = 0;
261
+ stickyBottom = 0;
262
+ }
263
+ }
264
+
265
+ const cssTop = stickyTop + topOffset;
266
+ const cssBottom = stickyBottom + bottomOffset;
267
+ let stickyCssStyle: CSSProperties = {};
268
+ if (newStickyState) {
269
+ stickyCssStyle = {
270
+ transform: 'translateZ(0)',
271
+ WebkitTransform: 'translateZ(0)',
272
+ position: stickyStyle === 'absolute' ? 'absolute' : 'fixed',
273
+ zIndex,
274
+ ...(isTopSticky
275
+ ? {
276
+ top: topFollowDifference > 0 ? cssTop : cssTop + topFollowDifference,
277
+ }
278
+ : {}),
279
+ ...(isBottomSticky
280
+ ? {
281
+ bottom:
282
+ bottomFollowDifference > 0
283
+ ? cssBottom
284
+ : cssBottom + bottomFollowDifference,
285
+ }
286
+ : {}),
287
+ left: stickyLeft,
288
+ width: placeholderClientRect.width,
289
+ ...(userSetStickyCssStyle || {}),
290
+ };
291
+ }
292
+ onTopChange?.(Math.max(0, contentClientRect.top - containerTop - topOffset));
293
+
294
+ setIsSticky(newStickyState);
295
+ setStickyStateStyle(stickyCssStyle);
296
+
297
+ if (newStickyState !== wasStickyRef.current) {
298
+ onStickyStateChange &&
299
+ onStickyStateChange({
300
+ isTopSticky,
301
+ isBottomSticky,
302
+ isSticky: newStickyState,
303
+ wasSticky: wasStickyRef.current,
304
+ });
305
+ }
306
+ },
307
+ [
308
+ position,
309
+ topOffset,
310
+ bottomOffset,
311
+ followOffset,
312
+ zIndex,
313
+ stickyStyle,
314
+ onStickyStateChange,
315
+ onTopChange,
316
+ userSetStickyCssStyle,
317
+ ],
318
+ );
319
+
320
+ const recalculatePosition = useCallback(() => {
321
+ if (framePendingRef.current) {
322
+ return;
323
+ }
324
+
325
+ execRAF(() => {
326
+ framePendingRef.current = false;
327
+
328
+ if (containerRef.current) {
329
+ const { top, bottom } = containerRef.current.getBoundingClientRect();
330
+
331
+ containerEventHandler({
332
+ followTop: top,
333
+ followBottom: bottom,
334
+ });
335
+ }
336
+ });
337
+
338
+ framePendingRef.current = true;
339
+ }, [containerEventHandler]);
340
+
341
+ const updatePlaceholderLayoutInner = useCallback(() => {
342
+ if (placeholderRef.current) {
343
+ const contentHeight = contentCalculateHeightRef.current;
344
+ // 当元素吸顶时,默认有一个占位的元素占住该元素的位置,避免布局产生抖动
345
+ // @en When an element is sticky to the top, a placeholder element occupies the element's position by default to avoid jitter in the layout
346
+ placeholderRef.current.style.height = `${isStickyRef.current ? contentHeight : 0}px`;
347
+ }
348
+ }, []);
349
+
350
+ const updatePlaceholderLayout = useCallback(() => {
351
+ if (contentRef.current) {
352
+ const contentClientRect = contentRef.current.getBoundingClientRect();
353
+ contentCalculateHeightRef.current = contentClientRect.height;
354
+ }
355
+ updatePlaceholderLayoutInner();
356
+ }, []);
357
+
358
+ useEffect(() => {
359
+ const containerEle = getActualContainer(getContainer) as HTMLElement;
360
+
361
+ containerRef.current = containerEle || document.body;
362
+
363
+ const eventTarget = getScrollContainer ? getActualContainer(getScrollContainer) : window;
364
+ if (!eventTarget) return;
365
+ scrollContainerRef.current = eventTarget;
366
+
367
+ const attachEventListeners = target => {
368
+ target.addEventListener('scroll', recalculatePosition);
369
+ };
370
+
371
+ const removeEventListeners = target => {
372
+ target.removeEventListener('scroll', recalculatePosition);
373
+ };
374
+
375
+ attachEventListeners(eventTarget);
376
+ recalculatePosition();
377
+
378
+ return () => {
379
+ removeEventListeners(eventTarget);
380
+ };
381
+ }, [getContainer, getScrollContainer, recalculatePosition]);
382
+
383
+ useEffect(() => {
384
+ updatePlaceholderLayoutInner();
385
+ }, [isSticky, wasSticky]);
386
+
387
+ useImperativeHandle(
388
+ ref,
389
+ () => ({
390
+ dom: contentRef.current,
391
+ recalculatePosition,
392
+ updatePlaceholderLayout,
393
+ }),
394
+ [recalculatePosition, updatePlaceholderLayout],
395
+ );
396
+
397
+ const computedStyle = useMemo(
398
+ () => ({ ...(style || {}), ...stickyStateStyle }),
399
+ [stickyStateStyle, style],
400
+ );
401
+
402
+ function renderSticky(prefixCls?: string) {
403
+ return (
404
+ <div
405
+ className={cls(`${prefixCls}-sticky`, className)}
406
+ ref={contentRef}
407
+ style={computedStyle}
408
+ >
409
+ {children}
410
+ </div>
411
+ );
412
+ }
413
+
414
+ return (
415
+ <ContextLayout>
416
+ {({ prefixCls }) => (
417
+ <div>
418
+ <div ref={placeholderRef} />
419
+ {portalWhenSticky && isSticky ? (
420
+ <Portal getContainer={getPortalContainer}>{renderSticky(prefixCls)}</Portal>
421
+ ) : (
422
+ renderSticky(prefixCls)
423
+ )}
424
+ </div>
425
+ )}
426
+ </ContextLayout>
427
+ );
428
+ });
429
+
430
+ export default Sticky;
@@ -0,0 +1,44 @@
1
+ ### 反馈
2
+
3
+ # 滑动操作 SwipeAction
4
+
5
+ 滑动操作组件,左右滑动拉出菜单栏
6
+
7
+ ======
8
+
9
+ > 属性/Props
10
+
11
+ |参数|描述|类型|默认值|
12
+ |----------|-------------|------|------|
13
+ |className|自定义类名|string|-|
14
+ |style|自定义样式|CSSProperties|-|
15
+ |children|子元素|ReactNode|必填|
16
+ |rightActions|右侧菜单|Action\[\]|-|
17
+ |leftActions|左侧菜单|Action\[\]|-|
18
+ |closeOnTouchOutside|点击外部是否自动归位|boolean|false|
19
+ |threshold|菜单滑出多少距离后自动滑出/关闭的系数 范围 0\-1|number|0.15|
20
+ |disabled|是否禁用|boolean|false|
21
+ |transitionDuration|动画的执行时间 (单位ms)|number|300|
22
+ |dampRate|阻尼系数|number|15|
23
+ |openStyleType|菜单滑入时的样式类型,layer \- 分层堆叠进入,push \- 直接依次推入|"layer" \| "push"|"layer"|
24
+ |onOpen|滑出动画结束后触发|(direction: "left" \| "right") =\> void|-|
25
+ |onClose|滑入动画结束后触发|(direction: "left" \| "right") =\> void|-|
26
+
27
+ > 引用/Refs
28
+
29
+ |参数|描述|类型|
30
+ |----------|-------------|------|
31
+ |dom|最外层元素 DOM|HTMLDivElement|
32
+ |close|使滑动条归位|() =\> void|
33
+ |open|打开滑动条,默认打开右边|(direction: "left" \| "right") =\> void|
34
+
35
+ > Action
36
+
37
+ |参数|描述|类型|
38
+ |----------|-------------|------|
39
+ |text|自定义内容|ReactNode|
40
+ |icon|自定义图标|ReactNode|
41
+ |style|自定义样式|CSSProperties|
42
+ |className|自定义类名|string|
43
+ |onClick|点击事件 返回true可以阻止菜单的关闭|() =\> boolean \| void \| Promise\<boolean \| void\>|
44
+ |children|子元素没有text或者icon的传递children|ReactNode|