@class-kit/react 0.1.1 → 0.1.2

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 (274) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +10 -2
  3. package/dist/components/affix.cjs.map +1 -1
  4. package/dist/components/affix.js.map +1 -1
  5. package/dist/components/backtop.cjs.map +1 -1
  6. package/dist/components/backtop.js.map +1 -1
  7. package/dist/components/badge.cjs.map +1 -1
  8. package/dist/components/badge.js.map +1 -1
  9. package/dist/components/barcode.cjs.map +1 -1
  10. package/dist/components/barcode.js.map +1 -1
  11. package/dist/components/breadcrumb.cjs.map +1 -1
  12. package/dist/components/breadcrumb.js.map +1 -1
  13. package/dist/components/button.cjs.map +1 -1
  14. package/dist/components/button.js.map +1 -1
  15. package/dist/components/calendar.cjs.map +1 -1
  16. package/dist/components/calendar.js.map +1 -1
  17. package/dist/components/canvas-editor.cjs.map +1 -1
  18. package/dist/components/canvas-editor.js.map +1 -1
  19. package/dist/components/canvas-image.cjs.map +1 -1
  20. package/dist/components/canvas-image.js.map +1 -1
  21. package/dist/components/chat-textarea.cjs +103 -0
  22. package/dist/components/chat-textarea.cjs.map +1 -0
  23. package/dist/components/chat-textarea.d.ts +3 -0
  24. package/dist/components/chat-textarea.d.ts.map +1 -0
  25. package/dist/components/chat-textarea.js +101 -0
  26. package/dist/components/chat-textarea.js.map +1 -0
  27. package/dist/components/chat-virtual-list.cjs +39 -7
  28. package/dist/components/chat-virtual-list.cjs.map +1 -1
  29. package/dist/components/chat-virtual-list.js +39 -7
  30. package/dist/components/chat-virtual-list.js.map +1 -1
  31. package/dist/components/checkbox.cjs.map +1 -1
  32. package/dist/components/checkbox.js.map +1 -1
  33. package/dist/components/checked.cjs.map +1 -1
  34. package/dist/components/checked.js.map +1 -1
  35. package/dist/components/code-preview.cjs +190 -0
  36. package/dist/components/code-preview.cjs.map +1 -0
  37. package/dist/components/code-preview.d.ts +3 -0
  38. package/dist/components/code-preview.d.ts.map +1 -0
  39. package/dist/components/code-preview.js +188 -0
  40. package/dist/components/code-preview.js.map +1 -0
  41. package/dist/components/color-picker.cjs +2 -2
  42. package/dist/components/color-picker.cjs.map +1 -1
  43. package/dist/components/color-picker.js +2 -2
  44. package/dist/components/color-picker.js.map +1 -1
  45. package/dist/components/comic-reader.cjs.map +1 -1
  46. package/dist/components/comic-reader.js.map +1 -1
  47. package/dist/components/config-provider.cjs.map +1 -1
  48. package/dist/components/config-provider.js.map +1 -1
  49. package/dist/components/config-table.cjs.map +1 -1
  50. package/dist/components/config-table.js.map +1 -1
  51. package/dist/components/countdown.cjs.map +1 -1
  52. package/dist/components/countdown.js.map +1 -1
  53. package/dist/components/danmaku.cjs.map +1 -1
  54. package/dist/components/danmaku.js.map +1 -1
  55. package/dist/components/date-picker.cjs.map +1 -1
  56. package/dist/components/date-picker.js.map +1 -1
  57. package/dist/components/date-range-picker.cjs.map +1 -1
  58. package/dist/components/date-range-picker.js.map +1 -1
  59. package/dist/components/design-effect.cjs.map +1 -1
  60. package/dist/components/design-effect.js.map +1 -1
  61. package/dist/components/drag-drop-board.cjs +24 -0
  62. package/dist/components/drag-drop-board.cjs.map +1 -1
  63. package/dist/components/drag-drop-board.js +24 -0
  64. package/dist/components/drag-drop-board.js.map +1 -1
  65. package/dist/components/draggable.cjs.map +1 -1
  66. package/dist/components/draggable.js.map +1 -1
  67. package/dist/components/ellipsis-text.cjs.map +1 -1
  68. package/dist/components/ellipsis-text.js.map +1 -1
  69. package/dist/components/empty.cjs.map +1 -1
  70. package/dist/components/empty.js.map +1 -1
  71. package/dist/components/field.cjs.map +1 -1
  72. package/dist/components/field.js.map +1 -1
  73. package/dist/components/file-preview.cjs.map +1 -1
  74. package/dist/components/file-preview.js.map +1 -1
  75. package/dist/components/floating-ball.cjs.map +1 -1
  76. package/dist/components/floating-ball.js.map +1 -1
  77. package/dist/components/form.cjs.map +1 -1
  78. package/dist/components/form.js.map +1 -1
  79. package/dist/components/gradient-text.cjs.map +1 -1
  80. package/dist/components/gradient-text.js.map +1 -1
  81. package/dist/components/height-transition.cjs +35 -0
  82. package/dist/components/height-transition.cjs.map +1 -0
  83. package/dist/components/height-transition.d.ts +3 -0
  84. package/dist/components/height-transition.d.ts.map +1 -0
  85. package/dist/components/height-transition.js +33 -0
  86. package/dist/components/height-transition.js.map +1 -0
  87. package/dist/components/input.cjs.map +1 -1
  88. package/dist/components/input.js.map +1 -1
  89. package/dist/components/lazy-image.cjs.map +1 -1
  90. package/dist/components/lazy-image.js.map +1 -1
  91. package/dist/components/live-room.cjs.map +1 -1
  92. package/dist/components/live-room.js.map +1 -1
  93. package/dist/components/loading.cjs.map +1 -1
  94. package/dist/components/loading.js.map +1 -1
  95. package/dist/components/marquee.cjs.map +1 -1
  96. package/dist/components/marquee.js.map +1 -1
  97. package/dist/components/masonry-virtual-list.cjs.map +1 -1
  98. package/dist/components/masonry-virtual-list.js.map +1 -1
  99. package/dist/components/menu.cjs +100 -0
  100. package/dist/components/menu.cjs.map +1 -0
  101. package/dist/components/menu.d.ts +3 -0
  102. package/dist/components/menu.d.ts.map +1 -0
  103. package/dist/components/menu.js +98 -0
  104. package/dist/components/menu.js.map +1 -0
  105. package/dist/components/modal.cjs.map +1 -1
  106. package/dist/components/modal.js.map +1 -1
  107. package/dist/components/multi-column-picker.cjs.map +1 -1
  108. package/dist/components/multi-column-picker.js.map +1 -1
  109. package/dist/components/novel-reader.cjs.map +1 -1
  110. package/dist/components/novel-reader.js.map +1 -1
  111. package/dist/components/number-input.cjs.map +1 -1
  112. package/dist/components/number-input.js.map +1 -1
  113. package/dist/components/orbital-sphere.cjs +40 -0
  114. package/dist/components/orbital-sphere.cjs.map +1 -0
  115. package/dist/components/orbital-sphere.d.ts +3 -0
  116. package/dist/components/orbital-sphere.d.ts.map +1 -0
  117. package/dist/components/orbital-sphere.js +38 -0
  118. package/dist/components/orbital-sphere.js.map +1 -0
  119. package/dist/components/pagination.cjs.map +1 -1
  120. package/dist/components/pagination.js.map +1 -1
  121. package/dist/components/password-input.cjs.map +1 -1
  122. package/dist/components/password-input.js.map +1 -1
  123. package/dist/components/popconfirm.cjs +40 -6
  124. package/dist/components/popconfirm.cjs.map +1 -1
  125. package/dist/components/popconfirm.js +41 -7
  126. package/dist/components/popconfirm.js.map +1 -1
  127. package/dist/components/popup.cjs +2 -1
  128. package/dist/components/popup.cjs.map +1 -1
  129. package/dist/components/popup.js +2 -1
  130. package/dist/components/popup.js.map +1 -1
  131. package/dist/components/progress-bar.cjs.map +1 -1
  132. package/dist/components/progress-bar.js.map +1 -1
  133. package/dist/components/qr-code.cjs.map +1 -1
  134. package/dist/components/qr-code.js.map +1 -1
  135. package/dist/components/radio-group.cjs.map +1 -1
  136. package/dist/components/radio-group.js.map +1 -1
  137. package/dist/components/rating.cjs.map +1 -1
  138. package/dist/components/rating.js.map +1 -1
  139. package/dist/components/rolling-number.cjs.map +1 -1
  140. package/dist/components/rolling-number.js.map +1 -1
  141. package/dist/components/select.cjs.map +1 -1
  142. package/dist/components/select.js.map +1 -1
  143. package/dist/components/signature.cjs +1 -1
  144. package/dist/components/signature.cjs.map +1 -1
  145. package/dist/components/signature.js +1 -1
  146. package/dist/components/signature.js.map +1 -1
  147. package/dist/components/skeleton.cjs.map +1 -1
  148. package/dist/components/skeleton.js.map +1 -1
  149. package/dist/components/slide-captcha.cjs.map +1 -1
  150. package/dist/components/slide-captcha.js.map +1 -1
  151. package/dist/components/swiper.cjs.map +1 -1
  152. package/dist/components/swiper.js.map +1 -1
  153. package/dist/components/switch.cjs.map +1 -1
  154. package/dist/components/switch.js.map +1 -1
  155. package/dist/components/table.cjs.map +1 -1
  156. package/dist/components/table.js.map +1 -1
  157. package/dist/components/tabs.cjs.map +1 -1
  158. package/dist/components/tabs.js.map +1 -1
  159. package/dist/components/tag.cjs.map +1 -1
  160. package/dist/components/tag.js.map +1 -1
  161. package/dist/components/textarea.cjs.map +1 -1
  162. package/dist/components/textarea.js.map +1 -1
  163. package/dist/components/tilt-card.cjs.map +1 -1
  164. package/dist/components/tilt-card.js.map +1 -1
  165. package/dist/components/timeline.cjs.map +1 -1
  166. package/dist/components/timeline.js.map +1 -1
  167. package/dist/components/toast.cjs +146 -14
  168. package/dist/components/toast.cjs.map +1 -1
  169. package/dist/components/toast.d.ts +1 -1
  170. package/dist/components/toast.d.ts.map +1 -1
  171. package/dist/components/toast.js +144 -15
  172. package/dist/components/toast.js.map +1 -1
  173. package/dist/components/tooltip.cjs +38 -5
  174. package/dist/components/tooltip.cjs.map +1 -1
  175. package/dist/components/tooltip.js +39 -6
  176. package/dist/components/tooltip.js.map +1 -1
  177. package/dist/components/typewriter-text.cjs.map +1 -1
  178. package/dist/components/typewriter-text.js.map +1 -1
  179. package/dist/components/upload.cjs.map +1 -1
  180. package/dist/components/upload.js.map +1 -1
  181. package/dist/components/verification-code.cjs.map +1 -1
  182. package/dist/components/verification-code.js.map +1 -1
  183. package/dist/components/video-detail-transition.cjs.map +1 -1
  184. package/dist/components/video-detail-transition.js.map +1 -1
  185. package/dist/components/video-player.cjs.map +1 -1
  186. package/dist/components/video-player.js.map +1 -1
  187. package/dist/components/virtual-list.cjs.map +1 -1
  188. package/dist/components/virtual-list.js.map +1 -1
  189. package/dist/components/virtual-select.cjs.map +1 -1
  190. package/dist/components/virtual-select.js.map +1 -1
  191. package/dist/components/virtual-table.cjs.map +1 -1
  192. package/dist/components/virtual-table.js.map +1 -1
  193. package/dist/{import-transform-jqLjtD6M.js → import-transform-Cw4K2Iky.js} +7 -1
  194. package/dist/import-transform-Cw4K2Iky.js.map +1 -0
  195. package/dist/{import-transform-DIRVOYvz.js → import-transform-ieMdZBuN.js} +7 -1
  196. package/dist/import-transform-ieMdZBuN.js.map +1 -0
  197. package/dist/import-transform.d.ts.map +1 -1
  198. package/dist/index.cjs +605 -36
  199. package/dist/index.cjs.map +1 -1
  200. package/dist/index.d.ts +71 -8
  201. package/dist/index.d.ts.map +1 -1
  202. package/dist/index.js +583 -39
  203. package/dist/index.js.map +1 -1
  204. package/dist/styles/base.css +168 -41
  205. package/dist/styles/components/barcode.css +206 -0
  206. package/dist/styles/components/button.css +7 -2
  207. package/dist/styles/components/calendar.css +0 -23
  208. package/dist/styles/components/canvas-editor.css +18 -21
  209. package/dist/styles/components/canvas-image.css +0 -23
  210. package/dist/styles/components/chat-textarea.css +124 -0
  211. package/dist/styles/components/chat-virtual-list.css +15 -26
  212. package/dist/styles/components/checkbox.css +39 -23
  213. package/dist/styles/components/checked.css +39 -23
  214. package/dist/styles/components/code-preview.css +208 -0
  215. package/dist/styles/components/color-picker.css +46 -27
  216. package/dist/styles/components/config-table.css +0 -23
  217. package/dist/styles/components/date-picker.css +39 -23
  218. package/dist/styles/components/date-range-picker.css +39 -23
  219. package/dist/styles/components/design-effect.css +5 -1
  220. package/dist/styles/components/drag-drop-board.css +6 -1
  221. package/dist/styles/components/field.css +39 -23
  222. package/dist/styles/components/form.css +39 -23
  223. package/dist/styles/components/gradient-text.css +4 -0
  224. package/dist/styles/components/height-transition.css +50 -0
  225. package/dist/styles/components/input.css +39 -23
  226. package/dist/styles/components/loading.css +47 -0
  227. package/dist/styles/components/menu.css +286 -0
  228. package/dist/styles/components/modal.css +2 -23
  229. package/dist/styles/components/number-input.css +39 -23
  230. package/dist/styles/components/orbital-sphere.css +224 -0
  231. package/dist/styles/components/password-input.css +39 -23
  232. package/dist/styles/components/popconfirm.css +5 -0
  233. package/dist/styles/components/popup.css +2 -23
  234. package/dist/styles/components/qr-code.css +206 -0
  235. package/dist/styles/components/radio-group.css +39 -23
  236. package/dist/styles/components/rating.css +39 -23
  237. package/dist/styles/components/select.css +39 -23
  238. package/dist/styles/components/signature.css +39 -23
  239. package/dist/styles/components/switch.css +39 -23
  240. package/dist/styles/components/table.css +0 -23
  241. package/dist/styles/components/tabs.css +10 -0
  242. package/dist/styles/components/textarea.css +39 -23
  243. package/dist/styles/components/tilt-card.css +2 -23
  244. package/dist/styles/components/toast.css +109 -48
  245. package/dist/styles/components/tooltip.css +8 -23
  246. package/dist/styles/components/typewriter-text.css +4 -0
  247. package/dist/styles/components/upload.css +39 -23
  248. package/dist/styles/components/verification-code.css +39 -23
  249. package/dist/styles/components/virtual-select.css +39 -23
  250. package/dist/styles/components/virtual-table.css +0 -23
  251. package/dist/styles/components.css +1250 -165
  252. package/dist/styles/themes/business-blue.css +375 -0
  253. package/dist/styles/themes/cartoon-3d.css +695 -0
  254. package/dist/styles/themes/creative-purple.css +376 -0
  255. package/dist/styles/themes/dark-tech.css +495 -0
  256. package/dist/styles/themes/liquid-glass.css +526 -21
  257. package/dist/styles/themes/minimal.css +406 -14
  258. package/dist/styles/themes/soft-pink.css +376 -0
  259. package/dist/styles.css +1250 -165
  260. package/dist/vite.cjs +1 -1
  261. package/dist/vite.cjs.map +1 -1
  262. package/dist/vite.d.ts +1 -1
  263. package/dist/vite.js +1 -1
  264. package/dist/vite.js.map +1 -1
  265. package/dist/webpack-loader.cjs +1 -1
  266. package/dist/webpack-loader.js +1 -1
  267. package/package.json +3 -3
  268. package/dist/import-transform-DIRVOYvz.js.map +0 -1
  269. package/dist/import-transform-jqLjtD6M.js.map +0 -1
  270. package/dist/styles/themes/amber.css +0 -19
  271. package/dist/styles/themes/emerald.css +0 -19
  272. package/dist/styles/themes/rose.css +0 -19
  273. package/dist/styles/themes/sky.css +0 -19
  274. package/dist/styles/themes/violet.css +0 -19
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
2
  import React, { useEffect, useMemo, useContext, useSyncExternalStore, createContext } from 'react';
3
3
  import { createPortal } from 'react-dom';
4
- import { ToastManager, configureClassComponents, FormController, getClassComponentsLocale, PasswordInputController, ColorPickerController, DatePickerController, DateRangePickerController, VerificationCodeController, SlideCaptchaController, VirtualSelectController, VirtualListController, BadgeController, TagController, SkeletonController, BreadcrumbController, PaginationController, getSafeTooltipPlacement, BacktopController, AffixController, ModalController, PopupController, TooltipController, TabsController, RollingNumberController, CountdownController, CalendarController, TypewriterTextController, DesignEffectController, GradientTextController, LazyImageController, TiltCardController, MarqueeController, ProgressController, SignatureController, VideoPlayerController, VideoDetailTransitionController, FilePreviewController, CanvasImageController, CanvasEditorController, TimelineController, DragController, DropController, GestureController, FloatingBallController, MultiColumnPickerController, SwiperController, MasonryVirtualListController, TableController, UploadController, NovelReaderController, ComicReaderController, DanmakuController, LiveRoomController, ChatVirtualListController } from '@class-kit/core';
5
- export { AffixController, BacktopController, BadgeController, BreadcrumbController, CalendarController, CanvasEditorController, CanvasImageController, ChatVirtualListController, ColorPickerController, ComicReaderController, CountdownController, DanmakuController, DatePickerController, DateRangePickerController, DesignEffectController, DragController, DropController, FilePreviewController, FloatingBallController, FormController, GestureController, GradientTextController, LazyImageController, LiveRoomController, MasonryVirtualListController, ModalController, MultiColumnPickerController, NovelReaderController, PaginationController, PasswordInputController, PopupController, ProgressController, SignatureController, SkeletonController, SlideCaptchaController, SwiperController, TableController, TabsController, TagController, TiltCardController, TimelineController, ToastManager, TooltipController, TypewriterTextController, UploadController, VerificationCodeController, VideoDetailTransitionController, VideoPlayerController, VirtualListController, VirtualSelectController, configureClassComponents, getClassComponentsConfig, getClassComponentsLocale, resetClassComponentsConfig } from '@class-kit/core';
4
+ import { ToastManager, configureClassComponents, FormController, getClassComponentsLocale, PasswordInputController, ColorPickerController, DatePickerController, DateRangePickerController, VerificationCodeController, SlideCaptchaController, ChatTextareaController, VirtualSelectController, VirtualListController, BadgeController, TagController, SkeletonController, BreadcrumbController, MenuController, PaginationController, getSafeTooltipPlacement, BacktopController, AffixController, ModalController, PopupController, TooltipController, TabsController, RollingNumberController, CountdownController, CalendarController, TypewriterTextController, DesignEffectController, GradientTextController, LazyImageController, TiltCardController, OrbitalSphereController, HeightTransitionController, CodePreviewController, MarqueeController, ProgressController, SignatureController, VideoPlayerController, VideoDetailTransitionController, FilePreviewController, CanvasImageController, CanvasEditorController, TimelineController, DragController, DropController, GestureController, FloatingBallController, MultiColumnPickerController, SwiperController, MasonryVirtualListController, TableController, UploadController, NovelReaderController, ComicReaderController, DanmakuController, LiveRoomController, ChatVirtualListController } from '@class-kit/core';
5
+ export { AffixController, BacktopController, BadgeController, BreadcrumbController, CalendarController, CanvasEditorController, CanvasImageController, ChatTextareaController, ChatVirtualListController, CodePreviewController, ColorPickerController, ComicReaderController, CountdownController, DanmakuController, DatePickerController, DateRangePickerController, DesignEffectController, DragController, DropController, FilePreviewController, FloatingBallController, FormController, GestureController, GradientTextController, HeightTransitionController, LazyImageController, LiveRoomController, MasonryVirtualListController, MenuController, ModalController, MultiColumnPickerController, NovelReaderController, OrbitalSphereController, PaginationController, PasswordInputController, PopupController, ProgressController, SignatureController, SkeletonController, SlideCaptchaController, SwiperController, TableController, TabsController, TagController, TiltCardController, TimelineController, ToastManager, TooltipController, TypewriterTextController, UploadController, VerificationCodeController, VideoDetailTransitionController, VideoPlayerController, VirtualListController, VirtualSelectController, configureClassComponents, getClassComponentsConfig, getClassComponentsLocale, resetClassComponentsConfig } from '@class-kit/core';
6
6
 
7
7
  const FormContext = /*#__PURE__*/ createContext(null);
8
8
  const defaultToastManager = /*#__PURE__*/ new ToastManager();
@@ -174,23 +174,27 @@ function usePresence(open, duration) {
174
174
  return [mounted, state];
175
175
  }
176
176
  function useAnimatedToasts(items, duration) {
177
- const [rendered, setRendered] = React.useState(() => items.map((item) => ({ item, state: "enter" })));
177
+ const [rendered, setRendered] = React.useState(() => items.map((item) => ({ item, motion: false, state: "enter" })));
178
178
  useEffect(() => {
179
179
  let enteringIds = [];
180
180
  setRendered((current) => {
181
181
  const currentIds = new Set(current.map(({ item }) => item.id));
182
182
  const incomingIds = new Set(items.map((item) => item.id));
183
+ const incomingById = new Map(items.map((item) => [item.id, item]));
183
184
  enteringIds = items
184
185
  .filter((item) => !currentIds.has(item.id))
185
186
  .map((item) => item.id);
186
- const next = items.map((item) => ({
187
- item,
188
- state: currentIds.has(item.id) ? "enter" : "exit",
187
+ const retainedOrExiting = current.map(({ item }) => ({
188
+ item: incomingById.get(item.id) ?? item,
189
+ motion: !incomingIds.has(item.id),
190
+ state: incomingIds.has(item.id)
191
+ ? "enter"
192
+ : "exit",
189
193
  }));
190
- const exiting = current
191
- .filter(({ item }) => !incomingIds.has(item.id))
192
- .map(({ item }) => ({ item, state: "exit" }));
193
- return [...next, ...exiting];
194
+ const entering = items
195
+ .filter((item) => !currentIds.has(item.id))
196
+ .map((item) => ({ item, motion: true, state: "prepare" }));
197
+ return [...retainedOrExiting, ...entering];
194
198
  });
195
199
  if (!enteringIds.length)
196
200
  return undefined;
@@ -201,6 +205,22 @@ function useAnimatedToasts(items, duration) {
201
205
  });
202
206
  return () => window.cancelAnimationFrame(frame);
203
207
  }, [items]);
208
+ useEffect(() => {
209
+ if (!rendered.some((entry) => entry.motion && entry.state === "enter"))
210
+ return;
211
+ if (duration <= 0) {
212
+ setRendered((current) => current.map((entry) => entry.motion && entry.state === "enter"
213
+ ? { ...entry, motion: false }
214
+ : entry));
215
+ return;
216
+ }
217
+ const timer = window.setTimeout(() => {
218
+ setRendered((current) => current.map((entry) => entry.motion && entry.state === "enter"
219
+ ? { ...entry, motion: false }
220
+ : entry));
221
+ }, duration);
222
+ return () => window.clearTimeout(timer);
223
+ }, [duration, rendered]);
204
224
  useEffect(() => {
205
225
  if (!rendered.some((entry) => entry.state === "exit"))
206
226
  return;
@@ -215,6 +235,80 @@ function useAnimatedToasts(items, duration) {
215
235
  }, [duration, rendered]);
216
236
  return rendered;
217
237
  }
238
+ function normalizeToastMaxVisible(maxVisible) {
239
+ if (typeof maxVisible !== "number" || !Number.isFinite(maxVisible))
240
+ return 3;
241
+ return Math.max(1, Math.min(6, Math.floor(maxVisible)));
242
+ }
243
+ function isToastTopPosition(position) {
244
+ return (position === "top" || position === "top-left" || position === "top-right");
245
+ }
246
+ function useToastFlip(entries, duration, easing) {
247
+ const nodeMapRef = React.useRef(new Map());
248
+ const rectMapRef = React.useRef(new Map());
249
+ const frameRef = React.useRef(0);
250
+ const setNode = React.useCallback((id, node) => {
251
+ if (node)
252
+ nodeMapRef.current.set(id, node);
253
+ else
254
+ nodeMapRef.current.delete(id);
255
+ }, []);
256
+ React.useLayoutEffect(() => {
257
+ if (frameRef.current)
258
+ window.cancelAnimationFrame(frameRef.current);
259
+ const previousRects = rectMapRef.current;
260
+ const nextRects = new Map();
261
+ const activeIds = new Set(entries
262
+ .filter((entry) => entry.motion && entry.state !== "exit")
263
+ .map((entry) => entry.item.id));
264
+ nodeMapRef.current.forEach((node, id) => {
265
+ if (!activeIds.has(id))
266
+ return;
267
+ const rect = node.getBoundingClientRect();
268
+ nextRects.set(id, rect);
269
+ const previous = previousRects.get(id);
270
+ if (!previous)
271
+ return;
272
+ const deltaY = previous.top - rect.top;
273
+ if (Math.abs(deltaY) < 1)
274
+ return;
275
+ node.style.transition = "none";
276
+ node.style.setProperty("--cc-toast-stack-offset", `${deltaY}px`);
277
+ node.style.willChange = "transform, opacity";
278
+ });
279
+ frameRef.current = window.requestAnimationFrame(() => {
280
+ nodeMapRef.current.forEach((node, id) => {
281
+ if (!nextRects.has(id))
282
+ return;
283
+ node.style.transition = `transform ${duration}ms ${easing}, opacity ${duration}ms ${easing}, margin ${duration}ms ${easing}`;
284
+ node.style.removeProperty("--cc-toast-stack-offset");
285
+ window.setTimeout(() => {
286
+ node.style.transition = "";
287
+ node.style.willChange = "";
288
+ }, duration);
289
+ });
290
+ frameRef.current = 0;
291
+ });
292
+ rectMapRef.current = nextRects;
293
+ return () => {
294
+ if (frameRef.current)
295
+ window.cancelAnimationFrame(frameRef.current);
296
+ };
297
+ }, [duration, easing, entries]);
298
+ return setNode;
299
+ }
300
+ function useToastItems(manager) {
301
+ const snapshotRef = React.useRef(manager.getToasts());
302
+ const managerRef = React.useRef(manager);
303
+ if (managerRef.current !== manager) {
304
+ managerRef.current = manager;
305
+ snapshotRef.current = manager.getToasts();
306
+ }
307
+ return useSyncExternalStore(React.useCallback((notify) => manager.subscribe((items) => {
308
+ snapshotRef.current = items;
309
+ notify();
310
+ }), [manager]), React.useCallback(() => snapshotRef.current, [manager]), React.useCallback(() => snapshotRef.current, [manager]));
311
+ }
218
312
  function resolveTabsDirection(tabs, previousId, nextId, direction) {
219
313
  if (direction === "none")
220
314
  return "none";
@@ -390,12 +484,12 @@ function PasswordInput({ name, label, className = "cc-field cc-password-field",
390
484
  const Field = Input;
391
485
  function ColorPicker({ name, label, className = "cc-field cc-color-picker", disabled, panelClassName = "cc-color-picker__panel", readOnly, initialValue, rules, showInputSteppers = false, validateOn, onChange, ...props }) {
392
486
  const field = useOptionalField(name, {
393
- initialValue: initialValue ?? "#7c3aed",
487
+ initialValue: initialValue ?? "#1d2129",
394
488
  rules,
395
489
  validateOn,
396
490
  });
397
491
  const interactivity = resolveFieldInteractivity(useOptionalFormInteractivity(), disabled, readOnly);
398
- const controller = React.useMemo(() => new ColorPickerController(String(field.value || "#7c3aed")), [field.value]);
492
+ const controller = React.useMemo(() => new ColorPickerController(String(field.value || "#1d2129")), [field.value]);
399
493
  const state = controller.getState();
400
494
  const rootRef = React.useRef(null);
401
495
  const panelRef = React.useRef(null);
@@ -1079,6 +1173,82 @@ function Textarea({ name, label, className = "cc-field", labelClassName = "cc-fi
1079
1173
  field.setValue(event.currentTarget.value);
1080
1174
  }, ...options }), canClear ? (jsx("button", { "aria-label": clearLabel, className: "cc-field__clear cc-field__clear--textarea", type: "button", onClick: () => field.setValue(""), children: clearIcon })) : null] }), jsx(FieldError, { className: errorClassName, errorId: errorId, errors: field.errors })] }));
1081
1175
  }
1176
+ function getTextareaMetrics(element) {
1177
+ const computed = window.getComputedStyle(element);
1178
+ const fontSize = Number.parseFloat(computed.fontSize) || 14;
1179
+ const lineHeight = Number.parseFloat(computed.lineHeight) || fontSize * 1.5;
1180
+ const paddingY = (Number.parseFloat(computed.paddingTop) || 0) +
1181
+ (Number.parseFloat(computed.paddingBottom) || 0);
1182
+ const borderY = (Number.parseFloat(computed.borderTopWidth) || 0) +
1183
+ (Number.parseFloat(computed.borderBottomWidth) || 0);
1184
+ return { borderY, lineHeight, paddingY };
1185
+ }
1186
+ const ChatTextarea = /*#__PURE__*/ React.forwardRef(function ChatTextarea({ className = "cc-chat-textarea", clearable = true, clearIcon = jsx(ClassIcon, { name: "x" }), clearLabel = getClassComponentsLocale().inputClearLabel, defaultValue = "", disabled, maxRows = 3, minRows = 1, onValueChange, placeholder, readOnly, style, textareaClassName = "cc-chat-textarea__control", textareaStyle, value, ...props }, ref) {
1187
+ const textareaRef = React.useRef(null);
1188
+ const controllerRef = React.useRef(new ChatTextareaController({
1189
+ maxRows,
1190
+ minRows,
1191
+ value: value ?? defaultValue,
1192
+ }));
1193
+ const controlled = value !== undefined;
1194
+ const [state, setState] = React.useState(() => controllerRef.current.getState());
1195
+ const resize = React.useCallback(() => {
1196
+ const element = textareaRef.current;
1197
+ if (!element || typeof window === "undefined")
1198
+ return;
1199
+ const { borderY, lineHeight, paddingY } = getTextareaMetrics(element);
1200
+ const minHeight = lineHeight * state.minRows + paddingY + borderY;
1201
+ const maxHeight = lineHeight * state.maxRows + paddingY + borderY;
1202
+ element.style.height = "auto";
1203
+ const nextHeight = Math.min(Math.max(element.scrollHeight, minHeight), maxHeight);
1204
+ element.style.height = `${nextHeight}px`;
1205
+ element.style.overflowY =
1206
+ element.scrollHeight > maxHeight + 1 ? "auto" : "hidden";
1207
+ }, [state.maxRows, state.minRows, state.value]);
1208
+ React.useImperativeHandle(ref, () => ({
1209
+ blur: () => textareaRef.current?.blur(),
1210
+ focus: () => textareaRef.current?.focus(),
1211
+ getElement: () => textareaRef.current,
1212
+ }), []);
1213
+ React.useEffect(() => {
1214
+ const next = controllerRef.current.update({
1215
+ maxRows,
1216
+ minRows,
1217
+ value: controlled ? value : state.value,
1218
+ });
1219
+ setState(next);
1220
+ }, [controlled, maxRows, minRows, value]);
1221
+ React.useLayoutEffect(() => {
1222
+ resize();
1223
+ }, [resize]);
1224
+ React.useEffect(() => {
1225
+ if (typeof ResizeObserver === "undefined" || !textareaRef.current)
1226
+ return undefined;
1227
+ const observer = new ResizeObserver(resize);
1228
+ observer.observe(textareaRef.current);
1229
+ return () => observer.disconnect();
1230
+ }, [resize]);
1231
+ const commit = (nextValue, event) => {
1232
+ const nextState = controllerRef.current.setValue(nextValue);
1233
+ if (!controlled)
1234
+ setState(nextState);
1235
+ onValueChange?.(nextValue, event);
1236
+ };
1237
+ const currentValue = controlled ? (value ?? "") : state.value;
1238
+ const canClear = clearable && currentValue !== "" && !disabled && !readOnly;
1239
+ return (jsxs("div", { className: className, "data-disabled": Boolean(disabled), "data-readonly": Boolean(readOnly), "data-scrollable": currentValue.length > 0, style: style, children: [jsx("textarea", { ...props, className: `${textareaClassName}${canClear ? " cc-chat-textarea__control--clearable" : ""}`, disabled: disabled, placeholder: placeholder, readOnly: readOnly, ref: textareaRef, rows: state.minRows, style: {
1240
+ "--cc-chat-textarea-max-rows": state.maxRows,
1241
+ "--cc-chat-textarea-min-rows": state.minRows,
1242
+ ...textareaStyle,
1243
+ }, value: currentValue, onChange: (event) => {
1244
+ if (readOnly)
1245
+ return;
1246
+ commit(event.currentTarget.value, event);
1247
+ } }), canClear ? (jsx("button", { "aria-label": clearLabel, className: "cc-chat-textarea__clear", type: "button", onClick: (event) => {
1248
+ commit("", event);
1249
+ textareaRef.current?.focus();
1250
+ }, children: clearIcon })) : null] }));
1251
+ });
1082
1252
  function getSelectMenuPosition(trigger, preferredHeight, anchorTopPlacement = false) {
1083
1253
  if (!trigger || typeof window === "undefined") {
1084
1254
  return { placement: "bottom", style: {} };
@@ -1495,6 +1665,53 @@ function Breadcrumb({ className = "cc-breadcrumb", items, separator = "/", ...pr
1495
1665
  const state = useMemo(() => new BreadcrumbController(items).getState(), [items]);
1496
1666
  return (jsx("nav", { className: className, "aria-label": "Breadcrumb", ...props, children: state.items.map((item, index) => (jsxs("span", { className: "cc-breadcrumb__item", children: [index > 0 ? (jsx("span", { className: "cc-breadcrumb__separator", children: separator })) : null, item.href && !item.disabled ? (jsx("a", { href: item.href, children: item.label })) : (jsx("span", { "data-disabled": item.disabled, children: item.label }))] }, String(item.key)))) }));
1497
1667
  }
1668
+ function renderMenuIcon(item, collapsed, iconRender) {
1669
+ const rendered = iconRender?.(item);
1670
+ if (rendered !== undefined)
1671
+ return rendered;
1672
+ if (item.icon)
1673
+ return item.icon;
1674
+ return collapsed ? item.label.slice(0, 1) : null;
1675
+ }
1676
+ function renderMenuItems(items, collapsed, iconRender, onToggle, onSelect) {
1677
+ return items.map((item) => {
1678
+ const hasChildren = item.children.length > 0;
1679
+ const icon = renderMenuIcon(item, collapsed, iconRender);
1680
+ return (jsxs("li", { className: "cc-menu__item", "data-active": item.isActive, "data-disabled": item.disabled, "data-expanded": item.expanded, "data-level": item.level, children: [jsxs("button", { "aria-current": item.isActive ? "page" : undefined, "aria-expanded": hasChildren ? item.expanded : undefined, className: "cc-menu__button", disabled: item.disabled, title: collapsed ? item.label : undefined, type: "button", onClick: () => {
1681
+ if (hasChildren && !collapsed)
1682
+ onToggle(item.key);
1683
+ onSelect(item.key, item);
1684
+ }, children: [icon ? (jsx("span", { className: "cc-menu__icon", "aria-hidden": "true", children: icon })) : null, jsx("span", { className: "cc-menu__label", children: item.label }), hasChildren ? (jsx(ClassIcon, { className: "cc-menu__arrow", name: "chevronDown" })) : null] }), hasChildren ? (jsx(HeightTransition, { className: "cc-height-transition cc-menu__transition", contentClassName: "cc-height-transition__content cc-menu__transition-content", duration: 180, expanded: !collapsed && item.expanded, mode: "grid", children: jsx("ul", { className: "cc-menu__list cc-menu__list--child", children: renderMenuItems(item.children, collapsed, iconRender, onToggle, onSelect) }) })) : null] }, item.key));
1685
+ });
1686
+ }
1687
+ function Menu({ activeKey, className = "cc-menu", collapsed, collapsible = true, defaultExpandedKeys = [], iconRender, items, onCollapsedChange, onSelect, ...props }) {
1688
+ const controller = React.useMemo(() => new MenuController({
1689
+ activeKey,
1690
+ collapsed,
1691
+ defaultExpandedKeys,
1692
+ items,
1693
+ }), []);
1694
+ const [state, setState] = React.useState(() => controller.getState());
1695
+ React.useEffect(() => {
1696
+ setState(controller.update({
1697
+ activeKey,
1698
+ collapsed,
1699
+ defaultExpandedKeys,
1700
+ items,
1701
+ }));
1702
+ }, [activeKey, collapsed, controller, defaultExpandedKeys, items]);
1703
+ const commitSelect = React.useCallback((key, item) => {
1704
+ setState(controller.activate(key));
1705
+ onSelect?.(key, item);
1706
+ }, [controller, onSelect]);
1707
+ const toggleExpanded = React.useCallback((key) => setState(controller.toggleExpanded(key)), [controller]);
1708
+ const toggleCollapsed = React.useCallback(() => {
1709
+ const next = controller.toggleCollapsed();
1710
+ setState(next);
1711
+ onCollapsedChange?.(next.collapsed);
1712
+ }, [controller, onCollapsedChange]);
1713
+ return (jsxs("nav", { className: className, "data-collapsed": state.collapsed, "data-collapsible": collapsible, ...props, children: [collapsible ? (jsx("button", { "aria-label": state.collapsed ? "展开菜单" : "收起菜单", className: "cc-menu__collapse", type: "button", onClick: toggleCollapsed, children: jsx(ClassIcon, { name: state.collapsed ? "chevronRight" : "chevronLeft" }) })) : null, jsx("ul", { className: "cc-menu__list", children: renderMenuItems(state.items, state.collapsed, iconRender, toggleExpanded, commitSelect) })] }));
1714
+ }
1498
1715
  function Pagination({ boundaryCount = 1, className = "cc-pagination", current = 1, pageSize = 10, siblingCount = 1, total = 0, previousIcon = jsx(ClassIcon, { name: "chevronLeft" }), nextIcon = jsx(ClassIcon, { name: "chevronRight" }), onChange, ...props }) {
1499
1716
  const state = useMemo(() => new PaginationController({
1500
1717
  boundaryCount,
@@ -1505,14 +1722,29 @@ function Pagination({ boundaryCount = 1, className = "cc-pagination", current =
1505
1722
  }).getState(), [boundaryCount, current, pageSize, siblingCount, total]);
1506
1723
  return (jsxs("div", { className: className, ...props, children: [jsx("button", { disabled: state.current <= 1, type: "button", onClick: () => onChange?.(state.current - 1), children: previousIcon }), state.pages.map((page, index) => page === "ellipsis" ? (jsx("span", { "aria-hidden": "true", className: "cc-pagination__ellipsis", children: "\u2022\u2022\u2022" }, `ellipsis-${index}`)) : (jsx("button", { "data-active": page === state.current, type: "button", onClick: () => onChange?.(page), children: page }, page))), jsx("button", { disabled: state.current >= state.pageCount, type: "button", onClick: () => onChange?.(state.current + 1), children: nextIcon })] }));
1507
1724
  }
1508
- function Popconfirm({ children, animation, autoAdjust = true, placement = "top", content = getClassComponentsLocale().popconfirmContent, confirmText = getClassComponentsLocale().popconfirmConfirmText, cancelText = getClassComponentsLocale().popconfirmCancelText, closeOnEsc = true, closeOnOutsideClick = true, onConfirm, }) {
1725
+ function Popconfirm({ children, animation, autoAdjust = true, placement = "top", content = getClassComponentsLocale().popconfirmContent, confirmText = getClassComponentsLocale().popconfirmConfirmText, cancelText = getClassComponentsLocale().popconfirmCancelText, closeOnEsc = true, closeOnOutsideClick = true, onConfirm, portal = true, }) {
1509
1726
  const rootRef = React.useRef(null);
1510
1727
  const panelRef = React.useRef(null);
1511
1728
  const [open, setOpen] = React.useState(false);
1512
1729
  const [safePlacement, setSafePlacement] = React.useState(placement);
1730
+ const [anchorStyle, setAnchorStyle] = React.useState({
1731
+ height: 0,
1732
+ left: -9999,
1733
+ top: -9999,
1734
+ width: 0,
1735
+ });
1513
1736
  const motion = resolveAnimation(animation, "scale");
1514
1737
  const [mounted, presence] = usePresence(open, motion.enabled ? motion.duration : 0);
1515
1738
  const updatePlacement = React.useCallback(() => {
1739
+ if (rootRef.current) {
1740
+ const rect = rootRef.current.getBoundingClientRect();
1741
+ setAnchorStyle({
1742
+ height: rect.height,
1743
+ left: rect.left,
1744
+ top: rect.top,
1745
+ width: rect.width,
1746
+ });
1747
+ }
1516
1748
  if (!autoAdjust || !rootRef.current || !panelRef.current) {
1517
1749
  setSafePlacement(placement);
1518
1750
  return;
@@ -1525,7 +1757,8 @@ function Popconfirm({ children, animation, autoAdjust = true, placement = "top",
1525
1757
  requestAnimationFrame(updatePlacement);
1526
1758
  const close = (event) => {
1527
1759
  if (!closeOnOutsideClick ||
1528
- rootRef.current?.contains(event.target))
1760
+ rootRef.current?.contains(event.target) ||
1761
+ panelRef.current?.contains(event.target))
1529
1762
  return;
1530
1763
  setOpen(false);
1531
1764
  };
@@ -1550,10 +1783,27 @@ function Popconfirm({ children, animation, autoAdjust = true, placement = "top",
1550
1783
  if (open)
1551
1784
  updatePlacement();
1552
1785
  }, [open, placement, updatePlacement]);
1553
- return (jsxs("span", { className: ["cc-popconfirm", `cc-popconfirm--${safePlacement}`].join(" "), "data-animation": motion.name, ref: rootRef, style: animationStyle(motion), children: [jsx("span", { onClick: () => setOpen(true), children: children }), mounted ? (jsxs("span", { className: "cc-popconfirm__panel", "data-state": presence, ref: panelRef, role: "dialog", children: [jsx("span", { children: content }), jsxs("span", { className: "cc-popconfirm__actions", children: [jsx("button", { type: "button", onClick: () => setOpen(false), children: cancelText }), jsx("button", { type: "button", onClick: () => {
1554
- onConfirm?.();
1555
- setOpen(false);
1556
- }, children: confirmText })] })] })) : null] }));
1786
+ const rootClassName = [
1787
+ "cc-popconfirm",
1788
+ `cc-popconfirm--${safePlacement}`,
1789
+ ].join(" ");
1790
+ const panelNode = mounted ? (jsxs("span", { className: "cc-popconfirm__panel", "data-state": presence, ref: panelRef, role: "dialog", children: [jsx("span", { children: content }), jsxs("span", { className: "cc-popconfirm__actions", children: [jsx("button", { type: "button", onClick: () => setOpen(false), children: cancelText }), jsx("button", { type: "button", onClick: () => {
1791
+ onConfirm?.();
1792
+ setOpen(false);
1793
+ }, children: confirmText })] })] })) : null;
1794
+ const rootNode = (jsxs("span", { className: rootClassName, "data-animation": motion.name, ref: rootRef, style: animationStyle(motion), children: [jsx("span", { onClick: () => setOpen(true), children: children }), portal ? null : panelNode] }));
1795
+ if (!portal)
1796
+ return rootNode;
1797
+ const portalNode = mounted ? (jsx("span", { className: `${rootClassName} cc-popconfirm--portal`, "data-animation": motion.name, style: {
1798
+ ...animationStyle(motion),
1799
+ height: `${anchorStyle.height}px`,
1800
+ left: `${anchorStyle.left}px`,
1801
+ top: `${anchorStyle.top}px`,
1802
+ width: `${anchorStyle.width}px`,
1803
+ }, children: panelNode })) : null;
1804
+ return (jsxs(Fragment, { children: [rootNode, portalNode && typeof document !== "undefined"
1805
+ ? createPortal(portalNode, document.body)
1806
+ : null] }));
1557
1807
  }
1558
1808
  function getBacktopTarget(target) {
1559
1809
  if (typeof target === "string")
@@ -1785,13 +2035,14 @@ function Popup({ open, controller, placement = "bottom", title, children, animat
1785
2035
  }, []);
1786
2036
  if (!mounted)
1787
2037
  return null;
1788
- const popupContainer = containerRef?.current ?? null;
2038
+ const popupContainer = containerRef?.current ??
2039
+ (typeof document !== "undefined" ? document.body : null);
1789
2040
  const popupElement = (jsxs("div", { className: className, "data-animation": motion.name, "data-contained": popupContainer ? "true" : "false", "data-placement": popupState.placement, "data-state": animationState, role: "presentation", style: animationStyle(motion, style), ...props, children: [jsx("button", { "aria-label": "Close popup", className: overlayClassName, type: "button", onClick: closeOnOverlayClick ? close : undefined }), jsxs("section", { "aria-modal": "true", className: panelClassName, ref: panelRef, role: "dialog", tabIndex: -1, children: [title ? (jsxs("header", { className: "cc-popup__header", children: [jsx("span", { children: title }), jsx("button", { "aria-label": "Close popup", className: "cc-popup__close", type: "button", onClick: close, children: closeIcon })] })) : null, jsx("div", { className: "cc-popup__body", children: children })] })] }));
1790
2041
  return popupContainer
1791
2042
  ? createPortal(popupElement, popupContainer)
1792
2043
  : popupElement;
1793
2044
  }
1794
- function Tooltip({ content, children, animation, placement = "top", trigger = "hover", autoAdjust = true, closeOnEsc = true, closeOnOutsideClick = true, className, id, style, ...props }) {
2045
+ function Tooltip({ content, children, animation, placement = "top", trigger = "hover", autoAdjust = true, closeOnEsc = true, closeOnOutsideClick = true, portal = true, className, id, style, ...props }) {
1795
2046
  const rootRef = React.useRef(null);
1796
2047
  const contentRef = React.useRef(null);
1797
2048
  const generatedId = React.useId();
@@ -1799,6 +2050,7 @@ function Tooltip({ content, children, animation, placement = "top", trigger = "h
1799
2050
  const tooltipController = React.useMemo(() => new TooltipController(), []);
1800
2051
  const [open, setOpen] = React.useState(() => tooltipController.isOpen());
1801
2052
  const [safePlacement, setSafePlacement] = React.useState(placement);
2053
+ const [anchorStyle, setAnchorStyle] = React.useState(null);
1802
2054
  const motion = resolveAnimation(animation, "fade");
1803
2055
  useEffect(() => {
1804
2056
  const unsubscribe = tooltipController.subscribe((state) => {
@@ -1810,6 +2062,15 @@ function Tooltip({ content, children, animation, placement = "top", trigger = "h
1810
2062
  };
1811
2063
  }, [tooltipController]);
1812
2064
  const updatePlacement = React.useCallback(() => {
2065
+ if (rootRef.current) {
2066
+ const rect = rootRef.current.getBoundingClientRect();
2067
+ setAnchorStyle({
2068
+ height: rect.height,
2069
+ left: rect.left,
2070
+ top: rect.top,
2071
+ width: rect.width,
2072
+ });
2073
+ }
1813
2074
  if (!autoAdjust || !rootRef.current || !contentRef.current) {
1814
2075
  setSafePlacement(placement);
1815
2076
  return;
@@ -1832,7 +2093,8 @@ function Tooltip({ content, children, animation, placement = "top", trigger = "h
1832
2093
  return undefined;
1833
2094
  const handlePointerDown = (event) => {
1834
2095
  if (!closeOnOutsideClick ||
1835
- rootRef.current?.contains(event.target))
2096
+ rootRef.current?.contains(event.target) ||
2097
+ contentRef.current?.contains(event.target))
1836
2098
  return;
1837
2099
  tooltipController.close();
1838
2100
  };
@@ -1859,19 +2121,45 @@ function Tooltip({ content, children, animation, placement = "top", trigger = "h
1859
2121
  onMouseEnter: () => tooltipController.open(),
1860
2122
  onMouseLeave: () => tooltipController.close(),
1861
2123
  };
1862
- return (jsxs("span", { className: ["cc-tooltip", `cc-tooltip--${safePlacement}`, className]
1863
- .filter(Boolean)
1864
- .join(" "), "aria-describedby": open ? contentId : undefined, "data-animation": motion.name, "data-open": open, ref: rootRef, style: animationStyle(motion, style), tabIndex: trigger === "click" ? 0 : undefined, ...props, ...triggerProps, children: [children, jsx("span", { className: "cc-tooltip__content", id: contentId, ref: contentRef, role: "tooltip", children: content })] }));
2124
+ const rootClassName = [
2125
+ "cc-tooltip",
2126
+ `cc-tooltip--${safePlacement}`,
2127
+ className,
2128
+ ]
2129
+ .filter(Boolean)
2130
+ .join(" ");
2131
+ const tooltipContent = (jsx("span", { className: "cc-tooltip__content", id: contentId, ref: contentRef, role: "tooltip", children: content }));
2132
+ const rootNode = (jsxs("span", { className: rootClassName, "aria-describedby": open ? contentId : undefined, "data-animation": motion.name, "data-open": open, ref: rootRef, style: animationStyle(motion, style), tabIndex: trigger === "click" ? 0 : undefined, ...props, ...triggerProps, children: [children, portal ? null : tooltipContent] }));
2133
+ if (!portal || typeof document === "undefined")
2134
+ return rootNode;
2135
+ const portalNode = open || anchorStyle ? (jsx("span", { className: `${rootClassName} cc-tooltip--portal`, "data-animation": motion.name, "data-open": open, style: {
2136
+ ...animationStyle(motion),
2137
+ height: anchorStyle?.height ?? 0,
2138
+ left: anchorStyle?.left ?? -9999,
2139
+ top: anchorStyle?.top ?? -9999,
2140
+ width: anchorStyle?.width ?? 0,
2141
+ }, children: tooltipContent })) : null;
2142
+ return (jsxs(Fragment, { children: [rootNode, portalNode ? renderBodyPortal(portalNode) : null] }));
1865
2143
  }
1866
- function ToastViewport({ animation, manager = defaultToastManager, className = "cc-toast-viewport", position = "top-right", renderToast, style, ...props }) {
1867
- const [items, setItems] = React.useState(() => manager.getToasts());
2144
+ function ToastViewport({ animation, manager = defaultToastManager, className = "cc-toast-viewport", maxVisible, portal = false, position = "top-right", renderToast, style, ...props }) {
2145
+ const items = useToastItems(manager);
1868
2146
  const motion = resolveAnimation(animation, "slide");
1869
- const visibleItems = React.useMemo(() => items.filter((item) => item.position === position), [items, position]);
2147
+ const resolvedMaxVisible = normalizeToastMaxVisible(maxVisible);
2148
+ const visibleItems = React.useMemo(() => {
2149
+ const positionItems = items.filter((item) => item.position === position);
2150
+ const visible = positionItems.slice(Math.max(0, positionItems.length - resolvedMaxVisible));
2151
+ return isToastTopPosition(position) ? [...visible].reverse() : visible;
2152
+ }, [items, position, resolvedMaxVisible]);
1870
2153
  const renderedItems = useAnimatedToasts(visibleItems, motion.enabled ? motion.duration : 0);
1871
- useEffect(() => manager.subscribe(setItems), [manager]);
1872
- return (jsx("div", { className: [className, `cc-toast-viewport--${position}`]
2154
+ const setToastNode = useToastFlip(renderedItems, motion.enabled ? motion.duration : 0, motion.easing);
2155
+ const viewportNode = (jsx("div", { className: [className, `cc-toast-viewport--${position}`]
1873
2156
  .filter(Boolean)
1874
- .join(" "), role: "status", "aria-live": "polite", style: animationStyle(motion, style), ...props, children: renderedItems.map(({ item, state }) => (jsx(React.Fragment, { children: renderToast ? (renderToast(item, (id) => manager.dismiss(id), state)) : (jsxs("article", { className: `cc-toast cc-toast--${item.tone}`, "data-animation": motion.name, "data-state": state, children: [item.title ? (jsx("strong", { className: "cc-toast__title", children: item.title })) : null, jsx("span", { className: "cc-toast__message", children: item.message }), jsx("button", { "aria-label": "Dismiss toast", className: "cc-toast__close", type: "button", onClick: () => manager.dismiss(item.id), children: "x" })] })) }, item.id))) }));
2157
+ .join(" "), role: "status", "aria-live": "polite", style: animationStyle(motion, style), ...props, children: renderedItems.map(({ item, motion: isMotionActive, state }, index) => (jsx(React.Fragment, { children: renderToast ? (renderToast(item, (id) => manager.dismiss(id), state)) : (jsxs("article", { className: `cc-toast cc-toast--${item.tone}`, "data-animation": motion.name, "data-motion": isMotionActive ? "true" : "false", "data-state": state, ref: (node) => setToastNode(item.id, node), style: {
2158
+ "--cc-toast-stack-index": index,
2159
+ }, children: [item.title ? (jsx("strong", { className: "cc-toast__title", children: item.title })) : null, jsx("span", { className: "cc-toast__message", children: item.message }), jsx("button", { "aria-label": "Dismiss toast", className: "cc-toast__close", type: "button", onClick: () => manager.dismiss(item.id), children: jsx(ClassIcon, { name: "x" }) })] })) }, item.id))) }));
2160
+ return portal
2161
+ ? renderBodyPortal(viewportNode)
2162
+ : viewportNode;
1875
2163
  }
1876
2164
  function resolveTabsFlag(source, activeId) {
1877
2165
  if (!source)
@@ -2265,6 +2553,212 @@ function TiltCard({ children, className = "cc-tilt-card", contentClassName = "cc
2265
2553
  ...style,
2266
2554
  }, onPointerEnter: handlePointerEnter, onPointerLeave: handlePointerLeave, onPointerMove: handlePointerMove, ...props, children: jsxs("div", { className: surfaceClassName, children: [jsx("div", { className: contentClassName, children: children }), state.glare ? (jsx("span", { "aria-hidden": "true", className: glareClassName })) : null] }) }));
2267
2555
  }
2556
+ function OrbitalSphere({ animated = true, className = "cc-orbital-sphere", cycleDuration = 12000, depth = 0.72, disabled = false, duration = 9000, itemClassName = "cc-orbital-sphere__item", itemContentClassName = "cc-orbital-sphere__item-content", itemSize = 72, items, onItemClick, radius = "50%", renderItem, shellClassName = "cc-orbital-sphere__shell", size = "360px", spread = 0.86, stageClassName = "cc-orbital-sphere__stage", style, visibleCount = 10, ...props }) {
2557
+ const state = React.useMemo(() => new OrbitalSphereController({
2558
+ animated,
2559
+ cycleDuration,
2560
+ depth,
2561
+ disabled,
2562
+ duration,
2563
+ itemSize,
2564
+ items,
2565
+ radius,
2566
+ size,
2567
+ spread,
2568
+ visibleCount,
2569
+ }).getState(), [
2570
+ animated,
2571
+ cycleDuration,
2572
+ depth,
2573
+ disabled,
2574
+ duration,
2575
+ itemSize,
2576
+ items,
2577
+ radius,
2578
+ size,
2579
+ spread,
2580
+ visibleCount,
2581
+ ]);
2582
+ return (jsxs("div", { className: className, "data-animated": state.animated ? "true" : "false", "data-disabled": state.disabled ? "true" : "false", "data-overflow": state.items.length > state.visibleCount ? "true" : "false", style: { ...state.styleVars, ...style }, ...props, children: [jsx("span", { "aria-hidden": "true", className: shellClassName }), jsx("div", { className: stageClassName, children: state.items.map((item) => (jsx("button", { "aria-label": item.label, className: itemClassName, "data-tone": item.tone, disabled: state.disabled, style: {
2583
+ "--cc-orbital-index": item.index,
2584
+ ...item.styleVars,
2585
+ }, type: "button", onClick: (event) => onItemClick?.(item, event), children: jsx("span", { className: itemContentClassName, children: renderItem?.(item) ?? item.content }) }, item.id))) })] }));
2586
+ }
2587
+ function HeightTransition({ children, className = "cc-height-transition", contentClassName = "cc-height-transition__content", duration = 220, easing, expanded = false, mode = "auto", style, ...props }) {
2588
+ const contentRef = React.useRef(null);
2589
+ const controller = React.useMemo(() => new HeightTransitionController({ duration, easing, expanded, mode }), []);
2590
+ const [state, setState] = React.useState(() => controller.getState());
2591
+ const [height, setHeight] = React.useState(0);
2592
+ React.useEffect(() => {
2593
+ setState(controller.update({ duration, easing, expanded, mode }));
2594
+ }, [controller, duration, easing, expanded, mode]);
2595
+ React.useLayoutEffect(() => {
2596
+ const element = contentRef.current;
2597
+ if (!element || typeof ResizeObserver === "undefined") {
2598
+ setHeight(element?.scrollHeight ?? 0);
2599
+ return undefined;
2600
+ }
2601
+ const observer = new ResizeObserver(() => setHeight(element.scrollHeight));
2602
+ observer.observe(element);
2603
+ setHeight(element.scrollHeight);
2604
+ return () => observer.disconnect();
2605
+ }, [children]);
2606
+ return (jsx("div", { className: className, "data-expanded": state.expanded, "data-mode": state.mode, style: {
2607
+ "--cc-height-transition-duration": `${state.duration}ms`,
2608
+ "--cc-height-transition-easing": state.easing,
2609
+ "--cc-height-transition-height": `${height}px`,
2610
+ ...style,
2611
+ }, ...props, children: jsx("div", { className: contentClassName, ref: contentRef, children: children }) }));
2612
+ }
2613
+ function CodePreview({ className = "cc-code-preview", code, defaultExpanded = false, language = "Vue / TSX", onCopy, placement = "auto", strategy = "fixed", title = "示例源码", transitionDuration = 220, transitionEasing = "cubic-bezier(0.22, 0.8, 0.28, 1)", ...props }) {
2614
+ const rootRef = React.useRef(null);
2615
+ const panelRef = React.useRef(null);
2616
+ const controller = React.useMemo(() => new CodePreviewController({
2617
+ code,
2618
+ defaultExpanded,
2619
+ language,
2620
+ placement,
2621
+ title: String(title),
2622
+ }), []);
2623
+ const [state, setState] = React.useState(() => controller.getState());
2624
+ const [panelStyle, setPanelStyle] = React.useState();
2625
+ React.useEffect(() => {
2626
+ setState(controller.update({ code, language, placement, title: String(title) }));
2627
+ }, [code, controller, language, placement, title]);
2628
+ const updatePanelPosition = React.useCallback((estimate = false) => {
2629
+ const root = rootRef.current;
2630
+ const panel = panelRef.current;
2631
+ if (!root || (!panel && !estimate) || typeof window === "undefined")
2632
+ return undefined;
2633
+ const rect = root.getBoundingClientRect();
2634
+ const padding = 10;
2635
+ const gap = 10;
2636
+ const viewportWidth = document.documentElement.clientWidth || window.innerWidth;
2637
+ const viewportHeight = document.documentElement.clientHeight || window.innerHeight;
2638
+ const maxPanelHeight = Math.max(160, viewportHeight - padding * 2);
2639
+ const maxPanelWidth = Math.max(160, viewportWidth - padding * 2);
2640
+ const minPanelHeight = Math.min(160, maxPanelHeight);
2641
+ const panelContent = panel?.querySelector("pre");
2642
+ const measuredPanelHeight = Math.max(panel?.offsetHeight ?? 0, panel?.scrollHeight ?? 0, panelContent?.scrollHeight ?? 0, estimate ? 420 : 0);
2643
+ const preferredPanelHeight = Math.min(Math.max(160, measuredPanelHeight || 420), maxPanelHeight);
2644
+ const panelWidth = Math.min(Math.max(rect.width, panel?.offsetWidth || 720), maxPanelWidth);
2645
+ const availableBelow = Math.max(minPanelHeight, viewportHeight - rect.bottom - gap - padding);
2646
+ const availableAbove = Math.max(minPanelHeight, rect.top - gap - padding);
2647
+ const placementHeight = Math.min(preferredPanelHeight, Math.max(availableBelow, availableAbove));
2648
+ const next = controller.resolvePlacement({
2649
+ anchorBottom: rect.bottom,
2650
+ anchorLeft: rect.left,
2651
+ anchorRight: rect.right,
2652
+ anchorTop: rect.top,
2653
+ panelHeight: placementHeight,
2654
+ panelWidth,
2655
+ viewportHeight,
2656
+ viewportWidth,
2657
+ });
2658
+ setState(next);
2659
+ if (strategy !== "fixed") {
2660
+ setPanelStyle(undefined);
2661
+ return;
2662
+ }
2663
+ const clamp = (value, min, max) => Math.min(Math.max(min, value), max);
2664
+ const width = panelWidth;
2665
+ const maxLeft = Math.max(padding, viewportWidth - width - padding);
2666
+ const viewportPanelHeight = Math.min(preferredPanelHeight, maxPanelHeight);
2667
+ const maxTop = Math.max(padding, viewportHeight - viewportPanelHeight - padding);
2668
+ let left = clamp(rect.left, padding, maxLeft);
2669
+ let top = rect.bottom + gap;
2670
+ let maxHeight = Math.min(preferredPanelHeight, Math.max(minPanelHeight, viewportHeight - top - padding));
2671
+ let transformOrigin = "top left";
2672
+ if (next.resolvedPlacement === "top") {
2673
+ maxHeight = Math.min(preferredPanelHeight, availableAbove);
2674
+ top = Math.max(padding, rect.top - gap - maxHeight);
2675
+ transformOrigin = "bottom left";
2676
+ }
2677
+ else if (next.resolvedPlacement === "right") {
2678
+ left = clamp(rect.right + gap, padding, maxLeft);
2679
+ top = clamp(rect.top, padding, maxTop);
2680
+ maxHeight = viewportPanelHeight;
2681
+ transformOrigin = "top left";
2682
+ }
2683
+ else if (next.resolvedPlacement === "left") {
2684
+ left = clamp(rect.left - width - gap, padding, maxLeft);
2685
+ top = clamp(rect.top, padding, maxTop);
2686
+ maxHeight = viewportPanelHeight;
2687
+ transformOrigin = "top right";
2688
+ }
2689
+ setPanelStyle({
2690
+ left,
2691
+ maxHeight,
2692
+ top,
2693
+ transformOrigin,
2694
+ width,
2695
+ });
2696
+ return next;
2697
+ }, [controller, strategy]);
2698
+ const updatePanelPositionFromViewport = React.useCallback(() => {
2699
+ updatePanelPosition();
2700
+ }, [updatePanelPosition]);
2701
+ React.useLayoutEffect(() => {
2702
+ if (!state.expanded) {
2703
+ setPanelStyle(undefined);
2704
+ return undefined;
2705
+ }
2706
+ updatePanelPosition();
2707
+ window.addEventListener("resize", updatePanelPositionFromViewport);
2708
+ window.addEventListener("scroll", updatePanelPositionFromViewport, true);
2709
+ return () => {
2710
+ window.removeEventListener("resize", updatePanelPositionFromViewport);
2711
+ window.removeEventListener("scroll", updatePanelPositionFromViewport, true);
2712
+ };
2713
+ }, [
2714
+ code,
2715
+ state.expanded,
2716
+ updatePanelPosition,
2717
+ updatePanelPositionFromViewport,
2718
+ ]);
2719
+ React.useEffect(() => {
2720
+ if (!state.expanded || typeof document === "undefined")
2721
+ return undefined;
2722
+ const close = () => {
2723
+ setPanelStyle(undefined);
2724
+ setState(controller.close());
2725
+ };
2726
+ const closeOnOutside = (event) => {
2727
+ const target = event.target;
2728
+ if (target &&
2729
+ (rootRef.current?.contains(target) ||
2730
+ panelRef.current?.contains(target)))
2731
+ return;
2732
+ close();
2733
+ };
2734
+ const closeOnEscape = (event) => {
2735
+ if (event.key === "Escape")
2736
+ close();
2737
+ };
2738
+ document.addEventListener("pointerdown", closeOnOutside, true);
2739
+ document.addEventListener("keydown", closeOnEscape, true);
2740
+ return () => {
2741
+ document.removeEventListener("pointerdown", closeOnOutside, true);
2742
+ document.removeEventListener("keydown", closeOnEscape, true);
2743
+ };
2744
+ }, [controller, state.expanded]);
2745
+ const copy = async () => {
2746
+ await (onCopy ? onCopy(code) : navigator.clipboard?.writeText(code));
2747
+ setState(controller.copied());
2748
+ window.setTimeout(() => setState(controller.resetCopied()), 1200);
2749
+ };
2750
+ const panel = (jsx("div", { className: "cc-code-preview__panel", "data-placement": state.resolvedPlacement, "data-strategy": strategy, "data-expanded": state.expanded, ref: panelRef, style: panelStyle, children: jsx(HeightTransition, { className: "cc-height-transition cc-code-preview__transition", contentClassName: "cc-height-transition__content cc-code-preview__panel-content", duration: transitionDuration, easing: transitionEasing, expanded: state.expanded, mode: "auto", children: jsx("pre", { children: jsx("code", { children: state.code }) }) }) }));
2751
+ return (jsxs("div", { className: className, "data-expanded": state.expanded, "data-placement": state.resolvedPlacement, "data-strategy": strategy, ref: rootRef, ...props, children: [jsxs("div", { className: "cc-code-preview__bar", children: [jsxs("div", { className: "cc-code-preview__meta", children: [jsx("span", { className: "cc-code-preview__title", children: title }), jsx("span", { className: "cc-code-preview__lang", children: state.language })] }), jsxs("div", { className: "cc-code-preview__actions", children: [jsx("button", { type: "button", onClick: () => {
2752
+ const next = controller.toggle();
2753
+ if (!next.expanded) {
2754
+ setPanelStyle(undefined);
2755
+ setState(next);
2756
+ return;
2757
+ }
2758
+ setState(updatePanelPosition(true) ?? next);
2759
+ window.requestAnimationFrame(() => updatePanelPosition());
2760
+ }, children: state.expanded ? "收起" : "展开" }), jsx("button", { type: "button", onClick: () => void copy(), children: state.copied ? "已复制" : "复制" })] })] }), strategy === "fixed" ? renderBodyPortal(panel) : panel] }));
2761
+ }
2268
2762
  function QRCode({ value, size = 160, margin = 2, darkColor = "#1f1a2e", lightColor = "#ffffff", className = "cc-code cc-qr-code", errorCorrectionLevel = "M", errorText = "QR code unavailable", logoSrc, logoAlt = "QR code logo", logoSize = Math.round(size * 0.22), logoPadding = 6, logoRadius = 8, logoBackground = "#ffffff", renderError, ...props }) {
2269
2763
  const [svg, setSvg] = React.useState("");
2270
2764
  const [error, setError] = React.useState(null);
@@ -2700,7 +3194,7 @@ function signaturePointFromEvent(canvas, event) {
2700
3194
  y: event.clientY - rect.top,
2701
3195
  };
2702
3196
  }
2703
- const Signature = /*#__PURE__*/ React.forwardRef(function Signature({ backgroundColor, canvasClassName = "cc-signature__canvas", className = "cc-signature", clearText = getClassComponentsLocale().signatureClearText, disabled = false, errorClassName, exportType = "image/png", fieldClassName = "cc-field cc-signature-field", height = 220, initialValue, label, labelClassName = "cc-field__label", lineWidth = 3, name, penColor = "#111827", readOnly = false, rules, showToolbar = true, style, toolbarClassName = "cc-signature__toolbar", undoText = getClassComponentsLocale().signatureUndoText, validateOn, width = "100%", onChange, onClear, onEnd, onUndo, ...props }, ref) {
3197
+ const Signature = /*#__PURE__*/ React.forwardRef(function Signature({ backgroundColor, canvasClassName = "cc-signature__canvas", className = "cc-signature", clearText = getClassComponentsLocale().signatureClearText, disabled = false, errorClassName, exportType = "image/png", fieldClassName = "cc-field cc-signature-field", height = 220, initialValue, label, labelClassName = "cc-field__label", lineWidth = 3, name, penColor = "#1d2129", readOnly = false, rules, showToolbar = true, style, toolbarClassName = "cc-signature__toolbar", undoText = getClassComponentsLocale().signatureUndoText, validateOn, width = "100%", onChange, onClear, onEnd, onUndo, ...props }, ref) {
2704
3198
  const formContext = React.useContext(FormContext);
2705
3199
  const formState = useSyncExternalStore((listener) => formContext
2706
3200
  ? formContext.controller.subscribe(listener)
@@ -3483,6 +3977,28 @@ function Draggable({ axis = "xy", boundaryRef, children, className = "cc-draggab
3483
3977
  ? children({ dragging: state.dragging, position: state.position })
3484
3978
  : children }));
3485
3979
  }
3980
+ function readDragDropPreviewStyleVars(element) {
3981
+ if (!element || typeof window === "undefined")
3982
+ return {};
3983
+ const styles = window.getComputedStyle(element);
3984
+ const read = (name) => styles.getPropertyValue(name).trim();
3985
+ const slotDraggingBackground = read("--cc-drag-drop-slot-dragging-background");
3986
+ const slotDraggingBorderColor = read("--cc-drag-drop-slot-dragging-border-color");
3987
+ const previewBackground = read("--cc-drag-drop-preview-background");
3988
+ const previewBorderColor = read("--cc-drag-drop-preview-border-color");
3989
+ const values = {
3990
+ "--cc-drag-drop-preview-background": previewBackground && !previewBackground.includes("var(")
3991
+ ? previewBackground
3992
+ : slotDraggingBackground,
3993
+ "--cc-drag-drop-preview-border-color": previewBorderColor && !previewBorderColor.includes("var(")
3994
+ ? previewBorderColor
3995
+ : slotDraggingBorderColor,
3996
+ "--cc-drag-drop-preview-color": read("--cc-drag-drop-preview-color"),
3997
+ "--cc-drag-drop-preview-shadow": read("--cc-drag-drop-preview-shadow"),
3998
+ "--cc-drag-drop-motion-duration": read("--cc-drag-drop-motion-duration"),
3999
+ };
4000
+ return Object.fromEntries(Object.entries(values).filter(([, value]) => value.length > 0));
4001
+ }
3486
4002
  function reorderDropItems(items, fromIndex, toIndex, mode) {
3487
4003
  if (fromIndex < 0 || toIndex < 0 || fromIndex === toIndex)
3488
4004
  return [...items];
@@ -3749,6 +4265,7 @@ function DragDropBoard({ columns, items, mode = "insert", renderItem, className
3749
4265
  offsetY: event.clientY - rect.top,
3750
4266
  originX: rect.left,
3751
4267
  originY: rect.top,
4268
+ styleVars: readDragDropPreviewStyleVars(boardRef.current),
3752
4269
  width: rect.width,
3753
4270
  x: rect.left,
3754
4271
  y: rect.top,
@@ -3796,6 +4313,7 @@ function DragDropBoard({ columns, items, mode = "insert", renderItem, className
3796
4313
  }, onPointerUp: endDrag, onPointerCancel: cancelDrag, children: jsx("div", { className: "cc-drag-drop-board__item", children: renderItem(item, { dragging, over }) }) }, item.id));
3797
4314
  }), preview
3798
4315
  ? renderBodyPortal(jsx("div", { "aria-hidden": "true", className: "cc-drag-drop-board__preview", "data-dropping": preview.dropping, "data-returning": preview.returning, ref: previewRef, style: {
4316
+ ...preview.styleVars,
3799
4317
  height: preview.height,
3800
4318
  transform: `translate3d(${preview.x}px, ${preview.y}px, 0)`,
3801
4319
  width: preview.width,
@@ -4650,7 +5168,9 @@ function MasonryVirtualList({ columns, data, estimateSize = 220, gap = 16, heade
4650
5168
  item,
4651
5169
  }) }, item.key))) })] }) }));
4652
5170
  }
4653
- function ChatVirtualListInner({ data, bottomBuffer = 8, bottomThreshold = 64, defaultStickToBottom = true, enablePullUp = false, estimateSize = 72, getKey, height = 420, itemClassName = "cc-chat-virtual-list__item", itemContent, listClassName = "cc-chat-virtual-list__inner", appendScrollBehavior = "smooth", pullUpClassName = "cc-chat-virtual-list__pull-up", pullUpContent, pullUpLoading = false, pullUpMinDuration = 420, pullUpThreshold = 48, stickToBottomOnAppend = true, stickToBottomOnUpdate = true, topLoadingClassName = "cc-chat-virtual-list__top-loading", topLoadingContent = "正在加载历史消息...", topBuffer = 10, topThreshold = 96, className = "cc-chat-virtual-list", viewportClassName = "cc-chat-virtual-list__viewport", onPullUp, onReachTop, onRangeChange, style, ...props }, ref) {
5171
+ const CHAT_PREPEND_MOMENTUM_LOCK_MS = 420;
5172
+ const CHAT_PREPEND_STABILIZE_FRAMES = 24;
5173
+ function ChatVirtualListInner({ data, bottomBuffer = 8, bottomThreshold = 64, defaultStickToBottom = true, enablePullUp = false, estimateSize = 72, getKey, height = 420, itemClassName = "cc-chat-virtual-list__item", itemContent, listClassName = "cc-chat-virtual-list__inner", appendScrollBehavior = "smooth", pullUpClassName = "cc-chat-virtual-list__pull-up", pullUpContent, pullUpLoading = false, pullUpMinDuration = 420, pullUpThreshold = 48, stickToBottomOnAppend = true, stickToBottomOnUpdate = true, topLoadingClassName = "cc-chat-virtual-list__top-loading", topLoadingContent = "", topBuffer = 10, topThreshold = 96, className = "cc-chat-virtual-list", viewportClassName = "cc-chat-virtual-list__viewport", onPullUp, onReachTop, onRangeChange, style, ...props }, ref) {
4654
5174
  const viewportRef = React.useRef(null);
4655
5175
  const pullUpRef = React.useRef(null);
4656
5176
  const observersRef = React.useRef(new Map());
@@ -4703,7 +5223,19 @@ function ChatVirtualListInner({ data, bottomBuffer = 8, bottomThreshold = 64, de
4703
5223
  }
4704
5224
  releaseTopLoadingLock();
4705
5225
  }, [releaseTopLoadingLock]);
4706
- const clearPendingPrependAnchor = React.useCallback(() => {
5226
+ const clearPendingPrependAnchor = React.useCallback((force = false) => {
5227
+ const pendingAnchor = pendingPrependAnchorRef.current;
5228
+ if (!force && pendingAnchor) {
5229
+ const remaining = pendingAnchor.releaseAt - Date.now();
5230
+ if (remaining > 0) {
5231
+ if (prependTimerRef.current !== undefined)
5232
+ window.clearTimeout(prependTimerRef.current);
5233
+ prependTimerRef.current = window.setTimeout(() => {
5234
+ clearPendingPrependAnchor(true);
5235
+ }, remaining);
5236
+ return;
5237
+ }
5238
+ }
4707
5239
  pendingPrependAnchorRef.current = null;
4708
5240
  if (prependStabilizeFrameRef.current !== undefined) {
4709
5241
  window.cancelAnimationFrame(prependStabilizeFrameRef.current);
@@ -4735,19 +5267,23 @@ function ChatVirtualListInner({ data, bottomBuffer = 8, bottomThreshold = 64, de
4735
5267
  if (prependStabilizeFrameRef.current !== undefined) {
4736
5268
  window.cancelAnimationFrame(prependStabilizeFrameRef.current);
4737
5269
  }
4738
- let remainingFrames = 8;
5270
+ let remainingFrames = CHAT_PREPEND_STABILIZE_FRAMES;
4739
5271
  const stabilize = () => {
4740
- if (!pendingPrependAnchorRef.current || remainingFrames <= 0) {
5272
+ const pendingAnchor = pendingPrependAnchorRef.current;
5273
+ if (!pendingAnchor) {
4741
5274
  prependStabilizeFrameRef.current = undefined;
4742
5275
  return;
4743
5276
  }
4744
5277
  applyPendingPrependAnchor();
4745
5278
  remainingFrames -= 1;
5279
+ if (remainingFrames <= 0 && pendingAnchor.releaseAt <= Date.now()) {
5280
+ prependStabilizeFrameRef.current = undefined;
5281
+ return;
5282
+ }
4746
5283
  prependStabilizeFrameRef.current =
4747
5284
  window.requestAnimationFrame(stabilize);
4748
5285
  };
4749
- prependStabilizeFrameRef.current =
4750
- window.requestAnimationFrame(stabilize);
5286
+ prependStabilizeFrameRef.current = window.requestAnimationFrame(stabilize);
4751
5287
  }, [applyPendingPrependAnchor]);
4752
5288
  const scheduleTopLoadingFallback = React.useCallback(() => {
4753
5289
  if (topLoadingFallbackTimerRef.current !== undefined) {
@@ -4894,6 +5430,7 @@ function ChatVirtualListInner({ data, bottomBuffer = 8, bottomThreshold = 64, de
4894
5430
  anchorOffset: previousAnchor.offset,
4895
5431
  measuredKeys: new Set(),
4896
5432
  prependKeys: new Set(keys.slice(0, prependCount)),
5433
+ releaseAt: Date.now() + CHAT_PREPEND_MOMENTUM_LOCK_MS,
4897
5434
  targetScrollTop: nextScrollTop,
4898
5435
  }
4899
5436
  : null;
@@ -5060,12 +5597,19 @@ function ChatVirtualListInner({ data, bottomBuffer = 8, bottomThreshold = 64, de
5060
5597
  useEffect(() => {
5061
5598
  onRangeChange?.({ endIndex: range.endIndex, startIndex: range.startIndex });
5062
5599
  }, [onRangeChange, range.endIndex, range.startIndex]);
5600
+ const hasPendingKeySync = () => {
5601
+ const previousKeys = previousKeysRef.current;
5602
+ return (previousKeys.length !== keys.length ||
5603
+ previousKeys.some((itemKey, index) => !Object.is(itemKey, keys[index])));
5604
+ };
5063
5605
  const observeItem = (index, key, element) => {
5064
5606
  observersRef.current.get(key)?.disconnect();
5065
5607
  observersRef.current.delete(key);
5066
5608
  if (!element)
5067
5609
  return;
5068
5610
  const measure = () => {
5611
+ if (!pendingPrependAnchorRef.current && hasPendingKeySync())
5612
+ return;
5069
5613
  const previousTotal = listControllerRef.current.getTotalSize();
5070
5614
  const previousItem = listControllerRef.current.getItem(index);
5071
5615
  const viewport = viewportRef.current;
@@ -5128,7 +5672,7 @@ function ChatVirtualListInner({ data, bottomBuffer = 8, bottomThreshold = 64, de
5128
5672
  return (jsxs("div", { className: className, "data-top-loading": topLoadingPending ? "true" : undefined, style: {
5129
5673
  "--cc-chat-virtual-list-height": resolvedHeight,
5130
5674
  ...style,
5131
- }, ...props, children: [jsx("div", { "aria-hidden": !topLoadingPending, className: topLoadingClassName, "data-active": topLoadingPending ? "true" : "false", role: topLoadingPending ? "status" : undefined, children: topLoadingContent }), jsxs("div", { className: viewportClassName, "data-top-loading": topLoadingPending ? "true" : undefined, ref: viewportRef, onScroll: (event) => {
5675
+ }, ...props, children: [jsx(Loading, { "aria-hidden": !topLoadingPending, className: topLoadingClassName, "data-active": topLoadingPending ? "true" : "false", role: topLoadingPending ? "status" : undefined, text: topLoadingContent }), jsxs("div", { className: viewportClassName, "data-top-loading": topLoadingPending ? "true" : undefined, ref: viewportRef, onScroll: (event) => {
5132
5676
  if (pendingPrependAnchorRef.current) {
5133
5677
  const stabilized = applyPendingPrependAnchor();
5134
5678
  if (stabilized)
@@ -5875,5 +6419,5 @@ function LiveRoom({ chats = EMPTY_LIVE_CHATS, className = "cc-live-room", danmak
5875
6419
  } }), jsx("button", { "aria-label": getClassComponentsLocale().liveRoomSendLabel, title: getClassComponentsLocale().liveRoomSendLabel, type: "button", onClick: send, children: jsx(LiveRoomIcon, { name: "send" }) })] })] })] }));
5876
6420
  }
5877
6421
 
5878
- export { Affix, Backtop, Badge, Barcode, Breadcrumb, Button, Calendar, CanvasEditor, CanvasImage, ChatVirtualList, Checkbox, Checked, ClassConfigProvider, ColorPicker, ComicReader, ConfigTable, Countdown, Danmaku, DatePicker, DateRangePicker, DesignEffect, DragDropBoard, Draggable, EllipsisText, Empty, Field, FilePreview, FloatingBall, FormProvider, GradientText, Input, LazyImage, LiveRoom, Loading, Marquee, MasonryVirtualList, Modal, MultiColumnPicker, NovelReader, NumberInput, Pagination, PasswordInput, Popconfirm, Popup, ProgressBar, QRCode, RadioGroup, Rating, RollingNumber, Select, Signature, Skeleton, SlideCaptcha, Swiper, Switch, Table, Tabs, Tag, Textarea, TiltCard, Timeline, ToastViewport, Tooltip, TypewriterText, Upload, VerificationCode, VideoDetailTransition, VideoPlayer, VirtualList, VirtualSelect, VirtualTable, defaultToastManager, useField, useForm, useFormState };
6422
+ export { Affix, Backtop, Badge, Barcode, Breadcrumb, Button, Calendar, CanvasEditor, CanvasImage, ChatTextarea, ChatVirtualList, Checkbox, Checked, ClassConfigProvider, CodePreview, ColorPicker, ComicReader, ConfigTable, Countdown, Danmaku, DatePicker, DateRangePicker, DesignEffect, DragDropBoard, Draggable, EllipsisText, Empty, Field, FilePreview, FloatingBall, FormProvider, GradientText, HeightTransition, Input, LazyImage, LiveRoom, Loading, Marquee, MasonryVirtualList, Menu, Modal, MultiColumnPicker, NovelReader, NumberInput, OrbitalSphere, Pagination, PasswordInput, Popconfirm, Popup, ProgressBar, QRCode, RadioGroup, Rating, RollingNumber, Select, Signature, Skeleton, SlideCaptcha, Swiper, Switch, Table, Tabs, Tag, Textarea, TiltCard, Timeline, ToastViewport, Tooltip, TypewriterText, Upload, VerificationCode, VideoDetailTransition, VideoPlayer, VirtualList, VirtualSelect, VirtualTable, defaultToastManager, useField, useForm, useFormState };
5879
6423
  //# sourceMappingURL=index.js.map