@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
|
@@ -1,3 +1,664 @@
|
|
|
1
|
-
#
|
|
1
|
+
# CascadeOptionSelect Component
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
A hierarchical dropdown component for selecting options from nested data structures. Perfect for location selectors (country/state/city), category hierarchies, organizational structures, and any multi-level selection scenarios.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Hierarchical Selection**: Navigate through nested option levels
|
|
8
|
+
- **Dynamic Loading**: Async loading of child options via callbacks
|
|
9
|
+
- **Flexible Data Structure**: Configurable field mapping for different data formats
|
|
10
|
+
- **Leaf Detection**: Custom logic to determine selectable end nodes
|
|
11
|
+
- **Display Modes**: Edit and display modes for different UI contexts
|
|
12
|
+
- **Keyboard & Focus Support**: Full keyboard navigation and focus management
|
|
13
|
+
- **Loading States**: Built-in loading indicators for async operations
|
|
14
|
+
- **Customizable Styling**: Flexible appearance options and variants
|
|
15
|
+
- **Clean/Mandatory Options**: Optional clear functionality and required selection
|
|
16
|
+
|
|
17
|
+
## Basic Usage
|
|
18
|
+
|
|
19
|
+
```svelte
|
|
20
|
+
<script>
|
|
21
|
+
import CascadeOptionSelect from '@ticatec/uniface-element/CascadeOptionSelect';
|
|
22
|
+
|
|
23
|
+
const locationData = [
|
|
24
|
+
{
|
|
25
|
+
code: 'US',
|
|
26
|
+
text: 'United States',
|
|
27
|
+
abbr: 'US',
|
|
28
|
+
children: [
|
|
29
|
+
{
|
|
30
|
+
code: 'CA',
|
|
31
|
+
text: 'California',
|
|
32
|
+
abbr: 'CA',
|
|
33
|
+
children: [
|
|
34
|
+
{ code: 'SF', text: 'San Francisco', abbr: 'SF' },
|
|
35
|
+
{ code: 'LA', text: 'Los Angeles', abbr: 'LA' }
|
|
36
|
+
]
|
|
37
|
+
}
|
|
38
|
+
]
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
|
|
42
|
+
let selectedValue = null;
|
|
43
|
+
|
|
44
|
+
const handleChange = (value) => {
|
|
45
|
+
console.log('Selected:', value);
|
|
46
|
+
selectedValue = value;
|
|
47
|
+
};
|
|
48
|
+
</script>
|
|
49
|
+
|
|
50
|
+
<CascadeOptionSelect
|
|
51
|
+
nodes={locationData}
|
|
52
|
+
bind:value={selectedValue}
|
|
53
|
+
onchange={handleChange}
|
|
54
|
+
placeholder="Select location..."
|
|
55
|
+
/>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Props
|
|
59
|
+
|
|
60
|
+
| Prop | Type | Default | Description |
|
|
61
|
+
|------|------|---------|-------------|
|
|
62
|
+
| `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Visual variant style |
|
|
63
|
+
| `disabled` | `boolean` | `false` | Whether the component is disabled |
|
|
64
|
+
| `readonly` | `boolean` | `false` | Whether the component is read-only |
|
|
65
|
+
| `compact` | `boolean` | `false` | Compact display mode |
|
|
66
|
+
| `mandatory` | `boolean` | `false` | Whether selection is required (disables clear) |
|
|
67
|
+
| `value` | `any` | `null` | Selected value (key field value) |
|
|
68
|
+
| `keyField` | `string` | `'code'` | Field name for option keys/values |
|
|
69
|
+
| `textField` | `string` | `'text'` | Field name for option display text |
|
|
70
|
+
| `abbrField` | `string` | `'abbr'` | Field name for abbreviated text in dropdown |
|
|
71
|
+
| `childrenField` | `string` | `'children'` | Field name for child options |
|
|
72
|
+
| `style` | `string` | `''` | Custom CSS styles |
|
|
73
|
+
| `placeholder` | `string` | `''` | Placeholder text |
|
|
74
|
+
| `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display or edit mode |
|
|
75
|
+
| `emptyText` | `string \| null` | `null` | Text to show when no selection |
|
|
76
|
+
| `checkLeaf` | `IsLeafDetermine \| null` | `null` | Function to determine if item is selectable leaf |
|
|
77
|
+
| `text` | `string` | `''` | Display text (automatically managed) |
|
|
78
|
+
| `nodes` | `Array<any>` | `[]` | Root level options array |
|
|
79
|
+
| `menu$height` | `number` | `150` | Dropdown menu height in pixels |
|
|
80
|
+
| `onSelect` | `OnSelectOption` | - | Async function to load child options |
|
|
81
|
+
| `box$style` | `string` | `''` | Custom styles for option boxes |
|
|
82
|
+
| `onchange` | `OnChangeHandler<any>` | - | Change event handler |
|
|
83
|
+
| `onfocus` | `(() => void) \| null` | `null` | Focus event handler |
|
|
84
|
+
| `onblur` | `(() => void) \| null` | `null` | Blur event handler |
|
|
85
|
+
|
|
86
|
+
## Type Definitions
|
|
87
|
+
|
|
88
|
+
```typescript
|
|
89
|
+
// Function to load child options asynchronously
|
|
90
|
+
type OnSelectOption = (item: any) => Promise<Array<any>>;
|
|
91
|
+
|
|
92
|
+
// Function to determine if an item is a selectable leaf node
|
|
93
|
+
type IsLeafDetermine = (item: any) => boolean;
|
|
94
|
+
|
|
95
|
+
// Change event handler
|
|
96
|
+
type OnChangeHandler<T> = (value: T) => void;
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Static Data Example
|
|
100
|
+
|
|
101
|
+
```svelte
|
|
102
|
+
<script>
|
|
103
|
+
const categories = [
|
|
104
|
+
{
|
|
105
|
+
code: 'electronics',
|
|
106
|
+
text: 'Electronics',
|
|
107
|
+
abbr: 'Electronics',
|
|
108
|
+
children: [
|
|
109
|
+
{
|
|
110
|
+
code: 'computers',
|
|
111
|
+
text: 'Computers',
|
|
112
|
+
abbr: 'Computers',
|
|
113
|
+
children: [
|
|
114
|
+
{ code: 'laptops', text: 'Laptops', abbr: 'Laptops' },
|
|
115
|
+
{ code: 'desktops', text: 'Desktops', abbr: 'Desktops' }
|
|
116
|
+
]
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
code: 'phones',
|
|
120
|
+
text: 'Mobile Phones',
|
|
121
|
+
abbr: 'Phones',
|
|
122
|
+
children: [
|
|
123
|
+
{ code: 'smartphones', text: 'Smartphones', abbr: 'Smartphones' },
|
|
124
|
+
{ code: 'basic-phones', text: 'Basic Phones', abbr: 'Basic' }
|
|
125
|
+
]
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
}
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
let selectedCategory = null;
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<CascadeOptionSelect
|
|
135
|
+
nodes={categories}
|
|
136
|
+
bind:value={selectedCategory}
|
|
137
|
+
placeholder="Select category..."
|
|
138
|
+
onchange={(value) => console.log('Selected category:', value)}
|
|
139
|
+
/>
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
## Dynamic Loading Example
|
|
143
|
+
|
|
144
|
+
```svelte
|
|
145
|
+
<script>
|
|
146
|
+
const loadRegions = async (country) => {
|
|
147
|
+
// Simulate API call
|
|
148
|
+
const response = await fetch(`/api/regions?country=${country.code}`);
|
|
149
|
+
return await response.json();
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
const loadCities = async (region) => {
|
|
153
|
+
const response = await fetch(`/api/cities?region=${region.code}`);
|
|
154
|
+
return await response.json();
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const dynamicLoader = async (item) => {
|
|
158
|
+
// Determine what type of data to load based on the item
|
|
159
|
+
if (!item.children) {
|
|
160
|
+
if (item.type === 'country') {
|
|
161
|
+
return await loadRegions(item);
|
|
162
|
+
} else if (item.type === 'region') {
|
|
163
|
+
return await loadCities(item);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return item.children || [];
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
const countries = [
|
|
170
|
+
{ code: 'US', text: 'United States', abbr: 'US', type: 'country' },
|
|
171
|
+
{ code: 'CA', text: 'Canada', abbr: 'CA', type: 'country' },
|
|
172
|
+
{ code: 'UK', text: 'United Kingdom', abbr: 'UK', type: 'country' }
|
|
173
|
+
];
|
|
174
|
+
|
|
175
|
+
let selectedLocation = null;
|
|
176
|
+
</script>
|
|
177
|
+
|
|
178
|
+
<CascadeOptionSelect
|
|
179
|
+
nodes={countries}
|
|
180
|
+
bind:value={selectedLocation}
|
|
181
|
+
onSelect={dynamicLoader}
|
|
182
|
+
placeholder="Select location..."
|
|
183
|
+
onchange={(value) => console.log('Selected location:', value)}
|
|
184
|
+
/>
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Custom Field Mapping
|
|
188
|
+
|
|
189
|
+
```svelte
|
|
190
|
+
<script>
|
|
191
|
+
// Data with different field names
|
|
192
|
+
const orgData = [
|
|
193
|
+
{
|
|
194
|
+
id: 'corp',
|
|
195
|
+
name: 'Corporation',
|
|
196
|
+
short: 'Corp',
|
|
197
|
+
divisions: [
|
|
198
|
+
{
|
|
199
|
+
id: 'tech',
|
|
200
|
+
name: 'Technology Division',
|
|
201
|
+
short: 'Tech',
|
|
202
|
+
departments: [
|
|
203
|
+
{ id: 'dev', name: 'Development', short: 'Dev' },
|
|
204
|
+
{ id: 'qa', name: 'Quality Assurance', short: 'QA' }
|
|
205
|
+
]
|
|
206
|
+
}
|
|
207
|
+
]
|
|
208
|
+
}
|
|
209
|
+
];
|
|
210
|
+
|
|
211
|
+
let selectedOrg = null;
|
|
212
|
+
</script>
|
|
213
|
+
|
|
214
|
+
<CascadeOptionSelect
|
|
215
|
+
nodes={orgData}
|
|
216
|
+
bind:value={selectedOrg}
|
|
217
|
+
keyField="id"
|
|
218
|
+
textField="name"
|
|
219
|
+
abbrField="short"
|
|
220
|
+
childrenField="divisions"
|
|
221
|
+
placeholder="Select organization..."
|
|
222
|
+
/>
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
## Leaf Detection Example
|
|
226
|
+
|
|
227
|
+
```svelte
|
|
228
|
+
<script>
|
|
229
|
+
const menuData = [
|
|
230
|
+
{
|
|
231
|
+
code: 'file',
|
|
232
|
+
text: 'File',
|
|
233
|
+
abbr: 'File',
|
|
234
|
+
isLeaf: false,
|
|
235
|
+
children: [
|
|
236
|
+
{ code: 'new', text: 'New File', abbr: 'New', isLeaf: true },
|
|
237
|
+
{ code: 'open', text: 'Open File', abbr: 'Open', isLeaf: true },
|
|
238
|
+
{ code: 'save', text: 'Save File', abbr: 'Save', isLeaf: true }
|
|
239
|
+
]
|
|
240
|
+
}
|
|
241
|
+
];
|
|
242
|
+
|
|
243
|
+
const checkIfLeaf = (item) => {
|
|
244
|
+
return item.isLeaf === true;
|
|
245
|
+
};
|
|
246
|
+
|
|
247
|
+
let selectedMenuItem = null;
|
|
248
|
+
</script>
|
|
249
|
+
|
|
250
|
+
<CascadeOptionSelect
|
|
251
|
+
nodes={menuData}
|
|
252
|
+
bind:value={selectedMenuItem}
|
|
253
|
+
checkLeaf={checkIfLeaf}
|
|
254
|
+
placeholder="Select menu item..."
|
|
255
|
+
/>
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
## Different Variants
|
|
259
|
+
|
|
260
|
+
```svelte
|
|
261
|
+
<!-- Default variant -->
|
|
262
|
+
<CascadeOptionSelect
|
|
263
|
+
nodes={data}
|
|
264
|
+
placeholder="Default style"
|
|
265
|
+
/>
|
|
266
|
+
|
|
267
|
+
<!-- Plain variant -->
|
|
268
|
+
<CascadeOptionSelect
|
|
269
|
+
nodes={data}
|
|
270
|
+
variant="plain"
|
|
271
|
+
placeholder="Plain style"
|
|
272
|
+
/>
|
|
273
|
+
|
|
274
|
+
<!-- Outlined variant -->
|
|
275
|
+
<CascadeOptionSelect
|
|
276
|
+
nodes={data}
|
|
277
|
+
variant="outlined"
|
|
278
|
+
placeholder="Outlined style"
|
|
279
|
+
/>
|
|
280
|
+
|
|
281
|
+
<!-- Filled variant -->
|
|
282
|
+
<CascadeOptionSelect
|
|
283
|
+
nodes={data}
|
|
284
|
+
variant="filled"
|
|
285
|
+
placeholder="Filled style"
|
|
286
|
+
/>
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Event Handling
|
|
290
|
+
|
|
291
|
+
```svelte
|
|
292
|
+
<script>
|
|
293
|
+
let currentValue = null;
|
|
294
|
+
let focusCount = 0;
|
|
295
|
+
|
|
296
|
+
const handleChange = (value) => {
|
|
297
|
+
console.log('Value changed to:', value);
|
|
298
|
+
currentValue = value;
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const handleFocus = () => {
|
|
302
|
+
console.log('Component focused');
|
|
303
|
+
focusCount++;
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const handleBlur = () => {
|
|
307
|
+
console.log('Component blurred');
|
|
308
|
+
};
|
|
309
|
+
</script>
|
|
310
|
+
|
|
311
|
+
<CascadeOptionSelect
|
|
312
|
+
nodes={data}
|
|
313
|
+
bind:value={currentValue}
|
|
314
|
+
onchange={handleChange}
|
|
315
|
+
onfocus={handleFocus}
|
|
316
|
+
onblur={handleBlur}
|
|
317
|
+
placeholder="Event handling example"
|
|
318
|
+
/>
|
|
319
|
+
|
|
320
|
+
<p>Current value: {currentValue}</p>
|
|
321
|
+
<p>Focus count: {focusCount}</p>
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
## Advanced Examples
|
|
325
|
+
|
|
326
|
+
### Location Selector with API Integration
|
|
327
|
+
|
|
328
|
+
```svelte
|
|
329
|
+
<script>
|
|
330
|
+
import { onMount } from 'svelte';
|
|
331
|
+
|
|
332
|
+
let countries = [];
|
|
333
|
+
let selectedLocation = null;
|
|
334
|
+
|
|
335
|
+
onMount(async () => {
|
|
336
|
+
// Load initial countries
|
|
337
|
+
const response = await fetch('/api/countries');
|
|
338
|
+
countries = await response.json();
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const loadLocationChildren = async (location) => {
|
|
342
|
+
let endpoint = '';
|
|
343
|
+
|
|
344
|
+
if (location.type === 'country') {
|
|
345
|
+
endpoint = `/api/states?country=${location.code}`;
|
|
346
|
+
} else if (location.type === 'state') {
|
|
347
|
+
endpoint = `/api/cities?state=${location.code}`;
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (endpoint) {
|
|
351
|
+
const response = await fetch(endpoint);
|
|
352
|
+
return await response.json();
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
return [];
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const isLocationLeaf = (location) => {
|
|
359
|
+
return location.type === 'city';
|
|
360
|
+
};
|
|
361
|
+
</script>
|
|
362
|
+
|
|
363
|
+
<div class="location-selector">
|
|
364
|
+
<label>Select Location:</label>
|
|
365
|
+
<CascadeOptionSelect
|
|
366
|
+
nodes={countries}
|
|
367
|
+
bind:value={selectedLocation}
|
|
368
|
+
onSelect={loadLocationChildren}
|
|
369
|
+
checkLeaf={isLocationLeaf}
|
|
370
|
+
placeholder="Country / State / City"
|
|
371
|
+
mandatory={true}
|
|
372
|
+
variant="outlined"
|
|
373
|
+
/>
|
|
374
|
+
</div>
|
|
375
|
+
```
|
|
376
|
+
|
|
377
|
+
### Product Category Navigator
|
|
378
|
+
|
|
379
|
+
```svelte
|
|
380
|
+
<script>
|
|
381
|
+
const productCategories = [
|
|
382
|
+
{
|
|
383
|
+
code: 'electronics',
|
|
384
|
+
text: 'Electronics',
|
|
385
|
+
abbr: 'Electronics',
|
|
386
|
+
children: [
|
|
387
|
+
{
|
|
388
|
+
code: 'computers',
|
|
389
|
+
text: 'Computers & Accessories',
|
|
390
|
+
abbr: 'Computers',
|
|
391
|
+
children: [
|
|
392
|
+
{ code: 'laptops', text: 'Laptops', abbr: 'Laptops' },
|
|
393
|
+
{ code: 'desktops', text: 'Desktop Computers', abbr: 'Desktops' },
|
|
394
|
+
{ code: 'accessories', text: 'Computer Accessories', abbr: 'Accessories' }
|
|
395
|
+
]
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
code: 'mobile',
|
|
399
|
+
text: 'Mobile Devices',
|
|
400
|
+
abbr: 'Mobile',
|
|
401
|
+
children: [
|
|
402
|
+
{ code: 'smartphones', text: 'Smartphones', abbr: 'Phones' },
|
|
403
|
+
{ code: 'tablets', text: 'Tablets', abbr: 'Tablets' },
|
|
404
|
+
{ code: 'wearables', text: 'Wearable Technology', abbr: 'Wearables' }
|
|
405
|
+
]
|
|
406
|
+
}
|
|
407
|
+
]
|
|
408
|
+
},
|
|
409
|
+
{
|
|
410
|
+
code: 'clothing',
|
|
411
|
+
text: 'Clothing & Fashion',
|
|
412
|
+
abbr: 'Clothing',
|
|
413
|
+
children: [
|
|
414
|
+
{
|
|
415
|
+
code: 'mens',
|
|
416
|
+
text: "Men's Clothing",
|
|
417
|
+
abbr: "Men's",
|
|
418
|
+
children: [
|
|
419
|
+
{ code: 'shirts', text: 'Shirts', abbr: 'Shirts' },
|
|
420
|
+
{ code: 'pants', text: 'Pants', abbr: 'Pants' },
|
|
421
|
+
{ code: 'shoes', text: 'Shoes', abbr: 'Shoes' }
|
|
422
|
+
]
|
|
423
|
+
}
|
|
424
|
+
]
|
|
425
|
+
}
|
|
426
|
+
];
|
|
427
|
+
|
|
428
|
+
let selectedCategory = null;
|
|
429
|
+
|
|
430
|
+
$: if (selectedCategory) {
|
|
431
|
+
console.log('Browse products in category:', selectedCategory);
|
|
432
|
+
}
|
|
433
|
+
</script>
|
|
434
|
+
|
|
435
|
+
<div class="category-navigator">
|
|
436
|
+
<h3>Browse Products</h3>
|
|
437
|
+
<CascadeOptionSelect
|
|
438
|
+
nodes={productCategories}
|
|
439
|
+
bind:value={selectedCategory}
|
|
440
|
+
placeholder="Select category to browse..."
|
|
441
|
+
variant="filled"
|
|
442
|
+
menu$height={200}
|
|
443
|
+
/>
|
|
444
|
+
</div>
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Organization Hierarchy Selector
|
|
448
|
+
|
|
449
|
+
```svelte
|
|
450
|
+
<script>
|
|
451
|
+
const organizationData = [
|
|
452
|
+
{
|
|
453
|
+
code: 'headquarters',
|
|
454
|
+
text: 'Headquarters',
|
|
455
|
+
abbr: 'HQ',
|
|
456
|
+
children: [
|
|
457
|
+
{
|
|
458
|
+
code: 'exec',
|
|
459
|
+
text: 'Executive',
|
|
460
|
+
abbr: 'Exec',
|
|
461
|
+
children: [
|
|
462
|
+
{ code: 'ceo', text: 'Chief Executive Officer', abbr: 'CEO' },
|
|
463
|
+
{ code: 'cto', text: 'Chief Technology Officer', abbr: 'CTO' }
|
|
464
|
+
]
|
|
465
|
+
},
|
|
466
|
+
{
|
|
467
|
+
code: 'engineering',
|
|
468
|
+
text: 'Engineering',
|
|
469
|
+
abbr: 'Eng',
|
|
470
|
+
children: [
|
|
471
|
+
{ code: 'frontend', text: 'Frontend Development', abbr: 'Frontend' },
|
|
472
|
+
{ code: 'backend', text: 'Backend Development', abbr: 'Backend' },
|
|
473
|
+
{ code: 'devops', text: 'DevOps', abbr: 'DevOps' }
|
|
474
|
+
]
|
|
475
|
+
}
|
|
476
|
+
]
|
|
477
|
+
}
|
|
478
|
+
];
|
|
479
|
+
|
|
480
|
+
let assignedDepartment = null;
|
|
481
|
+
|
|
482
|
+
const handleDepartmentChange = (value) => {
|
|
483
|
+
console.log('Assigned to department:', value);
|
|
484
|
+
// Update user assignment
|
|
485
|
+
};
|
|
486
|
+
</script>
|
|
487
|
+
|
|
488
|
+
<div class="department-assignment">
|
|
489
|
+
<label>Assign to Department:</label>
|
|
490
|
+
<CascadeOptionSelect
|
|
491
|
+
nodes={organizationData}
|
|
492
|
+
bind:value={assignedDepartment}
|
|
493
|
+
onchange={handleDepartmentChange}
|
|
494
|
+
placeholder="Select department..."
|
|
495
|
+
mandatory={true}
|
|
496
|
+
compact={true}
|
|
497
|
+
/>
|
|
498
|
+
</div>
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
### Menu System with Dynamic Loading
|
|
502
|
+
|
|
503
|
+
```svelte
|
|
504
|
+
<script>
|
|
505
|
+
let menuItems = [
|
|
506
|
+
{ code: 'file', text: 'File', abbr: 'File', hasChildren: true },
|
|
507
|
+
{ code: 'edit', text: 'Edit', abbr: 'Edit', hasChildren: true },
|
|
508
|
+
{ code: 'view', text: 'View', abbr: 'View', hasChildren: true }
|
|
509
|
+
];
|
|
510
|
+
|
|
511
|
+
const loadMenuChildren = async (menuItem) => {
|
|
512
|
+
// Simulate loading menu items from server
|
|
513
|
+
await new Promise(resolve => setTimeout(resolve, 500));
|
|
514
|
+
|
|
515
|
+
const menuMap = {
|
|
516
|
+
'file': [
|
|
517
|
+
{ code: 'new', text: 'New', abbr: 'New', action: 'file.new' },
|
|
518
|
+
{ code: 'open', text: 'Open', abbr: 'Open', action: 'file.open' },
|
|
519
|
+
{ code: 'save', text: 'Save', abbr: 'Save', action: 'file.save' }
|
|
520
|
+
],
|
|
521
|
+
'edit': [
|
|
522
|
+
{ code: 'cut', text: 'Cut', abbr: 'Cut', action: 'edit.cut' },
|
|
523
|
+
{ code: 'copy', text: 'Copy', abbr: 'Copy', action: 'edit.copy' },
|
|
524
|
+
{ code: 'paste', text: 'Paste', abbr: 'Paste', action: 'edit.paste' }
|
|
525
|
+
],
|
|
526
|
+
'view': [
|
|
527
|
+
{ code: 'zoom-in', text: 'Zoom In', abbr: 'Zoom+', action: 'view.zoomIn' },
|
|
528
|
+
{ code: 'zoom-out', text: 'Zoom Out', abbr: 'Zoom-', action: 'view.zoomOut' }
|
|
529
|
+
]
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
return menuMap[menuItem.code] || [];
|
|
533
|
+
};
|
|
534
|
+
|
|
535
|
+
const isMenuItem = (item) => {
|
|
536
|
+
return item.action != null;
|
|
537
|
+
};
|
|
538
|
+
|
|
539
|
+
let selectedAction = null;
|
|
540
|
+
|
|
541
|
+
$: if (selectedAction) {
|
|
542
|
+
console.log('Execute action:', selectedAction);
|
|
543
|
+
}
|
|
544
|
+
</script>
|
|
545
|
+
|
|
546
|
+
<CascadeOptionSelect
|
|
547
|
+
nodes={menuItems}
|
|
548
|
+
bind:value={selectedAction}
|
|
549
|
+
onSelect={loadMenuChildren}
|
|
550
|
+
checkLeaf={isMenuItem}
|
|
551
|
+
placeholder="Select action..."
|
|
552
|
+
variant="outlined"
|
|
553
|
+
/>
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
## Styling
|
|
557
|
+
|
|
558
|
+
The component uses the following CSS classes and can be styled through:
|
|
559
|
+
|
|
560
|
+
- Custom `style` prop for the main container
|
|
561
|
+
- `box$style` prop for individual option boxes
|
|
562
|
+
- `menu$height` prop for dropdown height
|
|
563
|
+
- CSS custom properties for deeper customization
|
|
564
|
+
|
|
565
|
+
### Example Styling
|
|
566
|
+
|
|
567
|
+
```svelte
|
|
568
|
+
<CascadeOptionSelect
|
|
569
|
+
nodes={data}
|
|
570
|
+
style="border-radius: 8px; border: 2px solid #007acc;"
|
|
571
|
+
box$style="background: #f5f5f5; border-radius: 4px;"
|
|
572
|
+
menu$height={250}
|
|
573
|
+
/>
|
|
574
|
+
```
|
|
575
|
+
|
|
576
|
+
## Accessibility
|
|
577
|
+
|
|
578
|
+
The component includes:
|
|
579
|
+
|
|
580
|
+
- Proper focus management
|
|
581
|
+
- Keyboard navigation support
|
|
582
|
+
- ARIA attributes for screen readers
|
|
583
|
+
- Focus and blur event handling
|
|
584
|
+
- Clear visual indicators for selected items
|
|
585
|
+
|
|
586
|
+
## Best Practices
|
|
587
|
+
|
|
588
|
+
1. **Data Structure**: Use consistent field naming across all levels
|
|
589
|
+
2. **Loading States**: Provide feedback during async operations
|
|
590
|
+
3. **Error Handling**: Handle API failures gracefully in onSelect callbacks
|
|
591
|
+
4. **Performance**: Consider virtualization for very large datasets
|
|
592
|
+
5. **Validation**: Validate leaf selection when mandatory is true
|
|
593
|
+
6. **Responsive Design**: Test dropdown behavior on mobile devices
|
|
594
|
+
7. **User Experience**: Provide clear visual hierarchy in option display
|
|
595
|
+
|
|
596
|
+
## Common Patterns
|
|
597
|
+
|
|
598
|
+
### Form Integration
|
|
599
|
+
|
|
600
|
+
```svelte
|
|
601
|
+
<script>
|
|
602
|
+
let formData = {
|
|
603
|
+
location: null,
|
|
604
|
+
category: null
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
const validateForm = () => {
|
|
608
|
+
return formData.location && formData.category;
|
|
609
|
+
};
|
|
610
|
+
</script>
|
|
611
|
+
|
|
612
|
+
<form>
|
|
613
|
+
<div class="form-field">
|
|
614
|
+
<label>Location:</label>
|
|
615
|
+
<CascadeOptionSelect
|
|
616
|
+
nodes={locationData}
|
|
617
|
+
bind:value={formData.location}
|
|
618
|
+
mandatory={true}
|
|
619
|
+
placeholder="Select location..."
|
|
620
|
+
/>
|
|
621
|
+
</div>
|
|
622
|
+
|
|
623
|
+
<button type="submit" disabled={!validateForm()}>
|
|
624
|
+
Submit
|
|
625
|
+
</button>
|
|
626
|
+
</form>
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
### State Management
|
|
630
|
+
|
|
631
|
+
```svelte
|
|
632
|
+
<script>
|
|
633
|
+
import { writable } from 'svelte/store';
|
|
634
|
+
|
|
635
|
+
const selectedValues = writable({
|
|
636
|
+
location: null,
|
|
637
|
+
category: null,
|
|
638
|
+
department: null
|
|
639
|
+
});
|
|
640
|
+
|
|
641
|
+
$: console.log('Current selections:', $selectedValues);
|
|
642
|
+
</script>
|
|
643
|
+
|
|
644
|
+
<CascadeOptionSelect
|
|
645
|
+
nodes={locationData}
|
|
646
|
+
value={$selectedValues.location}
|
|
647
|
+
onchange={(value) => selectedValues.update(s => ({...s, location: value}))}
|
|
648
|
+
/>
|
|
649
|
+
```
|
|
650
|
+
|
|
651
|
+
## Browser Support
|
|
652
|
+
|
|
653
|
+
Works in all modern browsers that support:
|
|
654
|
+
- ES6+ JavaScript
|
|
655
|
+
- CSS Flexbox
|
|
656
|
+
- Modern DOM APIs
|
|
657
|
+
- Promises/async-await
|
|
658
|
+
|
|
659
|
+
## Performance Considerations
|
|
660
|
+
|
|
661
|
+
- Efficient handling of large datasets through virtual scrolling in option boxes
|
|
662
|
+
- Debounced async loading to prevent excessive API calls
|
|
663
|
+
- Proper cleanup of event listeners and timeouts
|
|
664
|
+
- Optimized re-rendering with Svelte's reactivity system
|