@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.
- package/dist/accordion/README.md +169 -0
- package/dist/accordion/README_CN.md +176 -0
- package/dist/action-bar/README.md +275 -0
- package/dist/action-bar/README_CN.md +285 -0
- package/dist/app-layout/README.md +374 -0
- package/dist/app-layout/README_CN.md +381 -0
- package/dist/app-top-bar/README.md +357 -0
- package/dist/app-top-bar/README_CN.md +365 -0
- package/dist/attachment-files/AttachmentFilesField.svelte +67 -1
- package/dist/attachment-files/AttachmentFilesField.svelte.d.ts +8 -1
- package/dist/base-calendar/CalendarBase.svelte +0 -3
- package/dist/box/README.md +385 -0
- package/dist/box/README_CN.md +393 -0
- package/dist/breadcrumbs/README.md +442 -0
- package/dist/breadcrumbs/README_CN.md +442 -0
- package/dist/button/Button.svelte +27 -7
- package/dist/button/Button.svelte.d.ts +3 -1
- package/dist/button/IconButton.svelte +26 -6
- package/dist/button/IconButton.svelte.d.ts +3 -1
- package/dist/button/IconButton_README.md +513 -0
- package/dist/button/IconButton_README_CN.md +513 -0
- package/dist/button/README.md +428 -0
- package/dist/button/README_CN.md +428 -0
- package/dist/button/TextButton.svelte +26 -6
- package/dist/button/TextButton.svelte.d.ts +3 -1
- package/dist/button/TextButton_README.md +571 -0
- package/dist/button/TextButton_README_CN.md +571 -0
- package/dist/card/README.md +666 -0
- package/dist/card/README_CN.md +666 -0
- package/dist/cascade-options-select/CascadeOptionSelect.svelte +43 -7
- package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +3 -4
- package/dist/cascade-options-select/README.md +663 -2
- package/dist/cascade-options-select/README_CN.md +664 -0
- package/dist/checkbox/CheckBox.svelte +20 -6
- package/dist/checkbox/CheckBox.svelte.d.ts +4 -2
- package/dist/checkbox/README.md +562 -0
- package/dist/checkbox/README_CN.md +727 -0
- package/dist/common-editor/NumberInput.svelte +39 -26
- package/dist/common-editor/NumberInput.svelte.d.ts +5 -1
- package/dist/concise-data-table/ConciseListTable.svelte +133 -36
- package/dist/concise-data-table/ConciseListTable.svelte.d.ts +8 -1
- package/dist/concise-data-table/DataCell.svelte +5 -6
- package/dist/concise-data-table/DataRow.svelte +22 -2
- package/dist/concise-data-table/DataRow.svelte.d.ts +1 -0
- package/dist/concise-data-table/README.md +606 -0
- package/dist/concise-data-table/README_CN.md +611 -0
- package/dist/context-menu/ContextMenu.svelte +138 -21
- package/dist/context-menu/ContextMenu.svelte.d.ts +5 -0
- package/dist/context-menu/ContextMenuItem.d.ts +20 -4
- package/dist/context-menu/README.md +551 -0
- package/dist/context-menu/README_CN.md +551 -0
- package/dist/criteria-field/CriteriaField.svelte +3 -5
- package/dist/criteria-field/README.md +532 -0
- package/dist/criteria-field/README_CN.md +532 -0
- package/dist/data-table/README.md +712 -0
- package/dist/data-table/README_CN.md +712 -0
- package/dist/date-picker/DatePicker.svelte +44 -7
- package/dist/date-picker/DatePicker.svelte.d.ts +3 -4
- package/dist/date-picker/DateTimePicker.svelte +32 -8
- package/dist/date-picker/DateTimePicker.svelte.d.ts +3 -4
- package/dist/date-picker/README.md +326 -0
- package/dist/date-picker/README_CN.md +316 -0
- package/dist/date-picker/ScrollBar.svelte +18 -8
- package/dist/date-picker/ScrollBar.svelte.d.ts +1 -1
- package/dist/date-picker/TimePanel.svelte +5 -5
- package/dist/date-picker/TimePanel.svelte.d.ts +1 -1
- package/dist/date-range/README.md +374 -0
- package/dist/date-range/README_CN.md +374 -0
- package/dist/dialog/DialogBoard.svelte +1 -1
- package/dist/dialog/README.md +596 -0
- package/dist/dialog/README_CN.md +596 -0
- package/dist/drawer/README.md +679 -1
- package/dist/drawer/README_CN.md +679 -0
- package/dist/group-box/group-check-box/GroupCheckBox.svelte +62 -5
- package/dist/group-box/group-check-box/GroupCheckBox.svelte.d.ts +7 -2
- package/dist/group-box/group-check-box/README.md +749 -0
- package/dist/group-box/group-check-box/README_CN.md +750 -0
- package/dist/group-box/group-radio-box/GroupRadioBox.svelte +69 -4
- package/dist/group-box/group-radio-box/GroupRadioBox.svelte.d.ts +8 -2
- package/dist/group-box/group-radio-box/README.md +920 -0
- package/dist/group-box/group-radio-box/README_CN.md +920 -0
- package/dist/image-files/README.md +1346 -0
- package/dist/image-files/README_CN.md +1346 -0
- package/dist/input-options-select/InputOptionsSelect.svelte +161 -65
- package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +4 -1
- package/dist/lib/forwardAllEvents.d.ts +3 -0
- package/dist/lib/forwardAllEvents.js +24 -0
- package/dist/list-box/README.md +579 -0
- package/dist/list-box/README_CN.md +682 -0
- package/dist/lookup-editor/LookupEditor.svelte +15 -3
- package/dist/lookup-editor/LookupEditor.svelte.d.ts +3 -4
- package/dist/lookup-editor/README.md +684 -0
- package/dist/lookup-editor/README_CN.md +684 -0
- package/dist/memo-editor/MemoEditor.svelte +77 -27
- package/dist/memo-editor/MemoEditor.svelte.d.ts +6 -3
- package/dist/memo-editor/README.md +819 -0
- package/dist/memo-editor/README_CN.md +819 -0
- package/dist/message-box/README.md +398 -0
- package/dist/message-box/README_CN.md +398 -0
- package/dist/number-editor/NumberEditor.svelte +2 -2
- package/dist/number-editor/NumberEditor.svelte.d.ts +1 -1
- package/dist/number-editor/README.md +353 -22
- package/dist/number-editor/README_CN.md +357 -0
- package/dist/number-range/README.md +443 -0
- package/dist/number-range/README_CN.md +443 -0
- package/dist/options-multi-select/OptionsMultiSelect.svelte +87 -12
- package/dist/options-multi-select/OptionsMultiSelect.svelte.d.ts +3 -1
- package/dist/options-multi-select/README.md +480 -0
- package/dist/options-multi-select/README_CN.md +480 -0
- package/dist/options-select/OptionsSelect.svelte +36 -5
- package/dist/options-select/OptionsSelect.svelte.d.ts +3 -4
- package/dist/options-select/README.md +632 -0
- package/dist/options-select/README_CN.md +632 -0
- package/dist/page/README.md +605 -0
- package/dist/page/README_CN.md +605 -0
- package/dist/pagination/README.md +946 -0
- package/dist/pagination/README_CN.md +946 -0
- package/dist/pagination-panel/README.md +1075 -0
- package/dist/pagination-panel/README_CN.md +1075 -0
- package/dist/popup-hint/README.md +841 -0
- package/dist/popup-hint/README_CN.md +840 -0
- package/dist/progress-bar/README.md +242 -0
- package/dist/progress-bar/README_CN.md +242 -0
- package/dist/progress-step-bar/README.md +316 -0
- package/dist/progress-step-bar/README_CN.md +316 -0
- package/dist/prompts-text-editor/PromptsTextEditor.svelte +6 -3
- package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +3 -1
- package/dist/prompts-text-editor/README.md +329 -0
- package/dist/prompts-text-editor/README_CN.md +329 -0
- package/dist/property-editor/README.md +969 -0
- package/dist/property-editor/README_CN.md +969 -0
- package/dist/radio-button/README.md +372 -0
- package/dist/radio-button/README_CN.md +372 -0
- package/dist/radio-button/RadioButton.svelte +32 -3
- package/dist/radio-button/RadioButton.svelte.d.ts +12 -1
- package/dist/search-box/README.md +425 -0
- package/dist/search-box/README_CN.md +424 -0
- package/dist/search-box/SearchBox.svelte +22 -6
- package/dist/search-box/SearchBox.svelte.d.ts +4 -1
- package/dist/tabs/README.md +919 -0
- package/dist/tabs/README_CN.md +920 -0
- package/dist/tag/README.md +922 -0
- package/dist/tag/README_CN.md +922 -0
- package/dist/text-editor/PasswordEditor.svelte +17 -2
- package/dist/text-editor/PasswordEditor.svelte.d.ts +3 -3
- package/dist/text-editor/PasswordEditor_README.md +551 -0
- package/dist/text-editor/PasswordEditor_README_CN.md +551 -0
- package/dist/text-editor/README.md +466 -0
- package/dist/text-editor/README_CN.md +466 -0
- package/dist/text-editor/TextEditor.svelte +51 -19
- package/dist/text-editor/TextEditor.svelte.d.ts +0 -1
- package/dist/ticatec-uniface-web.css +1 -0
- package/dist/time-editor/README.md +498 -24
- package/dist/time-editor/README_CN.md +498 -0
- package/dist/time-editor/TimeEditor.svelte +7 -3
- package/dist/time-editor/TimeEditor.svelte.d.ts +3 -1
- package/dist/toast/README.md +667 -0
- package/dist/toast/README_CN.md +667 -0
- package/dist/transfer/README.md +795 -0
- package/dist/transfer/Transfer.svelte +6 -4
- package/dist/transfer/Transfer.svelte.d.ts +3 -1
- package/dist/tree-view/README.md +761 -0
- package/dist/tree-view/README_CN.md +761 -0
- package/dist/tree-view/TreeView.svelte +5 -3
- package/dist/tree-view/TreeView.svelte.d.ts +3 -1
- package/dist/unit-number-editor/README.md +546 -20
- package/dist/unit-number-editor/README_CN.md +525 -0
- package/dist/unit-number-editor/UnitNumberEditor.svelte +62 -8
- package/dist/unit-number-editor/UnitNumberEditor.svelte.d.ts +5 -1
- package/docs/form-field/cn/README_CN.md +364 -0
- package/docs/form-field/en/README.md +364 -0
- package/docs/form-panel/flex-form/cn/README_CN.md +586 -0
- package/docs/form-panel/flex-form/en/README.md +586 -0
- package/docs/form-panel/flex-row-form/cn/README_CN.md +787 -0
- package/docs/form-panel/flex-row-form/en/README.md +787 -0
- package/docs/form-panel/grid-form/en/README.md +744 -0
- package/package.json +1 -1
- package/dist/drawer/README-CN.md +0 -1
|
@@ -0,0 +1,551 @@
|
|
|
1
|
+
# ContextMenu Component
|
|
2
|
+
|
|
3
|
+
A powerful and accessible context menu component that provides right-click contextual actions with full keyboard navigation support. Perfect for creating rich interactive experiences with contextual commands and options.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Contextual Actions**: Right-click to show relevant menu options
|
|
8
|
+
- **Keyboard Navigation**: Full arrow key navigation and keyboard shortcuts
|
|
9
|
+
- **Accessibility**: ARIA attributes and screen reader support
|
|
10
|
+
- **Auto Positioning**: Smart positioning to stay within viewport bounds
|
|
11
|
+
- **Icon Support**: Optional icons for menu items
|
|
12
|
+
- **Disabled States**: Support for disabled menu items
|
|
13
|
+
- **Separators**: Visual separation between menu groups
|
|
14
|
+
- **Event Handling**: Focus, blur, and hide event callbacks
|
|
15
|
+
- **Portal Rendering**: Renders outside component hierarchy for proper layering
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
```svelte
|
|
20
|
+
<script>
|
|
21
|
+
import ContextMenu from '@ticatec/uniface-element/ContextMenu';
|
|
22
|
+
|
|
23
|
+
let contextMenu;
|
|
24
|
+
|
|
25
|
+
const menuItems = [
|
|
26
|
+
{ text: 'Copy', action: () => console.log('Copy') },
|
|
27
|
+
{ text: 'Paste', action: () => console.log('Paste') },
|
|
28
|
+
{ separator: true },
|
|
29
|
+
{ text: 'Delete', action: () => console.log('Delete') }
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const handleRightClick = (event) => {
|
|
33
|
+
contextMenu.show(event, menuItems);
|
|
34
|
+
};
|
|
35
|
+
</script>
|
|
36
|
+
|
|
37
|
+
<div on:contextmenu={handleRightClick}>
|
|
38
|
+
Right-click me to show context menu
|
|
39
|
+
</div>
|
|
40
|
+
|
|
41
|
+
<ContextMenu bind:this={contextMenu} />
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Props
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Default | Description |
|
|
47
|
+
|------|------|---------|-------------|
|
|
48
|
+
| `onfocus` | `((event: FocusEvent) => void) \| null` | `null` | Focus event handler |
|
|
49
|
+
| `onblur` | `((event: FocusEvent) => void) \| null` | `null` | Blur event handler |
|
|
50
|
+
| `onhide` | `(() => void) \| null` | `null` | Hide event handler |
|
|
51
|
+
|
|
52
|
+
## Methods
|
|
53
|
+
|
|
54
|
+
| Method | Signature | Description |
|
|
55
|
+
|--------|-----------|-------------|
|
|
56
|
+
| `show(event, items, width?, height?)` | Shows the context menu at the event position |
|
|
57
|
+
| `hide()` | Hides the context menu |
|
|
58
|
+
|
|
59
|
+
### show() Parameters
|
|
60
|
+
|
|
61
|
+
- `event`: MouseEvent - The triggering mouse event (for positioning)
|
|
62
|
+
- `items`: ContextMenuItem[] - Array of menu items to display
|
|
63
|
+
- `width`: number (optional, default: 150) - Menu width in pixels
|
|
64
|
+
- `height`: number (optional, default: 150) - Menu height in pixels
|
|
65
|
+
|
|
66
|
+
## ContextMenuItem Interface
|
|
67
|
+
|
|
68
|
+
```typescript
|
|
69
|
+
interface ContextMenuItem {
|
|
70
|
+
text: string; // Display text for the menu item
|
|
71
|
+
action?: () => void; // Action to execute when clicked
|
|
72
|
+
disabled?: boolean; // Whether the item is disabled
|
|
73
|
+
separator?: boolean; // Whether this is a separator item
|
|
74
|
+
icon?: string; // Icon class or name
|
|
75
|
+
style?: string; // Custom CSS styles
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
## Basic Examples
|
|
80
|
+
|
|
81
|
+
### Simple Context Menu
|
|
82
|
+
|
|
83
|
+
```svelte
|
|
84
|
+
<script>
|
|
85
|
+
let contextMenu;
|
|
86
|
+
|
|
87
|
+
const items = [
|
|
88
|
+
{ text: 'New File', action: () => createFile() },
|
|
89
|
+
{ text: 'New Folder', action: () => createFolder() },
|
|
90
|
+
{ separator: true },
|
|
91
|
+
{ text: 'Refresh', 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>Right-click for options</p>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<ContextMenu bind:this={contextMenu} />
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### With Icons and Disabled Items
|
|
107
|
+
|
|
108
|
+
```svelte
|
|
109
|
+
<script>
|
|
110
|
+
let contextMenu;
|
|
111
|
+
let canPaste = false;
|
|
112
|
+
|
|
113
|
+
const items = [
|
|
114
|
+
{
|
|
115
|
+
text: 'Cut',
|
|
116
|
+
icon: 'icon-cut',
|
|
117
|
+
action: () => cut()
|
|
118
|
+
},
|
|
119
|
+
{
|
|
120
|
+
text: 'Copy',
|
|
121
|
+
icon: 'icon-copy',
|
|
122
|
+
action: () => copy()
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
text: 'Paste',
|
|
126
|
+
icon: 'icon-paste',
|
|
127
|
+
action: () => paste(),
|
|
128
|
+
disabled: !canPaste
|
|
129
|
+
},
|
|
130
|
+
{ separator: true },
|
|
131
|
+
{
|
|
132
|
+
text: 'Delete',
|
|
133
|
+
icon: 'icon-delete',
|
|
134
|
+
action: () => deleteItem()
|
|
135
|
+
}
|
|
136
|
+
];
|
|
137
|
+
</script>
|
|
138
|
+
|
|
139
|
+
<div on:contextmenu={(e) => contextMenu.show(e, items)}>
|
|
140
|
+
Content with edit operations
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
<ContextMenu bind:this={contextMenu} />
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
### Dynamic Menu Items
|
|
147
|
+
|
|
148
|
+
```svelte
|
|
149
|
+
<script>
|
|
150
|
+
let contextMenu;
|
|
151
|
+
let selectedItems = [];
|
|
152
|
+
|
|
153
|
+
const getMenuItems = (target) => {
|
|
154
|
+
const baseItems = [
|
|
155
|
+
{ text: 'Properties', action: () => showProperties(target) }
|
|
156
|
+
];
|
|
157
|
+
|
|
158
|
+
if (selectedItems.length > 0) {
|
|
159
|
+
baseItems.unshift(
|
|
160
|
+
{ text: `Delete ${selectedItems.length} items`, action: () => deleteSelected() },
|
|
161
|
+
{ separator: true }
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
if (target.type === 'file') {
|
|
166
|
+
baseItems.unshift(
|
|
167
|
+
{ text: 'Open', action: () => openFile(target) },
|
|
168
|
+
{ text: 'Open with...', 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
|
+
## Event Handling
|
|
194
|
+
|
|
195
|
+
```svelte
|
|
196
|
+
<script>
|
|
197
|
+
let contextMenu;
|
|
198
|
+
let menuVisible = false;
|
|
199
|
+
|
|
200
|
+
const handleFocus = (event) => {
|
|
201
|
+
console.log('Context menu focused');
|
|
202
|
+
menuVisible = true;
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const handleBlur = (event) => {
|
|
206
|
+
console.log('Context menu blurred');
|
|
207
|
+
menuVisible = false;
|
|
208
|
+
};
|
|
209
|
+
|
|
210
|
+
const handleHide = () => {
|
|
211
|
+
console.log('Context menu hidden');
|
|
212
|
+
menuVisible = false;
|
|
213
|
+
};
|
|
214
|
+
|
|
215
|
+
const items = [
|
|
216
|
+
{ text: 'Action 1', action: () => console.log('Action 1') },
|
|
217
|
+
{ text: 'Action 2', action: () => console.log('Action 2') }
|
|
218
|
+
];
|
|
219
|
+
</script>
|
|
220
|
+
|
|
221
|
+
<div on:contextmenu={(e) => contextMenu.show(e, items)}>
|
|
222
|
+
Right-click me
|
|
223
|
+
</div>
|
|
224
|
+
|
|
225
|
+
<ContextMenu
|
|
226
|
+
bind:this={contextMenu}
|
|
227
|
+
onfocus={handleFocus}
|
|
228
|
+
onblur={handleBlur}
|
|
229
|
+
onhide={handleHide}
|
|
230
|
+
/>
|
|
231
|
+
|
|
232
|
+
<p>Menu visible: {menuVisible}</p>
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## Advanced Examples
|
|
236
|
+
|
|
237
|
+
### File Manager Context Menu
|
|
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: 'Open', icon: 'icon-open', action: () => openFile(file) },
|
|
258
|
+
{ text: 'Open with...', action: () => openWith(file) },
|
|
259
|
+
{ separator: true }
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
items.push(
|
|
264
|
+
{ text: 'Cut', icon: 'icon-cut', action: () => cutFile(file) },
|
|
265
|
+
{ text: 'Copy', icon: 'icon-copy', action: () => copyFile(file) },
|
|
266
|
+
{
|
|
267
|
+
text: 'Paste',
|
|
268
|
+
icon: 'icon-paste',
|
|
269
|
+
action: () => pasteFile(),
|
|
270
|
+
disabled: !clipboard
|
|
271
|
+
},
|
|
272
|
+
{ separator: true },
|
|
273
|
+
{ text: 'Rename', action: () => renameFile(file) },
|
|
274
|
+
{ text: 'Delete', icon: 'icon-delete', action: () => deleteFile(file) },
|
|
275
|
+
{ separator: true },
|
|
276
|
+
{ text: 'Properties', action: () => showProperties(file) }
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
return items;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
const getEmptySpaceMenuItems = () => [
|
|
283
|
+
{ text: 'New Folder', icon: 'icon-folder-plus', action: () => createFolder() },
|
|
284
|
+
{ text: 'New File', icon: 'icon-file-plus', action: () => createFile() },
|
|
285
|
+
{ separator: true },
|
|
286
|
+
{
|
|
287
|
+
text: 'Paste',
|
|
288
|
+
icon: 'icon-paste',
|
|
289
|
+
action: () => pasteFile(),
|
|
290
|
+
disabled: !clipboard
|
|
291
|
+
},
|
|
292
|
+
{ separator: true },
|
|
293
|
+
{ text: 'Refresh', 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('Opening', file.name);
|
|
307
|
+
const openWith = (file) => console.log('Open with...', file.name);
|
|
308
|
+
const cutFile = (file) => { clipboard = { type: 'cut', file }; };
|
|
309
|
+
const copyFile = (file) => { clipboard = { type: 'copy', file }; };
|
|
310
|
+
const pasteFile = () => console.log('Pasting', clipboard?.file?.name);
|
|
311
|
+
const renameFile = (file) => console.log('Renaming', file.name);
|
|
312
|
+
const deleteFile = (file) => console.log('Deleting', file.name);
|
|
313
|
+
const createFolder = () => console.log('Creating folder');
|
|
314
|
+
const createFile = () => console.log('Creating file');
|
|
315
|
+
const refresh = () => console.log('Refreshing');
|
|
316
|
+
const showProperties = (file) => console.log('Properties for', file.name);
|
|
317
|
+
</script>
|
|
318
|
+
|
|
319
|
+
<div class="file-manager" on:contextmenu={handleEmptySpaceContextMenu}>
|
|
320
|
+
<h3>File Manager</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
|
+
### Table Row Context Menu
|
|
379
|
+
|
|
380
|
+
```svelte
|
|
381
|
+
<script>
|
|
382
|
+
import ContextMenu from '@ticatec/uniface-element/ContextMenu';
|
|
383
|
+
|
|
384
|
+
let contextMenu;
|
|
385
|
+
let users = [
|
|
386
|
+
{ id: 1, name: 'John Doe', email: 'john@example.com', active: true },
|
|
387
|
+
{ id: 2, name: 'Jane Smith', email: 'jane@example.com', active: false },
|
|
388
|
+
{ id: 3, name: 'Bob Johnson', email: 'bob@example.com', active: true }
|
|
389
|
+
];
|
|
390
|
+
|
|
391
|
+
const getUserMenuItems = (user) => [
|
|
392
|
+
{ text: 'View Profile', icon: 'icon-user', action: () => viewProfile(user) },
|
|
393
|
+
{ text: 'Edit User', icon: 'icon-edit', action: () => editUser(user) },
|
|
394
|
+
{ separator: true },
|
|
395
|
+
{
|
|
396
|
+
text: user.active ? 'Deactivate' : 'Activate',
|
|
397
|
+
icon: user.active ? 'icon-pause' : 'icon-play',
|
|
398
|
+
action: () => toggleUserStatus(user)
|
|
399
|
+
},
|
|
400
|
+
{ text: 'Reset Password', action: () => resetPassword(user) },
|
|
401
|
+
{ separator: true },
|
|
402
|
+
{ text: 'Delete User', 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('Viewing profile for', user.name);
|
|
411
|
+
const editUser = (user) => console.log('Editing', user.name);
|
|
412
|
+
const toggleUserStatus = (user) => {
|
|
413
|
+
user.active = !user.active;
|
|
414
|
+
users = [...users];
|
|
415
|
+
console.log(`${user.active ? 'Activated' : 'Deactivated'} ${user.name}`);
|
|
416
|
+
};
|
|
417
|
+
const resetPassword = (user) => console.log('Resetting password for', user.name);
|
|
418
|
+
const deleteUser = (user) => {
|
|
419
|
+
users = users.filter(u => u.id !== user.id);
|
|
420
|
+
console.log('Deleted', user.name);
|
|
421
|
+
};
|
|
422
|
+
</script>
|
|
423
|
+
|
|
424
|
+
<div class="user-table">
|
|
425
|
+
<h3>User Management</h3>
|
|
426
|
+
|
|
427
|
+
<table>
|
|
428
|
+
<thead>
|
|
429
|
+
<tr>
|
|
430
|
+
<th>Name</th>
|
|
431
|
+
<th>Email</th>
|
|
432
|
+
<th>Status</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 ? 'Active' : 'Inactive'}
|
|
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
|
+
## Keyboard Navigation
|
|
496
|
+
|
|
497
|
+
The ContextMenu supports full keyboard navigation:
|
|
498
|
+
|
|
499
|
+
- **Arrow Up/Down**: Navigate between menu items
|
|
500
|
+
- **Enter/Space**: Execute the focused menu item
|
|
501
|
+
- **Escape**: Close the menu
|
|
502
|
+
- **Tab**: Close the menu (focus moves away)
|
|
503
|
+
|
|
504
|
+
## Accessibility
|
|
505
|
+
|
|
506
|
+
The ContextMenu component includes comprehensive accessibility features:
|
|
507
|
+
|
|
508
|
+
- Proper ARIA roles (`menu`, `menuitem`, `separator`)
|
|
509
|
+
- ARIA attributes (`aria-label`, `aria-disabled`)
|
|
510
|
+
- Keyboard navigation support
|
|
511
|
+
- Focus management
|
|
512
|
+
- Screen reader compatibility
|
|
513
|
+
- Semantic HTML structure
|
|
514
|
+
|
|
515
|
+
### Best Practices
|
|
516
|
+
|
|
517
|
+
```svelte
|
|
518
|
+
<!-- Good: Clear context indication -->
|
|
519
|
+
<div class="editable-content" on:contextmenu={showEditMenu}>
|
|
520
|
+
<!-- content -->
|
|
521
|
+
</div>
|
|
522
|
+
|
|
523
|
+
<!-- Good: Appropriate menu items for context -->
|
|
524
|
+
const editMenuItems = [
|
|
525
|
+
{ text: 'Cut', action: () => cut() },
|
|
526
|
+
{ text: 'Copy', action: () => copy() },
|
|
527
|
+
{ text: 'Paste', action: () => paste(), disabled: !canPaste }
|
|
528
|
+
];
|
|
529
|
+
|
|
530
|
+
<!-- Good: Visual feedback for disabled items -->
|
|
531
|
+
.menu-item.disabled {
|
|
532
|
+
opacity: 0.5;
|
|
533
|
+
cursor: not-allowed;
|
|
534
|
+
}
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
## Browser Support
|
|
538
|
+
|
|
539
|
+
Works in all modern browsers that support:
|
|
540
|
+
- ES6+ JavaScript
|
|
541
|
+
- Modern DOM APIs
|
|
542
|
+
- CSS custom properties
|
|
543
|
+
- Portal/Teleport functionality
|
|
544
|
+
|
|
545
|
+
## Performance Considerations
|
|
546
|
+
|
|
547
|
+
- Efficient event handling with proper cleanup
|
|
548
|
+
- Portal rendering for optimal layering
|
|
549
|
+
- Minimal DOM updates with reactive changes
|
|
550
|
+
- Smart positioning calculations
|
|
551
|
+
- Automatic cleanup on component destroy
|