xxf_react 0.8.5 → 0.8.6

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 (250) hide show
  1. package/dist/cache/CacheEntry.d.ts +28 -0
  2. package/dist/cache/CacheEntry.d.ts.map +1 -0
  3. package/dist/cache/CacheEntry.js +1 -0
  4. package/dist/cache/DiskCacheConfig.d.ts +56 -0
  5. package/dist/cache/DiskCacheConfig.d.ts.map +1 -0
  6. package/dist/cache/DiskCacheConfig.js +4 -0
  7. package/dist/cache/DiskLruCache.d.ts +69 -0
  8. package/dist/cache/DiskLruCache.d.ts.map +1 -0
  9. package/dist/cache/DiskLruCache.js +305 -0
  10. package/dist/cache/LruMetadata.d.ts +28 -0
  11. package/dist/cache/LruMetadata.d.ts.map +1 -0
  12. package/dist/cache/LruMetadata.js +6 -0
  13. package/dist/cache/index.d.ts +5 -0
  14. package/dist/cache/index.d.ts.map +1 -0
  15. package/dist/cache/index.js +2 -0
  16. package/dist/event-bus/EventBus.d.ts +176 -0
  17. package/dist/event-bus/EventBus.d.ts.map +1 -0
  18. package/dist/event-bus/EventBus.js +278 -0
  19. package/dist/event-bus/EventDemo.d.ts +71 -0
  20. package/dist/event-bus/EventDemo.d.ts.map +1 -0
  21. package/dist/event-bus/EventDemo.js +76 -0
  22. package/dist/event-bus/EventHooks.d.ts +48 -0
  23. package/dist/event-bus/EventHooks.d.ts.map +1 -0
  24. package/dist/event-bus/EventHooks.js +73 -0
  25. package/dist/event-bus/index.d.ts +3 -0
  26. package/dist/event-bus/index.d.ts.map +1 -0
  27. package/dist/event-bus/index.js +2 -0
  28. package/dist/fetch/Fetch.d.ts +9 -0
  29. package/dist/fetch/Fetch.d.ts.map +1 -0
  30. package/dist/fetch/Fetch.js +54 -0
  31. package/dist/fetch/TimeoutError.d.ts +7 -0
  32. package/dist/fetch/TimeoutError.d.ts.map +1 -0
  33. package/dist/fetch/TimeoutError.js +23 -0
  34. package/dist/fetch/index.d.ts +3 -0
  35. package/dist/fetch/index.d.ts.map +1 -0
  36. package/dist/fetch/index.js +2 -0
  37. package/dist/flow/PromiseExt.d.ts +8 -0
  38. package/dist/flow/PromiseExt.d.ts.map +1 -0
  39. package/dist/flow/PromiseExt.js +50 -0
  40. package/dist/flow/PromiseLifecycle.d.ts +33 -0
  41. package/dist/flow/PromiseLifecycle.d.ts.map +1 -0
  42. package/dist/flow/PromiseLifecycle.js +37 -0
  43. package/dist/flow/PromiseLoading.d.ts +25 -0
  44. package/dist/flow/PromiseLoading.d.ts.map +1 -0
  45. package/dist/flow/PromiseLoading.js +30 -0
  46. package/dist/flow/index.d.ts +4 -0
  47. package/dist/flow/index.d.ts.map +1 -0
  48. package/dist/flow/index.js +3 -0
  49. package/dist/foundation/Copy.d.ts +8 -0
  50. package/dist/foundation/Copy.d.ts.map +1 -0
  51. package/dist/foundation/Copy.js +21 -0
  52. package/dist/foundation/Debug.d.ts +7 -0
  53. package/dist/foundation/Debug.d.ts.map +1 -0
  54. package/dist/foundation/Debug.js +12 -0
  55. package/dist/foundation/LayoutSize.d.ts +5 -0
  56. package/dist/foundation/LayoutSize.d.ts.map +1 -0
  57. package/dist/foundation/LayoutSize.js +1 -0
  58. package/dist/foundation/PerformanceMonitor.d.ts +13 -0
  59. package/dist/foundation/PerformanceMonitor.d.ts.map +1 -0
  60. package/dist/foundation/PerformanceMonitor.js +26 -0
  61. package/dist/foundation/index.d.ts +5 -0
  62. package/dist/foundation/index.d.ts.map +1 -0
  63. package/dist/foundation/index.js +4 -0
  64. package/dist/http/api/ApiBuilder.d.ts +251 -0
  65. package/dist/http/api/ApiBuilder.d.ts.map +1 -0
  66. package/dist/http/api/ApiBuilder.js +189 -0
  67. package/dist/http/api/index.d.ts +2 -0
  68. package/dist/http/api/index.d.ts.map +1 -0
  69. package/dist/http/api/index.js +1 -0
  70. package/dist/http/cache/HttpCache.d.ts +59 -0
  71. package/dist/http/cache/HttpCache.d.ts.map +1 -0
  72. package/dist/http/cache/HttpCache.js +215 -0
  73. package/dist/http/cache/index.d.ts +3 -0
  74. package/dist/http/cache/index.d.ts.map +1 -0
  75. package/dist/http/cache/index.js +2 -0
  76. package/dist/http/client/ApiStream.d.ts +80 -0
  77. package/dist/http/client/ApiStream.d.ts.map +1 -0
  78. package/dist/http/client/ApiStream.js +190 -0
  79. package/dist/http/client/HttpClient.d.ts +88 -0
  80. package/dist/http/client/HttpClient.d.ts.map +1 -0
  81. package/dist/http/client/HttpClient.js +381 -0
  82. package/dist/http/client/index.d.ts +3 -0
  83. package/dist/http/client/index.d.ts.map +1 -0
  84. package/dist/http/client/index.js +2 -0
  85. package/dist/http/demo/api-builder.demo.d.ts +102 -0
  86. package/dist/http/demo/api-builder.demo.d.ts.map +1 -0
  87. package/dist/http/demo/api-builder.demo.js +343 -0
  88. package/dist/http/index.d.ts +52 -0
  89. package/dist/http/index.d.ts.map +1 -0
  90. package/dist/http/index.js +61 -0
  91. package/dist/http/interceptor/CacheInterceptor.d.ts +112 -0
  92. package/dist/http/interceptor/CacheInterceptor.d.ts.map +1 -0
  93. package/dist/http/interceptor/CacheInterceptor.js +6 -0
  94. package/dist/http/interceptor/DefaultCacheInterceptor.d.ts +53 -0
  95. package/dist/http/interceptor/DefaultCacheInterceptor.d.ts.map +1 -0
  96. package/dist/http/interceptor/DefaultCacheInterceptor.js +106 -0
  97. package/dist/http/interceptor/index.d.ts +3 -0
  98. package/dist/http/interceptor/index.d.ts.map +1 -0
  99. package/dist/http/interceptor/index.js +2 -0
  100. package/dist/http/models/ApiTypes.d.ts +54 -0
  101. package/dist/http/models/ApiTypes.d.ts.map +1 -0
  102. package/dist/http/models/ApiTypes.js +4 -0
  103. package/dist/http/models/CacheConfig.d.ts +58 -0
  104. package/dist/http/models/CacheConfig.d.ts.map +1 -0
  105. package/dist/http/models/CacheConfig.js +4 -0
  106. package/dist/http/models/CacheMode.d.ts +45 -0
  107. package/dist/http/models/CacheMode.d.ts.map +1 -0
  108. package/dist/http/models/CacheMode.js +45 -0
  109. package/dist/http/models/HttpClientConfig.d.ts +90 -0
  110. package/dist/http/models/HttpClientConfig.d.ts.map +1 -0
  111. package/dist/http/models/HttpClientConfig.js +4 -0
  112. package/dist/http/models/RequestConfig.d.ts +67 -0
  113. package/dist/http/models/RequestConfig.d.ts.map +1 -0
  114. package/dist/http/models/RequestConfig.js +4 -0
  115. package/dist/http/models/index.d.ts +24 -0
  116. package/dist/http/models/index.d.ts.map +1 -0
  117. package/dist/http/models/index.js +16 -0
  118. package/dist/http/types.d.ts +13 -0
  119. package/dist/http/types.d.ts.map +1 -0
  120. package/dist/http/types.js +14 -0
  121. package/dist/index.d.ts +15 -0
  122. package/dist/index.d.ts.map +1 -0
  123. package/dist/index.js +20 -0
  124. package/dist/layout/button/XButton.d.ts +99 -0
  125. package/dist/layout/button/XButton.d.ts.map +1 -0
  126. package/dist/layout/button/XButton.js +131 -0
  127. package/dist/layout/hover/XHover.d.ts +147 -0
  128. package/dist/layout/hover/XHover.d.ts.map +1 -0
  129. package/dist/layout/hover/XHover.js +128 -0
  130. package/dist/layout/image/XImage.d.ts +35 -0
  131. package/dist/layout/image/XImage.d.ts.map +1 -0
  132. package/dist/layout/image/XImage.effects.d.ts +16 -0
  133. package/dist/layout/image/XImage.effects.d.ts.map +1 -0
  134. package/dist/layout/image/XImage.effects.js +77 -0
  135. package/dist/layout/image/XImage.js +261 -0
  136. package/dist/layout/image/XImage.types.d.ts +130 -0
  137. package/dist/layout/image/XImage.types.d.ts.map +1 -0
  138. package/dist/layout/image/XImage.types.js +2 -0
  139. package/dist/layout/image/XImageGallery.d.ts +76 -0
  140. package/dist/layout/image/XImageGallery.d.ts.map +1 -0
  141. package/dist/layout/image/XImageGallery.js +94 -0
  142. package/dist/layout/image/index.d.ts +12 -0
  143. package/dist/layout/image/index.d.ts.map +1 -0
  144. package/dist/layout/image/index.js +4 -0
  145. package/dist/layout/index.d.ts +12 -0
  146. package/dist/layout/index.d.ts.map +1 -0
  147. package/dist/layout/index.js +11 -0
  148. package/dist/layout/resize/core/ResizeObserverHook.d.ts +41 -0
  149. package/dist/layout/resize/core/ResizeObserverHook.d.ts.map +1 -0
  150. package/dist/layout/resize/core/ResizeObserverHook.js +57 -0
  151. package/dist/layout/resize/core/SizedLayoutContext.d.ts +23 -0
  152. package/dist/layout/resize/core/SizedLayoutContext.d.ts.map +1 -0
  153. package/dist/layout/resize/core/SizedLayoutContext.js +23 -0
  154. package/dist/layout/resize/core/SizedLayoutProps.d.ts +19 -0
  155. package/dist/layout/resize/core/SizedLayoutProps.d.ts.map +1 -0
  156. package/dist/layout/resize/core/SizedLayoutProps.js +1 -0
  157. package/dist/layout/resize/impl/SizedContainer.d.ts +45 -0
  158. package/dist/layout/resize/impl/SizedContainer.d.ts.map +1 -0
  159. package/dist/layout/resize/impl/SizedContainer.js +65 -0
  160. package/dist/layout/resize/impl/SizedLayout.d.ts +45 -0
  161. package/dist/layout/resize/impl/SizedLayout.d.ts.map +1 -0
  162. package/dist/layout/resize/impl/SizedLayout.js +65 -0
  163. package/dist/layout/spinner/XSpinner.d.ts +43 -0
  164. package/dist/layout/spinner/XSpinner.d.ts.map +1 -0
  165. package/dist/layout/spinner/XSpinner.js +47 -0
  166. package/dist/layout/virtualized/VirtualizedConfig.d.ts +16 -0
  167. package/dist/layout/virtualized/VirtualizedConfig.d.ts.map +1 -0
  168. package/dist/layout/virtualized/VirtualizedConfig.js +15 -0
  169. package/dist/layout/visibility/ElementVisibilityHooks.d.ts +13 -0
  170. package/dist/layout/visibility/ElementVisibilityHooks.d.ts.map +1 -0
  171. package/dist/layout/visibility/ElementVisibilityHooks.js +119 -0
  172. package/dist/media/components/XVideo.d.ts +205 -0
  173. package/dist/media/components/XVideo.d.ts.map +1 -0
  174. package/dist/media/components/XVideo.js +297 -0
  175. package/dist/media/components/XVideoBufferingIndicator.d.ts +13 -0
  176. package/dist/media/components/XVideoBufferingIndicator.d.ts.map +1 -0
  177. package/dist/media/components/XVideoBufferingIndicator.js +13 -0
  178. package/dist/media/components/XVideoErrorIndicator.d.ts +15 -0
  179. package/dist/media/components/XVideoErrorIndicator.d.ts.map +1 -0
  180. package/dist/media/components/XVideoErrorIndicator.js +19 -0
  181. package/dist/media/index.d.ts +7 -0
  182. package/dist/media/index.d.ts.map +1 -0
  183. package/dist/media/index.js +7 -0
  184. package/dist/media/playback-queue-store.d.ts +746 -0
  185. package/dist/media/playback-queue-store.d.ts.map +1 -0
  186. package/dist/media/playback-queue-store.js +670 -0
  187. package/dist/media/video-play-safe.d.ts +26 -0
  188. package/dist/media/video-play-safe.d.ts.map +1 -0
  189. package/dist/media/video-play-safe.js +56 -0
  190. package/dist/media/video-state.d.ts +38 -0
  191. package/dist/media/video-state.d.ts.map +1 -0
  192. package/dist/media/video-state.js +125 -0
  193. package/dist/models/ApiPageDataFieldDTO.d.ts +9 -0
  194. package/dist/models/ApiPageDataFieldDTO.d.ts.map +1 -0
  195. package/dist/models/ApiPageDataFieldDTO.js +1 -0
  196. package/dist/models/ApiResponse.d.ts +29 -0
  197. package/dist/models/ApiResponse.d.ts.map +1 -0
  198. package/dist/models/ApiResponse.js +32 -0
  199. package/dist/models/PaginationDTO.d.ts +8 -0
  200. package/dist/models/PaginationDTO.d.ts.map +1 -0
  201. package/dist/models/PaginationDTO.js +6 -0
  202. package/dist/models/index.d.ts +4 -0
  203. package/dist/models/index.d.ts.map +1 -0
  204. package/dist/models/index.js +3 -0
  205. package/dist/refresh/LoadMoreAsync.d.ts +36 -0
  206. package/dist/refresh/LoadMoreAsync.d.ts.map +1 -0
  207. package/dist/refresh/LoadMoreAsync.js +55 -0
  208. package/dist/refresh/index.d.ts +2 -0
  209. package/dist/refresh/index.d.ts.map +1 -0
  210. package/dist/refresh/index.js +2 -0
  211. package/dist/responsive/BrowserAdapter.d.ts +26 -0
  212. package/dist/responsive/BrowserAdapter.d.ts.map +1 -0
  213. package/dist/responsive/BrowserAdapter.js +79 -0
  214. package/dist/responsive/ScreenAdapter.d.ts +2 -0
  215. package/dist/responsive/ScreenAdapter.d.ts.map +1 -0
  216. package/dist/responsive/ScreenAdapter.js +5 -0
  217. package/dist/responsive/index.d.ts +3 -0
  218. package/dist/responsive/index.d.ts.map +1 -0
  219. package/dist/responsive/index.js +3 -0
  220. package/dist/sse/SSEManager.d.ts +21 -0
  221. package/dist/sse/SSEManager.d.ts.map +1 -0
  222. package/dist/sse/SSEManager.js +73 -0
  223. package/dist/sse/SSERegistry.d.ts +20 -0
  224. package/dist/sse/SSERegistry.d.ts.map +1 -0
  225. package/dist/sse/SSERegistry.js +36 -0
  226. package/dist/sse/SSEStatus.d.ts +7 -0
  227. package/dist/sse/SSEStatus.d.ts.map +1 -0
  228. package/dist/sse/SSEStatus.js +7 -0
  229. package/dist/sse/UseSSE.d.ts +13 -0
  230. package/dist/sse/UseSSE.d.ts.map +1 -0
  231. package/dist/sse/UseSSE.js +39 -0
  232. package/dist/sse/index.d.ts +5 -0
  233. package/dist/sse/index.d.ts.map +1 -0
  234. package/dist/sse/index.js +5 -0
  235. package/dist/utils/MIME.d.ts +137 -0
  236. package/dist/utils/MIME.d.ts.map +1 -0
  237. package/dist/utils/MIME.js +192 -0
  238. package/dist/utils/Reload.d.ts +62 -0
  239. package/dist/utils/Reload.d.ts.map +1 -0
  240. package/dist/utils/Reload.js +66 -0
  241. package/dist/utils/ScrollToCenter.d.ts +72 -0
  242. package/dist/utils/ScrollToCenter.d.ts.map +1 -0
  243. package/dist/utils/ScrollToCenter.js +145 -0
  244. package/dist/utils/index.d.ts +5 -0
  245. package/dist/utils/index.d.ts.map +1 -0
  246. package/dist/utils/index.js +5 -0
  247. package/dist/utils/url-placholder.d.ts +14 -0
  248. package/dist/utils/url-placholder.d.ts.map +1 -0
  249. package/dist/utils/url-placholder.js +17 -0
  250. package/package.json +1 -1
@@ -0,0 +1,261 @@
1
+ "use client";
2
+ import React, { useState, useEffect, useCallback, useRef, forwardRef, memo, useMemo, useContext, } from "react";
3
+ import { LazyLoadImage } from "react-lazy-load-image-component";
4
+ import { ScrollPositionContext } from "./XImageGallery";
5
+ import { injectEffectStyles } from "./XImage.effects";
6
+ /**
7
+ * 生产级图片组件
8
+ *
9
+ * 基于 react-lazy-load-image-component 实现,支持:
10
+ * - 懒加载 + IntersectionObserver
11
+ * - 多种加载效果 (blur/opacity/black-and-white) - CSS 已内置,无需导入
12
+ * - 错误处理 + 自动重试
13
+ * - fallback 备用图/组件
14
+ * - 性能优化 (配合 XImageGallery 使用 trackWindowScroll)
15
+ *
16
+ * @example
17
+ * ```tsx
18
+ * // 基础用法
19
+ * <XImage src="/photo.jpg" alt="Photo" width={400} height={300} />
20
+ *
21
+ * // 带模糊效果(提供 placeholder URL 自动启用 blur)
22
+ * <XImage src="/photo.jpg" placeholder="/photo-tiny.jpg" />
23
+ *
24
+ * // 自定义占位组件
25
+ * <XImage src="/photo.jpg" placeholder={<Skeleton />} effect="opacity" />
26
+ *
27
+ * // 带错误处理
28
+ * <XImage
29
+ * src="/photo.jpg"
30
+ * fallback="/fallback.jpg"
31
+ * retryCount={2}
32
+ * retryDelay={1000}
33
+ * />
34
+ * ```
35
+ */
36
+ export const XImage = memo(forwardRef(function XImage({
37
+ // 基础属性
38
+ src, alt = "", width, height, className, style, objectFit, objectPosition, fill,
39
+ // 懒加载配置
40
+ lazy = true, threshold = 100, effect, placeholder, useIntersectionObserver = true, delayMethod, delayTime,
41
+ // 错误处理
42
+ fallback, retryCount = 0, retryDelay = 1000,
43
+ // 性能优化
44
+ scrollPosition, visibleByDefault = false,
45
+ // 事件回调
46
+ onLoad, onError, onVisible, onStatusChange,
47
+ // 包裹元素属性
48
+ wrapperProps, wrapperClassName,
49
+ // 原生属性
50
+ loading, decoding = "async", srcSet, sizes, crossOrigin, referrerPolicy, }, ref) {
51
+ // ============ 解析 placeholder 类型 ============
52
+ const isPlaceholderSrc = typeof placeholder === "string";
53
+ const placeholderSrc = isPlaceholderSrc ? placeholder : undefined;
54
+ const placeholderElement = !isPlaceholderSrc ? placeholder : undefined;
55
+ // ============ 智能默认 effect ============
56
+ // 只有当 placeholder 是字符串(URL)时才自动启用 blur
57
+ // ReactElement 类型不自动启用(因为没有图片可以模糊)
58
+ const effectiveEffect = effect !== null && effect !== void 0 ? effect : (isPlaceholderSrc ? "blur" : undefined);
59
+ // ============ 自动注入效果 CSS ============
60
+ // 使用 effect 属性时自动注入,确保 SSR 兼容
61
+ useEffect(() => {
62
+ if (effectiveEffect) {
63
+ injectEffectStyles();
64
+ }
65
+ }, [effectiveEffect]);
66
+ // ============ Context: 自动获取 Gallery 的 scrollPosition ============
67
+ const contextScrollPosition = useContext(ScrollPositionContext);
68
+ const effectiveScrollPosition = scrollPosition !== null && scrollPosition !== void 0 ? scrollPosition : contextScrollPosition;
69
+ // ============ 状态管理 ============
70
+ const [currentSrc, setCurrentSrc] = useState(src);
71
+ const [status, setStatus] = useState("idle");
72
+ const [hasError, setHasError] = useState(false);
73
+ const [retryAttempt, setRetryAttempt] = useState(0);
74
+ // Refs
75
+ const wrapperRef = useRef(null);
76
+ const retryTimerRef = useRef(null);
77
+ const hasCalledOnVisible = useRef(false);
78
+ // 使用 ref 存储回调,避免 effect 依赖问题
79
+ const onStatusChangeRef = useRef(onStatusChange);
80
+ onStatusChangeRef.current = onStatusChange;
81
+ // ============ src 变化重置状态 ============
82
+ useEffect(() => {
83
+ var _a;
84
+ setCurrentSrc(src);
85
+ setHasError(false);
86
+ setRetryAttempt(0);
87
+ setStatus("idle");
88
+ (_a = onStatusChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onStatusChangeRef, "idle");
89
+ hasCalledOnVisible.current = false;
90
+ // 清理重试定时器
91
+ if (retryTimerRef.current) {
92
+ clearTimeout(retryTimerRef.current);
93
+ retryTimerRef.current = null;
94
+ }
95
+ }, [src]);
96
+ // 清理定时器
97
+ useEffect(() => {
98
+ return () => {
99
+ if (retryTimerRef.current) {
100
+ clearTimeout(retryTimerRef.current);
101
+ }
102
+ };
103
+ }, []);
104
+ // ============ ref 转发:从 wrapper 中获取 img 元素 ============
105
+ useEffect(() => {
106
+ if (!ref || !wrapperRef.current)
107
+ return;
108
+ const imgElement = wrapperRef.current.querySelector("img");
109
+ if (imgElement) {
110
+ if (typeof ref === "function") {
111
+ ref(imgElement);
112
+ }
113
+ else {
114
+ ref.current = imgElement;
115
+ }
116
+ }
117
+ // 依赖 status 确保图片加载后能获取到正确的 img 元素
118
+ }, [ref, status]);
119
+ // ============ 状态更新辅助 ============
120
+ const updateStatus = useCallback((newStatus) => {
121
+ var _a;
122
+ setStatus(newStatus);
123
+ (_a = onStatusChangeRef.current) === null || _a === void 0 ? void 0 : _a.call(onStatusChangeRef, newStatus);
124
+ }, []);
125
+ // ============ 事件处理 ============
126
+ const handleLoad = useCallback((event) => {
127
+ updateStatus("loaded");
128
+ onLoad === null || onLoad === void 0 ? void 0 : onLoad(event);
129
+ }, [updateStatus, onLoad]);
130
+ const handleError = useCallback((event) => {
131
+ setRetryAttempt((currentRetry) => {
132
+ // 还有重试次数
133
+ if (currentRetry < retryCount) {
134
+ updateStatus("loading");
135
+ retryTimerRef.current = setTimeout(() => {
136
+ // 通过修改 src 触发重新加载(添加时间戳绕过缓存)
137
+ const separator = src.includes("?") ? "&" : "?";
138
+ setCurrentSrc(`${src}${separator}_retry=${Date.now()}`);
139
+ }, retryDelay);
140
+ return currentRetry + 1;
141
+ }
142
+ // 重试耗尽,检查 fallback
143
+ setHasError((currentHasError) => {
144
+ if (fallback && !currentHasError) {
145
+ if (typeof fallback === "string") {
146
+ setCurrentSrc(fallback);
147
+ updateStatus("loading");
148
+ }
149
+ return true;
150
+ }
151
+ // 最终失败
152
+ updateStatus("error");
153
+ onError === null || onError === void 0 ? void 0 : onError(event);
154
+ return currentHasError;
155
+ });
156
+ return currentRetry;
157
+ });
158
+ }, [retryCount, retryDelay, src, fallback, updateStatus, onError]);
159
+ // beforeLoad: 进入视口,开始加载前调用
160
+ const handleBeforeLoad = useCallback(() => {
161
+ if (!hasCalledOnVisible.current) {
162
+ hasCalledOnVisible.current = true;
163
+ updateStatus("loading");
164
+ onVisible === null || onVisible === void 0 ? void 0 : onVisible();
165
+ }
166
+ }, [updateStatus, onVisible]);
167
+ // ============ 计算样式 ============
168
+ const computedStyle = useMemo(() => {
169
+ const baseStyle = { ...style };
170
+ if (objectFit) {
171
+ baseStyle.objectFit = objectFit;
172
+ }
173
+ if (objectPosition) {
174
+ baseStyle.objectPosition = objectPosition;
175
+ }
176
+ // fill 模式:图片绝对定位填充
177
+ if (fill) {
178
+ baseStyle.position = "absolute";
179
+ baseStyle.width = "100%";
180
+ baseStyle.height = "100%";
181
+ baseStyle.inset = 0;
182
+ baseStyle.objectFit = objectFit || "cover";
183
+ }
184
+ return baseStyle;
185
+ }, [style, objectFit, objectPosition, fill]);
186
+ const wrapperStyle = useMemo(() => {
187
+ const base = { ...wrapperProps === null || wrapperProps === void 0 ? void 0 : wrapperProps.style };
188
+ // fill 模式下包裹元素需要绝对定位并填满父容器
189
+ if (fill) {
190
+ base.display = "block";
191
+ base.position = "absolute";
192
+ base.inset = 0;
193
+ base.width = "100%";
194
+ base.height = "100%";
195
+ }
196
+ return base;
197
+ }, [fill, wrapperProps === null || wrapperProps === void 0 ? void 0 : wrapperProps.style]);
198
+ // ============ 解析尺寸(简单计算,不需要 useMemo) ============
199
+ const parsedWidth = fill
200
+ ? undefined
201
+ : typeof width === "number"
202
+ ? width
203
+ : typeof width === "string"
204
+ ? parseInt(width, 10) || undefined
205
+ : undefined;
206
+ const parsedHeight = fill
207
+ ? undefined
208
+ : typeof height === "number"
209
+ ? height
210
+ : typeof height === "string"
211
+ ? parseInt(height, 10) || undefined
212
+ : undefined;
213
+ // ============ 合并 wrapperProps(处理 ref 合并) ============
214
+ const mergedWrapperProps = useMemo(() => {
215
+ // wrapperProps 可能包含 ref(通过类型扩展)
216
+ const userRef = wrapperProps === null || wrapperProps === void 0 ? void 0 : wrapperProps.ref;
217
+ // 合并 ref
218
+ const combinedRef = (node) => {
219
+ // 设置内部 ref
220
+ wrapperRef.current = node;
221
+ // 调用用户的 ref
222
+ if (userRef) {
223
+ if (typeof userRef === "function") {
224
+ userRef(node);
225
+ }
226
+ else {
227
+ userRef.current = node;
228
+ }
229
+ }
230
+ };
231
+ return {
232
+ ...wrapperProps,
233
+ ref: combinedRef,
234
+ style: wrapperStyle,
235
+ className: wrapperClassName,
236
+ };
237
+ }, [wrapperProps, wrapperStyle, wrapperClassName]);
238
+ // ============ 渲染 fallback ReactNode ============
239
+ if (hasError && fallback && typeof fallback !== "string") {
240
+ return (React.createElement("div", { ref: ref, className: className, style: {
241
+ width: parsedWidth,
242
+ height: parsedHeight,
243
+ position: fill ? "absolute" : undefined,
244
+ inset: fill ? 0 : undefined,
245
+ ...style,
246
+ } }, fallback));
247
+ }
248
+ // ============ 统一使用 LazyLoadImage ============
249
+ return (React.createElement(LazyLoadImage, { src: currentSrc, alt: alt, width: parsedWidth, height: parsedHeight, className: className, style: computedStyle,
250
+ // 懒加载配置 - lazy=false 时禁用懒加载特性
251
+ threshold: lazy ? threshold : 0, effect: lazy ? effectiveEffect : undefined, placeholderSrc: lazy ? placeholderSrc : undefined, placeholder: lazy ? placeholderElement : undefined, useIntersectionObserver: lazy ? useIntersectionObserver : false, visibleByDefault: !lazy || visibleByDefault, delayMethod: delayMethod, delayTime: delayTime,
252
+ // 性能优化
253
+ scrollPosition: lazy ? effectiveScrollPosition : undefined,
254
+ // 事件
255
+ beforeLoad: lazy ? handleBeforeLoad : undefined, onLoad: handleLoad, onError: handleError,
256
+ // 包裹元素
257
+ wrapperProps: mergedWrapperProps,
258
+ // 原生属性
259
+ loading: lazy ? loading : "eager", decoding: decoding, srcSet: srcSet, sizes: sizes, crossOrigin: crossOrigin, referrerPolicy: referrerPolicy }));
260
+ }));
261
+ export default XImage;
@@ -0,0 +1,130 @@
1
+ import type { CSSProperties, ReactElement, ReactNode, SyntheticEvent } from "react";
2
+ /**
3
+ * 懒加载效果类型
4
+ * - blur: 模糊渐变效果
5
+ * - opacity: 透明度渐变效果
6
+ * - black-and-white: 黑白到彩色渐变效果
7
+ */
8
+ export type XImageEffect = "blur" | "opacity" | "black-and-white";
9
+ /**
10
+ * 节流/防抖方法类型
11
+ */
12
+ export type DelayMethod = "throttle" | "debounce";
13
+ /**
14
+ * 图片加载状态
15
+ */
16
+ export type XImageStatus = "idle" | "loading" | "loaded" | "error";
17
+ /**
18
+ * 滚动位置类型 (用于 trackWindowScroll HOC)
19
+ */
20
+ export interface ScrollPosition {
21
+ x: number;
22
+ y: number;
23
+ }
24
+ /**
25
+ * XImage 组件 Props
26
+ */
27
+ export interface XImageProps {
28
+ /** 图片源地址 */
29
+ src: string;
30
+ /** 图片描述文本 */
31
+ alt?: string;
32
+ /** 图片宽度 */
33
+ width?: number | string;
34
+ /** 图片高度 */
35
+ height?: number | string;
36
+ /** CSS 类名 */
37
+ className?: string;
38
+ /** 内联样式 */
39
+ style?: CSSProperties;
40
+ /** 图片填充方式 */
41
+ objectFit?: CSSProperties["objectFit"];
42
+ /** 图片对齐方式 */
43
+ objectPosition?: CSSProperties["objectPosition"];
44
+ /** 是否使用 fill 模式(占满父容器) */
45
+ fill?: boolean;
46
+ /** 是否启用懒加载,默认 true */
47
+ lazy?: boolean;
48
+ /** 进入视口前多少像素开始加载,默认 100 */
49
+ threshold?: number;
50
+ /** 加载效果类型(如果提供了 placeholder URL 但未指定 effect,默认为 'blur') */
51
+ effect?: XImageEffect;
52
+ /**
53
+ * 占位内容
54
+ * - string: 占位图片 URL(自动启用 blur 效果)
55
+ * - ReactElement: 自定义占位组件(如 Skeleton,需手动指定 effect)
56
+ */
57
+ placeholder?: string | ReactElement | null;
58
+ /** 是否使用 IntersectionObserver,默认 true */
59
+ useIntersectionObserver?: boolean;
60
+ /** 滚动/resize 事件的节流方法 */
61
+ delayMethod?: DelayMethod;
62
+ /** 节流延迟时间(毫秒) */
63
+ delayTime?: number;
64
+ /**
65
+ * 加载失败时显示的备用内容
66
+ * - string: 备用图片 URL
67
+ * - ReactNode: 自定义错误展示组件
68
+ */
69
+ fallback?: string | ReactNode;
70
+ /** 加载失败后的重试次数,默认 0 */
71
+ retryCount?: number;
72
+ /** 重试间隔(毫秒),默认 1000 */
73
+ retryDelay?: number;
74
+ /**
75
+ * 滚动位置(来自 trackWindowScroll HOC)
76
+ * 当父组件使用 withScrollTracking 包裹时自动传入
77
+ */
78
+ scrollPosition?: ScrollPosition;
79
+ /**
80
+ * 设为 true 则图片立即显示(不触发懒加载)
81
+ * 适用于已在浏览器缓存中的图片
82
+ */
83
+ visibleByDefault?: boolean;
84
+ /** 图片加载完成回调 */
85
+ onLoad?: (event: SyntheticEvent<HTMLImageElement>) => void;
86
+ /** 图片加载失败回调 */
87
+ onError?: (event: SyntheticEvent<HTMLImageElement>) => void;
88
+ /** 图片进入视口时回调 */
89
+ onVisible?: () => void;
90
+ /** 加载状态变化回调 */
91
+ onStatusChange?: (status: XImageStatus) => void;
92
+ /** 传递给包裹 span 元素的属性 */
93
+ wrapperProps?: React.HTMLAttributes<HTMLSpanElement>;
94
+ /** 包裹元素的类名 */
95
+ wrapperClassName?: string;
96
+ /** 图片加载优先级 */
97
+ loading?: "lazy" | "eager";
98
+ /** 解码方式 */
99
+ decoding?: "async" | "auto" | "sync";
100
+ /** 响应式图片源集 */
101
+ srcSet?: string;
102
+ /** 响应式尺寸 */
103
+ sizes?: string;
104
+ /** 跨域设置 */
105
+ crossOrigin?: "anonymous" | "use-credentials" | "";
106
+ /** referrer 策略 */
107
+ referrerPolicy?: React.HTMLAttributeReferrerPolicy;
108
+ }
109
+ /**
110
+ * XImageGallery 组件 Props
111
+ * 用于包裹多个 XImage 实现统一的滚动监听优化
112
+ */
113
+ export interface XImageGalleryProps {
114
+ children: ReactNode;
115
+ /** 自定义容器类名 */
116
+ className?: string;
117
+ /** 自定义容器样式 */
118
+ style?: CSSProperties;
119
+ /** 节流方法: throttle 或 debounce */
120
+ delayMethod?: DelayMethod;
121
+ /** 节流/防抖延迟时间(毫秒) */
122
+ delayTime?: number;
123
+ }
124
+ /**
125
+ * withScrollTracking HOC 注入的 Props
126
+ */
127
+ export interface WithScrollTrackingProps {
128
+ scrollPosition: ScrollPosition;
129
+ }
130
+ //# sourceMappingURL=XImage.types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XImage.types.d.ts","sourceRoot":"","sources":["../../../src/layout/image/XImage.types.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ "use client";
2
+ export {};
@@ -0,0 +1,76 @@
1
+ import React, { ComponentType } from "react";
2
+ import type { XImageGalleryProps, ScrollPosition, WithScrollTrackingProps } from "./XImage.types";
3
+ /**
4
+ * ScrollPosition Context
5
+ * 用于在组件树中共享滚动位置,支持深层嵌套的 XImage 自动获取
6
+ */
7
+ export declare const ScrollPositionContext: React.Context<ScrollPosition | undefined>;
8
+ /**
9
+ * Hook: 获取当前的滚动位置
10
+ * 在 XImageGallery 内部的任意深度使用
11
+ */
12
+ export declare function useScrollPosition(): ScrollPosition | undefined;
13
+ /**
14
+ * XImageGallery - 图片画廊/列表性能优化组件
15
+ *
16
+ * 当页面中有大量图片需要懒加载时,使用此组件包裹可以:
17
+ * - 统一管理滚动监听,避免每个图片单独监听 scroll/resize 事件
18
+ * - 通过 trackWindowScroll HOC 实现性能优化
19
+ * - 通过 Context 自动向任意深度的子 XImage 组件传递 scrollPosition
20
+ *
21
+ * @example
22
+ * ```tsx
23
+ * // 基础用法 - 包裹多个 XImage(支持任意嵌套深度)
24
+ * <XImageGallery>
25
+ * <div className="grid">
26
+ * {images.map(img => (
27
+ * <div key={img.id} className="card">
28
+ * <XImage src={img.url} effect="blur" />
29
+ * </div>
30
+ * ))}
31
+ * </div>
32
+ * </XImageGallery>
33
+ *
34
+ * // 自定义节流配置
35
+ * <XImageGallery delayMethod="debounce" delayTime={200}>
36
+ * {images.map(img => (
37
+ * <XImage key={img.id} src={img.url} />
38
+ * ))}
39
+ * </XImageGallery>
40
+ * ```
41
+ *
42
+ * @note 注意事项:
43
+ * - 不要在 XImageGallery 内部嵌套另一个 XImageGallery
44
+ * - 内部的 XImage 会自动通过 Context 获取 scrollPosition,无需手动传递
45
+ */
46
+ export declare const XImageGallery: React.NamedExoticComponent<XImageGalleryProps & React.RefAttributes<HTMLDivElement>>;
47
+ /**
48
+ * HOC: 为任意组件添加滚动位置追踪能力
49
+ *
50
+ * 适用于需要自定义容器但又想使用 trackWindowScroll 优化的场景
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * // 自定义图片网格组件
55
+ * const ImageGrid = ({ images, scrollPosition }) => (
56
+ * <div className="grid grid-cols-3">
57
+ * {images.map(img => (
58
+ * <XImage
59
+ * key={img.id}
60
+ * src={img.url}
61
+ * scrollPosition={scrollPosition}
62
+ * />
63
+ * ))}
64
+ * </div>
65
+ * );
66
+ *
67
+ * // 使用 HOC 包裹
68
+ * const OptimizedImageGrid = withScrollTracking(ImageGrid);
69
+ *
70
+ * // 使用
71
+ * <OptimizedImageGrid images={images} />
72
+ * ```
73
+ */
74
+ export declare function withScrollTracking<P extends object>(WrappedComponent: ComponentType<P & WithScrollTrackingProps>): ComponentType<Omit<P, "scrollPosition">>;
75
+ export default XImageGallery;
76
+ //# sourceMappingURL=XImageGallery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XImageGallery.d.ts","sourceRoot":"","sources":["../../../src/layout/image/XImageGallery.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAQ,aAAa,EAAyC,MAAM,OAAO,CAAC;AAE1F,OAAO,KAAK,EACR,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EAC1B,MAAM,gBAAgB,CAAC;AAExB;;;GAGG;AACH,eAAO,MAAM,qBAAqB,2CAAuD,CAAC;AAE1F;;;GAGG;AACH,wBAAgB,iBAAiB,IAAI,cAAc,GAAG,SAAS,CAE9D;AAgCD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,eAAO,MAAM,aAAa,sFAiBzB,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,kBAAkB,CAAC,CAAC,SAAS,MAAM,EAC/C,gBAAgB,EAAE,aAAa,CAAC,CAAC,GAAG,uBAAuB,CAAC,GAC7D,aAAa,CAAC,IAAI,CAAC,CAAC,EAAE,gBAAgB,CAAC,CAAC,CAW1C;AAED,eAAe,aAAa,CAAC"}
@@ -0,0 +1,94 @@
1
+ "use client";
2
+ import React, { memo, forwardRef, createContext, useContext } from "react";
3
+ import { trackWindowScroll } from "react-lazy-load-image-component";
4
+ /**
5
+ * ScrollPosition Context
6
+ * 用于在组件树中共享滚动位置,支持深层嵌套的 XImage 自动获取
7
+ */
8
+ export const ScrollPositionContext = createContext(undefined);
9
+ /**
10
+ * Hook: 获取当前的滚动位置
11
+ * 在 XImageGallery 内部的任意深度使用
12
+ */
13
+ export function useScrollPosition() {
14
+ return useContext(ScrollPositionContext);
15
+ }
16
+ const InternalGallery = memo(forwardRef(function InternalGallery({ children, className, style, scrollPosition }, ref) {
17
+ return (React.createElement(ScrollPositionContext.Provider, { value: scrollPosition },
18
+ React.createElement("div", { ref: ref, className: className, style: style }, children)));
19
+ }));
20
+ /**
21
+ * 使用 trackWindowScroll HOC 包裹的 Gallery
22
+ */
23
+ const TrackedGallery = trackWindowScroll(InternalGallery);
24
+ /**
25
+ * XImageGallery - 图片画廊/列表性能优化组件
26
+ *
27
+ * 当页面中有大量图片需要懒加载时,使用此组件包裹可以:
28
+ * - 统一管理滚动监听,避免每个图片单独监听 scroll/resize 事件
29
+ * - 通过 trackWindowScroll HOC 实现性能优化
30
+ * - 通过 Context 自动向任意深度的子 XImage 组件传递 scrollPosition
31
+ *
32
+ * @example
33
+ * ```tsx
34
+ * // 基础用法 - 包裹多个 XImage(支持任意嵌套深度)
35
+ * <XImageGallery>
36
+ * <div className="grid">
37
+ * {images.map(img => (
38
+ * <div key={img.id} className="card">
39
+ * <XImage src={img.url} effect="blur" />
40
+ * </div>
41
+ * ))}
42
+ * </div>
43
+ * </XImageGallery>
44
+ *
45
+ * // 自定义节流配置
46
+ * <XImageGallery delayMethod="debounce" delayTime={200}>
47
+ * {images.map(img => (
48
+ * <XImage key={img.id} src={img.url} />
49
+ * ))}
50
+ * </XImageGallery>
51
+ * ```
52
+ *
53
+ * @note 注意事项:
54
+ * - 不要在 XImageGallery 内部嵌套另一个 XImageGallery
55
+ * - 内部的 XImage 会自动通过 Context 获取 scrollPosition,无需手动传递
56
+ */
57
+ export const XImageGallery = memo(forwardRef(function XImageGallery({ children, className, style, delayMethod, delayTime }, ref) {
58
+ return (React.createElement(TrackedGallery, { ref: ref, className: className, style: style, delayMethod: delayMethod, delayTime: delayTime }, children));
59
+ }));
60
+ /**
61
+ * HOC: 为任意组件添加滚动位置追踪能力
62
+ *
63
+ * 适用于需要自定义容器但又想使用 trackWindowScroll 优化的场景
64
+ *
65
+ * @example
66
+ * ```tsx
67
+ * // 自定义图片网格组件
68
+ * const ImageGrid = ({ images, scrollPosition }) => (
69
+ * <div className="grid grid-cols-3">
70
+ * {images.map(img => (
71
+ * <XImage
72
+ * key={img.id}
73
+ * src={img.url}
74
+ * scrollPosition={scrollPosition}
75
+ * />
76
+ * ))}
77
+ * </div>
78
+ * );
79
+ *
80
+ * // 使用 HOC 包裹
81
+ * const OptimizedImageGrid = withScrollTracking(ImageGrid);
82
+ *
83
+ * // 使用
84
+ * <OptimizedImageGrid images={images} />
85
+ * ```
86
+ */
87
+ export function withScrollTracking(WrappedComponent) {
88
+ const WithScrollTracking = trackWindowScroll(WrappedComponent);
89
+ // 设置 displayName 便于调试
90
+ const wrappedName = WrappedComponent.displayName || WrappedComponent.name || "Component";
91
+ WithScrollTracking.displayName = `withScrollTracking(${wrappedName})`;
92
+ return WithScrollTracking;
93
+ }
94
+ export default XImageGallery;
@@ -0,0 +1,12 @@
1
+ export { XImage, default as XImageDefault } from "./XImage";
2
+ export { XImageGallery, withScrollTracking, useScrollPosition, ScrollPositionContext, } from "./XImageGallery";
3
+ export type { XImageProps, XImageEffect, XImageStatus, XImageGalleryProps, ScrollPosition, WithScrollTrackingProps, DelayMethod, } from "./XImage.types";
4
+ /**
5
+ * XImage 效果 CSS 已内置,无需手动导入!
6
+ *
7
+ * 直接使用 effect 属性即可:
8
+ * <XImage src="..." effect="blur" />
9
+ * <XImage src="..." effect="opacity" />
10
+ * <XImage src="..." effect="black-and-white" />
11
+ */
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/layout/image/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,MAAM,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EACH,aAAa,EACb,kBAAkB,EAClB,iBAAiB,EACjB,qBAAqB,GACxB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACR,WAAW,EACX,YAAY,EACZ,YAAY,EACZ,kBAAkB,EAClB,cAAc,EACd,uBAAuB,EACvB,WAAW,GACd,MAAM,gBAAgB,CAAC;AAGxB;;;;;;;GAOG"}
@@ -0,0 +1,4 @@
1
+ "use client";
2
+ // ============ 组件导出 ============
3
+ export { XImage, default as XImageDefault } from "./XImage";
4
+ export { XImageGallery, withScrollTracking, useScrollPosition, ScrollPositionContext, } from "./XImageGallery";
@@ -0,0 +1,12 @@
1
+ export * from './resize/core/SizedLayoutProps';
2
+ export * from './resize/core/SizedLayoutContext';
3
+ export * from './resize/core/ResizeObserverHook';
4
+ export * from './resize/impl/SizedContainer';
5
+ export * from './resize/impl/SizedLayout';
6
+ export * from './image';
7
+ export * from './visibility/ElementVisibilityHooks';
8
+ export * from './virtualized/VirtualizedConfig';
9
+ export * from './hover/XHover';
10
+ export * from './button/XButton';
11
+ export * from './spinner/XSpinner';
12
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/layout/index.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,kCAAkC,CAAA;AAChD,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,cAAc,2BAA2B,CAAA;AACzC,cAAc,SAAS,CAAA;AACvB,cAAc,qCAAqC,CAAA;AACnD,cAAc,iCAAiC,CAAA;AAC/C,cAAc,gBAAgB,CAAA;AAC9B,cAAc,kBAAkB,CAAA;AAChC,cAAc,oBAAoB,CAAA"}
@@ -0,0 +1,11 @@
1
+ export * from './resize/core/SizedLayoutProps';
2
+ export * from './resize/core/SizedLayoutContext';
3
+ export * from './resize/core/ResizeObserverHook';
4
+ export * from './resize/impl/SizedContainer';
5
+ export * from './resize/impl/SizedLayout';
6
+ export * from './image';
7
+ export * from './visibility/ElementVisibilityHooks';
8
+ export * from './virtualized/VirtualizedConfig';
9
+ export * from './hover/XHover';
10
+ export * from './button/XButton';
11
+ export * from './spinner/XSpinner';
@@ -0,0 +1,41 @@
1
+ import { RefObject } from 'react';
2
+ import { LayoutSize } from "../../../foundation/LayoutSize";
3
+ interface UseResizeObserverOptions {
4
+ /** 防抖延迟,默认 0(不防抖) */
5
+ debounce?: number;
6
+ /** 初始尺寸 */
7
+ initialSize?: LayoutSize;
8
+ }
9
+ interface UseResizeObserverReturn<T extends HTMLElement> {
10
+ /** 绑定到容器元素的 ref */
11
+ containerRef: RefObject<T | null>;
12
+ /** 容器宽度 */
13
+ containerWidth: number;
14
+ /** 容器高度 */
15
+ containerHeight: number;
16
+ /** 是否已获取到尺寸 */
17
+ isContainerReady: boolean;
18
+ }
19
+ /**
20
+ * 基于 ResizeObserver 监听容器尺寸变化
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * const { containerRef, containerWidth, containerHeight, isContainerReady } = useResizeObserver();
25
+ *
26
+ * return (
27
+ * <div ref={containerRef}>
28
+ * {isContainerReady && <Chart width={containerWidth} height={containerHeight} />}
29
+ * </div>
30
+ * );
31
+ * ```
32
+ *
33
+ * @example
34
+ * ```tsx
35
+ * // 带防抖
36
+ * const { containerRef, containerHeight } = useResizeObserver({ debounce: 100 });
37
+ * ```
38
+ */
39
+ export declare function useResizeObserver<T extends HTMLElement = HTMLDivElement>(options?: UseResizeObserverOptions): UseResizeObserverReturn<T>;
40
+ export {};
41
+ //# sourceMappingURL=ResizeObserverHook.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ResizeObserverHook.d.ts","sourceRoot":"","sources":["../../../../src/layout/resize/core/ResizeObserverHook.ts"],"names":[],"mappings":"AAAA,OAAO,EAA8B,SAAS,EAAC,MAAM,OAAO,CAAC;AAC7D,OAAO,EAAC,UAAU,EAAC,MAAM,gCAAgC,CAAC;AAG1D,UAAU,wBAAwB;IAC9B,qBAAqB;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW;IACX,WAAW,CAAC,EAAE,UAAU,CAAC;CAC5B;AAED,UAAU,uBAAuB,CAAC,CAAC,SAAS,WAAW;IACnD,mBAAmB;IACnB,YAAY,EAAE,SAAS,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IAClC,WAAW;IACX,cAAc,EAAE,MAAM,CAAC;IACvB,WAAW;IACX,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe;IACf,gBAAgB,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,WAAW,GAAG,cAAc,EACpE,OAAO,GAAE,wBAA6B,GACvC,uBAAuB,CAAC,CAAC,CAAC,CAqC5B"}