@seakoi/native-ui 1.1.3 → 1.2.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 (224) hide show
  1. package/CHANGELOG.md +17 -0
  2. package/dist/commonjs/components/base/carousel/carousel-indicator.js +56 -0
  3. package/dist/commonjs/components/base/carousel/carousel-slides.js +140 -0
  4. package/dist/commonjs/components/base/carousel/carousel.js +114 -122
  5. package/dist/commonjs/components/base/carousel/hooks/index.js +0 -14
  6. package/dist/commonjs/components/base/carousel/hooks/use-carousel-index.js +16 -13
  7. package/dist/commonjs/components/base/carousel/hooks/use-carousel-lifecycle.js +6 -2
  8. package/dist/commonjs/components/base/carousel/hooks/use-carousel-pan-responder.js +40 -12
  9. package/dist/commonjs/components/base/carousel/hooks/use-carousel-position.js +6 -2
  10. package/dist/commonjs/components/base/carousel/index.js +1 -15
  11. package/dist/commonjs/components/base/carousel/style/index.js +12 -0
  12. package/dist/commonjs/components/base/date-picker/date-picker.js +56 -44
  13. package/dist/commonjs/components/base/date-picker/date-range-picker.js +142 -50
  14. package/dist/commonjs/components/base/date-picker/style/index.js +15 -0
  15. package/dist/commonjs/components/base/date-picker-view/date-picker-view.js +19 -53
  16. package/dist/commonjs/components/base/date-picker-view/index.js +0 -22
  17. package/dist/commonjs/components/base/index.js +30 -8
  18. package/dist/commonjs/components/base/picker/index.js +26 -4
  19. package/dist/commonjs/components/base/picker/picker-content.js +60 -0
  20. package/dist/commonjs/components/base/picker/picker-context.js +9 -0
  21. package/dist/commonjs/components/base/picker/picker-field.js +37 -0
  22. package/dist/commonjs/components/base/picker/picker.js +22 -96
  23. package/dist/commonjs/components/base/picker/style/index.js +1 -3
  24. package/dist/commonjs/components/base/picker-backup/base-picker-container.js +50 -0
  25. package/dist/commonjs/components/base/picker-backup/index.js +27 -0
  26. package/dist/commonjs/components/base/picker-backup/picker-backup.js +75 -0
  27. package/dist/commonjs/components/base/picker-backup/picker-copy.js +106 -0
  28. package/dist/commonjs/components/base/{picker → picker-backup}/picker-trigger.js +5 -5
  29. package/dist/commonjs/components/base/picker-backup/style/index.js +19 -0
  30. package/dist/commonjs/components/base/picker-backup/utils.js +53 -0
  31. package/dist/commonjs/components/base/picker-view/picker-view-column.js +15 -0
  32. package/dist/commonjs/components/base/picker-view/picker-view.js +4 -4
  33. package/dist/commonjs/components/base/tag/index.js +20 -0
  34. package/dist/commonjs/components/base/tag/style/index.js +89 -0
  35. package/dist/commonjs/components/base/tag/tag-context.js +12 -0
  36. package/dist/commonjs/components/base/tag/tag-group.js +35 -0
  37. package/dist/commonjs/components/base/tag/tag.js +47 -0
  38. package/dist/commonjs/components/base/tag/types.js +5 -0
  39. package/dist/module/components/base/carousel/carousel-indicator.js +51 -0
  40. package/dist/module/components/base/carousel/carousel-slides.js +135 -0
  41. package/dist/module/components/base/carousel/carousel.js +116 -124
  42. package/dist/module/components/base/carousel/hooks/index.js +0 -2
  43. package/dist/module/components/base/carousel/hooks/use-carousel-index.js +15 -11
  44. package/dist/module/components/base/carousel/hooks/use-carousel-lifecycle.js +6 -2
  45. package/dist/module/components/base/carousel/hooks/use-carousel-pan-responder.js +40 -11
  46. package/dist/module/components/base/carousel/hooks/use-carousel-position.js +5 -1
  47. package/dist/module/components/base/carousel/index.js +1 -5
  48. package/dist/module/components/base/carousel/style/index.js +12 -0
  49. package/dist/module/components/base/date-picker/date-picker.js +60 -48
  50. package/dist/module/components/base/date-picker/date-range-picker.js +146 -54
  51. package/dist/module/components/base/date-picker/style/index.js +11 -0
  52. package/dist/module/components/base/date-picker-view/date-picker-view.js +23 -57
  53. package/dist/module/components/base/date-picker-view/index.js +1 -3
  54. package/dist/module/components/base/index.js +2 -0
  55. package/dist/module/components/base/picker/index.js +9 -1
  56. package/dist/module/components/base/picker/picker-content.js +54 -0
  57. package/dist/module/components/base/picker/picker-context.js +4 -0
  58. package/dist/module/components/base/picker/picker-field.js +32 -0
  59. package/dist/module/components/base/picker/picker.js +25 -99
  60. package/dist/module/components/base/picker/style/index.js +1 -3
  61. package/dist/module/components/base/picker-backup/base-picker-container.js +44 -0
  62. package/dist/module/components/base/picker-backup/index.js +4 -0
  63. package/dist/module/components/base/picker-backup/picker-backup.js +69 -0
  64. package/dist/module/components/base/picker-backup/picker-copy.js +101 -0
  65. package/dist/module/components/base/{picker → picker-backup}/picker-trigger.js +2 -2
  66. package/dist/module/components/base/picker-backup/style/index.js +15 -0
  67. package/dist/module/components/base/picker-backup/utils.js +48 -0
  68. package/dist/module/components/base/picker-view/picker-view-column.js +15 -0
  69. package/dist/module/components/base/picker-view/picker-view.js +4 -4
  70. package/dist/module/components/base/tag/index.js +5 -0
  71. package/dist/module/components/base/tag/style/index.js +85 -0
  72. package/dist/module/components/base/tag/tag-context.js +8 -0
  73. package/dist/module/components/base/tag/tag-group.js +29 -0
  74. package/dist/module/components/base/tag/tag.js +41 -0
  75. package/dist/module/components/base/tag/types.js +3 -0
  76. package/dist/typescript/components/base/carousel/carousel-indicator.d.ts +42 -0
  77. package/dist/typescript/components/base/carousel/carousel-indicator.d.ts.map +1 -0
  78. package/dist/typescript/components/base/carousel/carousel-slides.d.ts +49 -0
  79. package/dist/typescript/components/base/carousel/carousel-slides.d.ts.map +1 -0
  80. package/dist/typescript/components/base/carousel/carousel.d.ts +16 -11
  81. package/dist/typescript/components/base/carousel/carousel.d.ts.map +1 -1
  82. package/dist/typescript/components/base/carousel/hooks/index.d.ts +0 -2
  83. package/dist/typescript/components/base/carousel/hooks/index.d.ts.map +1 -1
  84. package/dist/typescript/components/base/carousel/hooks/use-carousel-index.d.ts.map +1 -1
  85. package/dist/typescript/components/base/carousel/hooks/use-carousel-lifecycle.d.ts.map +1 -1
  86. package/dist/typescript/components/base/carousel/hooks/use-carousel-pan-responder.d.ts.map +1 -1
  87. package/dist/typescript/components/base/carousel/hooks/use-carousel-position.d.ts.map +1 -1
  88. package/dist/typescript/components/base/carousel/index.d.ts +1 -4
  89. package/dist/typescript/components/base/carousel/index.d.ts.map +1 -1
  90. package/dist/typescript/components/base/carousel/style/index.d.ts +12 -0
  91. package/dist/typescript/components/base/carousel/style/index.d.ts.map +1 -1
  92. package/dist/typescript/components/base/carousel/types.d.ts +8 -17
  93. package/dist/typescript/components/base/carousel/types.d.ts.map +1 -1
  94. package/dist/typescript/components/base/date-picker/date-picker.d.ts +4 -2
  95. package/dist/typescript/components/base/date-picker/date-picker.d.ts.map +1 -1
  96. package/dist/typescript/components/base/date-picker/date-range-picker.d.ts +12 -3
  97. package/dist/typescript/components/base/date-picker/date-range-picker.d.ts.map +1 -1
  98. package/dist/typescript/components/base/date-picker/style/index.d.ts +9 -0
  99. package/dist/typescript/components/base/date-picker/style/index.d.ts.map +1 -0
  100. package/dist/typescript/components/base/date-picker-view/date-picker-view.d.ts +1 -6
  101. package/dist/typescript/components/base/date-picker-view/date-picker-view.d.ts.map +1 -1
  102. package/dist/typescript/components/base/date-picker-view/index.d.ts +0 -2
  103. package/dist/typescript/components/base/date-picker-view/index.d.ts.map +1 -1
  104. package/dist/typescript/components/base/date-picker-view/types.d.ts +1 -1
  105. package/dist/typescript/components/base/index.d.ts +2 -0
  106. package/dist/typescript/components/base/index.d.ts.map +1 -1
  107. package/dist/typescript/components/base/picker/index.d.ts +7 -1
  108. package/dist/typescript/components/base/picker/index.d.ts.map +1 -1
  109. package/dist/typescript/components/base/picker/picker-content.d.ts +15 -0
  110. package/dist/typescript/components/base/picker/picker-content.d.ts.map +1 -0
  111. package/dist/typescript/components/base/picker/picker-context.d.ts +18 -0
  112. package/dist/typescript/components/base/picker/picker-context.d.ts.map +1 -0
  113. package/dist/typescript/components/base/picker/picker-field.d.ts +10 -0
  114. package/dist/typescript/components/base/picker/picker-field.d.ts.map +1 -0
  115. package/dist/typescript/components/base/picker/picker.d.ts +13 -11
  116. package/dist/typescript/components/base/picker/picker.d.ts.map +1 -1
  117. package/dist/typescript/components/base/picker/style/index.d.ts +0 -2
  118. package/dist/typescript/components/base/picker/style/index.d.ts.map +1 -1
  119. package/dist/typescript/components/base/picker-backup/base-picker-container.d.ts +15 -0
  120. package/dist/typescript/components/base/picker-backup/base-picker-container.d.ts.map +1 -0
  121. package/dist/typescript/components/base/picker-backup/index.d.ts +3 -0
  122. package/dist/typescript/components/base/picker-backup/index.d.ts.map +1 -0
  123. package/dist/typescript/components/base/picker-backup/picker-backup.d.ts +26 -0
  124. package/dist/typescript/components/base/picker-backup/picker-backup.d.ts.map +1 -0
  125. package/dist/typescript/components/base/picker-backup/picker-copy.d.ts +13 -0
  126. package/dist/typescript/components/base/picker-backup/picker-copy.d.ts.map +1 -0
  127. package/dist/typescript/components/base/picker-backup/picker-trigger.d.ts.map +1 -0
  128. package/dist/typescript/components/base/picker-backup/style/index.d.ts +13 -0
  129. package/dist/typescript/components/base/picker-backup/style/index.d.ts.map +1 -0
  130. package/dist/typescript/components/base/picker-backup/utils.d.ts +8 -0
  131. package/dist/typescript/components/base/picker-backup/utils.d.ts.map +1 -0
  132. package/dist/typescript/components/base/picker-view/picker-view-column.d.ts.map +1 -1
  133. package/dist/typescript/components/base/picker-view/utils/picker.d.ts +3 -3
  134. package/dist/typescript/components/base/picker-view/utils/picker.d.ts.map +1 -1
  135. package/dist/typescript/components/base/tag/index.d.ts +5 -0
  136. package/dist/typescript/components/base/tag/index.d.ts.map +1 -0
  137. package/dist/typescript/components/base/tag/style/index.d.ts +61 -0
  138. package/dist/typescript/components/base/tag/style/index.d.ts.map +1 -0
  139. package/dist/typescript/components/base/tag/tag-context.d.ts +3 -0
  140. package/dist/typescript/components/base/tag/tag-context.d.ts.map +1 -0
  141. package/dist/typescript/components/base/tag/tag-group.d.ts +4 -0
  142. package/dist/typescript/components/base/tag/tag-group.d.ts.map +1 -0
  143. package/dist/typescript/components/base/tag/tag.d.ts +4 -0
  144. package/dist/typescript/components/base/tag/tag.d.ts.map +1 -0
  145. package/dist/typescript/components/base/tag/types.d.ts +48 -0
  146. package/dist/typescript/components/base/tag/types.d.ts.map +1 -0
  147. package/package.json +1 -1
  148. package/src/components/base/carousel/carousel-indicator.tsx +80 -0
  149. package/src/components/base/carousel/carousel-slides.tsx +177 -0
  150. package/src/components/base/carousel/carousel.tsx +108 -118
  151. package/src/components/base/carousel/hooks/index.ts +0 -2
  152. package/src/components/base/carousel/hooks/use-carousel-index.ts +13 -9
  153. package/src/components/base/carousel/hooks/use-carousel-lifecycle.ts +4 -3
  154. package/src/components/base/carousel/hooks/use-carousel-pan-responder.ts +40 -16
  155. package/src/components/base/carousel/hooks/use-carousel-position.ts +4 -1
  156. package/src/components/base/carousel/index.ts +1 -3
  157. package/src/components/base/carousel/style/index.ts +12 -0
  158. package/src/components/base/carousel/types.ts +8 -21
  159. package/src/components/base/date-picker/date-picker.tsx +64 -61
  160. package/src/components/base/date-picker/date-range-picker.tsx +178 -70
  161. package/src/components/base/date-picker/style/index.ts +10 -0
  162. package/src/components/base/date-picker-view/date-picker-view.tsx +21 -68
  163. package/src/components/base/date-picker-view/index.ts +0 -2
  164. package/src/components/base/date-picker-view/types.ts +1 -1
  165. package/src/components/base/index.ts +2 -0
  166. package/src/components/base/picker/index.ts +11 -1
  167. package/src/components/base/picker/picker-content.tsx +75 -0
  168. package/src/components/base/picker/picker-context.ts +19 -0
  169. package/src/components/base/picker/picker-field.tsx +50 -0
  170. package/src/components/base/picker/picker.tsx +38 -114
  171. package/src/components/base/picker/style/index.ts +0 -2
  172. package/src/components/base/picker-backup/base-picker-container.tsx +55 -0
  173. package/src/components/base/picker-backup/index.ts +2 -0
  174. package/src/components/base/picker-backup/picker-backup.tsx +110 -0
  175. package/src/components/base/picker-backup/picker-copy.tsx +125 -0
  176. package/src/components/base/{picker → picker-backup}/picker-trigger.tsx +2 -2
  177. package/src/components/base/picker-backup/style/index.ts +14 -0
  178. package/src/components/base/picker-backup/utils.ts +62 -0
  179. package/src/components/base/picker-view/picker-view-column.tsx +20 -0
  180. package/src/components/base/picker-view/picker-view.tsx +4 -4
  181. package/src/components/base/picker-view/utils/picker.ts +3 -5
  182. package/src/components/base/tag/index.ts +5 -0
  183. package/src/components/base/tag/style/index.tsx +84 -0
  184. package/src/components/base/tag/tag-context.ts +9 -0
  185. package/src/components/base/tag/tag-group.tsx +31 -0
  186. package/src/components/base/tag/tag.tsx +50 -0
  187. package/src/components/base/tag/types.ts +71 -0
  188. package/dist/commonjs/components/base/carousel/carousel-item.js +0 -45
  189. package/dist/commonjs/components/base/carousel/constants.js +0 -25
  190. package/dist/commonjs/components/base/carousel/hooks/use-carousel-indicator.js +0 -63
  191. package/dist/commonjs/components/base/carousel/hooks/use-carousel-slides.js +0 -95
  192. package/dist/commonjs/components/base/carousel/utils.js +0 -63
  193. package/dist/commonjs/components/base/date-picker-view/date-range-picker-view.js +0 -145
  194. package/dist/commonjs/components/base/date-picker-view/date-time-picker.js +0 -39
  195. package/dist/module/components/base/carousel/carousel-item.js +0 -40
  196. package/dist/module/components/base/carousel/constants.js +0 -21
  197. package/dist/module/components/base/carousel/hooks/use-carousel-indicator.js +0 -58
  198. package/dist/module/components/base/carousel/hooks/use-carousel-slides.js +0 -90
  199. package/dist/module/components/base/carousel/utils.js +0 -55
  200. package/dist/module/components/base/date-picker-view/date-range-picker-view.js +0 -138
  201. package/dist/module/components/base/date-picker-view/date-time-picker.js +0 -34
  202. package/dist/typescript/components/base/carousel/carousel-item.d.ts +0 -26
  203. package/dist/typescript/components/base/carousel/carousel-item.d.ts.map +0 -1
  204. package/dist/typescript/components/base/carousel/constants.d.ts +0 -17
  205. package/dist/typescript/components/base/carousel/constants.d.ts.map +0 -1
  206. package/dist/typescript/components/base/carousel/hooks/use-carousel-indicator.d.ts +0 -37
  207. package/dist/typescript/components/base/carousel/hooks/use-carousel-indicator.d.ts.map +0 -1
  208. package/dist/typescript/components/base/carousel/hooks/use-carousel-slides.d.ts +0 -51
  209. package/dist/typescript/components/base/carousel/hooks/use-carousel-slides.d.ts.map +0 -1
  210. package/dist/typescript/components/base/carousel/utils.d.ts +0 -25
  211. package/dist/typescript/components/base/carousel/utils.d.ts.map +0 -1
  212. package/dist/typescript/components/base/date-picker-view/date-range-picker-view.d.ts +0 -26
  213. package/dist/typescript/components/base/date-picker-view/date-range-picker-view.d.ts.map +0 -1
  214. package/dist/typescript/components/base/date-picker-view/date-time-picker.d.ts +0 -3
  215. package/dist/typescript/components/base/date-picker-view/date-time-picker.d.ts.map +0 -1
  216. package/dist/typescript/components/base/picker/picker-trigger.d.ts.map +0 -1
  217. package/src/components/base/carousel/carousel-item.tsx +0 -35
  218. package/src/components/base/carousel/constants.ts +0 -19
  219. package/src/components/base/carousel/hooks/use-carousel-indicator.tsx +0 -84
  220. package/src/components/base/carousel/hooks/use-carousel-slides.tsx +0 -131
  221. package/src/components/base/carousel/utils.ts +0 -55
  222. package/src/components/base/date-picker-view/date-range-picker-view.tsx +0 -191
  223. package/src/components/base/date-picker-view/date-time-picker.tsx +0 -34
  224. /package/dist/typescript/components/base/{picker → picker-backup}/picker-trigger.d.ts +0 -0
@@ -2,12 +2,19 @@
2
2
 
3
3
  import { clamp } from 'lodash-es';
4
4
  import React, { useCallback, useMemo, useState } from 'react';
5
- import { Animated, StyleSheet, View } from 'react-native';
5
+ import { Animated, View } from 'react-native';
6
6
  import { useTheme } from "../../../native-provider/index.js";
7
- import { useCarouselAutoplay, useCarouselIndex, useCarouselIndicator, useCarouselLifecycle, useCarouselPanResponder, useCarouselPosition, useCarouselSlides, useCarouselSwipe } from "./hooks/index.js";
7
+ import { CarouselIndicator } from "./carousel-indicator.js";
8
+ import { CarouselSlides } from "./carousel-slides.js";
9
+ import { useCarouselAutoplay, useCarouselIndex, useCarouselLifecycle, useCarouselPanResponder, useCarouselPosition, useCarouselSwipe } from "./hooks/index.js";
8
10
  import { useCarouselStyles } from "./style/index.js";
9
- import { getDefaultTotal, isRenderPropChildren } from "./utils.js";
10
11
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
12
+ /**
13
+ * 虚拟渲染触发阈值
14
+ * 当轮播项数量超过此值时启用虚拟渲染优化
15
+ */
16
+ const VIRTUAL_RENDER_THRESHOLD = 10;
17
+
11
18
  /**
12
19
  * 轮播图组件
13
20
  *
@@ -16,20 +23,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
16
23
  * @example
17
24
  * ```tsx
18
25
  * // 基础用法
19
- * <Carousel>
20
- * <Carousel.Item><View /></Carousel.Item>
21
- * <Carousel.Item><View /></Carousel.Item>
22
- * </Carousel>
26
+ * <Carousel
27
+ * data={[1, 2, 3]}
28
+ * renderItem={(item) => <View><Text>{item}</Text></View>}
29
+ * />
23
30
  *
24
31
  * // 循环播放和自动轮播
25
- * <Carousel loop autoplay autoplayInterval={3000}>
26
- * {items.map(item => <Carousel.Item key={item.id}>{item.content}</Carousel.Item>)}
27
- * </Carousel>
32
+ * <Carousel
33
+ * data={items}
34
+ * renderItem={(item) => <View>{item.content}</View>}
35
+ * loop
36
+ * autoplay
37
+ * autoplayInterval={3000}
38
+ * />
28
39
  *
29
40
  * // 虚拟渲染(大量数据)
30
- * <Carousel total={1000}>
31
- * {(index) => <Carousel.Item><Text>{index}</Text></Carousel.Item>}
32
- * </Carousel>
41
+ * <Carousel
42
+ * data={largeDataArray}
43
+ * renderItem={(item, index) => <View><Text>{index}: {item}</Text></View>}
44
+ * />
33
45
  * ```
34
46
  *
35
47
  * @param props - 组件属性
@@ -51,35 +63,43 @@ export const Carousel = props => {
51
63
  stuckAtBoundary = true,
52
64
  rubberband = true,
53
65
  virtualOverscan = 2,
54
- total: totalProp,
55
- children,
66
+ data,
67
+ renderItem,
56
68
  style,
57
69
  blockNativeResponder = true,
58
70
  ref
59
71
  } = props;
60
72
  const styles = useCarouselStyles();
61
73
  const theme = useTheme();
74
+
75
+ // 使用 state 存储 layout,使依赖更明确
62
76
  const [layout, setLayout] = useState({
63
77
  width: 0,
64
78
  height: 0
65
79
  });
66
- const [dragging, setDragging] = useState(false);
67
- const [animating, setAnimating] = useState(false);
68
- const normalizedSlideSize = useMemo(() => {
69
- if (!Number.isFinite(slideSize)) return 100;
70
- return clamp(slideSize, 0, 100);
71
- }, [slideSize]);
72
- const normalizedTrackOffset = useMemo(() => {
80
+
81
+ // 分离拖动和动画状态,避免状态冲突
82
+ const [isDragging, setIsDragging] = useState(false);
83
+ const [isAnimating, setIsAnimating] = useState(false);
84
+
85
+ // 合并归一化计算,减少 useMemo 调用
86
+ const {
87
+ normalizedSlideSize,
88
+ normalizedTrackOffset
89
+ } = useMemo(() => {
90
+ const slideSize_ = Number.isFinite(slideSize) ? clamp(slideSize, 0, 100) : 100;
91
+ let trackOffset_;
73
92
  if (stuckAtBoundary) {
74
- return 100 - normalizedSlideSize;
93
+ trackOffset_ = 100 - slideSize_;
94
+ } else {
95
+ trackOffset_ = Number.isFinite(trackOffset) ? clamp(trackOffset, 0, 100 - slideSize_) : 0;
75
96
  }
76
- if (!Number.isFinite(trackOffset)) return 0;
77
- return clamp(trackOffset, 0, 100 - normalizedSlideSize);
78
- }, [normalizedSlideSize, trackOffset, stuckAtBoundary]);
79
- const total = useMemo(() => {
80
- const normalizedDefault = getDefaultTotal(children);
81
- return totalProp ?? normalizedDefault;
82
- }, [children, totalProp]);
97
+ return {
98
+ normalizedSlideSize: slideSize_,
99
+ normalizedTrackOffset: trackOffset_
100
+ };
101
+ }, [slideSize, trackOffset, stuckAtBoundary]);
102
+ const total = data.length;
83
103
  const loopEnabled = loop && total > 1;
84
104
 
85
105
  // 计算循环播放时需要克隆的前置节点数量
@@ -100,16 +120,22 @@ export const Carousel = props => {
100
120
  return Math.max(1, trailingSlides + 1);
101
121
  }, [loopEnabled, normalizedSlideSize, normalizedTrackOffset]);
102
122
  const extTotal = loopEnabled ? total + clonesBefore + clonesAfter : total;
103
- const slidePixels = useMemo(() => {
104
- const trackSize = direction === 'horizontal' ? layout.width : layout.height;
105
- if (trackSize <= 0) return 0;
106
- return trackSize * (normalizedSlideSize / 100);
107
- }, [direction, layout.height, layout.width, normalizedSlideSize]);
108
- const trackOffsetPixels = useMemo(() => {
123
+
124
+ // 合并像素计算,减少重复的 trackSize 获取
125
+ const {
126
+ slidePixels,
127
+ trackOffsetPixels
128
+ } = useMemo(() => {
109
129
  const trackSize = direction === 'horizontal' ? layout.width : layout.height;
110
- if (trackSize <= 0) return 0;
111
- return trackSize * (normalizedTrackOffset / 100);
112
- }, [direction, layout.height, layout.width, normalizedTrackOffset]);
130
+ if (trackSize <= 0) return {
131
+ slidePixels: 0,
132
+ trackOffsetPixels: 0
133
+ };
134
+ return {
135
+ slidePixels: trackSize * (normalizedSlideSize / 100),
136
+ trackOffsetPixels: trackSize * (normalizedTrackOffset / 100)
137
+ };
138
+ }, [direction, layout, normalizedSlideSize, normalizedTrackOffset]);
113
139
  const {
114
140
  current,
115
141
  updateCurrent,
@@ -140,6 +166,14 @@ export const Carousel = props => {
140
166
  setPositionImmediate
141
167
  } = useCarouselPosition();
142
168
 
169
+ // 状态设置函数
170
+ const setDragging = useCallback(dragging => {
171
+ setIsDragging(dragging);
172
+ }, []);
173
+ const setAnimating = useCallback(animating => {
174
+ setIsAnimating(animating);
175
+ }, []);
176
+
143
177
  // 切换逻辑
144
178
  const {
145
179
  swipeNext,
@@ -168,7 +202,7 @@ export const Carousel = props => {
168
202
  autoplay,
169
203
  autoplayInterval,
170
204
  total,
171
- dragging,
205
+ dragging: isDragging,
172
206
  current,
173
207
  swipeNext,
174
208
  swipePrev
@@ -192,11 +226,13 @@ export const Carousel = props => {
192
226
  height
193
227
  } = e.nativeEvent.layout;
194
228
  setLayout(prev => {
195
- if (prev.width === width && prev.height === height) return prev;
196
- return {
197
- width,
198
- height
199
- };
229
+ if (prev.width !== width || prev.height !== height) {
230
+ return {
231
+ width,
232
+ height
233
+ };
234
+ }
235
+ return prev;
200
236
  });
201
237
  }, []);
202
238
  const panResponder = useCarouselPanResponder({
@@ -231,15 +267,17 @@ export const Carousel = props => {
231
267
  }, [direction, position, trackOffsetPixels]);
232
268
 
233
269
  // 计算虚拟渲染的范围
234
- // 注意: extIndexRef 的变化不会触发重新计算,
235
- // 通过 dragging 和 animating 状态的变化来触发虚拟范围的更新
270
+ // 使用 current 状态而不是 extIndexRef,确保虚拟范围与当前索引同步
236
271
  const virtualRange = useMemo(() => {
237
272
  if (total <= 0 || slidePixels <= 0) {
238
273
  return null;
239
274
  }
240
- const isVirtual = isRenderPropChildren(children) && typeof totalProp === 'number';
241
- const effectiveOverscan = isVirtual ? Math.max(virtualOverscan, dragging || animating ? 1 : 0) : virtualOverscan;
242
- const currentExtIndex = extIndexRef.current;
275
+ const isVirtual = total > VIRTUAL_RENDER_THRESHOLD;
276
+ const isInteracting = isDragging || isAnimating;
277
+ const effectiveOverscan = isVirtual ? Math.max(virtualOverscan, isInteracting ? 1 : 0) : virtualOverscan;
278
+
279
+ // 使用 current 计算 extIndex,确保响应式更新
280
+ const currentExtIndex = loopEnabled ? current + clonesBefore : current;
243
281
  const start = isVirtual ? clamp(currentExtIndex - effectiveOverscan, 0, extTotal - 1) : 0;
244
282
  const end = isVirtual ? clamp(currentExtIndex + effectiveOverscan, 0, extTotal - 1) : extTotal - 1;
245
283
  return {
@@ -247,87 +285,41 @@ export const Carousel = props => {
247
285
  end,
248
286
  isVirtual
249
287
  };
250
- }, [total, slidePixels, children, totalProp, virtualOverscan, dragging, animating, extIndexRef,
251
- // 保留以表明依赖关系,虽然不会触发更新
252
- extTotal]);
288
+ }, [total, slidePixels, virtualOverscan, isDragging, isAnimating, current, loopEnabled, clonesBefore, extTotal]);
289
+ const trackInnerStyle = direction === 'horizontal' ? styles.trackInnerHorizontal : styles.trackInnerVertical;
253
290
 
254
- // 计算滑块包装器样式
255
- const slideWrapperStyle = useMemo(() => {
256
- return direction === 'horizontal' ? {
257
- width: slidePixels,
258
- height: '100%'
259
- } : {
260
- height: slidePixels,
261
- width: '100%'
262
- };
263
- }, [direction, slidePixels]);
264
-
265
- // 计算虚拟渲染的占位空间样式
266
- const spacerStyles = useMemo(() => {
267
- if (!virtualRange) return null;
268
- const {
269
- start,
270
- end
271
- } = virtualRange;
272
- const leadingSize = start * slidePixels;
273
- const trailingSize = (extTotal - end - 1) * slidePixels;
274
- return {
275
- leading: direction === 'horizontal' ? {
276
- width: leadingSize
277
- } : {
278
- height: leadingSize
279
- },
280
- trailing: direction === 'horizontal' ? {
281
- width: trailingSize
282
- } : {
283
- height: trailingSize
284
- },
285
- leadingSize,
286
- trailingSize
287
- };
288
- }, [virtualRange, slidePixels, extTotal, direction]);
289
- const {
290
- renderSlides
291
- } = useCarouselSlides({
292
- children,
293
- total,
294
- virtualRange,
295
- loopEnabled,
296
- clonesBefore,
297
- slideWrapperStyle,
298
- spacerStyles,
299
- slideStyles: styles
300
- });
301
- const {
302
- renderIndicator
303
- } = useCarouselIndicator({
304
- indicator,
305
- indicatorProps,
306
- total,
307
- current,
308
- activeColor: theme.palette.brand7,
309
- inactiveColor: theme.palette.fontGray5,
310
- styles
311
- });
312
- const trackInnerStyle = useMemo(() => {
313
- return direction === 'horizontal' ? {
314
- flexDirection: 'row',
315
- height: '100%'
316
- } : {
317
- flexDirection: 'column',
318
- width: '100%'
319
- };
320
- }, [direction]);
291
+ // 边界情况处理:空数据
292
+ if (!data || data.length === 0) {
293
+ return null;
294
+ }
321
295
  return /*#__PURE__*/_jsx(View, {
322
- style: StyleSheet.flatten([styles.container, style]),
296
+ style: [styles.container, style],
323
297
  children: /*#__PURE__*/_jsxs(View, {
324
298
  style: styles.track,
325
299
  onLayout: onLayoutTrack,
326
300
  ...panResponder?.panHandlers,
327
301
  children: [/*#__PURE__*/_jsx(Animated.View, {
328
- style: StyleSheet.flatten([styles.trackInner, trackInnerStyle, trackTransformStyle]),
329
- children: renderSlides()
330
- }), renderIndicator()]
302
+ style: [styles.trackInner, trackInnerStyle, trackTransformStyle],
303
+ children: /*#__PURE__*/_jsx(CarouselSlides, {
304
+ data: data,
305
+ renderItem: renderItem,
306
+ total: total,
307
+ virtualRange: virtualRange,
308
+ loopEnabled: loopEnabled,
309
+ clonesBefore: clonesBefore,
310
+ direction: direction,
311
+ slidePixels: slidePixels,
312
+ extTotal: extTotal
313
+ })
314
+ }), /*#__PURE__*/_jsx(CarouselIndicator, {
315
+ indicator: indicator,
316
+ indicatorProps: indicatorProps,
317
+ total: total,
318
+ current: current,
319
+ activeColor: theme.palette.brand7,
320
+ inactiveColor: theme.palette.fontGray5,
321
+ styles: styles
322
+ })]
331
323
  })
332
324
  });
333
325
  };
@@ -2,9 +2,7 @@
2
2
 
3
3
  export { useCarouselAutoplay } from "./use-carousel-autoplay.js";
4
4
  export { useCarouselIndex } from "./use-carousel-index.js";
5
- export { useCarouselIndicator } from "./use-carousel-indicator.js";
6
5
  export { useCarouselLifecycle } from "./use-carousel-lifecycle.js";
7
6
  export { useCarouselPanResponder } from "./use-carousel-pan-responder.js";
8
7
  export { useCarouselPosition } from "./use-carousel-position.js";
9
- export { useCarouselSlides } from "./use-carousel-slides.js";
10
8
  export { useCarouselSwipe } from "./use-carousel-swipe.js";
@@ -3,8 +3,11 @@
3
3
  import { useMemoizedFn } from 'ahooks';
4
4
  import { clamp } from 'lodash-es';
5
5
  import { useCallback, useRef, useState } from 'react';
6
- import { RUBBERBAND_DAMPING } from "../constants.js";
7
- import { getBoundaryIndexRange } from "../utils.js";
6
+
7
+ /**
8
+ * 橡皮筋效果阻尼系数
9
+ */
10
+ const RUBBERBAND_DAMPING = 0.35;
8
11
  /**
9
12
  * 轮播图索引管理 Hook
10
13
  *
@@ -89,15 +92,16 @@ export const useCarouselIndex = params => {
89
92
  if (loopEnabled) return nextPosition;
90
93
  if (slidePixels <= 0) return nextPosition;
91
94
  if (total <= 0) return 0;
92
- const {
93
- min,
94
- max
95
- } = getBoundaryIndexRange({
96
- total,
97
- slideSize: normalizedSlideSize,
98
- trackOffset: normalizedTrackOffset,
99
- stuckAtBoundary
100
- });
95
+
96
+ // 计算轮播边界索引范围
97
+ let min = 0;
98
+ let max = total - 1;
99
+ if (stuckAtBoundary) {
100
+ const slideRatio = normalizedSlideSize / 100;
101
+ const offsetRatio = normalizedTrackOffset / 100;
102
+ min = 0 + offsetRatio / (slideRatio || 1);
103
+ max = total - 1 - (1 - slideRatio - offsetRatio) / (slideRatio || 1);
104
+ }
101
105
  const minPos = min * slidePixels;
102
106
  const maxPos = max * slidePixels;
103
107
  if (nextPosition < minPos) {
@@ -51,12 +51,16 @@ export const useCarouselLifecycle = params => {
51
51
  if (slidePixels > 0) {
52
52
  setPositionImmediate(getBoundedPosition(extIndex * slidePixels));
53
53
  }
54
- }, [defaultIndex, getExtIndexFromIndex, getBoundedPosition, setPositionImmediate, slidePixels, total, updateCurrent, reportIndexRef, extIndexRef]);
54
+ // eslint-disable-next-line react-hooks/exhaustive-deps
55
+ }, [defaultIndex, getExtIndexFromIndex, getBoundedPosition, setPositionImmediate, slidePixels, total, updateCurrent
56
+ // refs 不需要在依赖数组中,它们的引用永远不变
57
+ ]);
55
58
 
56
59
  // 响应 slidePixels 变化
57
60
  useEffect(() => {
58
61
  if (slidePixels <= 0) return;
59
62
  const extIndex = extIndexRef.current;
60
63
  setPositionImmediate(getBoundedPosition(extIndex * slidePixels));
61
- }, [getBoundedPosition, setPositionImmediate, slidePixels, extIndexRef]);
64
+ // eslint-disable-next-line react-hooks/exhaustive-deps
65
+ }, [getBoundedPosition, setPositionImmediate, slidePixels]);
62
66
  };
@@ -1,9 +1,18 @@
1
1
  "use strict";
2
2
 
3
3
  import { clamp } from 'lodash-es';
4
- import { useMemo } from 'react';
4
+ import { useMemo, useRef } from 'react';
5
5
  import { PanResponder } from 'react-native';
6
- import { GESTURE_MIN_DISTANCE, VELOCITY_PROJECTION_FACTOR } from "../constants.js";
6
+
7
+ /**
8
+ * 手势识别最小移动距离(像素)
9
+ */
10
+ const GESTURE_MIN_DISTANCE = 5;
11
+
12
+ /**
13
+ * 速度投影系数(用于计算惯性滑动距离)
14
+ */
15
+ const VELOCITY_PROJECTION_FACTOR = 2000;
7
16
  /**
8
17
  * 轮播图手势响应 Hook
9
18
  *
@@ -50,6 +59,26 @@ export const useCarouselPanResponder = params => {
50
59
  getBoundedPosition,
51
60
  swipeToExtIndex
52
61
  } = params;
62
+
63
+ // 使用 ref 存储回调,减少 PanResponder 重建
64
+ const callbacksRef = useRef({
65
+ setDragging,
66
+ setAnimating,
67
+ updateCurrent,
68
+ getIndexFromExtIndex,
69
+ getBoundedPosition,
70
+ swipeToExtIndex
71
+ });
72
+
73
+ // 更新回调 ref
74
+ callbacksRef.current = {
75
+ setDragging,
76
+ setAnimating,
77
+ updateCurrent,
78
+ getIndexFromExtIndex,
79
+ getBoundedPosition,
80
+ swipeToExtIndex
81
+ };
53
82
  return useMemo(() => {
54
83
  if (!allowTouchMove) return null;
55
84
  if (total <= 1) return null;
@@ -63,8 +92,8 @@ export const useCarouselPanResponder = params => {
63
92
  return PanResponder.create({
64
93
  onMoveShouldSetPanResponder: shouldSet,
65
94
  onPanResponderGrant: () => {
66
- setDragging(true);
67
- setAnimating(false);
95
+ callbacksRef.current.setDragging(true);
96
+ callbacksRef.current.setAnimating(false);
68
97
  position.current.stopAnimation();
69
98
  startPosition = positionValueRef.current;
70
99
  },
@@ -87,15 +116,15 @@ export const useCarouselPanResponder = params => {
87
116
  startPosition -= totalPixels;
88
117
  }
89
118
  }
90
- const bounded = getBoundedPosition(nextPosition);
119
+ const bounded = callbacksRef.current.getBoundedPosition(nextPosition);
91
120
  position.current.setValue(bounded);
92
121
  positionValueRef.current = bounded;
93
122
  const nextExtIndex = clamp(Math.round(bounded / slidePixels), 0, extTotal - 1);
94
123
  extIndexRef.current = nextExtIndex;
95
- updateCurrent(getIndexFromExtIndex(nextExtIndex));
124
+ callbacksRef.current.updateCurrent(callbacksRef.current.getIndexFromExtIndex(nextExtIndex));
96
125
  },
97
126
  onPanResponderRelease: (_evt, gestureState) => {
98
- setDragging(false);
127
+ callbacksRef.current.setDragging(false);
99
128
  const velocity = axis === 'x' ? gestureState.vx : gestureState.vy;
100
129
  position.current.stopAnimation(value => {
101
130
  const baseIndex = value / slidePixels;
@@ -104,15 +133,15 @@ export const useCarouselPanResponder = params => {
104
133
  const maxAdj = minAdj + 1;
105
134
  const rounded = Math.round(projectedIndex);
106
135
  const adjacent = clamp(rounded, minAdj, maxAdj);
107
- swipeToExtIndex(adjacent);
136
+ callbacksRef.current.swipeToExtIndex(adjacent);
108
137
  });
109
138
  },
110
139
  onPanResponderTerminate: () => {
111
- setDragging(false);
112
- swipeToExtIndex(extIndexRef.current);
140
+ callbacksRef.current.setDragging(false);
141
+ callbacksRef.current.swipeToExtIndex(extIndexRef.current);
113
142
  },
114
143
  onPanResponderTerminationRequest: () => false,
115
144
  onShouldBlockNativeResponder: () => blockNativeResponder
116
145
  });
117
- }, [allowTouchMove, blockNativeResponder, clonesBefore, direction, extTotal, extIndexRef, getBoundedPosition, getIndexFromExtIndex, position, positionValueRef, setAnimating, setDragging, slidePixels, swipeToExtIndex, total, updateCurrent]);
146
+ }, [allowTouchMove, blockNativeResponder, clonesBefore, direction, extTotal, extIndexRef, position, positionValueRef, slidePixels, total]);
118
147
  };
@@ -2,7 +2,11 @@
2
2
 
3
3
  import { useCallback, useRef } from 'react';
4
4
  import { Animated, Easing } from 'react-native';
5
- import { CAROUSEL_ANIMATION_DURATION } from "../constants.js";
5
+
6
+ /**
7
+ * 轮播图动画时长(毫秒)
8
+ */
9
+ const CAROUSEL_ANIMATION_DURATION = 300;
6
10
 
7
11
  /**
8
12
  * 轮播图位置和动画控制 Hook
@@ -1,9 +1,5 @@
1
1
  "use strict";
2
2
 
3
3
  import { Carousel as _Carousel } from "./carousel.js";
4
- import { CarouselItem } from "./carousel-item.js";
5
4
  export * from "./carousel.js";
6
- export * from "./carousel-item.js";
7
- export const Carousel = Object.assign(_Carousel, {
8
- Item: CarouselItem
9
- });
5
+ export const Carousel = _Carousel;
@@ -16,6 +16,18 @@ export const useCarouselStyles = createThemedStyles(theme => ({
16
16
  flexGrow: 0,
17
17
  flexShrink: 0
18
18
  },
19
+ trackInnerHorizontal: {
20
+ flexDirection: 'row',
21
+ height: '100%',
22
+ flexGrow: 0,
23
+ flexShrink: 0
24
+ },
25
+ trackInnerVertical: {
26
+ flexDirection: 'column',
27
+ width: '100%',
28
+ flexGrow: 0,
29
+ flexShrink: 0
30
+ },
19
31
  slide: {
20
32
  flexGrow: 0,
21
33
  flexShrink: 0,
@@ -1,68 +1,80 @@
1
1
  "use strict";
2
2
 
3
- import { useControllableValue, useMemoizedFn } from 'ahooks';
3
+ import { useMemoizedFn } from 'ahooks';
4
4
  import dayjs from 'dayjs';
5
- import React, { useMemo, useState } from 'react';
6
- import { DatePickerView, Modal, PickerTrigger, Portal } from "./../index.js";
7
- import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
5
+ import React, { useCallback, useMemo, useRef, useState } from 'react';
6
+ import { Button, DatePickerView, Flex, Picker } from "./../index.js";
7
+ import { useDatePickerStyles } from "./style/index.js";
8
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
8
9
  export const DatePicker = ({
9
10
  placeholder = '请选择日期',
10
- disabled = false,
11
11
  formatter = 'YYYY/MM/DD',
12
- style,
13
- children,
14
12
  mode = 'Y-D',
15
- title,
16
- confirmText,
13
+ headerTitle,
14
+ confirmText = '确定',
17
15
  ...restProps
18
16
  }) => {
19
- const [value, setValue] = useControllableValue(restProps, {
20
- defaultValue: restProps.defaultValue
21
- });
22
- const [visible, setVisible] = useState(false);
17
+ const [draftValue, setDraftValue] = useState();
18
+ const styles = useDatePickerStyles();
19
+ const committedValueRef = useRef(new Date());
20
+ const handleOpen = useCallback(() => {
21
+ setDraftValue(committedValueRef.current);
22
+ }, []);
23
23
 
24
24
  /** 格式化显示文案 */
25
- const displayText = useMemo(() => {
26
- if (!value) return '';
25
+ const _renderValue = useMemoizedFn(value => {
26
+ if (!value) return;
27
27
  if (typeof formatter === 'string') {
28
28
  return dayjs(value).format(formatter);
29
29
  }
30
30
  return formatter(value);
31
- }, [value, mode, formatter]);
32
- const handleOpen = useMemoizedFn(() => {
33
- setVisible(true);
34
- });
35
- const handleChange = useMemoizedFn(date => {
36
- setValue(date);
37
- setVisible(false);
38
- });
39
- const handleClose = useMemoizedFn(() => {
40
- setVisible(false);
41
31
  });
42
- return /*#__PURE__*/_jsxs(_Fragment, {
43
- children: [/*#__PURE__*/_jsx(PickerTrigger, {
44
- displayText: displayText,
32
+ const _headerTitle = useMemo(() => {
33
+ if (headerTitle) {
34
+ return headerTitle;
35
+ }
36
+ switch (mode) {
37
+ case 'Y':
38
+ return '请选择年';
39
+ case 'Y-M':
40
+ return '请选择年月';
41
+ case 'Y-D':
42
+ return '请选择年月日';
43
+ default:
44
+ return '请选择日期';
45
+ }
46
+ }, [mode, headerTitle]);
47
+ return /*#__PURE__*/_jsxs(Picker, {
48
+ ...restProps,
49
+ children: [/*#__PURE__*/_jsx(Picker.Field, {
45
50
  placeholder: placeholder,
46
- disabled: disabled,
47
- style: style,
48
- onPress: handleOpen,
49
- children: children
50
- }), /*#__PURE__*/_jsx(Portal, {
51
- children: /*#__PURE__*/_jsx(Modal, {
52
- visible: visible,
53
- position: "bottom",
54
- safeAreaInsetBottom: true,
55
- contentHeight: '50%',
56
- children: /*#__PURE__*/_jsx(DatePickerView, {
57
- ...restProps,
58
- mode: mode,
59
- title: title,
60
- confirmText: confirmText,
61
- value: value,
62
- onChange: handleChange,
63
- onClose: handleClose
64
- })
65
- })
51
+ renderValue: _renderValue
52
+ }), /*#__PURE__*/_jsx(Picker.Content, {
53
+ headerTitle: _headerTitle,
54
+ onOpen: handleOpen,
55
+ children: ({
56
+ onChange,
57
+ value: contextValue
58
+ }) => {
59
+ // 同步 ref:始终保持最新的已提交值
60
+ committedValueRef.current = contextValue ?? new Date();
61
+ return /*#__PURE__*/_jsxs(Flex, {
62
+ vertical: true,
63
+ align: "stretch",
64
+ style: styles.container,
65
+ children: [/*#__PURE__*/_jsx(DatePickerView, {
66
+ mode: mode,
67
+ value: draftValue,
68
+ onChange: setDraftValue
69
+ }), /*#__PURE__*/_jsx(Button, {
70
+ text: confirmText,
71
+ size: "large",
72
+ onPress: () => {
73
+ onChange?.(draftValue);
74
+ }
75
+ })]
76
+ });
77
+ }
66
78
  })]
67
79
  });
68
80
  };