@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
@@ -0,0 +1,579 @@
1
+ # ListBox
2
+
3
+ A versatile list component that supports filtering, lazy loading, single/multiple selection modes, and custom item rendering.
4
+
5
+ ## Features
6
+
7
+ - **Multiple Selection Modes**: None, single, and multiple selection support
8
+ - **Search & Filter**: Built-in search functionality with custom filter functions
9
+ - **Lazy Loading**: Support for paginated data loading with infinite scroll
10
+ - **Custom Rendering**: Flexible item rendering with custom components
11
+ - **Interactive States**: Hover, selection, and click handling
12
+ - **Header/Footer Slots**: Customizable header and footer sections
13
+ - **Loading States**: Built-in loading indicators for async operations
14
+ - **Accessibility**: Keyboard navigation and screen reader support
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install @ticatec/uniface-element
20
+ ```
21
+
22
+ ## Usage
23
+
24
+ ### Basic Usage
25
+
26
+ ```svelte
27
+ <script>
28
+ import ListBox from '@ticatec/uniface-element/list-box';
29
+ import MyItemComponent from './MyItemComponent.svelte';
30
+
31
+ let items = [
32
+ { id: 1, name: 'Item 1', description: 'First item' },
33
+ { id: 2, name: 'Item 2', description: 'Second item' },
34
+ { id: 3, name: 'Item 3', description: 'Third item' }
35
+ ];
36
+
37
+ let selectedItem = null;
38
+ </script>
39
+
40
+ <ListBox
41
+ list={items}
42
+ itemRender={MyItemComponent}
43
+ selectMode="single"
44
+ bind:selectedItem
45
+ style="width: 300px; height: 400px;"
46
+ />
47
+ ```
48
+
49
+ ### Read-Only List Display
50
+
51
+ ```svelte
52
+ <ListBox
53
+ list={items}
54
+ itemRender={ItemRenderer}
55
+ selectMode="none"
56
+ readonly={true}
57
+ style="width: 100%; height: 300px;"
58
+ />
59
+ ```
60
+
61
+ ### Multiple Selection
62
+
63
+ ```svelte
64
+ <script>
65
+ let selectedList = [];
66
+ </script>
67
+
68
+ <ListBox
69
+ list={items}
70
+ itemRender={ItemRenderer}
71
+ selectMode="multiple"
72
+ bind:selectedList
73
+ title="Select Multiple Items"
74
+ style="width: 100%; height: 400px;"
75
+ />
76
+
77
+ <p>Selected: {selectedList.length} items</p>
78
+ ```
79
+
80
+ ### With Search/Filter
81
+
82
+ ```svelte
83
+ <script>
84
+ const filterFunction = (item, searchText) => {
85
+ return item.name.toLowerCase().includes(searchText.toLowerCase()) ||
86
+ item.description.toLowerCase().includes(searchText.toLowerCase());
87
+ };
88
+ </script>
89
+
90
+ <ListBox
91
+ list={items}
92
+ itemRender={ItemRenderer}
93
+ selectMode="single"
94
+ filter={filterFunction}
95
+ title="Searchable List"
96
+ bind:selectedItem
97
+ />
98
+ ```
99
+
100
+ ### Lazy Loading
101
+
102
+ ```svelte
103
+ <script>
104
+ const lazyLoader = async (searchText, pageNo) => {
105
+ const response = await fetch(`/api/items?search=${searchText}&page=${pageNo}`);
106
+ const data = await response.json();
107
+
108
+ return {
109
+ list: data.items,
110
+ hasMore: data.hasMore
111
+ };
112
+ };
113
+ </script>
114
+
115
+ <ListBox
116
+ lazyLoader={lazyLoader}
117
+ itemRender={ItemRenderer}
118
+ selectMode="single"
119
+ bind:selectedItem
120
+ style="width: 100%; height: 500px;"
121
+ />
122
+ ```
123
+
124
+ ### Custom Header and Footer
125
+
126
+ ```svelte
127
+ <ListBox
128
+ list={items}
129
+ itemRender={ItemRenderer}
130
+ selectMode="single"
131
+ bind:selectedItem
132
+ >
133
+ <div slot="header" style="padding: 12px; background: #f8f9fa; font-weight: 600;">
134
+ Custom Header - Total: {items.length}
135
+ </div>
136
+
137
+ <div slot="footer" style="padding: 8px; text-align: right; background: #f8f9fa;">
138
+ Selected: {selectedItem?.name || 'None'}
139
+ </div>
140
+ </ListBox>
141
+ ```
142
+
143
+ ## API Reference
144
+
145
+ ### Props
146
+
147
+ | Prop | Type | Default | Description |
148
+ |------|------|---------|-------------|
149
+ | `list` | `Array<any>` | `[]` | Array of items to display |
150
+ | `itemRender` | `SvelteComponent` | - | Component to render each item |
151
+ | `selectMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | Selection mode |
152
+ | `selectedItem` | `any` | `null` | Currently selected item (single mode) |
153
+ | `selectedList` | `Array<any>` | `[]` | Array of selected items (multiple mode) |
154
+ | `filter` | `FunFilter \| null` | `null` | Filter function for search |
155
+ | `lazyLoader` | `LazyLoader \| null` | `null` | Lazy loading function |
156
+ | `readonly` | `boolean` | `false` | Whether the list is read-only |
157
+ | `title` | `string` | - | Title text for the header |
158
+ | `style` | `string` | `''` | Custom CSS styles |
159
+ | `header$style` | `string` | `''` | Custom styles for header |
160
+ | `footer$style` | `string` | `''` | Custom styles for footer |
161
+ | `round` | `boolean` | `false` | Whether to use rounded corners |
162
+ | `item$props` | `any` | `null` | Additional props passed to item components |
163
+ | `class` | `string` | `''` | Additional CSS classes |
164
+
165
+ ### Events
166
+
167
+ | Event | Type | Description |
168
+ |-------|------|-------------|
169
+ | `onSelectChange` | `(item: any) => void` | Fired when selection changes (single mode) |
170
+ | `onItemClick` | `(item: any) => void` | Fired when an item is clicked |
171
+ | `onItemDblClick` | `(item: any) => void` | Fired when an item is double-clicked |
172
+
173
+ ### Slots
174
+
175
+ | Slot | Description |
176
+ |------|-------------|
177
+ | `header` | Custom header content |
178
+ | `footer` | Custom footer content |
179
+ | `loadMoreIndicator` | Custom loading indicator for lazy loading |
180
+
181
+ ### Types
182
+
183
+ ```typescript
184
+ // Filter function type
185
+ type FunFilter = (item: any, searchText: string) => boolean;
186
+
187
+ // Lazy loader function type
188
+ type LazyLoader = (searchText: string, pageNo: number) => Promise<LoadResult>;
189
+
190
+ // Load result interface
191
+ interface LoadResult {
192
+ list: Array<any>;
193
+ hasMore: boolean;
194
+ }
195
+ ```
196
+
197
+ ## Custom Item Renderer
198
+
199
+ Create a custom component to render list items:
200
+
201
+ ```svelte
202
+ <!-- EmployeeRenderer.svelte -->
203
+ <script lang="ts">
204
+ export let item;
205
+ export let selected = false;
206
+ export let readonly = false;
207
+ </script>
208
+
209
+ <div class="employee-item" class:selected>
210
+ <div class="employee-name">{item.name}</div>
211
+ <div class="employee-department">{item.department}</div>
212
+ <div class="employee-phone">{item.phone}</div>
213
+ </div>
214
+
215
+ <style>
216
+ .employee-item {
217
+ padding: 12px;
218
+ border-radius: 4px;
219
+ transition: background-color 0.2s;
220
+ }
221
+
222
+ .employee-item.selected {
223
+ background-color: #e3f2fd;
224
+ }
225
+
226
+ .employee-name {
227
+ font-weight: 600;
228
+ font-size: 1.1em;
229
+ margin-bottom: 4px;
230
+ }
231
+
232
+ .employee-department {
233
+ color: #666;
234
+ font-size: 0.9em;
235
+ }
236
+
237
+ .employee-phone {
238
+ color: #888;
239
+ font-size: 0.8em;
240
+ margin-top: 4px;
241
+ }
242
+ </style>
243
+ ```
244
+
245
+ ## Examples
246
+
247
+ ### Employee Directory
248
+
249
+ ```svelte
250
+ <script>
251
+ import ListBox from '@ticatec/uniface-element/list-box';
252
+ import EmployeeRenderer from './EmployeeRenderer.svelte';
253
+
254
+ let employees = [
255
+ { id: 1, name: 'John Doe', department: 'Engineering', phone: '+1-555-0123' },
256
+ { id: 2, name: 'Jane Smith', department: 'Marketing', phone: '+1-555-0124' },
257
+ { id: 3, name: 'Bob Johnson', department: 'Sales', phone: '+1-555-0125' }
258
+ ];
259
+
260
+ let selectedEmployee = null;
261
+
262
+ const filterEmployees = (employee, searchText) => {
263
+ const text = searchText.toLowerCase();
264
+ return employee.name.toLowerCase().includes(text) ||
265
+ employee.department.toLowerCase().includes(text);
266
+ };
267
+
268
+ function handleEmployeeSelect(employee) {
269
+ console.log('Selected employee:', employee);
270
+ }
271
+ </script>
272
+
273
+ <ListBox
274
+ list={employees}
275
+ itemRender={EmployeeRenderer}
276
+ selectMode="single"
277
+ filter={filterEmployees}
278
+ bind:selectedItem={selectedEmployee}
279
+ onSelectChange={handleEmployeeSelect}
280
+ title="Employee Directory"
281
+ style="width: 400px; height: 500px;"
282
+ >
283
+ <div slot="footer" style="padding: 8px; text-align: center; background: #f5f5f5;">
284
+ Total Employees: {employees.length}
285
+ {#if selectedEmployee}
286
+ | Selected: {selectedEmployee.name}
287
+ {/if}
288
+ </div>
289
+ </ListBox>
290
+ ```
291
+
292
+ ### Product Catalog with Lazy Loading
293
+
294
+ ```svelte
295
+ <script>
296
+ import ListBox from '@ticatec/uniface-element/list-box';
297
+ import ProductRenderer from './ProductRenderer.svelte';
298
+
299
+ let selectedProducts = [];
300
+
301
+ const loadProducts = async (searchText, pageNo) => {
302
+ const params = new URLSearchParams({
303
+ search: searchText || '',
304
+ page: pageNo.toString(),
305
+ limit: '20'
306
+ });
307
+
308
+ try {
309
+ const response = await fetch(`/api/products?${params}`);
310
+ const data = await response.json();
311
+
312
+ return {
313
+ list: data.products,
314
+ hasMore: data.totalPages > pageNo
315
+ };
316
+ } catch (error) {
317
+ console.error('Failed to load products:', error);
318
+ return { list: [], hasMore: false };
319
+ }
320
+ };
321
+ </script>
322
+
323
+ <ListBox
324
+ lazyLoader={loadProducts}
325
+ itemRender={ProductRenderer}
326
+ selectMode="multiple"
327
+ bind:selectedList={selectedProducts}
328
+ style="width: 100%; height: 600px;"
329
+ >
330
+ <div slot="header" style="padding: 12px; background: #2196f3; color: white;">
331
+ <h3 style="margin: 0;">Product Catalog</h3>
332
+ </div>
333
+
334
+ <div slot="footer" style="padding: 8px; background: #f0f0f0; text-align: right;">
335
+ Selected: {selectedProducts.length} products
336
+ <button
337
+ on:click={() => selectedProducts = []}
338
+ disabled={selectedProducts.length === 0}
339
+ >
340
+ Clear Selection
341
+ </button>
342
+ </div>
343
+
344
+ <div slot="loadMoreIndicator" style="padding: 16px; text-align: center;">
345
+ <div class="loading-spinner"></div>
346
+ Loading more products...
347
+ </div>
348
+ </ListBox>
349
+ ```
350
+
351
+ ### Contact List with Actions
352
+
353
+ ```svelte
354
+ <script>
355
+ import ListBox from '@ticatec/uniface-element/list-box';
356
+ import ContactRenderer from './ContactRenderer.svelte';
357
+
358
+ let contacts = [
359
+ { id: 1, name: 'Alice Brown', email: 'alice@example.com', phone: '+1-555-0001' },
360
+ { id: 2, name: 'Charlie Davis', email: 'charlie@example.com', phone: '+1-555-0002' }
361
+ ];
362
+
363
+ let selectedContact = null;
364
+
365
+ function handleContactDblClick(contact) {
366
+ // Open contact details or edit modal
367
+ console.log('Opening contact:', contact);
368
+ }
369
+
370
+ function handleContactCall(contact) {
371
+ console.log('Calling:', contact.phone);
372
+ }
373
+
374
+ function handleContactEmail(contact) {
375
+ window.location.href = `mailto:${contact.email}`;
376
+ }
377
+ </script>
378
+
379
+ <ListBox
380
+ list={contacts}
381
+ itemRender={ContactRenderer}
382
+ selectMode="single"
383
+ bind:selectedItem={selectedContact}
384
+ onItemDblClick={handleContactDblClick}
385
+ item$props={{ onCall: handleContactCall, onEmail: handleContactEmail }}
386
+ title="Contacts"
387
+ style="width: 350px; height: 450px;"
388
+ >
389
+ <div slot="footer" style="padding: 12px; display: flex; gap: 8px;">
390
+ <button
391
+ disabled={!selectedContact}
392
+ on:click={() => handleContactCall(selectedContact)}
393
+ >
394
+ Call
395
+ </button>
396
+ <button
397
+ disabled={!selectedContact}
398
+ on:click={() => handleContactEmail(selectedContact)}
399
+ >
400
+ Email
401
+ </button>
402
+ </div>
403
+ </ListBox>
404
+ ```
405
+
406
+ ## Styling
407
+
408
+ ### CSS Variables
409
+
410
+ The ListBox component uses CSS variables for consistent theming:
411
+
412
+ ```css
413
+ :root {
414
+ --uniface-listbox-separator-color: #f0f0f0;
415
+ --uniface-list-box-hover-bg: #ffffe1;
416
+ --uniface-list-box-selected-bg: #b1c8f6;
417
+ --uniface-list-box-header-bottom-border: 1px solid #f0f0f0;
418
+ --uniface-list-box-border-color: #f0f0f0;
419
+ --uniface-list-box-header-bg: #f8fafc;
420
+ --uniface-list-box-footer-bg: #f8fafc;
421
+ }
422
+ ```
423
+
424
+ ### Custom Styling
425
+
426
+ ```css
427
+ .custom-listbox {
428
+ --uniface-list-box-hover-bg: #e3f2fd;
429
+ --uniface-list-box-selected-bg: #1976d2;
430
+ --uniface-list-box-border-color: #1976d2;
431
+ border-radius: 8px;
432
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
433
+ }
434
+
435
+ .custom-listbox .listview-item {
436
+ transition: all 0.2s ease;
437
+ }
438
+
439
+ .custom-listbox .box-header {
440
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
441
+ color: white;
442
+ }
443
+ ```
444
+
445
+ ## Accessibility Features
446
+
447
+ - **Keyboard Navigation**: Arrow keys for navigation, Enter for selection
448
+ - **Screen Reader Support**: Proper ARIA labels and roles
449
+ - **Focus Management**: Visible focus indicators and logical tab order
450
+ - **Selection Announcements**: Screen reader feedback for selection changes
451
+ - **Search Accessibility**: Proper labeling for search functionality
452
+
453
+ ## Performance Considerations
454
+
455
+ ### Large Lists
456
+
457
+ For large datasets, use lazy loading:
458
+
459
+ ```svelte
460
+ <script>
461
+ const lazyLoader = async (searchText, pageNo) => {
462
+ // Implement efficient server-side pagination
463
+ const response = await fetch(`/api/items?search=${searchText}&page=${pageNo}&limit=50`);
464
+ return await response.json();
465
+ };
466
+ </script>
467
+
468
+ <ListBox
469
+ lazyLoader={lazyLoader}
470
+ itemRender={OptimizedItemRenderer}
471
+ style="height: 400px;"
472
+ />
473
+ ```
474
+
475
+ ### Virtual Scrolling
476
+
477
+ For extremely large lists, consider implementing virtual scrolling in your item renderer:
478
+
479
+ ```svelte
480
+ <!-- VirtualizedItemRenderer.svelte -->
481
+ <script>
482
+ export let item;
483
+ export let index;
484
+
485
+ // Implement virtual scrolling logic here
486
+ </script>
487
+ ```
488
+
489
+ ## Best Practices
490
+
491
+ ### 1. Optimize Item Renderers
492
+
493
+ Keep item renderers simple and efficient:
494
+
495
+ ```svelte
496
+ <!-- Good: Simple and efficient -->
497
+ <script>
498
+ export let item;
499
+ </script>
500
+
501
+ <div class="item">
502
+ <h4>{item.title}</h4>
503
+ <p>{item.description}</p>
504
+ </div>
505
+
506
+ <!-- Avoid: Heavy computations in renderer -->
507
+ <script>
508
+ export let item;
509
+
510
+ // Don't do heavy processing here
511
+ $: processedData = heavyComputation(item);
512
+ </script>
513
+ ```
514
+
515
+ ### 2. Implement Proper Loading States
516
+
517
+ ```svelte
518
+ <ListBox
519
+ lazyLoader={dataLoader}
520
+ itemRender={ItemRenderer}
521
+ >
522
+ <div slot="loadMoreIndicator" class="loading-indicator">
523
+ <div class="spinner"></div>
524
+ Loading more items...
525
+ </div>
526
+ </ListBox>
527
+ ```
528
+
529
+ ### 3. Handle Empty States
530
+
531
+ ```svelte
532
+ <script>
533
+ let items = [];
534
+ let isLoading = false;
535
+ </script>
536
+
537
+ {#if isLoading}
538
+ <div class="loading-state">Loading...</div>
539
+ {:else if items.length === 0}
540
+ <div class="empty-state">No items found</div>
541
+ {:else}
542
+ <ListBox list={items} itemRender={ItemRenderer} />
543
+ {/if}
544
+ ```
545
+
546
+ ### 4. Provide Clear Selection Feedback
547
+
548
+ ```svelte
549
+ <ListBox
550
+ bind:selectedItem
551
+ selectMode="single"
552
+ style="--uniface-list-box-selected-bg: #2196f3; --uniface-list-box-hover-bg: #e3f2fd;"
553
+ />
554
+
555
+ <div class="selection-info">
556
+ {#if selectedItem}
557
+ Selected: {selectedItem.name}
558
+ {:else}
559
+ No item selected
560
+ {/if}
561
+ </div>
562
+ ```
563
+
564
+ ## Browser Support
565
+
566
+ - **Modern Browsers**: Chrome, Firefox, Safari, Edge (latest versions)
567
+ - **Mobile Browsers**: iOS Safari, Chrome Mobile, Firefox Mobile
568
+ - **Flexbox Support**: Required for layout functionality
569
+ - **Intersection Observer**: Required for lazy loading (polyfill available)
570
+
571
+ ## Related Components
572
+
573
+ - **SearchBox**: Used internally for filtering functionality
574
+ - **CheckBox**: Used for multiple selection mode
575
+ - **Box**: Base layout component
576
+
577
+ ## License
578
+
579
+ MIT License - see LICENSE file for details.