@ticatec/uniface-element 0.2.3 → 0.3.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 (178) hide show
  1. package/dist/accordion/README.md +169 -0
  2. package/dist/accordion/README_CN.md +176 -0
  3. package/dist/action-bar/README.md +275 -0
  4. package/dist/action-bar/README_CN.md +285 -0
  5. package/dist/app-layout/README.md +374 -0
  6. package/dist/app-layout/README_CN.md +381 -0
  7. package/dist/app-top-bar/README.md +357 -0
  8. package/dist/app-top-bar/README_CN.md +365 -0
  9. package/dist/attachment-files/AttachmentFilesField.svelte +67 -1
  10. package/dist/attachment-files/AttachmentFilesField.svelte.d.ts +8 -1
  11. package/dist/base-calendar/CalendarBase.svelte +0 -3
  12. package/dist/box/README.md +385 -0
  13. package/dist/box/README_CN.md +393 -0
  14. package/dist/breadcrumbs/README.md +442 -0
  15. package/dist/breadcrumbs/README_CN.md +442 -0
  16. package/dist/button/Button.svelte +27 -7
  17. package/dist/button/Button.svelte.d.ts +3 -1
  18. package/dist/button/IconButton.svelte +26 -6
  19. package/dist/button/IconButton.svelte.d.ts +3 -1
  20. package/dist/button/IconButton_README.md +513 -0
  21. package/dist/button/IconButton_README_CN.md +513 -0
  22. package/dist/button/README.md +428 -0
  23. package/dist/button/README_CN.md +428 -0
  24. package/dist/button/TextButton.svelte +26 -6
  25. package/dist/button/TextButton.svelte.d.ts +3 -1
  26. package/dist/button/TextButton_README.md +571 -0
  27. package/dist/button/TextButton_README_CN.md +571 -0
  28. package/dist/card/README.md +666 -0
  29. package/dist/card/README_CN.md +666 -0
  30. package/dist/cascade-options-select/CascadeOptionSelect.svelte +43 -7
  31. package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +3 -4
  32. package/dist/cascade-options-select/README.md +663 -2
  33. package/dist/cascade-options-select/README_CN.md +664 -0
  34. package/dist/checkbox/CheckBox.svelte +20 -6
  35. package/dist/checkbox/CheckBox.svelte.d.ts +4 -2
  36. package/dist/checkbox/README.md +562 -0
  37. package/dist/checkbox/README_CN.md +727 -0
  38. package/dist/common-editor/NumberInput.svelte +39 -26
  39. package/dist/common-editor/NumberInput.svelte.d.ts +5 -1
  40. package/dist/concise-data-table/ConciseListTable.svelte +133 -36
  41. package/dist/concise-data-table/ConciseListTable.svelte.d.ts +8 -1
  42. package/dist/concise-data-table/DataCell.svelte +5 -6
  43. package/dist/concise-data-table/DataRow.svelte +22 -2
  44. package/dist/concise-data-table/DataRow.svelte.d.ts +1 -0
  45. package/dist/concise-data-table/README.md +606 -0
  46. package/dist/concise-data-table/README_CN.md +611 -0
  47. package/dist/context-menu/ContextMenu.svelte +138 -21
  48. package/dist/context-menu/ContextMenu.svelte.d.ts +5 -0
  49. package/dist/context-menu/ContextMenuItem.d.ts +20 -4
  50. package/dist/context-menu/README.md +551 -0
  51. package/dist/context-menu/README_CN.md +551 -0
  52. package/dist/criteria-field/CriteriaField.svelte +3 -5
  53. package/dist/criteria-field/README.md +532 -0
  54. package/dist/criteria-field/README_CN.md +532 -0
  55. package/dist/data-table/README.md +712 -0
  56. package/dist/data-table/README_CN.md +712 -0
  57. package/dist/date-picker/DatePicker.svelte +44 -7
  58. package/dist/date-picker/DatePicker.svelte.d.ts +3 -4
  59. package/dist/date-picker/DateTimePicker.svelte +32 -8
  60. package/dist/date-picker/DateTimePicker.svelte.d.ts +3 -4
  61. package/dist/date-picker/README.md +326 -0
  62. package/dist/date-picker/README_CN.md +316 -0
  63. package/dist/date-picker/ScrollBar.svelte +18 -8
  64. package/dist/date-picker/ScrollBar.svelte.d.ts +1 -1
  65. package/dist/date-picker/TimePanel.svelte +5 -5
  66. package/dist/date-picker/TimePanel.svelte.d.ts +1 -1
  67. package/dist/date-range/README.md +374 -0
  68. package/dist/date-range/README_CN.md +374 -0
  69. package/dist/dialog/DialogBoard.svelte +1 -1
  70. package/dist/dialog/README.md +596 -0
  71. package/dist/dialog/README_CN.md +596 -0
  72. package/dist/drawer/README.md +679 -1
  73. package/dist/drawer/README_CN.md +679 -0
  74. package/dist/group-box/group-check-box/GroupCheckBox.svelte +62 -5
  75. package/dist/group-box/group-check-box/GroupCheckBox.svelte.d.ts +7 -2
  76. package/dist/group-box/group-check-box/README.md +749 -0
  77. package/dist/group-box/group-check-box/README_CN.md +750 -0
  78. package/dist/group-box/group-radio-box/GroupRadioBox.svelte +69 -4
  79. package/dist/group-box/group-radio-box/GroupRadioBox.svelte.d.ts +8 -2
  80. package/dist/group-box/group-radio-box/README.md +920 -0
  81. package/dist/group-box/group-radio-box/README_CN.md +920 -0
  82. package/dist/image-files/README.md +1346 -0
  83. package/dist/image-files/README_CN.md +1346 -0
  84. package/dist/input-options-select/InputOptionsSelect.svelte +161 -65
  85. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +4 -1
  86. package/dist/lib/forwardAllEvents.d.ts +3 -0
  87. package/dist/lib/forwardAllEvents.js +24 -0
  88. package/dist/list-box/README.md +579 -0
  89. package/dist/list-box/README_CN.md +682 -0
  90. package/dist/lookup-editor/LookupEditor.svelte +15 -3
  91. package/dist/lookup-editor/LookupEditor.svelte.d.ts +3 -4
  92. package/dist/lookup-editor/README.md +684 -0
  93. package/dist/lookup-editor/README_CN.md +684 -0
  94. package/dist/memo-editor/MemoEditor.svelte +77 -27
  95. package/dist/memo-editor/MemoEditor.svelte.d.ts +6 -3
  96. package/dist/memo-editor/README.md +819 -0
  97. package/dist/memo-editor/README_CN.md +819 -0
  98. package/dist/message-box/README.md +398 -0
  99. package/dist/message-box/README_CN.md +398 -0
  100. package/dist/number-editor/NumberEditor.svelte +2 -2
  101. package/dist/number-editor/NumberEditor.svelte.d.ts +1 -1
  102. package/dist/number-editor/README.md +353 -22
  103. package/dist/number-editor/README_CN.md +357 -0
  104. package/dist/number-range/README.md +443 -0
  105. package/dist/number-range/README_CN.md +443 -0
  106. package/dist/options-multi-select/OptionsMultiSelect.svelte +87 -12
  107. package/dist/options-multi-select/OptionsMultiSelect.svelte.d.ts +3 -1
  108. package/dist/options-multi-select/README.md +480 -0
  109. package/dist/options-multi-select/README_CN.md +480 -0
  110. package/dist/options-select/OptionsSelect.svelte +36 -5
  111. package/dist/options-select/OptionsSelect.svelte.d.ts +3 -4
  112. package/dist/options-select/README.md +632 -0
  113. package/dist/options-select/README_CN.md +632 -0
  114. package/dist/page/README.md +605 -0
  115. package/dist/page/README_CN.md +605 -0
  116. package/dist/pagination/README.md +946 -0
  117. package/dist/pagination/README_CN.md +946 -0
  118. package/dist/pagination-panel/README.md +1075 -0
  119. package/dist/pagination-panel/README_CN.md +1075 -0
  120. package/dist/popup-hint/README.md +841 -0
  121. package/dist/popup-hint/README_CN.md +840 -0
  122. package/dist/progress-bar/README.md +242 -0
  123. package/dist/progress-bar/README_CN.md +242 -0
  124. package/dist/progress-step-bar/README.md +316 -0
  125. package/dist/progress-step-bar/README_CN.md +316 -0
  126. package/dist/prompts-text-editor/PromptsTextEditor.svelte +6 -3
  127. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +3 -1
  128. package/dist/prompts-text-editor/README.md +329 -0
  129. package/dist/prompts-text-editor/README_CN.md +329 -0
  130. package/dist/property-editor/README.md +969 -0
  131. package/dist/property-editor/README_CN.md +969 -0
  132. package/dist/radio-button/README.md +372 -0
  133. package/dist/radio-button/README_CN.md +372 -0
  134. package/dist/radio-button/RadioButton.svelte +32 -3
  135. package/dist/radio-button/RadioButton.svelte.d.ts +12 -1
  136. package/dist/search-box/README.md +425 -0
  137. package/dist/search-box/README_CN.md +424 -0
  138. package/dist/search-box/SearchBox.svelte +22 -6
  139. package/dist/search-box/SearchBox.svelte.d.ts +4 -1
  140. package/dist/tabs/README.md +919 -0
  141. package/dist/tabs/README_CN.md +920 -0
  142. package/dist/tag/README.md +922 -0
  143. package/dist/tag/README_CN.md +922 -0
  144. package/dist/text-editor/PasswordEditor.svelte +17 -2
  145. package/dist/text-editor/PasswordEditor.svelte.d.ts +3 -3
  146. package/dist/text-editor/PasswordEditor_README.md +551 -0
  147. package/dist/text-editor/PasswordEditor_README_CN.md +551 -0
  148. package/dist/text-editor/README.md +466 -0
  149. package/dist/text-editor/README_CN.md +466 -0
  150. package/dist/text-editor/TextEditor.svelte +51 -19
  151. package/dist/text-editor/TextEditor.svelte.d.ts +0 -1
  152. package/dist/ticatec-uniface-web.css +1 -0
  153. package/dist/time-editor/README.md +498 -24
  154. package/dist/time-editor/README_CN.md +498 -0
  155. package/dist/time-editor/TimeEditor.svelte +7 -3
  156. package/dist/time-editor/TimeEditor.svelte.d.ts +3 -1
  157. package/dist/toast/README.md +667 -0
  158. package/dist/toast/README_CN.md +667 -0
  159. package/dist/transfer/README.md +795 -0
  160. package/dist/transfer/Transfer.svelte +6 -4
  161. package/dist/transfer/Transfer.svelte.d.ts +3 -1
  162. package/dist/tree-view/README.md +761 -0
  163. package/dist/tree-view/README_CN.md +761 -0
  164. package/dist/tree-view/TreeView.svelte +5 -3
  165. package/dist/tree-view/TreeView.svelte.d.ts +3 -1
  166. package/dist/unit-number-editor/README.md +546 -20
  167. package/dist/unit-number-editor/README_CN.md +525 -0
  168. package/dist/unit-number-editor/UnitNumberEditor.svelte +62 -8
  169. package/dist/unit-number-editor/UnitNumberEditor.svelte.d.ts +5 -1
  170. package/docs/form-field/cn/README_CN.md +364 -0
  171. package/docs/form-field/en/README.md +364 -0
  172. package/docs/form-panel/flex-form/cn/README_CN.md +586 -0
  173. package/docs/form-panel/flex-form/en/README.md +586 -0
  174. package/docs/form-panel/flex-row-form/cn/README_CN.md +787 -0
  175. package/docs/form-panel/flex-row-form/en/README.md +787 -0
  176. package/docs/form-panel/grid-form/en/README.md +744 -0
  177. package/package.json +1 -1
  178. package/dist/drawer/README-CN.md +0 -1
@@ -3,11 +3,9 @@
3
3
  import {DisplayMode} from "../common/DisplayMode";
4
4
  import type {OnChangeHandler} from "../common/OnChangeHandler";
5
5
  import {tick} from "svelte";
6
- import type {LazyLoader} from "../list-box/types"
7
- import i18nRes from "../i18nRes";
8
-
9
- import loading from "../assets/loading.gif"
10
6
  import CommonPicker from "../common/CommonPicker.svelte";
7
+ import loadingGif from "../assets/loading.gif";
8
+ import type {LazyLoader} from "../list-box/types";
11
9
 
12
10
  export let variant: '' | 'plain' | 'outlined' | 'filled' = '';
13
11
  export let disabled: boolean = false;
@@ -22,84 +20,157 @@
22
20
  export let placeholder: string = "";
23
21
  export let displayMode: DisplayMode = DisplayMode.Edit;
24
22
  export let itemRender: any = null;
25
- export let onChange: OnChangeHandler<any> = null as unknown as OnChangeHandler<any>;
23
+ export let onchange: OnChangeHandler<any> = null as unknown as OnChangeHandler<any>;
24
+ export let oninput: OnChangeHandler<string> = null as unknown as OnChangeHandler<string>;
25
+ export let onfocus: (() => void) | null = null;
26
+ export let onblur: (() => void) | null = null;
26
27
  export let lazyLoader: LazyLoader = null as unknown as LazyLoader;
27
28
 
28
29
  let editor: any;
29
30
  let inputText: string;
30
31
  let oldValue: any = value;
31
- let options: Array<any> = [];
32
32
  let scrollElement: any;
33
-
33
+ let options: Array<any> = [];
34
+
34
35
  let idleTime = 0;
35
36
  let interval: any;
36
37
  let pageNo: number;
37
38
  let isBusy: boolean;
38
39
  let hasMore: boolean;
40
+ let loading: boolean = false;
41
+ let loadingController: AbortController | null = null;
39
42
 
40
43
  const handleInputText = () => {
41
- if ((text ?? '').trim().length > 0 && lazyLoader != null) {
42
- if (interval == null) {
43
- idleTime = 0;
44
- interval = setInterval(delayReload, 50)
45
- } else {
46
- idleTime = 0;
47
- }
44
+ if (lazyLoader != null) {
45
+ delayReload();
48
46
  }
49
47
  }
50
- const lazyLoad = async (clean: boolean = true) => {
51
- console.log('开始读取数据...', text)
52
- isBusy = true;
48
+
49
+ const lazyLoad = async (searchText: string, page: number, isLoadMore: boolean = false) => {
50
+ // 取消之前的加载请求
51
+ if (loadingController) {
52
+ loadingController.abort();
53
+ }
54
+
55
+ // 创建新的AbortController
56
+ loadingController = new AbortController();
57
+ const currentController = loadingController;
58
+
59
+ loading = true;
60
+ if (!isLoadMore) {
61
+ isBusy = true;
62
+ }
63
+
53
64
  try {
54
- let result = await lazyLoader?.(text, pageNo);
55
- if (result) {
56
- if (clean) {
57
- options = result.list;
58
- } else {
59
- options = [...options, ...result.list];
60
- }
61
- hasMore = result.hasMore;
65
+ let res = await lazyLoader(searchText, page);
66
+
67
+ // 检查请求是否被取消
68
+ if (currentController.signal.aborted) {
69
+ return;
70
+ }
71
+
72
+ if (page == 1) {
73
+ options = res.list;
74
+ } else {
75
+ options = [...options, ...res.list];
76
+ }
77
+ hasMore = res.hasMore;
78
+ pageNo = page;
79
+ } catch (e) {
80
+ // 如果是取消请求的错误,忽略它
81
+ if (currentController.signal.aborted) {
82
+ return;
83
+ }
84
+ console.error('LazyLoader error:', e);
85
+ if (page == 1) {
86
+ options = [];
87
+ hasMore = false;
62
88
  }
63
- showPopup = true;
64
89
  } finally {
65
- isBusy = false;
90
+ // 只有当前请求没有被取消时才更新loading状态
91
+ if (!currentController.signal.aborted) {
92
+ loading = false;
93
+ isBusy = false;
94
+ loadingController = null;
95
+ }
66
96
  }
67
97
  }
68
98
 
69
- const delayReload = async () => {
70
- idleTime++;
71
- if (idleTime > 10) {
99
+ const delayReload = () => {
100
+ // 取消之前的延迟加载
101
+ if (interval) {
72
102
  clearInterval(interval);
73
- interval = null;
74
- pageNo = 1;
75
- if (showPopup) {
76
- scrollElement.scrollTop = 0;
103
+ }
104
+
105
+ // 取消当前正在进行的加载
106
+ if (loadingController) {
107
+ loadingController.abort();
108
+ loadingController = null;
109
+ loading = false;
110
+ isBusy = false;
111
+ }
112
+
113
+ // 重置状态
114
+ options = [];
115
+ hasMore = false;
116
+
117
+ // 设置新的延迟加载
118
+ idleTime = 0;
119
+ interval = setInterval(() => {
120
+ idleTime += 100;
121
+ if (idleTime >= 500) {
122
+ clearInterval(interval);
123
+ lazyLoad(text, 1, false);
77
124
  }
78
- await lazyLoad();
79
- await tick();
80
- editor.focus();
125
+ }, 100);
126
+ }
127
+
128
+ const loadMore = () => {
129
+ if (hasMore && !isBusy) {
130
+ lazyLoad(text, pageNo + 1, true);
131
+ }
132
+ }
133
+
134
+ const handleScroll = (event: Event) => {
135
+ const target = event.target as HTMLElement;
136
+ const scrollTop = target.scrollTop;
137
+ const scrollHeight = target.scrollHeight;
138
+ const clientHeight = target.clientHeight;
139
+
140
+ console.log('Scroll event:', { scrollTop, scrollHeight, clientHeight, hasMore, isBusy });
141
+
142
+ // 当滚动到距离底部20px以内时,自动加载下一页
143
+ if (scrollTop + clientHeight >= scrollHeight - 20 && hasMore && !isBusy) {
144
+ console.log('Auto loading more...');
145
+ loadMore();
81
146
  }
82
147
  }
83
148
 
84
149
  const handleItemClick = (data: any) => () => {
150
+ isUserTyping = false;
85
151
  value = data[keyField];
86
152
  text = data[textField];
87
153
  if (value != oldValue) {
88
- onChange?.(data);
154
+ onchange?.(data);
89
155
  }
90
156
  editor.focus();
91
157
  showPopup = false;
92
158
  }
93
159
 
94
160
  let composing: boolean = false;
161
+ let hasFocus: boolean = false;
162
+ let isUserTyping: boolean = false;
95
163
 
96
164
  const handleInput = () => {
97
- if (composing == false) {
165
+ if (!composing) {
166
+ isUserTyping = true;
98
167
  text = inputText;
99
168
  value = null;
169
+ oninput?.(text);
100
170
  handleInputText();
101
171
  }
102
172
  };
173
+
103
174
  const handleCompositionStart = (event: CompositionEvent) => {
104
175
  composing = true;
105
176
  };
@@ -108,13 +179,28 @@
108
179
  composing = false;
109
180
  text = inputText;
110
181
  value = null;
182
+ oninput?.(text);
111
183
  handleInputText();
112
184
  };
113
185
 
186
+ const handleFocus = () => {
187
+ if (!hasFocus) {
188
+ hasFocus = true;
189
+ onfocus?.();
190
+ }
191
+ };
192
+
193
+ const handleBlur = (event: FocusEvent) => {
194
+ if (!showPopup) {
195
+ hasFocus = false;
196
+ onblur?.();
197
+ }
198
+ };
199
+
114
200
  const clean = () => {
115
201
  value = null;
116
202
  text = '';
117
- onChange?.(value);
203
+ onchange?.(value);
118
204
  showPopup = false;
119
205
  editor.focus();
120
206
  }
@@ -123,24 +209,43 @@
123
209
 
124
210
  let mh;
125
211
 
126
- $: mh = `min-height: 80px; height: ${menu$height > 0 ? menu$height + 'px' : 'auto'}`;
212
+ $: mh = `min-height: 80px; ${menu$height > 0 ? 'height: ' + menu$height + 'px;' : 'max-height: 300px;'} overflow-y: auto;`;
127
213
 
128
- $: showPopup = options && options.length > 0;
214
+ $: showPopup = (options && options.length > 0) || loading;
129
215
 
130
- $: inputText = text;
131
-
132
- const loadMore = async () => {
133
- editor.focus();
134
- if (lazyLoader != null && !isBusy && hasMore) {
135
- pageNo++;
136
- await lazyLoad(false);
216
+ $: {
217
+ // 不要在用户正在输入时更新inputText
218
+ if (!isUserTyping) {
219
+ if (value == null) {
220
+ inputText = text;
221
+ } else {
222
+ // 如果已选择值,根据焦点状态显示keyField或textField
223
+ let selectedItem = options.find(op => op[keyField] == value);
224
+ if (selectedItem) {
225
+ inputText = hasFocus ? selectedItem[keyField] : selectedItem[textField];
226
+ } else {
227
+ inputText = hasFocus ? value : text;
228
+ }
229
+ }
137
230
  }
138
231
  }
139
232
 
140
- $: if (!showPopup && value == null) {
233
+
234
+ $: if (!showPopup && value == null && !isUserTyping) {
141
235
  text = '';
142
236
  }
143
237
 
238
+ // 监听popup关闭,如果是点击外部关闭且之前有焦点,触发blur
239
+ $: if (!showPopup && hasFocus) {
240
+ // 延迟检查,如果input仍然有焦点,说明是选择项目导致的关闭
241
+ setTimeout(() => {
242
+ if (document.activeElement !== editor) {
243
+ hasFocus = false;
244
+ onblur?.();
245
+ }
246
+ }, 50);
247
+ }
248
+
144
249
 
145
250
  </script>
146
251
  <!-- 待解决浏览模式显示的问题 -->
@@ -148,17 +253,18 @@
148
253
  <CommonPicker {displayMode} {variant} {style} {compact}
149
254
  bind:showPopup canClean={value!=null} autoFit {clean} textValue={text} {readonly} {disabled}>
150
255
  <input style="width: 100%" bind:this={editor} {placeholder}
151
- class="text-editor" bind:value={inputText} readonly={isBusy}
256
+ class="text-editor" bind:value={inputText} {readonly}
152
257
  on:input={handleInput}
153
- on:compositionstart={handleCompositionStart} on:compositionend={handleCompositionEnd}/>
154
- {#if isBusy}
258
+ on:compositionstart={handleCompositionStart} on:compositionend={handleCompositionEnd}
259
+ on:focus={handleFocus} on:blur={handleBlur}/>
260
+ {#if loading}
155
261
  <div style="position: absolute; top: 0px; bottom: 0px; right: 8px">
156
262
  <div style="position: relative; top: 50%; transform: translateY(-50%)">
157
- <img src={loading} alt="loading" width="16" height="16"/>
263
+ <img src={loadingGif} alt="loading" width="16" height="16"/>
158
264
  </div>
159
265
  </div>
160
266
  {/if}
161
- <div class="options-popover" bind:this={scrollElement} style={mh} slot="popup-panel">
267
+ <div class="options-popover" bind:this={scrollElement} style={mh} slot="popup-panel" on:scroll={handleScroll}>
162
268
  {#each options as op}
163
269
  <div class="option-item" on:click={handleItemClick(op)} aria-hidden="true">
164
270
  {#if itemRender != null}
@@ -170,15 +276,5 @@
170
276
  {/if}
171
277
  </div>
172
278
  {/each}
173
- {#if hasMore}
174
- <div class="more-indicator-footer" aria-hidden="true" on:click={loadMore}>
175
- {i18nRes.common.textMore}
176
- </div>
177
- {/if}
178
- {#if isBusy}
179
- <div class="popover-mask-overlay">
180
-
181
- </div>
182
- {/if}
183
279
  </div>
184
280
  </CommonPicker>
@@ -28,7 +28,10 @@ declare const InputOptionsSelect: $$__sveltets_2_IsomorphicComponent<{
28
28
  placeholder?: string;
29
29
  displayMode?: DisplayMode;
30
30
  itemRender?: any;
31
- onChange?: OnChangeHandler<any>;
31
+ onchange?: OnChangeHandler<any>;
32
+ oninput?: OnChangeHandler<string>;
33
+ onfocus?: (() => void) | null;
34
+ onblur?: (() => void) | null;
32
35
  lazyLoader?: LazyLoader;
33
36
  }, {
34
37
  [evt: string]: CustomEvent<any>;
@@ -0,0 +1,3 @@
1
+ export declare function forwardAllEvents<T extends HTMLElement>(node: T, props: Record<string, any>, internalHandlers?: Partial<Record<string, (e: Event) => void>>): {
2
+ destroy(): void;
3
+ };
@@ -0,0 +1,24 @@
1
+ // forwardAllEvents.ts
2
+ export function forwardAllEvents(node, props, internalHandlers = {}) {
3
+ const removeFns = [];
4
+ Object.keys(props).forEach(key => {
5
+ if (key.startsWith("on") && typeof props[key] === "function") {
6
+ const eventName = key.slice(2).toLowerCase(); // onblur -> blur
7
+ const externalHandler = props[key];
8
+ const internalHandler = internalHandlers[eventName];
9
+ const listener = (e) => {
10
+ // 先执行内部逻辑
11
+ internalHandler?.(e);
12
+ // 再执行外部逻辑
13
+ externalHandler?.(e);
14
+ };
15
+ node.addEventListener(eventName, listener);
16
+ removeFns.push(() => node.removeEventListener(eventName, listener));
17
+ }
18
+ });
19
+ return {
20
+ destroy() {
21
+ removeFns.forEach(fn => fn());
22
+ }
23
+ };
24
+ }