@baishuyun/ai-design 2.0.37 → 2.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (269) hide show
  1. package/.storybook/main.ts +31 -31
  2. package/.storybook/preview.ts +16 -16
  3. package/CHANGELOG.md +512 -492
  4. package/components.json +22 -22
  5. package/package.json +9 -6
  6. package/scripts/strip-layers.cjs +41 -41
  7. package/src/components/abs-fullscreen-gradient-bg.tsx +35 -35
  8. package/src/components/agent-helper/agent-category-select-menu/index.tsx +57 -57
  9. package/src/components/agent-helper/agent-entry-card/index.tsx +94 -94
  10. package/src/components/agent-helper/agent-helper-card/index.tsx +179 -179
  11. package/src/components/agent-helper/agent-helper-card-list/index.tsx +59 -59
  12. package/src/components/agent-helper/agent-helper-main-layout/index.tsx +60 -60
  13. package/src/components/agent-helper/agent-sort-select/index.tsx +89 -89
  14. package/src/components/agent-helper/agent-tag/index.tsx +29 -29
  15. package/src/components/agent-helper/app-select/index.tsx +559 -559
  16. package/src/components/agent-helper/condition-group/index.tsx +75 -75
  17. package/src/components/agent-helper/condition-input/index.tsx +233 -233
  18. package/src/components/agent-helper/condition-item/index.tsx +237 -237
  19. package/src/components/agent-helper/condition-quantifier-select/index.tsx +142 -142
  20. package/src/components/agent-helper/condition-trigger-description/index.tsx +49 -49
  21. package/src/components/agent-helper/date-picker/calendar-panel.tsx +164 -164
  22. package/src/components/agent-helper/date-picker/date-input.tsx +91 -91
  23. package/src/components/agent-helper/date-picker/date-picker.tsx +327 -327
  24. package/src/components/agent-helper/date-picker/footer-panel.tsx +44 -44
  25. package/src/components/agent-helper/date-picker/index.ts +3 -3
  26. package/src/components/agent-helper/date-picker/month-panel.tsx +82 -82
  27. package/src/components/agent-helper/date-picker/time-panel.tsx +146 -146
  28. package/src/components/agent-helper/date-picker/types.ts +37 -37
  29. package/src/components/agent-helper/date-picker/utils.ts +121 -121
  30. package/src/components/agent-helper/date-picker/year-panel.tsx +86 -86
  31. package/src/components/agent-helper/exec-log-filter/index.tsx +232 -232
  32. package/src/components/agent-helper/field-edit-preference-select/index.tsx +291 -291
  33. package/src/components/agent-helper/field-select/index.tsx +466 -466
  34. package/src/components/agent-helper/field-value-input/china-address-data.ts +4117 -4117
  35. package/src/components/agent-helper/field-value-input/display.tsx +71 -71
  36. package/src/components/agent-helper/field-value-input/icons.tsx +38 -38
  37. package/src/components/agent-helper/field-value-input/index.tsx +144 -144
  38. package/src/components/agent-helper/field-value-input/inputs.tsx +247 -247
  39. package/src/components/agent-helper/field-value-input/picker-inputs.tsx +1141 -1141
  40. package/src/components/agent-helper/flow-node-action-trigger-select/index.tsx +57 -57
  41. package/src/components/agent-helper/form-action-trigger-select/index.tsx +60 -60
  42. package/src/components/agent-helper/form-divider/index.tsx +44 -44
  43. package/src/components/agent-helper/form-select/index.tsx +732 -732
  44. package/src/components/agent-helper/monthdays-select/index.tsx +378 -378
  45. package/src/components/agent-helper/offset-preference-select/index.tsx +268 -268
  46. package/src/components/agent-helper/offset-type-select/index.tsx +66 -66
  47. package/src/components/agent-helper/offset-unit-select/index.tsx +54 -54
  48. package/src/components/agent-helper/placeholder-card/index.tsx +75 -75
  49. package/src/components/agent-helper/prompt-input/index.tsx +646 -640
  50. package/src/components/agent-helper/relational-operator-select/index.tsx +179 -179
  51. package/src/components/agent-helper/repeat-by-type-select/index.tsx +53 -53
  52. package/src/components/agent-helper/repeat-preference-select/index.tsx +162 -162
  53. package/src/components/agent-helper/repeat-preference-type-select/index.tsx +58 -58
  54. package/src/components/agent-helper/search-input/index.tsx +35 -35
  55. package/src/components/agent-helper/table/index.tsx +114 -114
  56. package/src/components/agent-helper/trigger-select/index.tsx +121 -121
  57. package/src/components/agent-helper/trigger-time-preference-select/index.tsx +189 -189
  58. package/src/components/agent-helper/trigger-time-source-type-select/index.tsx +53 -53
  59. package/src/components/agent-helper/weekdays-select/index.tsx +230 -230
  60. package/src/components/agent-scroll-selector.tsx +193 -193
  61. package/src/components/agent-select.tsx +154 -154
  62. package/src/components/attachment-part-group.tsx +35 -35
  63. package/src/components/attachment-part.tsx +296 -296
  64. package/src/components/attachments-previewer.tsx +272 -272
  65. package/src/components/base-button.tsx +49 -49
  66. package/src/components/border-animation.tsx +107 -107
  67. package/src/components/border-color-animation.tsx +66 -66
  68. package/src/components/bot-avatar-name.tsx +36 -36
  69. package/src/components/bot-icon.tsx +23 -23
  70. package/src/components/bs-entry-select/app-group-folder.tsx +61 -61
  71. package/src/components/bs-entry-select/bs-entry-select.tsx +296 -296
  72. package/src/components/bs-entry-select/build-tree.ts +265 -265
  73. package/src/components/bs-entry-select/entry-item.tsx +45 -45
  74. package/src/components/bs-entry-select/entry-popover.tsx +99 -99
  75. package/src/components/bs-entry-select/index.ts +7 -7
  76. package/src/components/bs-entry-select/other-app-section.tsx +96 -96
  77. package/src/components/bs-entry-select/scroll-slider.tsx +872 -872
  78. package/src/components/bs-entry-select/search-input.tsx +4 -4
  79. package/src/components/bs-entry-select/tree-item-node.tsx +84 -84
  80. package/src/components/bs-entry-select/types.ts +46 -46
  81. package/src/components/bs-icons.tsx +1362 -1362
  82. package/src/components/card-field.tsx +23 -23
  83. package/src/components/card.tsx +36 -36
  84. package/src/components/chat-area-header.tsx +65 -65
  85. package/src/components/check-card.tsx +77 -77
  86. package/src/components/circle-checker.tsx +66 -66
  87. package/src/components/collapsible-txt-msg.tsx +75 -75
  88. package/src/components/collapsible.tsx +9 -9
  89. package/src/components/confirm-dialog.tsx +139 -139
  90. package/src/components/date-range-picker.tsx +91 -91
  91. package/src/components/fake-bot-msg.tsx +51 -51
  92. package/src/components/field-checker-list-msg.tsx +146 -146
  93. package/src/components/field-checker.tsx +185 -185
  94. package/src/components/field-icon.tsx +13 -13
  95. package/src/components/field-value-checker.tsx +116 -116
  96. package/src/components/fields-design-info-table.tsx +160 -160
  97. package/src/components/fields-generating-indicator.tsx +95 -95
  98. package/src/components/fields-portal.tsx +18 -18
  99. package/src/components/fields-previewer.tsx +216 -216
  100. package/src/components/font-icon.tsx +65 -65
  101. package/src/components/form-info-editor.tsx +263 -263
  102. package/src/components/formula-tag.tsx +32 -32
  103. package/src/components/generate-animation.tsx +56 -56
  104. package/src/components/icon-btn.tsx +43 -43
  105. package/src/components/icon-card.tsx +67 -67
  106. package/src/components/icons/calendar-icon.tsx +5 -5
  107. package/src/components/icons/clear-all-icon.tsx +5 -5
  108. package/src/components/icons/empty-agent-icon.tsx +93 -93
  109. package/src/components/icons/empty-table-icon.tsx +104 -104
  110. package/src/components/icons/grids-icon.tsx +5 -5
  111. package/src/components/img-part.tsx +27 -27
  112. package/src/components/legacy-slot.tsx +110 -110
  113. package/src/components/line-checker.tsx +168 -168
  114. package/src/components/linear-gradient-border-btn.tsx +48 -48
  115. package/src/components/linear-gradient-color-bg-animation.tsx +103 -103
  116. package/src/components/memoized-markdown.tsx +32 -32
  117. package/src/components/message-content.tsx +21 -21
  118. package/src/components/number-part.tsx +46 -46
  119. package/src/components/office-container.tsx +289 -265
  120. package/src/components/option-item.tsx +27 -27
  121. package/src/components/output-config-editor.tsx +478 -478
  122. package/src/components/previewer-header.tsx +270 -270
  123. package/src/components/primary-confirm-btn.tsx +58 -58
  124. package/src/components/primary-entry-btn.tsx +48 -48
  125. package/src/components/radio-card.tsx +63 -63
  126. package/src/components/scroll-to-bottom-btn.tsx +28 -28
  127. package/src/components/split-line.tsx +9 -9
  128. package/src/components/square-checker.tsx +87 -87
  129. package/src/components/subform-fields-value-checker.tsx +184 -184
  130. package/src/components/tab-radio-group.tsx +83 -83
  131. package/src/components/tooltip.tsx +53 -53
  132. package/src/components/ui/button.tsx +51 -51
  133. package/src/components/ui/calendar.tsx +57 -57
  134. package/src/components/ui/dialog.tsx +104 -104
  135. package/src/components/ui/drawer.tsx +279 -279
  136. package/src/components/ui/form.tsx +202 -202
  137. package/src/components/ui/icons.tsx +1267 -1267
  138. package/src/components/ui/input.tsx +28 -28
  139. package/src/components/ui/label.tsx +30 -30
  140. package/src/components/ui/popover.tsx +85 -85
  141. package/src/components/ui/select.tsx +236 -236
  142. package/src/components/ui/spinner.tsx +17 -17
  143. package/src/components/ui/switch.tsx +33 -33
  144. package/src/components/ui/tabs.tsx +62 -62
  145. package/src/components/ui/textarea.tsx +28 -28
  146. package/src/components/ui/tooltip.tsx +53 -53
  147. package/src/components/user-txt-msg-bubble.tsx +47 -47
  148. package/src/components/warning-msg.tsx +27 -27
  149. package/src/const/ui.ts +119 -119
  150. package/src/css.d.ts +4 -4
  151. package/src/hooks/use-column-appear.ts +78 -78
  152. package/src/hooks/use-portal-container.ts +27 -27
  153. package/src/hooks/use-resizable-width.ts +129 -129
  154. package/src/hooks/use-select-popover-position.ts +74 -74
  155. package/src/hooks/use-shadow.ts +127 -127
  156. package/src/index.ts +226 -226
  157. package/src/lib/utils.ts +138 -138
  158. package/src/stories/AbsFullscreenGradientBg.stories.tsx +36 -36
  159. package/src/stories/AgentCategorySelectMenu.stories.tsx +33 -33
  160. package/src/stories/AgentEntryCard.stories.tsx +90 -90
  161. package/src/stories/AgentHelperCard.stories.tsx +105 -105
  162. package/src/stories/AgentHelperCardList.stories.tsx +120 -120
  163. package/src/stories/AgentHelperMainLayout.stories.tsx +71 -71
  164. package/src/stories/AgentScrollSelector.stories.tsx +95 -95
  165. package/src/stories/AgentSelect.stories.tsx +134 -134
  166. package/src/stories/AgentTag.stories.tsx +44 -44
  167. package/src/stories/AppSelect.stories.tsx +250 -250
  168. package/src/stories/AttachmentPart.stories.tsx +122 -122
  169. package/src/stories/AttachmentPartGroup.stories.tsx +152 -152
  170. package/src/stories/AttachmentsPreviewer.stories.tsx +306 -306
  171. package/src/stories/BaseButton.stories.tsx +33 -33
  172. package/src/stories/BorderAnimation.stories.tsx +116 -116
  173. package/src/stories/BorderColorAnimation.stories.tsx +63 -63
  174. package/src/stories/BotAvatarAndName.stories.ts +24 -24
  175. package/src/stories/BotIcon.stories.ts +22 -22
  176. package/src/stories/BsConditionInput.stories.tsx +460 -460
  177. package/src/stories/BsEntrySelect.stories.tsx +343 -343
  178. package/src/stories/BsTooltip.stories.tsx +32 -32
  179. package/src/stories/Card.stories.tsx +28 -28
  180. package/src/stories/CardField.stories.tsx +87 -87
  181. package/src/stories/ChatAreaHeader.stories.ts +26 -26
  182. package/src/stories/CheckCard.stories.tsx +114 -114
  183. package/src/stories/CircleChecker.stories.tsx +89 -89
  184. package/src/stories/CollapsibleTextMsg.stories.ts +44 -44
  185. package/src/stories/ConditionGroup.stories.tsx +216 -216
  186. package/src/stories/ConditionInput.stories.tsx +502 -502
  187. package/src/stories/ConditionItem.stories.tsx +163 -163
  188. package/src/stories/ConditonQuantifierSelect.stories.tsx +54 -54
  189. package/src/stories/ConditonTriggerDescription.stories.tsx +61 -61
  190. package/src/stories/ConfirmDialog.stories.tsx +123 -123
  191. package/src/stories/DataTable.stories.tsx +191 -191
  192. package/src/stories/DatePicker.stories.tsx +174 -174
  193. package/src/stories/ExecLogFilter.stories.tsx +145 -145
  194. package/src/stories/FakeBotMsg.stories.tsx +36 -36
  195. package/src/stories/FieldEditPreferenceSelect.stories.tsx +161 -161
  196. package/src/stories/FieldSelect.stories.tsx +228 -228
  197. package/src/stories/FieldValueInput.stories.tsx +442 -442
  198. package/src/stories/FlowNodeActionTriggerSelect.stories.tsx +80 -80
  199. package/src/stories/Form.stories.tsx +302 -302
  200. package/src/stories/FormActionTriggerSelect.stories.tsx +80 -80
  201. package/src/stories/FormDivider.stories.tsx +31 -31
  202. package/src/stories/FormInfoEditor.stories.tsx +173 -173
  203. package/src/stories/FormSelect.stories.tsx +222 -222
  204. package/src/stories/FormulaTag.stories.tsx +68 -68
  205. package/src/stories/GenerateAnimation.stories.ts +20 -20
  206. package/src/stories/IconBtn.stories.tsx +32 -32
  207. package/src/stories/IconCard.stories.tsx +35 -35
  208. package/src/stories/IconLib.tsx +45 -45
  209. package/src/stories/Icons.stories.ts +22 -22
  210. package/src/stories/ImgMsgPart.stories.tsx +42 -42
  211. package/src/stories/Input.stories.tsx +102 -102
  212. package/src/stories/Label.stories.tsx +66 -66
  213. package/src/stories/LegacySlot.stories.tsx +56 -56
  214. package/src/stories/LineChecker.stories.tsx +133 -133
  215. package/src/stories/LinearGradientBorderBtn.stories.tsx +86 -86
  216. package/src/stories/LinearGradientColorBgAnimation.stories.tsx +60 -60
  217. package/src/stories/MemoizedMarkdown.stories.tsx +102 -102
  218. package/src/stories/MessageContent.stories.tsx +36 -36
  219. package/src/stories/MonthdaysSelect.stories.tsx +78 -78
  220. package/src/stories/NumbersMsgPart.stories.tsx +42 -42
  221. package/src/stories/OfficeContainer.stories.tsx +287 -287
  222. package/src/stories/OffsetPreferenceSelect.stories.tsx +118 -118
  223. package/src/stories/OffsetTypeSelect.stories.tsx +75 -75
  224. package/src/stories/OffsetUnitSelect.stories.tsx +61 -61
  225. package/src/stories/OptionItem.stories.tsx +77 -77
  226. package/src/stories/OutputConfigEditor.stories.tsx +96 -96
  227. package/src/stories/PlaceholderCard.stories.tsx +35 -35
  228. package/src/stories/PreviewerHeader.stories.tsx +91 -91
  229. package/src/stories/PrimaryConfirmBtn.stories.tsx +60 -60
  230. package/src/stories/PrimaryEntryBtn.stories.tsx +74 -74
  231. package/src/stories/PromptInput.stories.tsx +228 -228
  232. package/src/stories/RadioCard.stories.tsx +103 -103
  233. package/src/stories/RelationalOperatorSelect.stories.tsx +61 -61
  234. package/src/stories/RepeatByTypeSelect.stories.tsx +58 -58
  235. package/src/stories/RepeatPreferenceSelect.stories.tsx +107 -107
  236. package/src/stories/RepeatPreferenceTypeSelect.stories.tsx +58 -58
  237. package/src/stories/ScrollToBottom.stories.tsx +24 -24
  238. package/src/stories/SearchInput.stories.tsx +50 -50
  239. package/src/stories/Select.stories.tsx +128 -128
  240. package/src/stories/SplitLine.stories.tsx +40 -40
  241. package/src/stories/SquareChecker.stories.tsx +96 -96
  242. package/src/stories/TabRadioGroup.stories.tsx +84 -84
  243. package/src/stories/Textarea.stories.tsx +67 -67
  244. package/src/stories/TriggerSelect.stories.tsx +48 -48
  245. package/src/stories/TriggerTimePreferenceSelect.stories.tsx +106 -106
  246. package/src/stories/TriggerTimeSourceTypeSelect.stories.tsx +68 -68
  247. package/src/stories/UserTextMsgBubble.stories.ts +24 -24
  248. package/src/stories/WarningMessage.stories.tsx +23 -23
  249. package/src/stories/WeekdaysSelect.stories.tsx +66 -66
  250. package/src/stories/assets/demo.css +539 -539
  251. package/src/stories/assets/demo_index.html +7988 -7988
  252. package/src/stories/assets/iconfont.css +1377 -1377
  253. package/src/stories/assets/iconfont.json +2382 -2382
  254. package/src/stories/assets/iconfont.svg +697 -697
  255. package/src/stories/collapsible.stories.tsx +47 -47
  256. package/src/stories/drawer.stories.tsx +196 -196
  257. package/src/stories/field-checker-list-msg.stories.tsx +95 -95
  258. package/src/stories/field-checker.stories.tsx +117 -117
  259. package/src/stories/field-icon.stories.tsx +70 -70
  260. package/src/stories/field-value-checker.stories.tsx +113 -113
  261. package/src/stories/fields-design-info-table.stories.tsx +203 -203
  262. package/src/stories/fields-generating.stories.tsx +41 -41
  263. package/src/stories/fields-previewer.stories.tsx +77 -77
  264. package/src/stories/subform-fields-value-checker.stories.tsx +98 -98
  265. package/src/style.css +226 -226
  266. package/src/types.ts +8 -8
  267. package/style.css +3652 -3652
  268. package/tsconfig.json +13 -13
  269. package/vite.config.ts +44 -44
@@ -1,129 +1,129 @@
1
- import { useCallback, useEffect, useRef, useState } from 'react';
2
-
3
- interface UseResizableWidthOptions {
4
- /** 宽度范围 [min, max],单位 px */
5
- range: [number, number];
6
- /** 初始宽度,未指定时取 range 上限 */
7
- initialWidth?: number;
8
- /** 反转拖拽方向:拖拽鼠标向右时宽度减小而非增大 */
9
- invertDrag?: boolean;
10
- /** localStorage 键名,用于持久化用户拖拽偏好。提供后会在 mount 时读取、drag end 时保存 */
11
- storageKey?: string;
12
- }
13
-
14
- interface UseResizableWidthResult {
15
- /** 当前宽度 */
16
- width: number;
17
- /** 拖拽手柄的 onMouseDown 处理器 */
18
- handleMouseDown: (e: React.MouseEvent) => void;
19
- /** 是否正在拖拽 */
20
- isDragging: boolean;
21
- /** 是否到达边缘(最小或最大值) */
22
- isAtEdge: boolean;
23
- }
24
-
25
- /**
26
- * 支持通过拖拽调整宽度的 Hook
27
- * @param options 配置项:宽度范围、初始宽度
28
- * @returns 当前宽度、拖拽处理器、拖拽状态
29
- */
30
- export const useResizableWidth = ({
31
- range,
32
- initialWidth,
33
- invertDrag,
34
- storageKey,
35
- }: UseResizableWidthOptions): UseResizableWidthResult => {
36
- const [minWidth, maxWidth] = range;
37
-
38
- const resolveInitialWidth = (): number => {
39
- if (storageKey) {
40
- try {
41
- const stored = localStorage.getItem(storageKey);
42
- if (stored !== null) {
43
- const parsed = Number(stored);
44
- if (!Number.isNaN(parsed) && parsed >= minWidth && parsed <= maxWidth) {
45
- return parsed;
46
- }
47
- }
48
- } catch { /* localStorage unavailable */ }
49
- }
50
- return initialWidth ?? maxWidth;
51
- };
52
-
53
- const [width, setWidth] = useState<number>(resolveInitialWidth);
54
- const [isDragging, setIsDragging] = useState(false);
55
-
56
- const stateRef = useRef({
57
- startX: 0,
58
- startWidth: 0,
59
- });
60
-
61
- const handleMouseMove = useCallback(
62
- (e: MouseEvent) => {
63
- const delta = e.clientX - stateRef.current.startX;
64
- const adjustedDelta = invertDrag ? -delta : delta;
65
- const newWidth = Math.min(
66
- Math.max(stateRef.current.startWidth + adjustedDelta, minWidth),
67
- maxWidth
68
- );
69
-
70
- setWidth(newWidth);
71
- },
72
- [minWidth, maxWidth, invertDrag]
73
- );
74
-
75
- const hasDraggedRef = useRef(false);
76
-
77
- const handleMouseUp = useCallback(() => {
78
- setIsDragging(false);
79
- hasDraggedRef.current = true;
80
- document.body.style.userSelect = '';
81
- document.removeEventListener('mousemove', handleMouseMove);
82
- document.removeEventListener('mouseup', handleMouseUp);
83
-
84
- window.dispatchEvent(new Event('resize'));
85
- document.body.style.cursor = '';
86
- }, [handleMouseMove]);
87
-
88
- // Persist width to localStorage after drag ends
89
- useEffect(() => {
90
- if (!isDragging && hasDraggedRef.current && storageKey) {
91
- try { localStorage.setItem(storageKey, String(width)); } catch { /* unavailable */ }
92
- }
93
- }, [isDragging, storageKey, width]);
94
-
95
- const handleMouseDown = useCallback(
96
- (e: React.MouseEvent) => {
97
- setIsDragging(true);
98
- stateRef.current = {
99
- startX: e.clientX,
100
- startWidth: width,
101
- };
102
- document.body.style.userSelect = 'none';
103
- document.addEventListener('mousemove', handleMouseMove);
104
- document.addEventListener('mouseup', handleMouseUp);
105
-
106
- document.body.style.cursor = 'col-resize'; // 设置全局拖拽光标
107
- },
108
- [width, handleMouseMove, handleMouseUp]
109
- );
110
-
111
- useEffect(() => {
112
- return () => {
113
- document.removeEventListener('mousemove', handleMouseMove);
114
- document.removeEventListener('mouseup', handleMouseUp);
115
- document.body.style.userSelect = '';
116
-
117
- document.body.style.cursor = ''; // 清理光标样式
118
- };
119
- }, [handleMouseMove, handleMouseUp]);
120
-
121
- const isAtEdge = width === minWidth || width === maxWidth;
122
-
123
- return {
124
- width,
125
- handleMouseDown,
126
- isDragging,
127
- isAtEdge,
128
- };
129
- };
1
+ import { useCallback, useEffect, useRef, useState } from 'react';
2
+
3
+ interface UseResizableWidthOptions {
4
+ /** 宽度范围 [min, max],单位 px */
5
+ range: [number, number];
6
+ /** 初始宽度,未指定时取 range 上限 */
7
+ initialWidth?: number;
8
+ /** 反转拖拽方向:拖拽鼠标向右时宽度减小而非增大 */
9
+ invertDrag?: boolean;
10
+ /** localStorage 键名,用于持久化用户拖拽偏好。提供后会在 mount 时读取、drag end 时保存 */
11
+ storageKey?: string;
12
+ }
13
+
14
+ interface UseResizableWidthResult {
15
+ /** 当前宽度 */
16
+ width: number;
17
+ /** 拖拽手柄的 onMouseDown 处理器 */
18
+ handleMouseDown: (e: React.MouseEvent) => void;
19
+ /** 是否正在拖拽 */
20
+ isDragging: boolean;
21
+ /** 是否到达边缘(最小或最大值) */
22
+ isAtEdge: boolean;
23
+ }
24
+
25
+ /**
26
+ * 支持通过拖拽调整宽度的 Hook
27
+ * @param options 配置项:宽度范围、初始宽度
28
+ * @returns 当前宽度、拖拽处理器、拖拽状态
29
+ */
30
+ export const useResizableWidth = ({
31
+ range,
32
+ initialWidth,
33
+ invertDrag,
34
+ storageKey,
35
+ }: UseResizableWidthOptions): UseResizableWidthResult => {
36
+ const [minWidth, maxWidth] = range;
37
+
38
+ const resolveInitialWidth = (): number => {
39
+ if (storageKey) {
40
+ try {
41
+ const stored = localStorage.getItem(storageKey);
42
+ if (stored !== null) {
43
+ const parsed = Number(stored);
44
+ if (!Number.isNaN(parsed) && parsed >= minWidth && parsed <= maxWidth) {
45
+ return parsed;
46
+ }
47
+ }
48
+ } catch { /* localStorage unavailable */ }
49
+ }
50
+ return initialWidth ?? maxWidth;
51
+ };
52
+
53
+ const [width, setWidth] = useState<number>(resolveInitialWidth);
54
+ const [isDragging, setIsDragging] = useState(false);
55
+
56
+ const stateRef = useRef({
57
+ startX: 0,
58
+ startWidth: 0,
59
+ });
60
+
61
+ const handleMouseMove = useCallback(
62
+ (e: MouseEvent) => {
63
+ const delta = e.clientX - stateRef.current.startX;
64
+ const adjustedDelta = invertDrag ? -delta : delta;
65
+ const newWidth = Math.min(
66
+ Math.max(stateRef.current.startWidth + adjustedDelta, minWidth),
67
+ maxWidth
68
+ );
69
+
70
+ setWidth(newWidth);
71
+ },
72
+ [minWidth, maxWidth, invertDrag]
73
+ );
74
+
75
+ const hasDraggedRef = useRef(false);
76
+
77
+ const handleMouseUp = useCallback(() => {
78
+ setIsDragging(false);
79
+ hasDraggedRef.current = true;
80
+ document.body.style.userSelect = '';
81
+ document.removeEventListener('mousemove', handleMouseMove);
82
+ document.removeEventListener('mouseup', handleMouseUp);
83
+
84
+ window.dispatchEvent(new Event('resize'));
85
+ document.body.style.cursor = '';
86
+ }, [handleMouseMove]);
87
+
88
+ // Persist width to localStorage after drag ends
89
+ useEffect(() => {
90
+ if (!isDragging && hasDraggedRef.current && storageKey) {
91
+ try { localStorage.setItem(storageKey, String(width)); } catch { /* unavailable */ }
92
+ }
93
+ }, [isDragging, storageKey, width]);
94
+
95
+ const handleMouseDown = useCallback(
96
+ (e: React.MouseEvent) => {
97
+ setIsDragging(true);
98
+ stateRef.current = {
99
+ startX: e.clientX,
100
+ startWidth: width,
101
+ };
102
+ document.body.style.userSelect = 'none';
103
+ document.addEventListener('mousemove', handleMouseMove);
104
+ document.addEventListener('mouseup', handleMouseUp);
105
+
106
+ document.body.style.cursor = 'col-resize'; // 设置全局拖拽光标
107
+ },
108
+ [width, handleMouseMove, handleMouseUp]
109
+ );
110
+
111
+ useEffect(() => {
112
+ return () => {
113
+ document.removeEventListener('mousemove', handleMouseMove);
114
+ document.removeEventListener('mouseup', handleMouseUp);
115
+ document.body.style.userSelect = '';
116
+
117
+ document.body.style.cursor = ''; // 清理光标样式
118
+ };
119
+ }, [handleMouseMove, handleMouseUp]);
120
+
121
+ const isAtEdge = width === minWidth || width === maxWidth;
122
+
123
+ return {
124
+ width,
125
+ handleMouseDown,
126
+ isDragging,
127
+ isAtEdge,
128
+ };
129
+ };
@@ -1,74 +1,74 @@
1
- import { useState, useCallback } from 'react';
2
-
3
- interface UseSelectPopoverPositionOptions {
4
- estimatedHeight?: number;
5
- gap?: number;
6
- minWidth?: number;
7
- zIndex?: number;
8
- }
9
-
10
- export function useSelectPopoverPosition(
11
- triggerRef: React.RefObject<HTMLElement | null>,
12
- options?: UseSelectPopoverPositionOptions,
13
- ): {
14
- popoverStyle: React.CSSProperties;
15
- updatePopoverPosition: () => void;
16
- };
17
-
18
- export function useSelectPopoverPosition(
19
- getTrigger: () => HTMLElement | null,
20
- options?: UseSelectPopoverPositionOptions,
21
- ): {
22
- popoverStyle: React.CSSProperties;
23
- updatePopoverPosition: () => void;
24
- };
25
-
26
- export function useSelectPopoverPosition(
27
- triggerRefOrGetter:
28
- | React.RefObject<HTMLElement | null>
29
- | (() => HTMLElement | null),
30
- options: UseSelectPopoverPositionOptions = {},
31
- ) {
32
- const {
33
- estimatedHeight = 450,
34
- gap = 4,
35
- minWidth = 240,
36
- zIndex = 9999,
37
- } = options;
38
-
39
- const [popoverStyle, setPopoverStyle] = useState<React.CSSProperties>({});
40
-
41
- const getTrigger: () => HTMLElement | null =
42
- typeof triggerRefOrGetter === 'function'
43
- ? triggerRefOrGetter
44
- : () => triggerRefOrGetter.current;
45
-
46
- const updatePopoverPosition = useCallback(() => {
47
- const trigger = getTrigger();
48
- if (!trigger) return;
49
-
50
- const rect = trigger.getBoundingClientRect();
51
- const spaceBelow = window.innerHeight - rect.bottom - gap;
52
- const spaceAbove = rect.top - gap;
53
- const positionBelow =
54
- spaceBelow >= estimatedHeight || spaceBelow >= spaceAbove;
55
-
56
- setPopoverStyle({
57
- position: 'fixed',
58
- top: positionBelow ? rect.bottom + gap : undefined,
59
- bottom: positionBelow
60
- ? undefined
61
- : window.innerHeight - rect.top + gap,
62
- left: rect.left,
63
- minWidth: Math.max(rect.width, minWidth),
64
- maxHeight: Math.min(
65
- estimatedHeight,
66
- positionBelow ? spaceBelow : spaceAbove,
67
- ),
68
- zIndex,
69
- pointerEvents: 'auto',
70
- });
71
- }, [getTrigger, estimatedHeight, gap, minWidth, zIndex]);
72
-
73
- return { popoverStyle, updatePopoverPosition } as const;
74
- }
1
+ import { useState, useCallback } from 'react';
2
+
3
+ interface UseSelectPopoverPositionOptions {
4
+ estimatedHeight?: number;
5
+ gap?: number;
6
+ minWidth?: number;
7
+ zIndex?: number;
8
+ }
9
+
10
+ export function useSelectPopoverPosition(
11
+ triggerRef: React.RefObject<HTMLElement | null>,
12
+ options?: UseSelectPopoverPositionOptions,
13
+ ): {
14
+ popoverStyle: React.CSSProperties;
15
+ updatePopoverPosition: () => void;
16
+ };
17
+
18
+ export function useSelectPopoverPosition(
19
+ getTrigger: () => HTMLElement | null,
20
+ options?: UseSelectPopoverPositionOptions,
21
+ ): {
22
+ popoverStyle: React.CSSProperties;
23
+ updatePopoverPosition: () => void;
24
+ };
25
+
26
+ export function useSelectPopoverPosition(
27
+ triggerRefOrGetter:
28
+ | React.RefObject<HTMLElement | null>
29
+ | (() => HTMLElement | null),
30
+ options: UseSelectPopoverPositionOptions = {},
31
+ ) {
32
+ const {
33
+ estimatedHeight = 450,
34
+ gap = 4,
35
+ minWidth = 240,
36
+ zIndex = 9999,
37
+ } = options;
38
+
39
+ const [popoverStyle, setPopoverStyle] = useState<React.CSSProperties>({});
40
+
41
+ const getTrigger: () => HTMLElement | null =
42
+ typeof triggerRefOrGetter === 'function'
43
+ ? triggerRefOrGetter
44
+ : () => triggerRefOrGetter.current;
45
+
46
+ const updatePopoverPosition = useCallback(() => {
47
+ const trigger = getTrigger();
48
+ if (!trigger) return;
49
+
50
+ const rect = trigger.getBoundingClientRect();
51
+ const spaceBelow = window.innerHeight - rect.bottom - gap;
52
+ const spaceAbove = rect.top - gap;
53
+ const positionBelow =
54
+ spaceBelow >= estimatedHeight || spaceBelow >= spaceAbove;
55
+
56
+ setPopoverStyle({
57
+ position: 'fixed',
58
+ top: positionBelow ? rect.bottom + gap : undefined,
59
+ bottom: positionBelow
60
+ ? undefined
61
+ : window.innerHeight - rect.top + gap,
62
+ left: rect.left,
63
+ minWidth: Math.max(rect.width, minWidth),
64
+ maxHeight: Math.min(
65
+ estimatedHeight,
66
+ positionBelow ? spaceBelow : spaceAbove,
67
+ ),
68
+ zIndex,
69
+ pointerEvents: 'auto',
70
+ });
71
+ }, [getTrigger, estimatedHeight, gap, minWidth, zIndex]);
72
+
73
+ return { popoverStyle, updatePopoverPosition } as const;
74
+ }
@@ -1,127 +1,127 @@
1
- import { useState, useEffect, useRef } from 'react';
2
-
3
- interface UseShadowOptions {
4
- /** Shadow DOM挂载的根元素(默认挂到body) */
5
- rootEl?: HTMLElement;
6
- /** 要注入到Shadow DOM中的样式文本 */
7
- style?: string;
8
- /** Shadow内部容器的类名 */
9
- containerClasses?: string[];
10
- /** 包裹Shadow的外层元素类名 */
11
- wrapperClasses?: string[];
12
- /** 包裹元素的内联样式 */
13
- wrapperStyle?: React.CSSProperties;
14
-
15
- extraHtml?: string;
16
-
17
- id: string;
18
- }
19
-
20
- /**
21
- * 通用的创建Shadow DOM的Hook
22
- * @param options 配置项:样式、根元素、类名等
23
- * @returns Shadow DOM内部的容器元素(用于React Portal挂载)
24
- */
25
- export const useShadow = ({
26
- id,
27
- style = '',
28
- rootEl,
29
- containerClasses = [],
30
- wrapperClasses = [],
31
- wrapperStyle = {},
32
- extraHtml = '',
33
- }: UseShadowOptions): { shadowContainer: HTMLElement | null; destroy: () => void } => {
34
- const [shadowContainer, setShadowContainer] = useState<HTMLElement | null>(null);
35
- const wrapperRef = useRef<HTMLDivElement | null>(null);
36
-
37
- useEffect(() => {
38
- wrapperRef.current?.classList.add(...wrapperClasses);
39
- shadowContainer?.classList.add(...containerClasses);
40
- }, [wrapperClasses, containerClasses]);
41
-
42
- useEffect(() => {
43
- if (wrapperRef.current) {
44
- Object.entries(wrapperStyle).forEach(([key, value]) => {
45
- if (value !== undefined) {
46
- // @ts-ignore
47
- wrapperRef.current!.style[key as any] = value;
48
- }
49
- });
50
- }
51
- }, [wrapperStyle]);
52
-
53
- useEffect(() => {
54
- // Cleanup previous shadow container if it exists
55
- if (wrapperRef.current && wrapperRef.current.parentNode) {
56
- wrapperRef.current.parentNode.removeChild(wrapperRef.current);
57
- wrapperRef.current = null;
58
- }
59
-
60
- try {
61
- // 1. 创建外层包裹元素(挂载Shadow Root的载体)
62
- const wrapperEl = document.createElement('div');
63
- wrapperEl.classList.add(...wrapperClasses, 'wrapper');
64
- // wrapperEl.style.height = '100%';
65
- wrapperRef.current = wrapperEl;
66
-
67
- // apply wrapper styles
68
- Object.entries(wrapperStyle).forEach(([key, value]) => {
69
- if (value !== undefined) {
70
- // @ts-ignore
71
- wrapperEl.style[key as any] = value;
72
- }
73
- });
74
-
75
- // 2. 创建并挂载Shadow Root
76
- const shadowRoot = wrapperEl.attachShadow({ mode: 'open' });
77
-
78
- // 注入额外的HTML内容
79
- if (extraHtml) {
80
- shadowRoot.innerHTML = extraHtml;
81
- }
82
-
83
- // 3. 注入样式到Shadow DOM
84
- if (style) {
85
- const styleEl = document.createElement('style');
86
- styleEl.textContent = style;
87
- shadowRoot.appendChild(styleEl);
88
- }
89
-
90
- // 4. 创建Shadow内部的容器(最终挂载React Portal的元素)
91
- const containerEl = document.createElement('div');
92
- containerEl.classList.add(...containerClasses, 'shadow-container');
93
- shadowRoot.appendChild(containerEl);
94
-
95
- // 5. 将外层元素挂载到指定根节点
96
- const mountRoot = rootEl || document.body;
97
- mountRoot.appendChild(wrapperEl);
98
-
99
- setShadowContainer(containerEl);
100
- } catch (error) {
101
- console.error('创建Shadow DOM失败:', error);
102
- setShadowContainer(null);
103
- }
104
-
105
- // Cleanup on unmount or when rootEl changes
106
- // return () => {
107
- // if (wrapperRef.current && wrapperRef.current.parentNode) {
108
- // wrapperRef.current.parentNode.removeChild(wrapperRef.current);
109
- // wrapperRef.current = null;
110
- // }
111
- // };
112
- }, [rootEl]); // Recreate when rootEl changes
113
-
114
- if (shadowContainer) {
115
- shadowContainer.id = id;
116
- }
117
-
118
- return {
119
- shadowContainer,
120
- destroy: () => {
121
- if (wrapperRef.current && wrapperRef.current.parentNode) {
122
- wrapperRef.current.parentNode.removeChild(wrapperRef.current);
123
- wrapperRef.current = null;
124
- }
125
- },
126
- };
127
- };
1
+ import { useState, useEffect, useRef } from 'react';
2
+
3
+ interface UseShadowOptions {
4
+ /** Shadow DOM挂载的根元素(默认挂到body) */
5
+ rootEl?: HTMLElement;
6
+ /** 要注入到Shadow DOM中的样式文本 */
7
+ style?: string;
8
+ /** Shadow内部容器的类名 */
9
+ containerClasses?: string[];
10
+ /** 包裹Shadow的外层元素类名 */
11
+ wrapperClasses?: string[];
12
+ /** 包裹元素的内联样式 */
13
+ wrapperStyle?: React.CSSProperties;
14
+
15
+ extraHtml?: string;
16
+
17
+ id: string;
18
+ }
19
+
20
+ /**
21
+ * 通用的创建Shadow DOM的Hook
22
+ * @param options 配置项:样式、根元素、类名等
23
+ * @returns Shadow DOM内部的容器元素(用于React Portal挂载)
24
+ */
25
+ export const useShadow = ({
26
+ id,
27
+ style = '',
28
+ rootEl,
29
+ containerClasses = [],
30
+ wrapperClasses = [],
31
+ wrapperStyle = {},
32
+ extraHtml = '',
33
+ }: UseShadowOptions): { shadowContainer: HTMLElement | null; destroy: () => void } => {
34
+ const [shadowContainer, setShadowContainer] = useState<HTMLElement | null>(null);
35
+ const wrapperRef = useRef<HTMLDivElement | null>(null);
36
+
37
+ useEffect(() => {
38
+ wrapperRef.current?.classList.add(...wrapperClasses);
39
+ shadowContainer?.classList.add(...containerClasses);
40
+ }, [wrapperClasses, containerClasses]);
41
+
42
+ useEffect(() => {
43
+ if (wrapperRef.current) {
44
+ Object.entries(wrapperStyle).forEach(([key, value]) => {
45
+ if (value !== undefined) {
46
+ // @ts-ignore
47
+ wrapperRef.current!.style[key as any] = value;
48
+ }
49
+ });
50
+ }
51
+ }, [wrapperStyle]);
52
+
53
+ useEffect(() => {
54
+ // Cleanup previous shadow container if it exists
55
+ if (wrapperRef.current && wrapperRef.current.parentNode) {
56
+ wrapperRef.current.parentNode.removeChild(wrapperRef.current);
57
+ wrapperRef.current = null;
58
+ }
59
+
60
+ try {
61
+ // 1. 创建外层包裹元素(挂载Shadow Root的载体)
62
+ const wrapperEl = document.createElement('div');
63
+ wrapperEl.classList.add(...wrapperClasses, 'wrapper');
64
+ // wrapperEl.style.height = '100%';
65
+ wrapperRef.current = wrapperEl;
66
+
67
+ // apply wrapper styles
68
+ Object.entries(wrapperStyle).forEach(([key, value]) => {
69
+ if (value !== undefined) {
70
+ // @ts-ignore
71
+ wrapperEl.style[key as any] = value;
72
+ }
73
+ });
74
+
75
+ // 2. 创建并挂载Shadow Root
76
+ const shadowRoot = wrapperEl.attachShadow({ mode: 'open' });
77
+
78
+ // 注入额外的HTML内容
79
+ if (extraHtml) {
80
+ shadowRoot.innerHTML = extraHtml;
81
+ }
82
+
83
+ // 3. 注入样式到Shadow DOM
84
+ if (style) {
85
+ const styleEl = document.createElement('style');
86
+ styleEl.textContent = style;
87
+ shadowRoot.appendChild(styleEl);
88
+ }
89
+
90
+ // 4. 创建Shadow内部的容器(最终挂载React Portal的元素)
91
+ const containerEl = document.createElement('div');
92
+ containerEl.classList.add(...containerClasses, 'shadow-container');
93
+ shadowRoot.appendChild(containerEl);
94
+
95
+ // 5. 将外层元素挂载到指定根节点
96
+ const mountRoot = rootEl || document.body;
97
+ mountRoot.appendChild(wrapperEl);
98
+
99
+ setShadowContainer(containerEl);
100
+ } catch (error) {
101
+ console.error('创建Shadow DOM失败:', error);
102
+ setShadowContainer(null);
103
+ }
104
+
105
+ // Cleanup on unmount or when rootEl changes
106
+ // return () => {
107
+ // if (wrapperRef.current && wrapperRef.current.parentNode) {
108
+ // wrapperRef.current.parentNode.removeChild(wrapperRef.current);
109
+ // wrapperRef.current = null;
110
+ // }
111
+ // };
112
+ }, [rootEl]); // Recreate when rootEl changes
113
+
114
+ if (shadowContainer) {
115
+ shadowContainer.id = id;
116
+ }
117
+
118
+ return {
119
+ shadowContainer,
120
+ destroy: () => {
121
+ if (wrapperRef.current && wrapperRef.current.parentNode) {
122
+ wrapperRef.current.parentNode.removeChild(wrapperRef.current);
123
+ wrapperRef.current = null;
124
+ }
125
+ },
126
+ };
127
+ };