@ticatec/uniface-element 0.2.0 → 0.2.2

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 (209) hide show
  1. package/README.md +320 -1
  2. package/README_CN.md +392 -0
  3. package/dist/accordion/Accordion.svelte +1 -1
  4. package/dist/action-bar/ActionBar.svelte +7 -1
  5. package/dist/attachment-files/FileRender.svelte +1 -1
  6. package/dist/attachment-files/FileUploadBar.svelte +7 -6
  7. package/dist/attachment-files/FileUploadPanel.svelte +2 -2
  8. package/dist/base-calendar/DateContext.js +5 -4
  9. package/dist/base-calendar/YearPickupPanel.svelte +4 -4
  10. package/dist/card/Card.svelte +1 -1
  11. package/dist/card/Card.svelte.d.ts +1 -1
  12. package/dist/cascade-options-select/CascadeOptionSelect.svelte +2 -3
  13. package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +46 -1
  14. package/dist/cascade-options-select/CascadePanel.svelte +1 -1
  15. package/dist/checkbox/CheckBox.svelte +1 -1
  16. package/dist/color-picker/ColorPicker.svelte +9 -9
  17. package/dist/color-picker/ColorPicker.svelte.d.ts +0 -2
  18. package/dist/color-picker/ColorPickerPanel.svelte +11 -15
  19. package/dist/color-picker/ColorPickerPanel.svelte.d.ts +1 -1
  20. package/dist/common/CommonPicker.svelte +2 -2
  21. package/dist/common/CommonPicker.svelte.d.ts +1 -1
  22. package/dist/common/MouseClickHandler.d.ts +1 -1
  23. package/dist/common/Popover.svelte +28 -6
  24. package/dist/common/Popover.svelte.d.ts +9 -3
  25. package/dist/common/uniface-utils.js +6 -4
  26. package/dist/common-editor/CommonEditor.svelte +1 -1
  27. package/dist/common-editor/CommonEditor.svelte.d.ts +1 -1
  28. package/dist/common-editor/NumberInput.svelte +1 -1
  29. package/dist/common-editor/NumberInput.svelte.d.ts +1 -1
  30. package/dist/concise-data-table/ConciseListTable.svelte +7 -2
  31. package/dist/concise-data-table/ConciseListTable.svelte.d.ts +1 -0
  32. package/dist/concise-data-table/DataRow.svelte +1 -1
  33. package/dist/concise-data-table/TableOptions.d.ts +1 -1
  34. package/dist/data-table/DataTable.svelte +1 -1
  35. package/dist/data-table/parts/ActionsPanel.svelte +4 -3
  36. package/dist/data-table/parts/ActionsRow.svelte +3 -3
  37. package/dist/data-table/parts/ContentPanel.svelte +3 -2
  38. package/dist/data-table/parts/FixedColumnsPanel.svelte +0 -1
  39. package/dist/data-table/parts/FixedColumnsPanel.svelte.d.ts +1 -2
  40. package/dist/data-table/parts/FixedHeaderPanel.svelte +2 -2
  41. package/dist/data-table/parts/FixedRow.svelte +2 -1
  42. package/dist/data-table/parts/FixedRow.svelte.d.ts +1 -1
  43. package/dist/data-table/parts/HrefCell.svelte +23 -2
  44. package/dist/data-table/parts/PopupMenu.svelte +25 -2
  45. package/dist/data-table/parts/PopupMenu.svelte.d.ts +8 -1
  46. package/dist/date-picker/DatePicker.svelte +0 -1
  47. package/dist/date-picker/DateTimePicker.svelte +3 -3
  48. package/dist/date-picker/ScrollBar.svelte +4 -7
  49. package/dist/date-range/DateRangeEditor.svelte +1 -1
  50. package/dist/dialog/CommonDialog.svelte +8 -5
  51. package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
  52. package/dist/dialog/Dialog.svelte +37 -12
  53. package/dist/dialog/Dialog.svelte.d.ts +4 -3
  54. package/dist/dialog/DialogBoard.svelte +11 -8
  55. package/dist/dialog/DialogWrapper.svelte +10 -0
  56. package/dist/{common-editor/DateInput.svelte.d.ts → dialog/DialogWrapper.svelte.d.ts} +6 -13
  57. package/dist/dialog/Dialogs.js +1 -1
  58. package/dist/dialog/ModalResult.d.ts +5 -0
  59. package/dist/dialog/ModalResult.js +5 -0
  60. package/dist/drawer/Drawer.svelte +1 -1
  61. package/dist/form-field/FormField.svelte +2 -1
  62. package/dist/form-field/FormField.svelte.d.ts +1 -0
  63. package/dist/form-panel/flex-row-form/FormContainer.svelte +1 -1
  64. package/dist/form-panel/grid-form/EmptyCell.svelte +8 -7
  65. package/dist/form-panel/grid-form/EmptyCell.svelte.d.ts +2 -2
  66. package/dist/form-panel/grid-form/GridField.svelte +1 -1
  67. package/dist/i18nRes/i18nRes.d.ts +2 -0
  68. package/dist/i18nRes/i18nRes.js +44 -0
  69. package/dist/i18nRes/index.d.ts +2 -0
  70. package/dist/i18nRes/index.js +2 -0
  71. package/dist/image-files/ImageFilesField.svelte +1 -1
  72. package/dist/indicator/IndicatorBoard.svelte +1 -1
  73. package/dist/inline-cell-editor/InvalidEditor.svelte +1 -0
  74. package/dist/input-options-select/InputOptionsSelect.svelte +6 -6
  75. package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +1 -1
  76. package/dist/layout/flex/FlexBlock.svelte +1 -1
  77. package/dist/lookup-editor/LookupEditor.svelte +1 -1
  78. package/dist/memo-editor/MemoEditor.svelte +2 -2
  79. package/dist/message-box/IMessageBox.d.ts +2 -4
  80. package/dist/message-box/IMessageBox.js +4 -6
  81. package/dist/message-box/MessageBoxBoard.svelte +1 -3
  82. package/dist/options-multi-select/OptionsMultiSelect.svelte +1 -1
  83. package/dist/prompts-text-editor/PromptsTextEditor.svelte +2 -2
  84. package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +1 -1
  85. package/dist/property-editor/PropertyEditor.svelte +3 -3
  86. package/dist/text-editor/PasswordEditor.svelte +1 -1
  87. package/dist/transfer/Transfer.svelte +17 -12
  88. package/dist/transfer/Transfer.svelte.d.ts +0 -1
  89. package/dist/unit-number-editor/UnitNumberEditor.svelte +2 -2
  90. package/docs/buttons/cn/ActionBar.md +459 -0
  91. package/docs/buttons/cn/Button.md +228 -0
  92. package/docs/buttons/cn/IconButton.md +294 -0
  93. package/docs/buttons/cn/README.md +600 -0
  94. package/docs/buttons/cn/TextButton.md +163 -0
  95. package/docs/buttons/en/ActionBar.md +459 -0
  96. package/docs/buttons/en/Button.md +228 -0
  97. package/docs/buttons/en/IconButton.md +294 -0
  98. package/docs/buttons/en/README.md +600 -0
  99. package/docs/buttons/en/TextButton.md +163 -0
  100. package/docs/containers/cn/accordion.md +622 -0
  101. package/docs/containers/cn/box.md +445 -0
  102. package/docs/containers/cn/card.md +404 -0
  103. package/docs/containers/cn/page.md +576 -0
  104. package/docs/containers/cn/tabs.md +686 -0
  105. package/docs/containers/en/accordion.md +622 -0
  106. package/docs/containers/en/box.md +445 -0
  107. package/docs/containers/en/card.md +404 -0
  108. package/docs/containers/en/page.md +576 -0
  109. package/docs/containers/en/tabs.md +686 -0
  110. package/docs/data-display/cn/concise-data-table.md +731 -0
  111. package/docs/data-display/cn/listbox.md +786 -0
  112. package/docs/data-display/cn/treeview.md +863 -0
  113. package/docs/data-display/en/concise-data-table.md +732 -0
  114. package/docs/data-display/en/listbox.md +786 -0
  115. package/docs/data-display/en/treeview.md +863 -0
  116. package/docs/data-table/cn/README.md +596 -0
  117. package/docs/data-table/en/README.md +596 -0
  118. package/docs/dialog/cn/README.md +767 -0
  119. package/docs/dialog/en/README.md +767 -0
  120. package/docs/form/cn/README.md +847 -0
  121. package/docs/form/en/README.md +847 -0
  122. package/docs/form-components/cn/README.md +495 -0
  123. package/docs/form-components/cn/attachmentfilesfield.md +757 -0
  124. package/docs/form-components/cn/cascade-options-select.md +374 -0
  125. package/docs/form-components/cn/checkbox.md +58 -0
  126. package/docs/form-components/cn/date-picker.md +138 -0
  127. package/docs/form-components/cn/datetime-picker.md +228 -0
  128. package/docs/form-components/cn/group-checkbox.md +405 -0
  129. package/docs/form-components/cn/group-radiobox.md +525 -0
  130. package/docs/form-components/cn/imagefilesfield.md +651 -0
  131. package/docs/form-components/cn/input-options-select.md +250 -0
  132. package/docs/form-components/cn/lookup-editor.md +406 -0
  133. package/docs/form-components/cn/memoeditor.md +409 -0
  134. package/docs/form-components/cn/number-editor.md +261 -0
  135. package/docs/form-components/cn/options-multi-select.md +177 -0
  136. package/docs/form-components/cn/options-select.md +83 -0
  137. package/docs/form-components/cn/passwordeditor.md +538 -0
  138. package/docs/form-components/cn/prompts-text-editor.md +241 -0
  139. package/docs/form-components/cn/radiobutton.md +84 -0
  140. package/docs/form-components/cn/switch.md +178 -0
  141. package/docs/form-components/cn/text-editor.md +142 -0
  142. package/docs/form-components/cn/time-editor.md +159 -0
  143. package/docs/form-components/cn/unit-number-editor.md +164 -0
  144. package/docs/form-components/en/README.md +463 -0
  145. package/docs/form-components/en/attachmentfilesfield.md +757 -0
  146. package/docs/form-components/en/cascade-options-select.md +358 -0
  147. package/docs/form-components/en/checkbox.md +59 -0
  148. package/docs/form-components/en/date-picker.md +138 -0
  149. package/docs/form-components/en/datetime-picker.md +228 -0
  150. package/docs/form-components/en/group-checkbox.md +395 -0
  151. package/docs/form-components/en/group-radiobox.md +498 -0
  152. package/docs/form-components/en/imagefilesfield.md +651 -0
  153. package/docs/form-components/en/input-options-select.md +239 -0
  154. package/docs/form-components/en/lookup-editor.md +389 -0
  155. package/docs/form-components/en/memoeditor.md +409 -0
  156. package/docs/form-components/en/number-editor.md +249 -0
  157. package/docs/form-components/en/options-multi-select.md +177 -0
  158. package/docs/form-components/en/options-select.md +83 -0
  159. package/docs/form-components/en/passwordeditor.md +538 -0
  160. package/docs/form-components/en/prompts-text-editor.md +241 -0
  161. package/docs/form-components/en/radiobutton.md +84 -0
  162. package/docs/form-components/en/switch.md +180 -0
  163. package/docs/form-components/en/text-editor.md +142 -0
  164. package/docs/form-components/en/time-editor.md +159 -0
  165. package/docs/form-components/en/unit-number-editor.md +164 -0
  166. package/docs/form-layout/cn/criteria-field.md +652 -0
  167. package/docs/form-layout/cn/flex-form.md +454 -0
  168. package/docs/form-layout/cn/flex-row-form.md +542 -0
  169. package/docs/form-layout/cn/form-field.md +923 -0
  170. package/docs/form-layout/cn/grid-form.md +676 -0
  171. package/docs/form-layout/en/criteria-field.md +652 -0
  172. package/docs/form-layout/en/flex-form.md +454 -0
  173. package/docs/form-layout/en/flex-row-form.md +542 -0
  174. package/docs/form-layout/en/form-field.md +923 -0
  175. package/docs/form-layout/en/grid-form.md +676 -0
  176. package/docs/global/cn/README.md +534 -0
  177. package/docs/global/en/README.md +534 -0
  178. package/docs/layout/cn/classiclayout.md +460 -0
  179. package/docs/layout/cn/headerlayout.md +524 -0
  180. package/docs/layout/cn/sidebarlayout.md +263 -0
  181. package/docs/layout/en/classiclayout.md +951 -0
  182. package/docs/layout/en/headerlayout.md +524 -0
  183. package/docs/layout/en/sidebarlayout.md +262 -0
  184. package/docs/misc/cn/README.md +1217 -0
  185. package/docs/misc/en/README.md +1217 -0
  186. package/docs/navigation/cn/breadcrumb.md +291 -0
  187. package/docs/navigation/cn/navigator.md +322 -0
  188. package/docs/navigation/cn/navigatormenu.md +512 -0
  189. package/docs/navigation/cn/progressbar.md +199 -0
  190. package/docs/navigation/cn/progressstepbar.md +299 -0
  191. package/docs/navigation/en/breadcrumb.md +291 -0
  192. package/docs/navigation/en/navigator.md +322 -0
  193. package/docs/navigation/en/navigatormenu.md +512 -0
  194. package/docs/navigation/en/progressbar.md +199 -0
  195. package/docs/navigation/en/progressstepbar.md +299 -0
  196. package/docs/search-filters/cn/daterange.md +1156 -0
  197. package/docs/search-filters/cn/numberrange.md +688 -0
  198. package/docs/search-filters/cn/searchbox.md +1582 -0
  199. package/docs/search-filters/en/daterange.md +1156 -0
  200. package/docs/search-filters/en/numberrange.md +688 -0
  201. package/docs/search-filters/en/searchbox.md +1582 -0
  202. package/package.json +53 -13
  203. package/dist/common-editor/DateInput.svelte +0 -27
  204. package/dist/i18n_resources/index.d.ts +0 -3
  205. package/dist/i18n_resources/index.js +0 -3
  206. /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.d.ts +0 -0
  207. /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.js +0 -0
  208. /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.d.ts +0 -0
  209. /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.js +0 -0
@@ -0,0 +1,786 @@
1
+ # ListBox Component
2
+
3
+ A versatile list display component that provides item selection, filtering, lazy loading, and multiple selection modes for displaying collections of data.
4
+
5
+ ## Overview
6
+
7
+ The ListBox component offers a comprehensive solution for displaying lists of items with rich interaction capabilities. It supports single and multiple selection modes, real-time filtering, lazy loading for large datasets, and custom item rendering. Perfect for user selection interfaces, data browsers, and content management systems.
8
+
9
+ ## Installation
10
+
11
+ ```typescript
12
+ import ListBox from '@ticatec/uniface-element/ListBox';
13
+ import type { LazyLoader, FunFilter, LoadResult } from '@ticatec/uniface-element/ListBox';
14
+ ```
15
+
16
+ ## Basic Usage
17
+
18
+ ```svelte
19
+ <script lang="ts">
20
+ import ListBox from '@ticatec/uniface-element/ListBox';
21
+
22
+ // Simple item renderer component
23
+ const ItemRenderer = ({ item }) => `
24
+ <div class="list-item">
25
+ <h4>${item.title}</h4>
26
+ <p>${item.description}</p>
27
+ </div>
28
+ `;
29
+
30
+ let items = [
31
+ { id: 1, title: 'Item 1', description: 'First item description' },
32
+ { id: 2, title: 'Item 2', description: 'Second item description' },
33
+ { id: 3, title: 'Item 3', description: 'Third item description' }
34
+ ];
35
+
36
+ let selectedItem = null;
37
+ </script>
38
+
39
+ <ListBox
40
+ list={items}
41
+ itemRender={ItemRenderer}
42
+ selectMode="single"
43
+ bind:selectedItem
44
+ />
45
+ ```
46
+
47
+ ## Properties
48
+
49
+ | Property | Type | Default | Description |
50
+ |----------|------|---------|-------------|
51
+ | `readonly` | `boolean` | `false` | Make the list read-only |
52
+ | `style` | `string \| null` | `null` | Custom CSS styles for container |
53
+ | `header$style` | `string \| null` | `null` | Custom styles for header area |
54
+ | `footer$style` | `string \| null` | `null` | Custom styles for footer area |
55
+ | `list` | `Array<any>` | - | Array of items to display |
56
+ | `itemRender` | `any` | - | Component for rendering each item |
57
+ | `selectMode` | `'none' \| 'single' \| 'multiple'` | `'none'` | Selection behavior mode |
58
+ | `filter` | `FunFilter \| null` | `null` | Filter function for items |
59
+ | `lazyLoader` | `LazyLoader \| null` | `null` | Lazy loading configuration |
60
+ | `selectedItem` | `any` | `null` | Currently selected item (single mode) |
61
+ | `selectedList` | `Array<any>` | `[]` | Selected items (multiple mode) |
62
+ | `class` | `string` | `''` | Additional CSS class names |
63
+ | `item$props` | `any` | `null` | Additional props for item renderer |
64
+ | `onSelectChange` | `OnSelectChange` | `null` | Selection change callback |
65
+ | `onItemDblClick` | `OnItemDblClick` | `null` | Item double-click callback |
66
+ | `onItemClick` | `OnItemClick` | `null` | Item click callback |
67
+ | `title` | `string` | `null` | Header title |
68
+ | `round` | `boolean` | `false` | Apply rounded corners |
69
+
70
+ ## Slots
71
+
72
+ | Slot | Description |
73
+ |------|-------------|
74
+ | `header` | Custom header content |
75
+ | `footer` | Custom footer content |
76
+ | `loadMoreIndicator` | Custom loading indicator for lazy loading |
77
+
78
+ ## Type Definitions
79
+
80
+ ```typescript
81
+ /**
82
+ * Filter function for items
83
+ */
84
+ export type FunFilter = (item: any, text: string) => boolean;
85
+
86
+ /**
87
+ * Lazy loading result structure
88
+ */
89
+ export interface LoadResult {
90
+ hasMore: boolean;
91
+ list: Array<any>;
92
+ }
93
+
94
+ /**
95
+ * Lazy loader function
96
+ */
97
+ export type LazyLoader = (text: string, pageNo: number) => Promise<LoadResult>;
98
+
99
+ /**
100
+ * Event handler types
101
+ */
102
+ type OnSelectChange = (item: any) => void;
103
+ type OnItemDblClick = (item: any) => void;
104
+ type OnItemClick = (item: any) => void;
105
+ ```
106
+
107
+ ## Usage Examples
108
+
109
+ ### Single Selection List
110
+
111
+ ```svelte
112
+ <script lang="ts">
113
+ import ListBox from '@ticatec/uniface-element/ListBox';
114
+
115
+ // Custom item renderer
116
+ const UserRenderer = ({ item, selected }) => `
117
+ <div class="user-item ${selected ? 'selected' : ''}">
118
+ <div class="user-avatar">
119
+ <img src="${item.avatar}" alt="${item.name}" width="32" height="32" />
120
+ </div>
121
+ <div class="user-info">
122
+ <div class="user-name">${item.name}</div>
123
+ <div class="user-role">${item.role}</div>
124
+ </div>
125
+ </div>
126
+ `;
127
+
128
+ let users = [
129
+ { id: 1, name: 'Alice Johnson', role: 'Developer', avatar: '/avatars/alice.jpg' },
130
+ { id: 2, name: 'Bob Smith', role: 'Designer', avatar: '/avatars/bob.jpg' },
131
+ { id: 3, name: 'Carol Davis', role: 'Manager', avatar: '/avatars/carol.jpg' }
132
+ ];
133
+
134
+ let selectedUser = null;
135
+
136
+ function handleUserSelect(user: any) {
137
+ console.log('Selected user:', user);
138
+ }
139
+ </script>
140
+
141
+ <ListBox
142
+ title="Select User"
143
+ list={users}
144
+ itemRender={UserRenderer}
145
+ selectMode="single"
146
+ bind:selectedItem={selectedUser}
147
+ onSelectChange={handleUserSelect}
148
+ style="width: 300px; height: 400px; border: 1px solid #ddd;"
149
+ />
150
+
151
+ <style>
152
+ :global(.user-item) {
153
+ display: flex;
154
+ align-items: center;
155
+ gap: 12px;
156
+ padding: 12px;
157
+ border-bottom: 1px solid #f0f0f0;
158
+ cursor: pointer;
159
+ transition: background-color 0.2s;
160
+ }
161
+
162
+ :global(.user-item:hover) {
163
+ background-color: #f8f9fa;
164
+ }
165
+
166
+ :global(.user-item.selected) {
167
+ background-color: #e3f2fd;
168
+ }
169
+
170
+ :global(.user-avatar img) {
171
+ border-radius: 50%;
172
+ }
173
+
174
+ :global(.user-name) {
175
+ font-weight: 500;
176
+ margin-bottom: 2px;
177
+ }
178
+
179
+ :global(.user-role) {
180
+ font-size: 0.875rem;
181
+ color: #666;
182
+ }
183
+ </style>
184
+ ```
185
+
186
+ ### Multiple Selection List
187
+
188
+ ```svelte
189
+ <script lang="ts">
190
+ import ListBox from '@ticatec/uniface-element/ListBox';
191
+
192
+ const TaskRenderer = ({ item }) => `
193
+ <div class="task-item">
194
+ <div class="task-title">${item.title}</div>
195
+ <div class="task-meta">
196
+ <span class="task-priority priority-${item.priority.toLowerCase()}">${item.priority}</span>
197
+ <span class="task-due">Due: ${new Date(item.dueDate).toLocaleDateString()}</span>
198
+ </div>
199
+ </div>
200
+ `;
201
+
202
+ let tasks = [
203
+ { id: 1, title: 'Review pull request', priority: 'High', dueDate: '2024-03-20' },
204
+ { id: 2, title: 'Update documentation', priority: 'Medium', dueDate: '2024-03-22' },
205
+ { id: 3, title: 'Fix minor bugs', priority: 'Low', dueDate: '2024-03-25' },
206
+ { id: 4, title: 'Plan next sprint', priority: 'High', dueDate: '2024-03-18' }
207
+ ];
208
+
209
+ let selectedTasks = [];
210
+
211
+ $: console.log('Selected tasks:', selectedTasks);
212
+ </script>
213
+
214
+ <ListBox
215
+ title="Select Tasks"
216
+ list={tasks}
217
+ itemRender={TaskRenderer}
218
+ selectMode="multiple"
219
+ bind:selectedList={selectedTasks}
220
+ style="width: 400px; height: 500px;"
221
+ round={true}
222
+ />
223
+
224
+ <div class="selection-summary">
225
+ <p>Selected: {selectedTasks.length} task(s)</p>
226
+ {#if selectedTasks.length > 0}
227
+ <ul>
228
+ {#each selectedTasks as task}
229
+ <li>{task.title}</li>
230
+ {/each}
231
+ </ul>
232
+ {/if}
233
+ </div>
234
+
235
+ <style>
236
+ :global(.task-item) {
237
+ padding: 12px;
238
+ border-bottom: 1px solid #eee;
239
+ }
240
+
241
+ :global(.task-title) {
242
+ font-weight: 500;
243
+ margin-bottom: 6px;
244
+ }
245
+
246
+ :global(.task-meta) {
247
+ display: flex;
248
+ justify-content: space-between;
249
+ align-items: center;
250
+ font-size: 0.875rem;
251
+ }
252
+
253
+ :global(.task-priority) {
254
+ padding: 2px 8px;
255
+ border-radius: 12px;
256
+ font-size: 0.75rem;
257
+ font-weight: 500;
258
+ }
259
+
260
+ :global(.priority-high) {
261
+ background: #ffebee;
262
+ color: #c62828;
263
+ }
264
+
265
+ :global(.priority-medium) {
266
+ background: #fff3e0;
267
+ color: #ef6c00;
268
+ }
269
+
270
+ :global(.priority-low) {
271
+ background: #e8f5e8;
272
+ color: #2e7d32;
273
+ }
274
+
275
+ :global(.task-due) {
276
+ color: #666;
277
+ }
278
+
279
+ .selection-summary {
280
+ margin-top: 16px;
281
+ padding: 12px;
282
+ background: #f8f9fa;
283
+ border-radius: 4px;
284
+ }
285
+ </style>
286
+ ```
287
+
288
+ ### Filtered List
289
+
290
+ ```svelte
291
+ <script lang="ts">
292
+ import ListBox from '@ticatec/uniface-element/ListBox';
293
+ import type { FunFilter } from '@ticatec/uniface-element/ListBox';
294
+
295
+ const ProductRenderer = ({ item }) => `
296
+ <div class="product-item">
297
+ <img src="${item.image}" alt="${item.name}" class="product-image" />
298
+ <div class="product-info">
299
+ <div class="product-name">${item.name}</div>
300
+ <div class="product-category">${item.category}</div>
301
+ <div class="product-price">$${item.price.toFixed(2)}</div>
302
+ </div>
303
+ </div>
304
+ `;
305
+
306
+ let products = [
307
+ { id: 1, name: 'Laptop Pro', category: 'Electronics', price: 1299.99, image: '/images/laptop.jpg' },
308
+ { id: 2, name: 'Coffee Maker', category: 'Appliances', price: 89.99, image: '/images/coffee.jpg' },
309
+ { id: 3, name: 'Smartphone', category: 'Electronics', price: 699.99, image: '/images/phone.jpg' },
310
+ { id: 4, name: 'Desk Chair', category: 'Furniture', price: 249.99, image: '/images/chair.jpg' },
311
+ { id: 5, name: 'Tablet', category: 'Electronics', price: 329.99, image: '/images/tablet.jpg' }
312
+ ];
313
+
314
+ const productFilter: FunFilter = (item, text) => {
315
+ if (!text) return true;
316
+ const searchText = text.toLowerCase();
317
+ return (
318
+ item.name.toLowerCase().includes(searchText) ||
319
+ item.category.toLowerCase().includes(searchText)
320
+ );
321
+ };
322
+
323
+ let selectedProduct = null;
324
+ </script>
325
+
326
+ <ListBox
327
+ title="Product Catalog"
328
+ list={products}
329
+ itemRender={ProductRenderer}
330
+ selectMode="single"
331
+ filter={productFilter}
332
+ bind:selectedItem={selectedProduct}
333
+ style="width: 350px; height: 600px;"
334
+ header$style="padding: 16px;"
335
+ />
336
+
337
+ {#if selectedProduct}
338
+ <div class="product-details">
339
+ <h3>Selected Product</h3>
340
+ <p><strong>Name:</strong> {selectedProduct.name}</p>
341
+ <p><strong>Category:</strong> {selectedProduct.category}</p>
342
+ <p><strong>Price:</strong> ${selectedProduct.price.toFixed(2)}</p>
343
+ </div>
344
+ {/if}
345
+
346
+ <style>
347
+ :global(.product-item) {
348
+ display: flex;
349
+ align-items: center;
350
+ gap: 12px;
351
+ padding: 12px;
352
+ border-bottom: 1px solid #f0f0f0;
353
+ cursor: pointer;
354
+ }
355
+
356
+ :global(.product-item:hover) {
357
+ background-color: #f8f9fa;
358
+ }
359
+
360
+ :global(.product-image) {
361
+ width: 48px;
362
+ height: 48px;
363
+ object-fit: cover;
364
+ border-radius: 4px;
365
+ }
366
+
367
+ :global(.product-name) {
368
+ font-weight: 500;
369
+ margin-bottom: 2px;
370
+ }
371
+
372
+ :global(.product-category) {
373
+ font-size: 0.875rem;
374
+ color: #666;
375
+ margin-bottom: 2px;
376
+ }
377
+
378
+ :global(.product-price) {
379
+ font-weight: 600;
380
+ color: #007bff;
381
+ }
382
+
383
+ .product-details {
384
+ margin-top: 20px;
385
+ padding: 16px;
386
+ background: #f8f9fa;
387
+ border-radius: 4px;
388
+ width: 350px;
389
+ }
390
+ </style>
391
+ ```
392
+
393
+ ### Lazy Loading List
394
+
395
+ ```svelte
396
+ <script lang="ts">
397
+ import ListBox from '@ticatec/uniface-element/ListBox';
398
+ import type { LazyLoader, LoadResult } from '@ticatec/uniface-element/ListBox';
399
+
400
+ const MessageRenderer = ({ item }) => `
401
+ <div class="message-item">
402
+ <div class="message-header">
403
+ <span class="sender">${item.sender}</span>
404
+ <span class="timestamp">${new Date(item.timestamp).toLocaleTimeString()}</span>
405
+ </div>
406
+ <div class="message-subject">${item.subject}</div>
407
+ <div class="message-preview">${item.preview}</div>
408
+ </div>
409
+ `;
410
+
411
+ // Simulate API call for lazy loading
412
+ const messageLoader: LazyLoader = async (searchText, pageNo) => {
413
+ console.log(`Loading page ${pageNo} with search: "${searchText}"`);
414
+
415
+ // Simulate network delay
416
+ await new Promise(resolve => setTimeout(resolve, 1000));
417
+
418
+ const pageSize = 10;
419
+ const totalMessages = 100;
420
+
421
+ // Generate mock messages
422
+ const messages = Array.from({ length: pageSize }, (_, i) => {
423
+ const messageId = (pageNo - 1) * pageSize + i + 1;
424
+ return {
425
+ id: messageId,
426
+ sender: `User ${messageId}`,
427
+ subject: searchText
428
+ ? `Message about ${searchText} #${messageId}`
429
+ : `Message Subject ${messageId}`,
430
+ preview: `This is a preview of message ${messageId}. It contains some sample content...`,
431
+ timestamp: new Date(Date.now() - Math.random() * 86400000).toISOString()
432
+ };
433
+ });
434
+
435
+ // Filter messages if search text provided
436
+ const filteredMessages = searchText
437
+ ? messages.filter(msg =>
438
+ msg.subject.toLowerCase().includes(searchText.toLowerCase()) ||
439
+ msg.sender.toLowerCase().includes(searchText.toLowerCase())
440
+ )
441
+ : messages;
442
+
443
+ return {
444
+ list: filteredMessages,
445
+ hasMore: pageNo * pageSize < totalMessages
446
+ };
447
+ };
448
+
449
+ let selectedMessage = null;
450
+ </script>
451
+
452
+ <ListBox
453
+ title="Messages (Lazy Loading)"
454
+ itemRender={MessageRenderer}
455
+ selectMode="single"
456
+ lazyLoader={messageLoader}
457
+ bind:selectedItem={selectedMessage}
458
+ style="width: 400px; height: 500px;"
459
+ />
460
+
461
+ <div slot="loadMoreIndicator" class="load-more">
462
+ <div class="loading-spinner">Loading more messages...</div>
463
+ </div>
464
+
465
+ {#if selectedMessage}
466
+ <div class="message-details">
467
+ <h3>Selected Message</h3>
468
+ <p><strong>From:</strong> {selectedMessage.sender}</p>
469
+ <p><strong>Subject:</strong> {selectedMessage.subject}</p>
470
+ <p><strong>Time:</strong> {new Date(selectedMessage.timestamp).toLocaleString()}</p>
471
+ <div class="message-content">
472
+ <p>{selectedMessage.preview}</p>
473
+ </div>
474
+ </div>
475
+ {/if}
476
+
477
+ <style>
478
+ :global(.message-item) {
479
+ padding: 12px;
480
+ border-bottom: 1px solid #eee;
481
+ cursor: pointer;
482
+ transition: background-color 0.2s;
483
+ }
484
+
485
+ :global(.message-item:hover) {
486
+ background-color: #f8f9fa;
487
+ }
488
+
489
+ :global(.message-header) {
490
+ display: flex;
491
+ justify-content: space-between;
492
+ align-items: center;
493
+ margin-bottom: 4px;
494
+ }
495
+
496
+ :global(.sender) {
497
+ font-weight: 500;
498
+ color: #333;
499
+ }
500
+
501
+ :global(.timestamp) {
502
+ font-size: 0.75rem;
503
+ color: #666;
504
+ }
505
+
506
+ :global(.message-subject) {
507
+ font-weight: 500;
508
+ margin-bottom: 4px;
509
+ }
510
+
511
+ :global(.message-preview) {
512
+ font-size: 0.875rem;
513
+ color: #666;
514
+ display: -webkit-box;
515
+ -webkit-line-clamp: 2;
516
+ -webkit-box-orient: vertical;
517
+ overflow: hidden;
518
+ }
519
+
520
+ .load-more {
521
+ padding: 16px;
522
+ text-align: center;
523
+ color: #666;
524
+ }
525
+
526
+ .loading-spinner {
527
+ display: flex;
528
+ align-items: center;
529
+ justify-content: center;
530
+ gap: 8px;
531
+ }
532
+
533
+ .message-details {
534
+ margin-top: 20px;
535
+ padding: 16px;
536
+ background: #f8f9fa;
537
+ border-radius: 4px;
538
+ width: 400px;
539
+ }
540
+
541
+ .message-content {
542
+ margin-top: 12px;
543
+ padding-top: 12px;
544
+ border-top: 1px solid #dee2e6;
545
+ }
546
+ </style>
547
+ ```
548
+
549
+ ### Custom Item Renderer
550
+
551
+ ```svelte
552
+ <script lang="ts">
553
+ import ListBox from '@ticatec/uniface-element/ListBox';
554
+
555
+ // Custom Svelte component for item rendering
556
+ import FileItemRenderer from './FileItemRenderer.svelte';
557
+
558
+ let files = [
559
+ { id: 1, name: 'document.pdf', size: 2048000, type: 'pdf', modified: '2024-03-15T10:30:00Z' },
560
+ { id: 2, name: 'image.jpg', size: 1536000, type: 'image', modified: '2024-03-14T15:45:00Z' },
561
+ { id: 3, name: 'script.js', size: 8192, type: 'code', modified: '2024-03-13T09:20:00Z' },
562
+ { id: 4, name: 'data.csv', size: 512000, type: 'data', modified: '2024-03-12T14:10:00Z' }
563
+ ];
564
+
565
+ let selectedFiles = [];
566
+
567
+ function handleFileDoubleClick(file: any) {
568
+ console.log('Opening file:', file.name);
569
+ // Implement file opening logic
570
+ }
571
+ </script>
572
+
573
+ <ListBox
574
+ title="File Browser"
575
+ list={files}
576
+ itemRender={FileItemRenderer}
577
+ selectMode="multiple"
578
+ bind:selectedList={selectedFiles}
579
+ onItemDblClick={handleFileDoubleClick}
580
+ style="width: 500px; height: 400px;"
581
+ item$props={{ showDetails: true, allowPreview: true }}
582
+ >
583
+ <div slot="footer" class="file-footer">
584
+ <span>{files.length} item(s), {selectedFiles.length} selected</span>
585
+ </div>
586
+ </ListBox>
587
+ ```
588
+
589
+ FileItemRenderer.svelte:
590
+ ```svelte
591
+ <script lang="ts">
592
+ export let item: any;
593
+ export let selected: boolean = false;
594
+ export let readonly: boolean = false;
595
+ export let showDetails: boolean = false;
596
+ export let allowPreview: boolean = false;
597
+
598
+ function formatFileSize(bytes: number) {
599
+ const sizes = ['B', 'KB', 'MB', 'GB'];
600
+ if (bytes === 0) return '0 B';
601
+ const i = Math.floor(Math.log(bytes) / Math.log(1024));
602
+ return Math.round(bytes / Math.pow(1024, i) * 100) / 100 + ' ' + sizes[i];
603
+ }
604
+
605
+ function getFileIcon(type: string) {
606
+ const icons = {
607
+ pdf: '📄',
608
+ image: '🖼️',
609
+ code: '💻',
610
+ data: '📊',
611
+ default: '📁'
612
+ };
613
+ return icons[type] || icons.default;
614
+ }
615
+ </script>
616
+
617
+ <div class="file-item" class:selected class:readonly>
618
+ <div class="file-icon">
619
+ {getFileIcon(item.type)}
620
+ </div>
621
+
622
+ <div class="file-info">
623
+ <div class="file-name">{item.name}</div>
624
+ {#if showDetails}
625
+ <div class="file-details">
626
+ <span class="file-size">{formatFileSize(item.size)}</span>
627
+ <span class="file-modified">Modified: {new Date(item.modified).toLocaleDateString()}</span>
628
+ </div>
629
+ {/if}
630
+ </div>
631
+
632
+ {#if allowPreview && item.type === 'image'}
633
+ <button class="preview-btn" on:click|stopPropagation={() => console.log('Preview', item.name)}>
634
+ 👁️
635
+ </button>
636
+ {/if}
637
+ </div>
638
+
639
+ <style>
640
+ .file-item {
641
+ display: flex;
642
+ align-items: center;
643
+ gap: 12px;
644
+ padding: 8px 12px;
645
+ border-bottom: 1px solid #f0f0f0;
646
+ cursor: pointer;
647
+ transition: background-color 0.2s;
648
+ }
649
+
650
+ .file-item:hover:not(.readonly) {
651
+ background-color: #f8f9fa;
652
+ }
653
+
654
+ .file-item.selected {
655
+ background-color: #e3f2fd;
656
+ }
657
+
658
+ .file-item.readonly {
659
+ cursor: default;
660
+ opacity: 0.7;
661
+ }
662
+
663
+ .file-icon {
664
+ font-size: 24px;
665
+ flex-shrink: 0;
666
+ }
667
+
668
+ .file-info {
669
+ flex: 1;
670
+ min-width: 0;
671
+ }
672
+
673
+ .file-name {
674
+ font-weight: 500;
675
+ white-space: nowrap;
676
+ overflow: hidden;
677
+ text-overflow: ellipsis;
678
+ }
679
+
680
+ .file-details {
681
+ display: flex;
682
+ gap: 16px;
683
+ font-size: 0.875rem;
684
+ color: #666;
685
+ margin-top: 2px;
686
+ }
687
+
688
+ .preview-btn {
689
+ background: none;
690
+ border: 1px solid #ddd;
691
+ border-radius: 4px;
692
+ padding: 4px 8px;
693
+ cursor: pointer;
694
+ opacity: 0.7;
695
+ transition: opacity 0.2s;
696
+ }
697
+
698
+ .preview-btn:hover {
699
+ opacity: 1;
700
+ }
701
+ </style>
702
+ ```
703
+
704
+ ## Styling
705
+
706
+ The ListBox component uses the following CSS classes:
707
+
708
+ ```css
709
+ .uniface-listbox {
710
+ /* Main list container */
711
+ }
712
+
713
+ .uniface-listbox.round {
714
+ /* Rounded corners variant */
715
+ }
716
+
717
+ .box-header {
718
+ /* Header container */
719
+ }
720
+
721
+ .header-search {
722
+ /* Search box container */
723
+ }
724
+
725
+ .listbox-content {
726
+ /* Main content area */
727
+ }
728
+
729
+ .listbox-content.selectable {
730
+ /* Selectable list styling */
731
+ }
732
+
733
+ .listview-item {
734
+ /* Individual list item */
735
+ }
736
+
737
+ .listview-item.selected {
738
+ /* Selected item styling */
739
+ }
740
+
741
+ .box-footer {
742
+ /* Footer container */
743
+ }
744
+
745
+ .list-view-mask {
746
+ /* Loading overlay */
747
+ }
748
+ ```
749
+
750
+ ## API Reference
751
+
752
+ ### ListBox Component Props
753
+
754
+ ```typescript
755
+ interface ListBoxProps {
756
+ readonly?: boolean; // Read-only mode
757
+ style?: string | null; // Container styles
758
+ header$style?: string | null; // Header styles
759
+ footer$style?: string | null; // Footer styles
760
+ list: Array<any>; // Items to display
761
+ itemRender: any; // Item renderer component
762
+ selectMode: 'none' | 'single' | 'multiple'; // Selection mode
763
+ filter?: FunFilter | null; // Filter function
764
+ lazyLoader?: LazyLoader | null; // Lazy loading config
765
+ selectedItem?: any; // Selected item (single mode)
766
+ selectedList?: Array<any>; // Selected items (multiple mode)
767
+ class?: string; // CSS classes
768
+ item$props?: any; // Props for item renderer
769
+ onSelectChange?: OnSelectChange; // Selection callback
770
+ onItemDblClick?: OnItemDblClick; // Double-click callback
771
+ onItemClick?: OnItemClick; // Click callback
772
+ title?: string; // Header title
773
+ round?: boolean; // Rounded corners
774
+ }
775
+ ```
776
+
777
+ ## Best Practices
778
+
779
+ 1. **Performance** - Use lazy loading for large datasets (>100 items)
780
+ 2. **Item Renderers** - Keep item rendering components lightweight and focused
781
+ 3. **Filtering** - Implement efficient filter functions for responsive search
782
+ 4. **Selection Management** - Always bind to selectedItem/selectedList for state tracking
783
+ 5. **Accessibility** - Ensure item renderers support keyboard navigation
784
+ 6. **Error Handling** - Handle loading errors gracefully in lazy loader
785
+ 7. **Visual Feedback** - Provide clear visual indicators for selection and loading states
786
+ 8. **Mobile Support** - Consider touch-friendly item sizes and interactions