@ticatec/uniface-element 0.2.4 → 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 (176) 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/README.md +596 -0
  70. package/dist/dialog/README_CN.md +596 -0
  71. package/dist/drawer/README.md +679 -1
  72. package/dist/drawer/README_CN.md +679 -0
  73. package/dist/group-box/group-check-box/GroupCheckBox.svelte +62 -5
  74. package/dist/group-box/group-check-box/GroupCheckBox.svelte.d.ts +7 -2
  75. package/dist/group-box/group-check-box/README.md +749 -0
  76. package/dist/group-box/group-check-box/README_CN.md +750 -0
  77. package/dist/group-box/group-radio-box/GroupRadioBox.svelte +69 -4
  78. package/dist/group-box/group-radio-box/GroupRadioBox.svelte.d.ts +8 -2
  79. package/dist/group-box/group-radio-box/README.md +920 -0
  80. package/dist/group-box/group-radio-box/README_CN.md +920 -0
  81. package/dist/image-files/README.md +1346 -0
  82. package/dist/image-files/README_CN.md +1346 -0
  83. package/dist/input-options-select/InputOptionsSelect.svelte +161 -65
  84. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +4 -1
  85. package/dist/lib/forwardAllEvents.d.ts +3 -0
  86. package/dist/lib/forwardAllEvents.js +24 -0
  87. package/dist/list-box/README.md +579 -0
  88. package/dist/list-box/README_CN.md +682 -0
  89. package/dist/lookup-editor/LookupEditor.svelte +15 -3
  90. package/dist/lookup-editor/LookupEditor.svelte.d.ts +3 -4
  91. package/dist/lookup-editor/README.md +684 -0
  92. package/dist/lookup-editor/README_CN.md +684 -0
  93. package/dist/memo-editor/MemoEditor.svelte +77 -27
  94. package/dist/memo-editor/MemoEditor.svelte.d.ts +6 -3
  95. package/dist/memo-editor/README.md +819 -0
  96. package/dist/memo-editor/README_CN.md +819 -0
  97. package/dist/message-box/README.md +398 -0
  98. package/dist/message-box/README_CN.md +398 -0
  99. package/dist/number-editor/NumberEditor.svelte +2 -2
  100. package/dist/number-editor/NumberEditor.svelte.d.ts +1 -1
  101. package/dist/number-editor/README.md +353 -22
  102. package/dist/number-editor/README_CN.md +357 -0
  103. package/dist/number-range/README.md +443 -0
  104. package/dist/number-range/README_CN.md +443 -0
  105. package/dist/options-multi-select/OptionsMultiSelect.svelte +87 -12
  106. package/dist/options-multi-select/OptionsMultiSelect.svelte.d.ts +3 -1
  107. package/dist/options-multi-select/README.md +480 -0
  108. package/dist/options-multi-select/README_CN.md +480 -0
  109. package/dist/options-select/OptionsSelect.svelte +36 -5
  110. package/dist/options-select/OptionsSelect.svelte.d.ts +3 -4
  111. package/dist/options-select/README.md +632 -0
  112. package/dist/options-select/README_CN.md +632 -0
  113. package/dist/page/README.md +605 -0
  114. package/dist/page/README_CN.md +605 -0
  115. package/dist/pagination/README.md +946 -0
  116. package/dist/pagination/README_CN.md +946 -0
  117. package/dist/pagination-panel/README.md +1075 -0
  118. package/dist/pagination-panel/README_CN.md +1075 -0
  119. package/dist/popup-hint/README.md +841 -0
  120. package/dist/popup-hint/README_CN.md +840 -0
  121. package/dist/progress-bar/README.md +242 -0
  122. package/dist/progress-bar/README_CN.md +242 -0
  123. package/dist/progress-step-bar/README.md +316 -0
  124. package/dist/progress-step-bar/README_CN.md +316 -0
  125. package/dist/prompts-text-editor/PromptsTextEditor.svelte +6 -3
  126. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +3 -1
  127. package/dist/prompts-text-editor/README.md +329 -0
  128. package/dist/prompts-text-editor/README_CN.md +329 -0
  129. package/dist/property-editor/README.md +969 -0
  130. package/dist/property-editor/README_CN.md +969 -0
  131. package/dist/radio-button/README.md +372 -0
  132. package/dist/radio-button/README_CN.md +372 -0
  133. package/dist/radio-button/RadioButton.svelte +32 -3
  134. package/dist/radio-button/RadioButton.svelte.d.ts +12 -1
  135. package/dist/search-box/README.md +425 -0
  136. package/dist/search-box/README_CN.md +424 -0
  137. package/dist/search-box/SearchBox.svelte +22 -6
  138. package/dist/search-box/SearchBox.svelte.d.ts +4 -1
  139. package/dist/tabs/README.md +919 -0
  140. package/dist/tabs/README_CN.md +920 -0
  141. package/dist/tag/README.md +922 -0
  142. package/dist/tag/README_CN.md +922 -0
  143. package/dist/text-editor/PasswordEditor.svelte +17 -2
  144. package/dist/text-editor/PasswordEditor.svelte.d.ts +3 -3
  145. package/dist/text-editor/PasswordEditor_README.md +551 -0
  146. package/dist/text-editor/PasswordEditor_README_CN.md +551 -0
  147. package/dist/text-editor/README.md +466 -0
  148. package/dist/text-editor/README_CN.md +466 -0
  149. package/dist/text-editor/TextEditor.svelte +51 -19
  150. package/dist/text-editor/TextEditor.svelte.d.ts +0 -1
  151. package/dist/time-editor/README.md +498 -24
  152. package/dist/time-editor/README_CN.md +498 -0
  153. package/dist/time-editor/TimeEditor.svelte +7 -3
  154. package/dist/time-editor/TimeEditor.svelte.d.ts +3 -1
  155. package/dist/toast/README.md +667 -0
  156. package/dist/toast/README_CN.md +667 -0
  157. package/dist/transfer/README.md +795 -0
  158. package/dist/transfer/Transfer.svelte +6 -4
  159. package/dist/transfer/Transfer.svelte.d.ts +3 -1
  160. package/dist/tree-view/README.md +761 -0
  161. package/dist/tree-view/README_CN.md +761 -0
  162. package/dist/tree-view/TreeView.svelte +5 -3
  163. package/dist/tree-view/TreeView.svelte.d.ts +3 -1
  164. package/dist/unit-number-editor/README.md +546 -20
  165. package/dist/unit-number-editor/README_CN.md +525 -0
  166. package/dist/unit-number-editor/UnitNumberEditor.svelte +62 -8
  167. package/dist/unit-number-editor/UnitNumberEditor.svelte.d.ts +5 -1
  168. package/docs/form-field/cn/README_CN.md +364 -0
  169. package/docs/form-field/en/README.md +364 -0
  170. package/docs/form-panel/flex-form/cn/README_CN.md +586 -0
  171. package/docs/form-panel/flex-form/en/README.md +586 -0
  172. package/docs/form-panel/flex-row-form/cn/README_CN.md +787 -0
  173. package/docs/form-panel/flex-row-form/en/README.md +787 -0
  174. package/docs/form-panel/grid-form/en/README.md +744 -0
  175. package/package.json +1 -1
  176. package/dist/drawer/README-CN.md +0 -1
@@ -0,0 +1,551 @@
1
+ # ContextMenu 右键菜单组件
2
+
3
+ 一个功能强大且易于使用的右键菜单组件,支持完整的键盘导航和无障碍访问。非常适合创建丰富的交互体验和上下文操作。
4
+
5
+ ## 功能特性
6
+
7
+ - **上下文操作**:右键点击显示相关菜单选项
8
+ - **键盘导航**:完整的方向键导航和键盘快捷键支持
9
+ - **无障碍访问**:ARIA 属性和屏幕阅读器支持
10
+ - **智能定位**:自动调整位置以保持在视口范围内
11
+ - **图标支持**:菜单项可选图标显示
12
+ - **禁用状态**:支持禁用菜单项
13
+ - **分隔符**:菜单组之间的视觉分隔
14
+ - **事件处理**:焦点、失焦和隐藏事件回调
15
+ - **Portal 渲染**:在组件层次结构之外渲染,确保正确的层级
16
+
17
+ ## 基本用法
18
+
19
+ ```svelte
20
+ <script>
21
+ import ContextMenu from '@ticatec/uniface-element/ContextMenu';
22
+
23
+ let contextMenu;
24
+
25
+ const menuItems = [
26
+ { text: '复制', action: () => console.log('复制') },
27
+ { text: '粘贴', action: () => console.log('粘贴') },
28
+ { separator: true },
29
+ { text: '删除', action: () => console.log('删除') }
30
+ ];
31
+
32
+ const handleRightClick = (event) => {
33
+ contextMenu.show(event, menuItems);
34
+ };
35
+ </script>
36
+
37
+ <div on:contextmenu={handleRightClick}>
38
+ 右键点击我显示上下文菜单
39
+ </div>
40
+
41
+ <ContextMenu bind:this={contextMenu} />
42
+ ```
43
+
44
+ ## 属性
45
+
46
+ | 属性 | 类型 | 默认值 | 描述 |
47
+ |------|------|---------|-------------|
48
+ | `onfocus` | `((event: FocusEvent) => void) \| null` | `null` | 焦点事件处理器 |
49
+ | `onblur` | `((event: FocusEvent) => void) \| null` | `null` | 失焦事件处理器 |
50
+ | `onhide` | `(() => void) \| null` | `null` | 隐藏事件处理器 |
51
+
52
+ ## 方法
53
+
54
+ | 方法 | 签名 | 描述 |
55
+ |--------|-----------|-------------|
56
+ | `show(event, items, width?, height?)` | 在事件位置显示上下文菜单 |
57
+ | `hide()` | 隐藏上下文菜单 |
58
+
59
+ ### show() 参数
60
+
61
+ - `event`: MouseEvent - 触发的鼠标事件(用于定位)
62
+ - `items`: ContextMenuItem[] - 要显示的菜单项数组
63
+ - `width`: number(可选,默认: 150)- 菜单宽度(像素)
64
+ - `height`: number(可选,默认: 150)- 菜单高度(像素)
65
+
66
+ ## ContextMenuItem 接口
67
+
68
+ ```typescript
69
+ interface ContextMenuItem {
70
+ text: string; // 菜单项显示文本
71
+ action?: () => void; // 点击时执行的操作
72
+ disabled?: boolean; // 是否禁用该项
73
+ separator?: boolean; // 是否为分隔符项
74
+ icon?: string; // 图标类名或名称
75
+ style?: string; // 自定义 CSS 样式
76
+ }
77
+ ```
78
+
79
+ ## 基础示例
80
+
81
+ ### 简单右键菜单
82
+
83
+ ```svelte
84
+ <script>
85
+ let contextMenu;
86
+
87
+ const items = [
88
+ { text: '新建文件', action: () => createFile() },
89
+ { text: '新建文件夹', action: () => createFolder() },
90
+ { separator: true },
91
+ { text: '刷新', action: () => refresh() }
92
+ ];
93
+
94
+ const showMenu = (event) => {
95
+ contextMenu.show(event, items);
96
+ };
97
+ </script>
98
+
99
+ <div class="file-explorer" on:contextmenu={showMenu}>
100
+ <p>右键点击查看选项</p>
101
+ </div>
102
+
103
+ <ContextMenu bind:this={contextMenu} />
104
+ ```
105
+
106
+ ### 带图标和禁用项
107
+
108
+ ```svelte
109
+ <script>
110
+ let contextMenu;
111
+ let canPaste = false;
112
+
113
+ const items = [
114
+ {
115
+ text: '剪切',
116
+ icon: 'icon-cut',
117
+ action: () => cut()
118
+ },
119
+ {
120
+ text: '复制',
121
+ icon: 'icon-copy',
122
+ action: () => copy()
123
+ },
124
+ {
125
+ text: '粘贴',
126
+ icon: 'icon-paste',
127
+ action: () => paste(),
128
+ disabled: !canPaste
129
+ },
130
+ { separator: true },
131
+ {
132
+ text: '删除',
133
+ icon: 'icon-delete',
134
+ action: () => deleteItem()
135
+ }
136
+ ];
137
+ </script>
138
+
139
+ <div on:contextmenu={(e) => contextMenu.show(e, items)}>
140
+ 包含编辑操作的内容
141
+ </div>
142
+
143
+ <ContextMenu bind:this={contextMenu} />
144
+ ```
145
+
146
+ ### 动态菜单项
147
+
148
+ ```svelte
149
+ <script>
150
+ let contextMenu;
151
+ let selectedItems = [];
152
+
153
+ const getMenuItems = (target) => {
154
+ const baseItems = [
155
+ { text: '属性', action: () => showProperties(target) }
156
+ ];
157
+
158
+ if (selectedItems.length > 0) {
159
+ baseItems.unshift(
160
+ { text: `删除 ${selectedItems.length} 个项目`, action: () => deleteSelected() },
161
+ { separator: true }
162
+ );
163
+ }
164
+
165
+ if (target.type === 'file') {
166
+ baseItems.unshift(
167
+ { text: '打开', action: () => openFile(target) },
168
+ { text: '打开方式...', action: () => openWith(target) },
169
+ { separator: true }
170
+ );
171
+ }
172
+
173
+ return baseItems;
174
+ };
175
+
176
+ const handleContextMenu = (event, target) => {
177
+ const items = getMenuItems(target);
178
+ contextMenu.show(event, items);
179
+ };
180
+ </script>
181
+
182
+ <div class="item-list">
183
+ {#each items as item}
184
+ <div class="item" on:contextmenu={(e) => handleContextMenu(e, item)}>
185
+ {item.name}
186
+ </div>
187
+ {/each}
188
+ </div>
189
+
190
+ <ContextMenu bind:this={contextMenu} />
191
+ ```
192
+
193
+ ## 事件处理
194
+
195
+ ```svelte
196
+ <script>
197
+ let contextMenu;
198
+ let menuVisible = false;
199
+
200
+ const handleFocus = (event) => {
201
+ console.log('右键菜单获得焦点');
202
+ menuVisible = true;
203
+ };
204
+
205
+ const handleBlur = (event) => {
206
+ console.log('右键菜单失去焦点');
207
+ menuVisible = false;
208
+ };
209
+
210
+ const handleHide = () => {
211
+ console.log('右键菜单隐藏');
212
+ menuVisible = false;
213
+ };
214
+
215
+ const items = [
216
+ { text: '操作 1', action: () => console.log('操作 1') },
217
+ { text: '操作 2', action: () => console.log('操作 2') }
218
+ ];
219
+ </script>
220
+
221
+ <div on:contextmenu={(e) => contextMenu.show(e, items)}>
222
+ 右键点击我
223
+ </div>
224
+
225
+ <ContextMenu
226
+ bind:this={contextMenu}
227
+ onfocus={handleFocus}
228
+ onblur={handleBlur}
229
+ onhide={handleHide}
230
+ />
231
+
232
+ <p>菜单可见: {menuVisible}</p>
233
+ ```
234
+
235
+ ## 高级示例
236
+
237
+ ### 文件管理器右键菜单
238
+
239
+ ```svelte
240
+ <script>
241
+ import ContextMenu from '@ticatec/uniface-element/ContextMenu';
242
+
243
+ let contextMenu;
244
+ let files = [
245
+ { name: 'document.pdf', type: 'file', selected: false },
246
+ { name: 'images', type: 'folder', selected: false },
247
+ { name: 'script.js', type: 'file', selected: true }
248
+ ];
249
+
250
+ let clipboard = null;
251
+
252
+ const getFileMenuItems = (file) => {
253
+ const items = [];
254
+
255
+ if (file.type === 'file') {
256
+ items.push(
257
+ { text: '打开', icon: 'icon-open', action: () => openFile(file) },
258
+ { text: '打开方式...', action: () => openWith(file) },
259
+ { separator: true }
260
+ );
261
+ }
262
+
263
+ items.push(
264
+ { text: '剪切', icon: 'icon-cut', action: () => cutFile(file) },
265
+ { text: '复制', icon: 'icon-copy', action: () => copyFile(file) },
266
+ {
267
+ text: '粘贴',
268
+ icon: 'icon-paste',
269
+ action: () => pasteFile(),
270
+ disabled: !clipboard
271
+ },
272
+ { separator: true },
273
+ { text: '重命名', action: () => renameFile(file) },
274
+ { text: '删除', icon: 'icon-delete', action: () => deleteFile(file) },
275
+ { separator: true },
276
+ { text: '属性', action: () => showProperties(file) }
277
+ );
278
+
279
+ return items;
280
+ };
281
+
282
+ const getEmptySpaceMenuItems = () => [
283
+ { text: '新建文件夹', icon: 'icon-folder-plus', action: () => createFolder() },
284
+ { text: '新建文件', icon: 'icon-file-plus', action: () => createFile() },
285
+ { separator: true },
286
+ {
287
+ text: '粘贴',
288
+ icon: 'icon-paste',
289
+ action: () => pasteFile(),
290
+ disabled: !clipboard
291
+ },
292
+ { separator: true },
293
+ { text: '刷新', icon: 'icon-refresh', action: () => refresh() }
294
+ ];
295
+
296
+ const handleFileContextMenu = (event, file) => {
297
+ const items = getFileMenuItems(file);
298
+ contextMenu.show(event, items, 200, 300);
299
+ };
300
+
301
+ const handleEmptySpaceContextMenu = (event) => {
302
+ const items = getEmptySpaceMenuItems();
303
+ contextMenu.show(event, items);
304
+ };
305
+
306
+ const openFile = (file) => console.log('打开', file.name);
307
+ const openWith = (file) => console.log('打开方式...', file.name);
308
+ const cutFile = (file) => { clipboard = { type: 'cut', file }; };
309
+ const copyFile = (file) => { clipboard = { type: 'copy', file }; };
310
+ const pasteFile = () => console.log('粘贴', clipboard?.file?.name);
311
+ const renameFile = (file) => console.log('重命名', file.name);
312
+ const deleteFile = (file) => console.log('删除', file.name);
313
+ const createFolder = () => console.log('创建文件夹');
314
+ const createFile = () => console.log('创建文件');
315
+ const refresh = () => console.log('刷新');
316
+ const showProperties = (file) => console.log('属性', file.name);
317
+ </script>
318
+
319
+ <div class="file-manager" on:contextmenu={handleEmptySpaceContextMenu}>
320
+ <h3>文件管理器</h3>
321
+
322
+ <div class="file-list">
323
+ {#each files as file}
324
+ <div
325
+ class="file-item"
326
+ class:selected={file.selected}
327
+ on:contextmenu|stopPropagation={(e) => handleFileContextMenu(e, file)}
328
+ >
329
+ <span class="file-icon {file.type === 'folder' ? 'icon-folder' : 'icon-file'}"></span>
330
+ <span class="file-name">{file.name}</span>
331
+ </div>
332
+ {/each}
333
+ </div>
334
+ </div>
335
+
336
+ <ContextMenu bind:this={contextMenu} />
337
+
338
+ <style>
339
+ .file-manager {
340
+ padding: 20px;
341
+ border: 1px solid #ddd;
342
+ border-radius: 8px;
343
+ min-height: 300px;
344
+ background: #f9f9f9;
345
+ }
346
+
347
+ .file-list {
348
+ margin-top: 16px;
349
+ }
350
+
351
+ .file-item {
352
+ display: flex;
353
+ align-items: center;
354
+ padding: 8px;
355
+ margin: 4px 0;
356
+ border-radius: 4px;
357
+ cursor: pointer;
358
+ transition: background 0.2s;
359
+ }
360
+
361
+ .file-item:hover {
362
+ background: #e9e9e9;
363
+ }
364
+
365
+ .file-item.selected {
366
+ background: #007acc;
367
+ color: white;
368
+ }
369
+
370
+ .file-icon {
371
+ margin-right: 8px;
372
+ width: 16px;
373
+ height: 16px;
374
+ }
375
+ </style>
376
+ ```
377
+
378
+ ### 表格行右键菜单
379
+
380
+ ```svelte
381
+ <script>
382
+ import ContextMenu from '@ticatec/uniface-element/ContextMenu';
383
+
384
+ let contextMenu;
385
+ let users = [
386
+ { id: 1, name: '张三', email: 'zhang@example.com', active: true },
387
+ { id: 2, name: '李四', email: 'li@example.com', active: false },
388
+ { id: 3, name: '王五', email: 'wang@example.com', active: true }
389
+ ];
390
+
391
+ const getUserMenuItems = (user) => [
392
+ { text: '查看资料', icon: 'icon-user', action: () => viewProfile(user) },
393
+ { text: '编辑用户', icon: 'icon-edit', action: () => editUser(user) },
394
+ { separator: true },
395
+ {
396
+ text: user.active ? '停用' : '启用',
397
+ icon: user.active ? 'icon-pause' : 'icon-play',
398
+ action: () => toggleUserStatus(user)
399
+ },
400
+ { text: '重置密码', action: () => resetPassword(user) },
401
+ { separator: true },
402
+ { text: '删除用户', icon: 'icon-trash', action: () => deleteUser(user) }
403
+ ];
404
+
405
+ const handleRowContextMenu = (event, user) => {
406
+ const items = getUserMenuItems(user);
407
+ contextMenu.show(event, items, 180, 200);
408
+ };
409
+
410
+ const viewProfile = (user) => console.log('查看资料', user.name);
411
+ const editUser = (user) => console.log('编辑', user.name);
412
+ const toggleUserStatus = (user) => {
413
+ user.active = !user.active;
414
+ users = [...users];
415
+ console.log(`${user.active ? '启用' : '停用'} ${user.name}`);
416
+ };
417
+ const resetPassword = (user) => console.log('重置密码', user.name);
418
+ const deleteUser = (user) => {
419
+ users = users.filter(u => u.id !== user.id);
420
+ console.log('删除', user.name);
421
+ };
422
+ </script>
423
+
424
+ <div class="user-table">
425
+ <h3>用户管理</h3>
426
+
427
+ <table>
428
+ <thead>
429
+ <tr>
430
+ <th>姓名</th>
431
+ <th>邮箱</th>
432
+ <th>状态</th>
433
+ </tr>
434
+ </thead>
435
+ <tbody>
436
+ {#each users as user}
437
+ <tr on:contextmenu={(e) => handleRowContextMenu(e, user)}>
438
+ <td>{user.name}</td>
439
+ <td>{user.email}</td>
440
+ <td>
441
+ <span class="status" class:active={user.active}>
442
+ {user.active ? '活跃' : '非活跃'}
443
+ </span>
444
+ </td>
445
+ </tr>
446
+ {/each}
447
+ </tbody>
448
+ </table>
449
+ </div>
450
+
451
+ <ContextMenu bind:this={contextMenu} />
452
+
453
+ <style>
454
+ .user-table {
455
+ padding: 20px;
456
+ }
457
+
458
+ table {
459
+ width: 100%;
460
+ border-collapse: collapse;
461
+ margin-top: 16px;
462
+ }
463
+
464
+ th, td {
465
+ text-align: left;
466
+ padding: 12px;
467
+ border-bottom: 1px solid #ddd;
468
+ }
469
+
470
+ th {
471
+ background: #f5f5f5;
472
+ font-weight: 600;
473
+ }
474
+
475
+ tr:hover {
476
+ background: #f9f9f9;
477
+ cursor: context-menu;
478
+ }
479
+
480
+ .status {
481
+ padding: 4px 8px;
482
+ border-radius: 12px;
483
+ font-size: 12px;
484
+ font-weight: 500;
485
+ background: #dc3545;
486
+ color: white;
487
+ }
488
+
489
+ .status.active {
490
+ background: #28a745;
491
+ }
492
+ </style>
493
+ ```
494
+
495
+ ## 键盘导航
496
+
497
+ ContextMenu 支持完整的键盘导航:
498
+
499
+ - **上/下方向键**:在菜单项之间导航
500
+ - **Enter/空格键**:执行当前焦点的菜单项
501
+ - **Escape**:关闭菜单
502
+ - **Tab**:关闭菜单(焦点移开)
503
+
504
+ ## 无障碍访问
505
+
506
+ ContextMenu 组件包含全面的无障碍功能:
507
+
508
+ - 正确的 ARIA 角色(`menu`、`menuitem`、`separator`)
509
+ - ARIA 属性(`aria-label`、`aria-disabled`)
510
+ - 键盘导航支持
511
+ - 焦点管理
512
+ - 屏幕阅读器兼容性
513
+ - 语义化 HTML 结构
514
+
515
+ ### 最佳实践
516
+
517
+ ```svelte
518
+ <!-- 好的:清晰的上下文指示 -->
519
+ <div class="editable-content" on:contextmenu={showEditMenu}>
520
+ <!-- 内容 -->
521
+ </div>
522
+
523
+ <!-- 好的:适合上下文的菜单项 -->
524
+ const editMenuItems = [
525
+ { text: '剪切', action: () => cut() },
526
+ { text: '复制', action: () => copy() },
527
+ { text: '粘贴', action: () => paste(), disabled: !canPaste }
528
+ ];
529
+
530
+ <!-- 好的:禁用项的视觉反馈 -->
531
+ .menu-item.disabled {
532
+ opacity: 0.5;
533
+ cursor: not-allowed;
534
+ }
535
+ ```
536
+
537
+ ## 浏览器支持
538
+
539
+ 支持所有现代浏览器:
540
+ - ES6+ JavaScript
541
+ - 现代 DOM API
542
+ - CSS 自定义属性
543
+ - Portal/Teleport 功能
544
+
545
+ ## 性能考虑
546
+
547
+ - 高效的事件处理和适当的清理
548
+ - Portal 渲染以获得最佳层级
549
+ - 响应式变化时最小的 DOM 更新
550
+ - 智能定位计算
551
+ - 组件销毁时自动清理
@@ -1,16 +1,14 @@
1
1
  <script lang="ts">
2
-
3
- export {className as class }
4
- export let label: string = "Label"
2
+ export {className as class}
3
+ export let label: string = "Label";
5
4
  export let style: string = '';
6
5
  export let label$style: string = '';
7
6
  export let size: '' | 'x15' | 'x20' | 'x25' | 'x30' | 'x35' | 'x40' = '';
8
7
  export let labelSuffix: string = ':';
9
8
 
10
9
  let className: string = '';
11
-
12
10
  </script>
13
- <div class="uniface-filter-field {size} {className}" {style} >
11
+ <div class="uniface-filter-field {size} {className}" {style}>
14
12
  <div class="field-container">
15
13
  <div class="field-label" style={label$style}>
16
14
  <span>{label}{labelSuffix}</span>