xxf_react 0.8.5 → 0.8.7

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 +54 -0
  95. package/dist/http/interceptor/DefaultCacheInterceptor.d.ts.map +1 -0
  96. package/dist/http/interceptor/DefaultCacheInterceptor.js +111 -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,99 @@
1
+ import React, { ButtonHTMLAttributes, ReactNode } from 'react';
2
+ /**
3
+ * 加载指示器位置
4
+ * - `start`: 指示器在内容左侧
5
+ * - `center`: 指示器居中,内容隐藏(保持宽度)
6
+ * - `end`: 指示器在内容右侧
7
+ */
8
+ export type LoadingGravity = 'start' | 'center' | 'end';
9
+ /**
10
+ * XButton 组件属性
11
+ * @extends ButtonHTMLAttributes<HTMLButtonElement> 继承原生 button 所有属性
12
+ */
13
+ export interface XButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
14
+ /**
15
+ * 加载状态
16
+ * - 为 `true` 时按钮不可点击,显示加载指示器
17
+ * @default false
18
+ */
19
+ loading?: boolean;
20
+ /**
21
+ * 加载指示器位置
22
+ * - `start`: 左侧
23
+ * - `center`: 居中(隐藏内容,保持宽度避免抖动)
24
+ * - `end`: 右侧
25
+ * @default 'start'
26
+ */
27
+ loadingGravity?: LoadingGravity;
28
+ /**
29
+ * 自定义加载指示器(回调形式,懒创建)
30
+ * - 只有 loading=true 时才会调用
31
+ * - 不传则使用默认的 XSpinner
32
+ * - 尺寸建议使用 `em` 单位以跟随字体大小
33
+ * @example () => <MySpinner className="w-5 h-5" />
34
+ */
35
+ loadingIndicator?: () => ReactNode;
36
+ /**
37
+ * 指示器与内容的间距(像素)
38
+ * - 仅在 `loadingGravity` 为 `start` 或 `end` 时生效
39
+ * @default 8
40
+ */
41
+ loadingGap?: number;
42
+ /**
43
+ * 点击防抖等待时间(毫秒)
44
+ * - 防止用户快速连续点击
45
+ * - 使用 leading 模式:首次点击立即执行,后续点击在等待时间内被忽略
46
+ * - 设为 0 时禁用防抖
47
+ * @default 500
48
+ */
49
+ debounceWait?: number;
50
+ /**
51
+ * 是否阻止事件冒泡
52
+ * @default false
53
+ */
54
+ stopPropagation?: boolean;
55
+ /** 按钮内容,支持任意 ReactNode(文本、元素、组件等) */
56
+ children?: ReactNode;
57
+ }
58
+ /**
59
+ * XButton - 支持加载状态的按钮组件
60
+ *
61
+ * @description
62
+ * 封装了常见的按钮加载交互:
63
+ * - 加载时自动禁用点击
64
+ * - 支持自定义加载指示器位置(左/中/右)
65
+ * - 居中模式保持按钮宽度,避免布局抖动
66
+ * - 支持 ref 转发
67
+ * - 支持点击防抖,防止重复提交
68
+ * - 不依赖外部库,纯内联样式实现
69
+ *
70
+ * @example
71
+ * ```tsx
72
+ * // 基本用法
73
+ * <XButton loading={isLoading} onClick={handleSubmit}>
74
+ * 提交
75
+ * </XButton>
76
+ *
77
+ * // 加载指示器在左侧
78
+ * <XButton loading loadingGravity="start">
79
+ * 加载中...
80
+ * </XButton>
81
+ *
82
+ * // 自定义加载指示器(回调形式,懒创建)
83
+ * <XButton loading loadingIndicator={() => <MySpinner />}>
84
+ * 处理中
85
+ * </XButton>
86
+ *
87
+ * // 防抖点击(500ms 内只响应第一次)
88
+ * <XButton debounceWait={500} onClick={handleSubmit}>
89
+ * 提交订单
90
+ * </XButton>
91
+ *
92
+ * // 阻止冒泡 + 防抖
93
+ * <XButton debounceWait={500} stopPropagation onClick={handleSubmit}>
94
+ * 提交
95
+ * </XButton>
96
+ * ```
97
+ */
98
+ export declare const XButton: React.ForwardRefExoticComponent<XButtonProps & React.RefAttributes<HTMLButtonElement>>;
99
+ //# sourceMappingURL=XButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XButton.d.ts","sourceRoot":"","sources":["../../../src/layout/button/XButton.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,EAAa,oBAAoB,EAAE,SAAS,EAAgB,MAAM,OAAO,CAAC;AAIxF;;;;;GAKG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,QAAQ,GAAG,KAAK,CAAC;AAExD;;;GAGG;AACH,MAAM,WAAW,YAAa,SAAQ,oBAAoB,CAAC,iBAAiB,CAAC;IACzE;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;;;OAMG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAEhC;;;;;;OAMG;IACH,gBAAgB,CAAC,EAAE,MAAM,SAAS,CAAC;IAEnC;;;;OAIG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IAEpB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;IAEtB;;;OAGG;IACH,eAAe,CAAC,EAAE,OAAO,CAAC;IAE1B,qCAAqC;IACrC,QAAQ,CAAC,EAAE,SAAS,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuCG;AACH,eAAO,MAAM,OAAO,wFA6InB,CAAC"}
@@ -0,0 +1,131 @@
1
+ 'use client';
2
+ import React, { forwardRef } from 'react';
3
+ import { useDebouncedCallback } from 'use-debounce';
4
+ import { XSpinner } from "../spinner/XSpinner";
5
+ /**
6
+ * XButton - 支持加载状态的按钮组件
7
+ *
8
+ * @description
9
+ * 封装了常见的按钮加载交互:
10
+ * - 加载时自动禁用点击
11
+ * - 支持自定义加载指示器位置(左/中/右)
12
+ * - 居中模式保持按钮宽度,避免布局抖动
13
+ * - 支持 ref 转发
14
+ * - 支持点击防抖,防止重复提交
15
+ * - 不依赖外部库,纯内联样式实现
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // 基本用法
20
+ * <XButton loading={isLoading} onClick={handleSubmit}>
21
+ * 提交
22
+ * </XButton>
23
+ *
24
+ * // 加载指示器在左侧
25
+ * <XButton loading loadingGravity="start">
26
+ * 加载中...
27
+ * </XButton>
28
+ *
29
+ * // 自定义加载指示器(回调形式,懒创建)
30
+ * <XButton loading loadingIndicator={() => <MySpinner />}>
31
+ * 处理中
32
+ * </XButton>
33
+ *
34
+ * // 防抖点击(500ms 内只响应第一次)
35
+ * <XButton debounceWait={500} onClick={handleSubmit}>
36
+ * 提交订单
37
+ * </XButton>
38
+ *
39
+ * // 阻止冒泡 + 防抖
40
+ * <XButton debounceWait={500} stopPropagation onClick={handleSubmit}>
41
+ * 提交
42
+ * </XButton>
43
+ * ```
44
+ */
45
+ export const XButton = forwardRef(function XButton({ loading = false, loadingGravity = 'start', loadingIndicator, loadingGap = 8, debounceWait = 500, stopPropagation = false, children, onClick, disabled, style, type = 'button', ...rest }, ref) {
46
+ /**
47
+ * 获取加载指示器(懒创建)
48
+ * - 只在 loading=true 时才实际创建节点
49
+ */
50
+ const getIndicator = () => { var _a; return (_a = loadingIndicator === null || loadingIndicator === void 0 ? void 0 : loadingIndicator()) !== null && _a !== void 0 ? _a : React.createElement(XSpinner, null); };
51
+ /**
52
+ * 防抖处理后的点击回调
53
+ * - leading: true 首次点击立即执行
54
+ * - trailing: false 等待时间结束后不再执行
55
+ */
56
+ const debouncedOnClick = useDebouncedCallback((e) => {
57
+ onClick === null || onClick === void 0 ? void 0 : onClick(e);
58
+ }, debounceWait, { leading: true, trailing: false });
59
+ /**
60
+ * 点击事件处理
61
+ * - 阻止冒泡(可选)
62
+ * - loading 或 disabled 时拦截
63
+ * - debounceWait > 0 时使用防抖回调
64
+ */
65
+ const handleClick = (e) => {
66
+ // 阻止冒泡
67
+ if (stopPropagation) {
68
+ e.stopPropagation();
69
+ }
70
+ // loading 或 disabled 时拦截
71
+ if (loading || disabled) {
72
+ e.preventDefault();
73
+ return;
74
+ }
75
+ // 根据 debounceWait 决定是否使用防抖
76
+ if (debounceWait > 0) {
77
+ debouncedOnClick(e);
78
+ }
79
+ else {
80
+ onClick === null || onClick === void 0 ? void 0 : onClick(e);
81
+ }
82
+ };
83
+ /** 按钮基础样式,使用 flexbox 布局 */
84
+ const baseStyle = {
85
+ display: 'inline-flex',
86
+ alignItems: 'center',
87
+ justifyContent: 'center',
88
+ position: 'relative',
89
+ // 仅在 start/end 模式下应用 gap
90
+ gap: loading && loadingGravity !== 'center' ? loadingGap : undefined,
91
+ ...style,
92
+ };
93
+ /**
94
+ * 渲染按钮内容
95
+ * - 非加载状态:直接渲染 children
96
+ * - start:指示器 + children
97
+ * - end:children + 指示器
98
+ * - center:children 隐藏占位 + 指示器绝对定位居中
99
+ */
100
+ const renderContent = () => {
101
+ if (!loading) {
102
+ return children;
103
+ }
104
+ const indicator = getIndicator();
105
+ switch (loadingGravity) {
106
+ case 'start':
107
+ return (React.createElement(React.Fragment, null,
108
+ indicator,
109
+ children));
110
+ case 'end':
111
+ return (React.createElement(React.Fragment, null,
112
+ children,
113
+ indicator));
114
+ case 'center':
115
+ default:
116
+ // children 保持可见,indicator 绝对定位叠加在上面
117
+ // 背景透明,可以看到 children 内容
118
+ return (React.createElement(React.Fragment, null,
119
+ children,
120
+ React.createElement("div", { style: {
121
+ position: 'absolute',
122
+ inset: 0,
123
+ display: 'flex',
124
+ alignItems: 'center',
125
+ justifyContent: 'center',
126
+ backgroundColor: 'transparent',
127
+ } }, indicator)));
128
+ }
129
+ };
130
+ return (React.createElement("button", { ref: ref, type: type, ...rest, style: baseStyle, disabled: disabled || loading, onClick: handleClick, "aria-busy": loading, "aria-disabled": disabled || loading }, renderContent()));
131
+ });
@@ -0,0 +1,147 @@
1
+ import React, { ReactNode, HTMLAttributes } from 'react';
2
+ /**
3
+ * XHover 组件属性
4
+ */
5
+ export interface XHoverProps extends Omit<HTMLAttributes<HTMLDivElement>, 'onMouseEnter' | 'onMouseLeave'> {
6
+ /**
7
+ * 子组件
8
+ */
9
+ children: ReactNode;
10
+ /**
11
+ * 悬浮触发延迟时间(毫秒)
12
+ *
13
+ * 鼠标进入后,需要持续悬浮该时间才会触发 onHover 回调和显示 hoverLayer。
14
+ * - 设为 0 或不设置:鼠标进入立即触发
15
+ * - 设为正数:鼠标需要停留指定毫秒后才触发
16
+ *
17
+ * @example
18
+ * ```tsx
19
+ * // 悬浮 2 秒后触发
20
+ * <XHover hoverDelay={2000} onHover={handleHover}>
21
+ *
22
+ * // 立即触发(默认)
23
+ * <XHover onHover={handleHover}>
24
+ * ```
25
+ *
26
+ * @default 0
27
+ */
28
+ hoverDelay?: number;
29
+ /**
30
+ * 鼠标进入时立即触发的回调(不等待 hoverDelay)
31
+ *
32
+ * 适用于需要在鼠标进入时立即做一些事情的场景,如显示边框高亮等
33
+ */
34
+ onEnter?: () => void;
35
+ /**
36
+ * 悬浮回调
37
+ *
38
+ * 当鼠标悬浮达到 hoverDelay 时间后触发
39
+ */
40
+ onHover?: () => void;
41
+ /**
42
+ * 鼠标离开回调
43
+ *
44
+ * @param triggered - 是否已触发过 onHover(用于判断是否需要隐藏 tooltip 等)
45
+ */
46
+ onLeave?: (triggered: boolean) => void;
47
+ /**
48
+ * 悬浮覆盖层
49
+ *
50
+ * 当悬浮触发(达到 hoverDelay 时间)后,显示在 children 上方的内容。
51
+ * 鼠标离开后自动隐藏。
52
+ *
53
+ * @example
54
+ * ```tsx
55
+ * <XHover
56
+ * hoverDelay={1000}
57
+ * hoverLayer={() => (
58
+ * <div className="absolute inset-0 bg-black/50 flex items-center justify-center">
59
+ * <span className="text-white">悬浮提示</span>
60
+ * </div>
61
+ * )}
62
+ * >
63
+ * <img src="..." />
64
+ * </XHover>
65
+ * ```
66
+ */
67
+ hoverLayer?: () => ReactNode;
68
+ /**
69
+ * 是否禁用悬浮检测
70
+ *
71
+ * @default false
72
+ */
73
+ disabled?: boolean;
74
+ /**
75
+ * 容器元素类型
76
+ *
77
+ * @default 'div'
78
+ */
79
+ as?: 'div' | 'span';
80
+ }
81
+ /**
82
+ * 悬浮触发组件
83
+ *
84
+ * 支持延迟触发悬浮回调,适用于需要用户停留一段时间后才响应的场景。
85
+ *
86
+ * @example
87
+ * ```tsx
88
+ * // 基础用法:鼠标悬浮 2 秒后触发
89
+ * <XHover hoverDelay={2000} onHover={() => console.log('悬浮触发')}>
90
+ * <div>悬浮我</div>
91
+ * </XHover>
92
+ *
93
+ * // 无延迟:立即触发
94
+ * <XHover onHover={() => console.log('立即触发')}>
95
+ * <div>悬浮我</div>
96
+ * </XHover>
97
+ *
98
+ * // 带离开回调,判断是否触发过
99
+ * <XHover
100
+ * hoverDelay={1000}
101
+ * onHover={() => setShowTooltip(true)}
102
+ * onLeave={(triggered) => {
103
+ * if (triggered) setShowTooltip(false)
104
+ * }}
105
+ * >
106
+ * <Button>悬浮显示提示</Button>
107
+ * </XHover>
108
+ *
109
+ * // 使用 hoverLayer 显示悬浮覆盖层
110
+ * <XHover
111
+ * hoverDelay={1000}
112
+ * hoverLayer={() => (
113
+ * <div className="absolute inset-0 bg-black/50 flex items-center justify-center">
114
+ * <PlayIcon className="text-white w-12 h-12" />
115
+ * </div>
116
+ * )}
117
+ * >
118
+ * <img src="thumbnail.jpg" />
119
+ * </XHover>
120
+ *
121
+ * // 使用 span 作为容器(适用于 inline 场景)
122
+ * <XHover as="span" hoverDelay={500} onHover={handleHover}>
123
+ * <span>inline 文本</span>
124
+ * </XHover>
125
+ *
126
+ * // 禁用状态
127
+ * <XHover disabled={isLoading} hoverDelay={1000} onHover={handleHover}>
128
+ * <div>内容</div>
129
+ * </XHover>
130
+ *
131
+ * // 使用 onEnter 立即响应 + onHover 延迟响应
132
+ * <XHover
133
+ * hoverDelay={1000}
134
+ * onEnter={() => setHighlight(true)}
135
+ * onHover={() => setShowDetail(true)}
136
+ * onLeave={() => {
137
+ * setHighlight(false)
138
+ * setShowDetail(false)
139
+ * }}
140
+ * >
141
+ * <Card />
142
+ * </XHover>
143
+ * ```
144
+ */
145
+ export declare const XHover: React.ForwardRefExoticComponent<XHoverProps & React.RefAttributes<HTMLElement>>;
146
+ export default XHover;
147
+ //# sourceMappingURL=XHover.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XHover.d.ts","sourceRoot":"","sources":["../../../src/layout/hover/XHover.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAuD,SAAS,EAAE,cAAc,EAAC,MAAM,OAAO,CAAA;AAE5G;;GAEG;AACH,MAAM,WAAW,WAAY,SAAQ,IAAI,CAAC,cAAc,CAAC,cAAc,CAAC,EAAE,cAAc,GAAG,cAAc,CAAC;IACtG;;OAEG;IACH,QAAQ,EAAE,SAAS,CAAA;IAEnB;;;;;;;;;;;;;;;;;OAiBG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IAEnB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;IAEpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,CAAC,SAAS,EAAE,OAAO,KAAK,IAAI,CAAA;IAEtC;;;;;;;;;;;;;;;;;;;OAmBG;IACH,UAAU,CAAC,EAAE,MAAM,SAAS,CAAA;IAE5B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,OAAO,CAAA;IAElB;;;;OAIG;IACH,EAAE,CAAC,EAAE,KAAK,GAAG,MAAM,CAAA;CACtB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+DG;AACH,eAAO,MAAM,MAAM,iFAyFjB,CAAA;AAEF,eAAe,MAAM,CAAA"}
@@ -0,0 +1,128 @@
1
+ import React, { forwardRef, useCallback, useRef, useEffect, useState } from 'react';
2
+ /**
3
+ * 悬浮触发组件
4
+ *
5
+ * 支持延迟触发悬浮回调,适用于需要用户停留一段时间后才响应的场景。
6
+ *
7
+ * @example
8
+ * ```tsx
9
+ * // 基础用法:鼠标悬浮 2 秒后触发
10
+ * <XHover hoverDelay={2000} onHover={() => console.log('悬浮触发')}>
11
+ * <div>悬浮我</div>
12
+ * </XHover>
13
+ *
14
+ * // 无延迟:立即触发
15
+ * <XHover onHover={() => console.log('立即触发')}>
16
+ * <div>悬浮我</div>
17
+ * </XHover>
18
+ *
19
+ * // 带离开回调,判断是否触发过
20
+ * <XHover
21
+ * hoverDelay={1000}
22
+ * onHover={() => setShowTooltip(true)}
23
+ * onLeave={(triggered) => {
24
+ * if (triggered) setShowTooltip(false)
25
+ * }}
26
+ * >
27
+ * <Button>悬浮显示提示</Button>
28
+ * </XHover>
29
+ *
30
+ * // 使用 hoverLayer 显示悬浮覆盖层
31
+ * <XHover
32
+ * hoverDelay={1000}
33
+ * hoverLayer={() => (
34
+ * <div className="absolute inset-0 bg-black/50 flex items-center justify-center">
35
+ * <PlayIcon className="text-white w-12 h-12" />
36
+ * </div>
37
+ * )}
38
+ * >
39
+ * <img src="thumbnail.jpg" />
40
+ * </XHover>
41
+ *
42
+ * // 使用 span 作为容器(适用于 inline 场景)
43
+ * <XHover as="span" hoverDelay={500} onHover={handleHover}>
44
+ * <span>inline 文本</span>
45
+ * </XHover>
46
+ *
47
+ * // 禁用状态
48
+ * <XHover disabled={isLoading} hoverDelay={1000} onHover={handleHover}>
49
+ * <div>内容</div>
50
+ * </XHover>
51
+ *
52
+ * // 使用 onEnter 立即响应 + onHover 延迟响应
53
+ * <XHover
54
+ * hoverDelay={1000}
55
+ * onEnter={() => setHighlight(true)}
56
+ * onHover={() => setShowDetail(true)}
57
+ * onLeave={() => {
58
+ * setHighlight(false)
59
+ * setShowDetail(false)
60
+ * }}
61
+ * >
62
+ * <Card />
63
+ * </XHover>
64
+ * ```
65
+ */
66
+ export const XHover = forwardRef(function XHover({ children, hoverDelay = 0, onEnter, onHover, onLeave, hoverLayer, disabled = false, as: Component = 'div', style, ...rest }, ref) {
67
+ const timerRef = useRef(null);
68
+ const hasTriggeredRef = useRef(false);
69
+ // 只有 hoverLayer 存在时才需要状态
70
+ const [showLayer, setShowLayer] = useState(false);
71
+ const clearTimer = useCallback(() => {
72
+ if (timerRef.current) {
73
+ clearTimeout(timerRef.current);
74
+ timerRef.current = null;
75
+ }
76
+ }, []);
77
+ // 组件卸载时清理定时器
78
+ useEffect(() => {
79
+ return clearTimer;
80
+ }, [clearTimer]);
81
+ // disabled 变化时清理定时器和状态
82
+ useEffect(() => {
83
+ if (disabled) {
84
+ clearTimer();
85
+ if (hoverLayer) {
86
+ setShowLayer(false);
87
+ }
88
+ }
89
+ }, [disabled, clearTimer, hoverLayer]);
90
+ const handleMouseEnter = useCallback(() => {
91
+ if (disabled)
92
+ return;
93
+ hasTriggeredRef.current = false;
94
+ clearTimer();
95
+ // 立即触发 onEnter
96
+ onEnter === null || onEnter === void 0 ? void 0 : onEnter();
97
+ if (hoverDelay <= 0) {
98
+ hasTriggeredRef.current = true;
99
+ if (hoverLayer)
100
+ setShowLayer(true);
101
+ onHover === null || onHover === void 0 ? void 0 : onHover();
102
+ }
103
+ else {
104
+ timerRef.current = setTimeout(() => {
105
+ hasTriggeredRef.current = true;
106
+ if (hoverLayer)
107
+ setShowLayer(true);
108
+ onHover === null || onHover === void 0 ? void 0 : onHover();
109
+ }, hoverDelay);
110
+ }
111
+ }, [hoverDelay, onEnter, onHover, clearTimer, disabled, hoverLayer]);
112
+ const handleMouseLeave = useCallback(() => {
113
+ if (disabled)
114
+ return;
115
+ clearTimer();
116
+ if (hoverLayer)
117
+ setShowLayer(false);
118
+ onLeave === null || onLeave === void 0 ? void 0 : onLeave(hasTriggeredRef.current);
119
+ }, [clearTimer, onLeave, disabled, hoverLayer]);
120
+ // 如果有 hoverLayer,需要使用 relative 定位(用户 style 可覆盖)
121
+ const containerStyle = hoverLayer
122
+ ? { position: 'relative', ...style }
123
+ : style;
124
+ return (React.createElement(Component, { ref: ref, ...rest, style: containerStyle, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave },
125
+ children,
126
+ hoverLayer && showLayer && hoverLayer()));
127
+ });
128
+ export default XHover;
@@ -0,0 +1,35 @@
1
+ import React from "react";
2
+ import type { XImageProps } from "./XImage.types";
3
+ /**
4
+ * 生产级图片组件
5
+ *
6
+ * 基于 react-lazy-load-image-component 实现,支持:
7
+ * - 懒加载 + IntersectionObserver
8
+ * - 多种加载效果 (blur/opacity/black-and-white) - CSS 已内置,无需导入
9
+ * - 错误处理 + 自动重试
10
+ * - fallback 备用图/组件
11
+ * - 性能优化 (配合 XImageGallery 使用 trackWindowScroll)
12
+ *
13
+ * @example
14
+ * ```tsx
15
+ * // 基础用法
16
+ * <XImage src="/photo.jpg" alt="Photo" width={400} height={300} />
17
+ *
18
+ * // 带模糊效果(提供 placeholder URL 自动启用 blur)
19
+ * <XImage src="/photo.jpg" placeholder="/photo-tiny.jpg" />
20
+ *
21
+ * // 自定义占位组件
22
+ * <XImage src="/photo.jpg" placeholder={<Skeleton />} effect="opacity" />
23
+ *
24
+ * // 带错误处理
25
+ * <XImage
26
+ * src="/photo.jpg"
27
+ * fallback="/fallback.jpg"
28
+ * retryCount={2}
29
+ * retryDelay={1000}
30
+ * />
31
+ * ```
32
+ */
33
+ export declare const XImage: React.NamedExoticComponent<XImageProps & React.RefAttributes<HTMLDivElement | HTMLImageElement>>;
34
+ export default XImage;
35
+ //# sourceMappingURL=XImage.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XImage.d.ts","sourceRoot":"","sources":["../../../src/layout/image/XImage.tsx"],"names":[],"mappings":"AAEA,OAAO,KASN,MAAM,OAAO,CAAC;AAEf,OAAO,KAAK,EAAE,WAAW,EAAgB,MAAM,gBAAgB,CAAC;AAIhE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,eAAO,MAAM,MAAM,kGAoUlB,CAAC;AAEF,eAAe,MAAM,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * XImage 效果样式管理
3
+ * 自动注入 CSS 到 document.head,用户无需手动导入
4
+ */
5
+ /**
6
+ * 注入效果 CSS 到 document.head
7
+ * - 仅在浏览器环境执行
8
+ * - 只执行一次(多个 XImage 实例共享)
9
+ * - SSR 安全
10
+ */
11
+ export declare function injectEffectStyles(): void;
12
+ /**
13
+ * 移除已注入的效果 CSS(用于测试或清理)
14
+ */
15
+ export declare function removeEffectStyles(): void;
16
+ //# sourceMappingURL=XImage.effects.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"XImage.effects.d.ts","sourceRoot":"","sources":["../../../src/layout/image/XImage.effects.ts"],"names":[],"mappings":"AAAA;;;GAGG;AA8CH;;;;;GAKG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAczC;AAED;;GAEG;AACH,wBAAgB,kBAAkB,IAAI,IAAI,CAQzC"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * XImage 效果样式管理
3
+ * 自动注入 CSS 到 document.head,用户无需手动导入
4
+ */
5
+ // ============ 效果 CSS 定义 ============
6
+ const EFFECT_STYLES = `
7
+ .lazy-load-image-background.blur {
8
+ filter: blur(15px);
9
+ }
10
+ .lazy-load-image-background.blur.lazy-load-image-loaded {
11
+ filter: blur(0);
12
+ transition: filter .3s;
13
+ }
14
+ .lazy-load-image-background.blur > img {
15
+ opacity: 0;
16
+ }
17
+ .lazy-load-image-background.blur.lazy-load-image-loaded > img {
18
+ opacity: 1;
19
+ transition: opacity .3s;
20
+ }
21
+ .lazy-load-image-background.opacity {
22
+ opacity: 0;
23
+ }
24
+ .lazy-load-image-background.opacity.lazy-load-image-loaded {
25
+ opacity: 1;
26
+ transition: opacity .3s;
27
+ }
28
+ .lazy-load-image-background.black-and-white {
29
+ filter: grayscale(1);
30
+ }
31
+ .lazy-load-image-background.black-and-white.lazy-load-image-loaded {
32
+ filter: grayscale(0);
33
+ transition: filter .3s;
34
+ }
35
+ .lazy-load-image-background.black-and-white > img {
36
+ opacity: 0;
37
+ }
38
+ .lazy-load-image-background.black-and-white.lazy-load-image-loaded > img {
39
+ opacity: 1;
40
+ transition: opacity .3s;
41
+ }
42
+ `;
43
+ const STYLE_ID = "ximage-effect-styles";
44
+ // CSS 注入标记,确保只注入一次
45
+ let stylesInjected = false;
46
+ /**
47
+ * 注入效果 CSS 到 document.head
48
+ * - 仅在浏览器环境执行
49
+ * - 只执行一次(多个 XImage 实例共享)
50
+ * - SSR 安全
51
+ */
52
+ export function injectEffectStyles() {
53
+ if (stylesInjected || typeof document === "undefined")
54
+ return;
55
+ // 双重检查:防止多实例并发注入
56
+ if (document.getElementById(STYLE_ID)) {
57
+ stylesInjected = true;
58
+ return;
59
+ }
60
+ const styleElement = document.createElement("style");
61
+ styleElement.id = STYLE_ID;
62
+ styleElement.textContent = EFFECT_STYLES;
63
+ document.head.appendChild(styleElement);
64
+ stylesInjected = true;
65
+ }
66
+ /**
67
+ * 移除已注入的效果 CSS(用于测试或清理)
68
+ */
69
+ export function removeEffectStyles() {
70
+ if (typeof document === "undefined")
71
+ return;
72
+ const styleElement = document.getElementById(STYLE_ID);
73
+ if (styleElement) {
74
+ styleElement.remove();
75
+ stylesInjected = false;
76
+ }
77
+ }