@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,136 @@
1
+ import React, {
2
+ forwardRef,
3
+ Ref,
4
+ useContext,
5
+ useEffect,
6
+ useImperativeHandle,
7
+ useRef,
8
+ useState,
9
+ } from 'react';
10
+ import { cls } from '@arco-design/mobile-utils';
11
+ import { Collapse } from './collapse';
12
+ import { defaultContextKey, getCollapseContext, CollapseKeyContext } from './utils';
13
+ import { GlobalContext } from '../context-provider';
14
+ import {
15
+ CollapseItemContent,
16
+ CollapseProps,
17
+ CollapseRef,
18
+ CollapseGroupProps,
19
+ CollapseGroupRef,
20
+ } from './type';
21
+
22
+ export function componentGenerator<
23
+ P extends CollapseItemContent = CollapseProps,
24
+ R extends CollapseRef = CollapseRef,
25
+ >(Comp: React.ForwardRefExoticComponent<P & React.RefAttributes<R>>) {
26
+ return forwardRef((props: CollapseGroupProps<P>, ref: Ref<CollapseGroupRef | null>) => {
27
+ const {
28
+ items = [],
29
+ className = '',
30
+ style = {},
31
+ defaultActiveItems = [],
32
+ useAccordion = false,
33
+ disabled = false,
34
+ children,
35
+ groupKey,
36
+ } = props;
37
+ const [innerActiveItems, setInnerActiveItems] = useState<boolean[]>([]);
38
+ const [activeItems, setActiveItems] = useState<boolean[]>([]);
39
+ /** 用于children模式下的active管理 */
40
+ const [childActiveItems, setChildActiveItems] = useState<string[]>([]);
41
+ const contextKey = groupKey || defaultContextKey;
42
+ const CollapseContext = getCollapseContext(contextKey);
43
+ const domRef = useRef<HTMLDivElement | null>(null);
44
+ const { prefixCls } = useContext(GlobalContext);
45
+
46
+ const formatArray = (input: string[]) => {
47
+ const arr = input;
48
+ return items.map(item => arr.indexOf(item.value) > -1);
49
+ };
50
+
51
+ const handleChange = (value: string) => {
52
+ if (disabled) return;
53
+ if (props.onCollapse) {
54
+ props.onCollapse(value);
55
+ }
56
+ if (props.activeItems !== void 0) {
57
+ setInnerActiveItems(formatArray(props.activeItems));
58
+ setChildActiveItems(props.activeItems);
59
+ return;
60
+ }
61
+ if (!children) {
62
+ const temp = items.findIndex(item => item.value === value);
63
+ if (temp < 0 || items[temp].disabled) return;
64
+ const tempActiveItems = innerActiveItems.map((activeItem, index) =>
65
+ index === temp ? !activeItem : !useAccordion && activeItem,
66
+ );
67
+ setInnerActiveItems(tempActiveItems);
68
+ } else {
69
+ const tempValue = childActiveItems.includes(value);
70
+ setChildActiveItems(
71
+ tempValue
72
+ ? childActiveItems.filter(item => item !== value)
73
+ : useAccordion // 手风琴模式只有一个展开项
74
+ ? [value]
75
+ : [...childActiveItems, value],
76
+ );
77
+ }
78
+ };
79
+
80
+ useEffect(() => {
81
+ setInnerActiveItems(formatArray(defaultActiveItems));
82
+ setChildActiveItems(defaultActiveItems);
83
+ }, []);
84
+
85
+ useEffect(() => {
86
+ setActiveItems(
87
+ props.activeItems === void 0 ? innerActiveItems : formatArray(props.activeItems),
88
+ );
89
+ if (children && props.activeItems) {
90
+ setChildActiveItems(props.activeItems);
91
+ }
92
+ }, [props.activeItems, innerActiveItems]);
93
+
94
+ useImperativeHandle(ref, () => ({
95
+ dom: domRef.current,
96
+ }));
97
+
98
+ return (
99
+ <div
100
+ className={cls(`${prefixCls}-collapse-group`, className)}
101
+ style={style}
102
+ ref={domRef}
103
+ >
104
+ <CollapseKeyContext.Provider value={{ key: contextKey }}>
105
+ <CollapseContext.Provider
106
+ value={{
107
+ isGroup: true,
108
+ onCollapse: handleChange,
109
+ disabled,
110
+ value: children ? childActiveItems : void 0,
111
+ }}
112
+ >
113
+ {children || (
114
+ <>
115
+ {items.map((item, index) => {
116
+ const compProps = {
117
+ active: activeItems[index],
118
+ disabled: disabled || item.disabled,
119
+ defaultActive: formatArray(defaultActiveItems)[index],
120
+ ...item,
121
+ };
122
+
123
+ return <Comp key={item.value} {...compProps} />;
124
+ })}
125
+ </>
126
+ )}
127
+ </CollapseContext.Provider>
128
+ </CollapseKeyContext.Provider>
129
+ </div>
130
+ );
131
+ });
132
+ }
133
+
134
+ export const Group = componentGenerator(Collapse);
135
+
136
+ export default Group;
@@ -0,0 +1,16 @@
1
+ import { componentWrapper } from '@arco-design/mobile-utils';
2
+ import { Collapse } from './collapse';
3
+ import Group from './group';
4
+
5
+ export * from './collapse';
6
+ export * from './type';
7
+
8
+ /**
9
+ * 折叠面板组件,支持手风琴模式。
10
+ * @en Collapse supports accordion mode.
11
+ * @type 信息展示
12
+ * @type_en Data Display
13
+ * @name 折叠面板
14
+ * @name_en Collapse
15
+ */
16
+ export default componentWrapper(Collapse, { Group });
@@ -0,0 +1,20 @@
1
+ import React, { Context } from 'react';
2
+ import { GroupContextParams } from './type';
3
+
4
+ export const defaultContextKey = '__COLLAPSE_CONTEXT__';
5
+ export const allContexts: Record<string, Context<GroupContextParams>> = {};
6
+
7
+ export function getCollapseContext(key: string) {
8
+ if (!allContexts[key]) {
9
+ allContexts[key] = React.createContext<GroupContextParams>({
10
+ isGroup: false,
11
+ value: [],
12
+ onCollapse: () => {},
13
+ });
14
+ }
15
+ return allContexts[key];
16
+ }
17
+
18
+ export const CollapseKeyContext = React.createContext<{ key: string }>({
19
+ key: defaultContextKey,
20
+ });
@@ -0,0 +1,44 @@
1
+ ### 其他
2
+
3
+ # 全局配置 ContextProvider
4
+
5
+ 全局数据控制组件,用于替换全局数据。
6
+
7
+ ======
8
+
9
+ > 属性/Props
10
+
11
+ |参数|描述|类型|默认值|
12
+ |----------|-------------|------|------|
13
+ |prefixCls|组件类名前缀|string|"arco"|
14
+ |system|手动控制当前所在系统,传入后将直接使用传入的值,ssr场景需指定系统初始值时适用|"" \| "pc" \| "android" \| "ios"|""|
15
+ |useDarkMode|是否监听系统原生的暗黑模式变化(prefers\-color\-scheme: dark)以判断是否切为暗黑模式|boolean|false|
16
+ |isDarkMode|是否处于暗黑模式,指定后以指定的值为准|boolean|false|
17
+ |darkModeSelector|当处于暗黑模式时,body上挂载的类名,为空值时不挂载类名|string|"arco-theme-dark"|
18
+ |theme|主题变量,传入后将在线替换css变量,需设置less变量 @use\-css\-vars: 1|Record\<string, string\>|-|
19
+ |locale|国际化语言包配置|ILocale|-|
20
+ |useRtl|是否使用Rtl模式|boolean|false|
21
+ |onDarkModeChange|当系统原生暗黑模式发生变化时触发,useDarkMode=true 时有效|(isDark: boolean) =\> void|-|
22
+ |createRoot|React19 修改了 createRoot 的引入路径,导致组件内部无法直接引入(低react版本会找不到模块)。因此使用 react 19 的用户需从外部传入 createRoot 方法|CreateRootFnType|-|
23
+
24
+ > ILocale
25
+
26
+ |参数|描述|类型|
27
+ |----------|-------------|------|
28
+ |locale|语言类型|string|
29
+ |LoadMore|-|\{ loadMoreText: string; loadingText: string; noDataText: string; failLoadText: string; prepareScrollText: string; prepareClickText: string; \}|
30
+ |Picker|-|\{ okText: string; cancelText: string; \}|
31
+ |Tag|-|\{ addTag: string; \}|
32
+ |Dialog|-|\{ okText: string; cancelText: string; \}|
33
+ |SwipeLoad|-|\{ normalText: string; activeText: string; \}|
34
+ |PullRefresh|-|\{ loadingText: string; pullingText: string; finishText: string; loosingText: string; \}|
35
+ |DropdownMenu|-|\{ select: string; \}|
36
+ |Pagination|-|\{ previousPage: string; nextPage: string; \}|
37
+ |Image|-|\{ loadError: string; \}|
38
+ |ImagePicker|-|\{ loadError: string; \}|
39
+ |SearchBar|-|\{ placeholder: string; cancelBtn: string; \}|
40
+ |Stepper|-|\{ minusButtonName: string; addButtonName: string; \}|
41
+ |Keyboard|-|\{ confirm: string; \}|
42
+ |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; \}|
43
+ |NavBar|-|\{ backBtnAriaLabel: string; \}|
44
+ |Uploader|-|\{ uploadBtn: string; retryUpload: string; \}|
@@ -0,0 +1,208 @@
1
+ import React, {
2
+ createContext,
3
+ useState,
4
+ useEffect,
5
+ useCallback,
6
+ useMemo,
7
+ useRef,
8
+ Attributes,
9
+ } from 'react';
10
+ import { addCssRules, removeCssStyleDom, defaultLocale, ILocale } from '@arco-design/mobile-utils';
11
+ import { CreateRootFnType } from '../_helpers';
12
+
13
+ export interface GlobalContextParams {
14
+ /**
15
+ * 组件类名前缀
16
+ * @en Component classname prefix
17
+ * @default "arco"
18
+ */
19
+ prefixCls?: string;
20
+ /**
21
+ * 手动控制当前所在系统,传入后将直接使用传入的值,ssr场景需指定系统初始值时适用
22
+ * @en Manually control the current system, and the incoming value will be used directly after being passed in. It is applicable when the initial value of the system needs to be specified in the ssr scenario.
23
+ * @default ""
24
+ */
25
+ system?: 'pc' | 'android' | 'ios' | '';
26
+ /**
27
+ * 是否监听系统原生的暗黑模式变化(prefers-color-scheme: dark)以判断是否切为暗黑模式
28
+ * @en Whether to monitor the system's native dark mode changes (prefers-color-scheme: dark) to determine whether to switch to dark mode
29
+ * @default false
30
+ */
31
+ useDarkMode?: boolean;
32
+ /**
33
+ * 是否处于暗黑模式,指定后以指定的值为准
34
+ * @en Whether it is in dark mode, the value shall prevail after being specified
35
+ * @default false
36
+ */
37
+ isDarkMode?: boolean;
38
+ /**
39
+ * 当处于暗黑模式时,body上挂载的类名,为空值时不挂载类名
40
+ * @en When in dark mode, the class name mounted on the body, if it is empty, the class name will not be mounted
41
+ * @default "arco-theme-dark"
42
+ */
43
+ darkModeSelector?: string;
44
+ /**
45
+ * 主题变量,传入后将在线替换css变量,需设置less变量 @use-css-vars: 1
46
+ * @en Theme variable. The css variable will be replaced online after input. The less variable needs to be set @use-css-vars: 1
47
+ */
48
+ theme?: Record<string, string>;
49
+ /**
50
+ * 国际化语言包配置
51
+ * @en Internationalized language configuration
52
+ */
53
+ locale?: ILocale;
54
+ /**
55
+ * 是否使用Rtl模式
56
+ * @en Whether to use rtl
57
+ * @default false
58
+ */
59
+ useRtl?: boolean;
60
+ /**
61
+ * 当系统原生暗黑模式发生变化时触发,useDarkMode=true 时有效
62
+ * @en Triggered when the system's native dark mode changes, valid when useDarkMode=true
63
+ */
64
+ onDarkModeChange?: (isDark: boolean) => void;
65
+ /**
66
+ * React19 修改了 createRoot 的引入路径,导致组件内部无法直接引入(低react版本会找不到模块)。因此使用 react 19 的用户需从外部传入 createRoot 方法
67
+ * @en Users using react 19 need to pass in the createRoot method from outside
68
+ */
69
+ createRoot?: CreateRootFnType;
70
+ }
71
+
72
+ const DEFAULT_DARK_MODE_SELECTOR = 'arco-theme-dark';
73
+
74
+ export const defaultContext: GlobalContextParams = {
75
+ prefixCls: 'arco',
76
+ system: '',
77
+ useDarkMode: false,
78
+ darkModeSelector: DEFAULT_DARK_MODE_SELECTOR,
79
+ locale: defaultLocale,
80
+ useRtl: false,
81
+ };
82
+
83
+ export const GlobalContext = createContext<GlobalContextParams>(defaultContext);
84
+
85
+ export interface ContextProviderProps extends GlobalContextParams {
86
+ children: React.ReactNode;
87
+ }
88
+
89
+ export type WithGlobalContext<T> = T & { context?: GlobalContextParams };
90
+
91
+ /**
92
+ * 全局数据控制组件,用于替换全局数据。
93
+ * @en Global data control component, used to replace global data.
94
+ * @type 其他
95
+ * @type_en Others
96
+ * @name 全局配置
97
+ * @name_en ContextProvider
98
+ */
99
+ export default function ContextProvider(props: ContextProviderProps) {
100
+ const {
101
+ children,
102
+ useDarkMode,
103
+ isDarkMode: userSetIsDarkMode,
104
+ darkModeSelector = DEFAULT_DARK_MODE_SELECTOR,
105
+ theme,
106
+ locale = defaultLocale,
107
+ onDarkModeChange,
108
+ ...restProps
109
+ } = props;
110
+
111
+ const [isDarkModeState, setIsDarkModeState] = useState<boolean>(() => {
112
+ if (typeof window !== 'undefined' && useDarkMode) {
113
+ return window.matchMedia('(prefers-color-scheme: dark)').matches;
114
+ }
115
+ return false;
116
+ });
117
+ const mountedRef = useRef(false);
118
+
119
+ const setDarkModeState = (isDark: boolean, needChange = true) => {
120
+ setIsDarkModeState(isDark);
121
+ needChange && onDarkModeChange && onDarkModeChange(isDark);
122
+ };
123
+
124
+ const isDarkMode = useMemo(() => {
125
+ // 如果未开启暗黑模式则不对body做操作
126
+ // @en If dark mode is not turned on, no operation will be performed on the body
127
+ if (userSetIsDarkMode === void 0 && !useDarkMode) {
128
+ return false;
129
+ }
130
+ const value = Boolean(userSetIsDarkMode !== void 0 ? userSetIsDarkMode : isDarkModeState);
131
+ const needUpdateBody = darkModeSelector && typeof document !== 'undefined';
132
+ if (value) {
133
+ needUpdateBody && document.body.classList.add(darkModeSelector);
134
+ } else {
135
+ needUpdateBody && document.body.classList.remove(darkModeSelector);
136
+ }
137
+ return value;
138
+ }, [userSetIsDarkMode, isDarkModeState, darkModeSelector, useDarkMode]);
139
+
140
+ const changeDarkMode = useCallback(
141
+ (res: MediaQueryListEvent) => setDarkModeState(res.matches),
142
+ [],
143
+ );
144
+
145
+ useEffect(() => {
146
+ const matchMedia = window.matchMedia('(prefers-color-scheme: dark)');
147
+ if (useDarkMode) {
148
+ const dark = matchMedia.matches;
149
+ setDarkModeState(dark, mountedRef.current);
150
+ if (typeof matchMedia.addEventListener === 'function') {
151
+ matchMedia.addEventListener('change', changeDarkMode);
152
+ } else if (typeof matchMedia.addListener === 'function') {
153
+ matchMedia.addListener(changeDarkMode);
154
+ }
155
+ }
156
+ mountedRef.current = true;
157
+ return () => {
158
+ if (useDarkMode) {
159
+ if (typeof matchMedia.removeEventListener === 'function') {
160
+ matchMedia.removeEventListener('change', changeDarkMode);
161
+ } else if (typeof matchMedia.removeListener === 'function') {
162
+ matchMedia.removeListener(changeDarkMode);
163
+ }
164
+ }
165
+ };
166
+ }, [useDarkMode]);
167
+
168
+ useEffect(() => {
169
+ if (!theme) {
170
+ return;
171
+ }
172
+ addCssRules('arcoCustomTheme', theme);
173
+ return () => {
174
+ removeCssStyleDom('arcoCustomTheme');
175
+ };
176
+ }, [theme]);
177
+
178
+ return (
179
+ <GlobalContext.Provider
180
+ value={{
181
+ ...defaultContext,
182
+ ...restProps,
183
+ isDarkMode,
184
+ useDarkMode,
185
+ locale: locale || defaultLocale,
186
+ }}
187
+ >
188
+ {children}
189
+ </GlobalContext.Provider>
190
+ );
191
+ }
192
+
193
+ export const ContextLayout = GlobalContext.Consumer;
194
+
195
+ export function CompWithGlobalContext<P extends Attributes>(Component: React.FunctionComponent<P>) {
196
+ return function (props: WithGlobalContext<P>) {
197
+ const { context: propsContext, ...others } = props;
198
+ return (
199
+ <ContextLayout>
200
+ {context => (
201
+ <ContextProvider {...{ ...context, ...propsContext }}>
202
+ <Component {...(others as P)} />
203
+ </ContextProvider>
204
+ )}
205
+ </ContextLayout>
206
+ );
207
+ };
208
+ }
@@ -0,0 +1,40 @@
1
+ ### 信息展示
2
+
3
+ # 倒计时 CountDown
4
+
5
+ 倒计时组件
6
+
7
+ ======
8
+
9
+ > 属性/Props
10
+
11
+ |参数|描述|类型|默认值|
12
+ |----------|-------------|------|------|
13
+ |className|自定义类名|string|-|
14
+ |style|自定义样式|CSSProperties|-|
15
+ |time|倒计时时长,单位毫秒|number \| TimeDataType|0|
16
+ |format|自定义格式 D:天数 DD:天数(个位数补0) H:小时 HH:小时(个位数补0) m:分钟 mm:分钟(个位数补0) s:秒数 ss:秒数(个位数补0) S:毫秒(1 位)SS:毫秒(2 位)SSS:毫秒(3 位)|string|HH:mm:ss|
17
+ |autoStart|是否自动开始倒计时|boolean|true|
18
+ |millisecond|是否开启毫秒级渲染|boolean|false|
19
+ |onFinish|倒计时结束时触发|() =\> void|-|
20
+ |onChange|倒计时变化时触发|(val: TimeDataType, ts: number) =\> void|-|
21
+ |renderChild|自定义内容|(val: TimeDataType) =\> ReactNode|-|
22
+
23
+ > 引用/Refs
24
+
25
+ |参数|描述|类型|
26
+ |----------|-------------|------|
27
+ |dom|最外层元素 DOM|HTMLDivElement|
28
+ |start|开始|() =\> void|
29
+ |pause|暂停|() =\> void|
30
+ |reset|重置|() =\> void|
31
+
32
+ > TimeDataType
33
+
34
+ |参数|描述|类型|
35
+ |----------|-------------|------|
36
+ |days|天数|number|
37
+ |hours|小时|number|
38
+ |minutes|分钟|number|
39
+ |seconds|秒数|number|
40
+ |milliseconds|毫秒|number|
@@ -0,0 +1,118 @@
1
+ import { useState, useEffect, useRef } from 'react';
2
+ import { useRefState } from '../_helpers';
3
+ import { startTask, stopTask } from './singleton';
4
+ import { CountDownProps, TimeDataType } from './type';
5
+ import { parseTime } from './util';
6
+
7
+ export type UseCountDownOptions = {
8
+ time: number;
9
+ } & Pick<CountDownProps, 'millisecond' | 'autoStart' | 'onChange' | 'onFinish'>;
10
+
11
+ export const useCountDown = (options: UseCountDownOptions) => {
12
+ const taskIdRef = useRef<number>(0);
13
+ const endTimeRef = useRef<number | undefined>(undefined);
14
+ const countingRef = useRef<boolean | undefined>(undefined);
15
+ const [remain, remainRef, setRemain] = useRefState(options.time);
16
+ const [current, setCurrent] = useState<TimeDataType>(parseTime(options.time));
17
+ const taskType = options.millisecond ? 'micro' : 'macro';
18
+
19
+ // 暂停
20
+ // @en Pause
21
+ const pause = () => {
22
+ countingRef.current = false;
23
+ stopTask(taskType, taskIdRef.current);
24
+ };
25
+ // 计算当前剩余时间,以毫秒为单位
26
+ // @en Calculate the current remaining time in milliseconds
27
+ const getCurrentRemain = () => {
28
+ const leftTime = Math.max((endTimeRef.current as number) - Date.now(), 0);
29
+ if (options.millisecond) {
30
+ return leftTime;
31
+ }
32
+ return Math.round(leftTime / 1000) * 1000;
33
+ };
34
+ const setRemainCallback = (value: number) => {
35
+ setRemain(value);
36
+ const time: TimeDataType = parseTime(value);
37
+ if (options.onChange && value !== options.time) {
38
+ options.onChange(time, value);
39
+ }
40
+ if (value === 0) {
41
+ setCurrent(time);
42
+ pause();
43
+ options.onFinish?.();
44
+ }
45
+ };
46
+ // 开启任务
47
+ // @en start tasks
48
+ const tick = () => {
49
+ taskIdRef.current = startTask(taskType, () => {
50
+ if (countingRef.current) {
51
+ setRemainCallback(getCurrentRemain());
52
+ return remainRef.current > 0;
53
+ }
54
+ return false;
55
+ });
56
+ };
57
+ // 开始
58
+ // @en Start
59
+ const start = (reStart = false) => {
60
+ if (!countingRef.current) {
61
+ if (reStart) {
62
+ endTimeRef.current = Date.now() + options.time;
63
+ } else {
64
+ endTimeRef.current = Date.now() + remainRef.current;
65
+ }
66
+ countingRef.current = true;
67
+ tick();
68
+ }
69
+ };
70
+ // 重置
71
+ // @en Reset
72
+ const reset = () => {
73
+ const totalTime = options.time;
74
+ endTimeRef.current = Date.now() + totalTime;
75
+ pause();
76
+ setRemainCallback(totalTime);
77
+ if (options.autoStart) {
78
+ start(true);
79
+ }
80
+ };
81
+
82
+ useEffect(() => {
83
+ // ummounted时如果正在运行倒计时则暂停
84
+ // @en Pause if the countdown is running when ummounted
85
+ return () => {
86
+ if (countingRef.current) {
87
+ pause();
88
+ }
89
+ };
90
+ }, []);
91
+
92
+ // 设置自动开始倒计时时自动启动
93
+ // @en Set to start automatically when the countdown starts automatically
94
+ useEffect(() => {
95
+ if (options.autoStart) {
96
+ start();
97
+ }
98
+ }, [options.autoStart]);
99
+
100
+ // 倒计时设置变化时重新计时
101
+ // @en Re-time when countdown settings change
102
+ useEffect(() => {
103
+ reset();
104
+ }, [options.time]);
105
+
106
+ // remain变化时同步current 即把毫秒转化为TimeDataType类型
107
+ // @en Synchronize current when remain changes, that is, convert milliseconds to TimeDataType
108
+ useEffect(() => {
109
+ setCurrent(parseTime(remain));
110
+ }, [remain]);
111
+
112
+ return {
113
+ start,
114
+ pause,
115
+ reset,
116
+ current,
117
+ };
118
+ };
@@ -0,0 +1,63 @@
1
+ import React, { useRef, forwardRef, Ref, useImperativeHandle, useMemo } from 'react';
2
+ import { unParseTime, parseFormat } from './util';
3
+ import { useCountDown } from './hooks';
4
+ import { ContextLayout } from '../context-provider';
5
+ import { CountDownProps, CountDownRef } from './type';
6
+
7
+ export * from './type';
8
+
9
+ /**
10
+ * 倒计时组件
11
+ * @en Countdown Component
12
+ * @name 倒计时
13
+ * @name_en CountDown
14
+ * @type 信息展示
15
+ * @type_en Data Display
16
+ */
17
+ const CountDown = forwardRef((props: CountDownProps, ref: Ref<CountDownRef>) => {
18
+ const {
19
+ className = '',
20
+ style = {},
21
+ time = 0,
22
+ format = 'HH:mm:ss',
23
+ autoStart = true,
24
+ millisecond = false,
25
+ onFinish,
26
+ onChange,
27
+ renderChild,
28
+ } = props;
29
+ const domRef = useRef<HTMLDivElement>(null);
30
+
31
+ // 传入倒计时等变量得到开始暂停启动三个方法以及目前所剩时间current(TimeDataType格式)
32
+ // @en get start, pause, reset methods and the current remaining time —— current (TimeDataType format) by inputing variables such as countdown
33
+ const { start, pause, reset, current } = useCountDown({
34
+ time: typeof time === 'number' ? time : unParseTime(time),
35
+ millisecond,
36
+ onChange,
37
+ onFinish,
38
+ autoStart,
39
+ });
40
+
41
+ // 导出dom以及start,pause,reset三个方法
42
+ // @en Export dom and three methods of start, pause and reset
43
+ useImperativeHandle(ref, () => ({
44
+ dom: domRef.current,
45
+ start,
46
+ pause,
47
+ reset,
48
+ }));
49
+
50
+ const currentStr = useMemo(() => parseFormat(format, current), [format, current]);
51
+
52
+ return (
53
+ <ContextLayout>
54
+ {({ prefixCls }) => (
55
+ <div className={`${prefixCls}-count-down ${className}`} style={style} ref={domRef}>
56
+ {renderChild ? renderChild(current) : currentStr}
57
+ </div>
58
+ )}
59
+ </ContextLayout>
60
+ );
61
+ });
62
+
63
+ export default CountDown;