@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,239 @@
1
+ # InputOptionsSelect Component
2
+
3
+ Selection component with input and async search functionality.
4
+
5
+ ## Type Definitions
6
+
7
+ ```typescript
8
+ type LazyLoader = (keyword: string, pageNo: number) => Promise<{
9
+ list: Array<any>;
10
+ hasMore: boolean;
11
+ }>;
12
+ ```
13
+
14
+ ## Properties
15
+
16
+ | Property | Type | Default | Description |
17
+ |----------|------|---------|-------------|
18
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Appearance variant |
19
+ | `disabled` | `boolean` | `false` | Whether disabled |
20
+ | `readonly` | `boolean` | `false` | Whether read-only |
21
+ | `compact` | `boolean` | `false` | Whether compact mode |
22
+ | `text` | `string` | `''` | Display text |
23
+ | `value` | `any` | `null` | Selected value |
24
+ | `keyField` | `string` | `'code'` | Value field name |
25
+ | `textField` | `string` | `'text'` | Display field name |
26
+ | `menu$height` | `number` | `0` | Dropdown menu height |
27
+ | `placeholder` | `string` | `''` | Placeholder text |
28
+ | `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode |
29
+ | `itemRender` | `any` | `null` | Custom option render component |
30
+ | `lazyLoader` | `LazyLoader` | - | Async data loader |
31
+ | `style` | `string` | `''` | Custom styles |
32
+ | `onChange` | `OnChangeHandler<any>` | - | Value change callback |
33
+
34
+ ## Usage Examples
35
+
36
+ ```svelte
37
+ <script lang="ts">
38
+ import InputOptionsSelect, { type LazyLoader } from '@ticatec/uniface-element/InputOptionsSelect';
39
+
40
+ interface User {
41
+ id: string;
42
+ name: string;
43
+ email: string;
44
+ department: string;
45
+ }
46
+
47
+ interface Product {
48
+ code: string;
49
+ text: string;
50
+ category: string;
51
+ price: number;
52
+ }
53
+
54
+ let selectedUser: User | null = null;
55
+ let selectedProduct: Product | null = null;
56
+
57
+ // User search
58
+ const searchUsers: LazyLoader = async (keyword: string, pageNo: number) => {
59
+ const response = await fetch(`/api/users/search?q=${encodeURIComponent(keyword)}&page=${pageNo}`);
60
+ const data = await response.json();
61
+ return {
62
+ list: data.users,
63
+ hasMore: data.hasMore
64
+ };
65
+ };
66
+
67
+ // Product search
68
+ const searchProducts: LazyLoader = async (keyword: string, pageNo: number) => {
69
+ // Simulate API delay
70
+ await new Promise(resolve => setTimeout(resolve, 300));
71
+
72
+ const mockProducts: Product[] = [
73
+ { code: 'P001', text: 'iPhone 15 Pro', category: 'Phone', price: 999 },
74
+ { code: 'P002', text: 'MacBook Air M2', category: 'Laptop', price: 1299 },
75
+ { code: 'P003', text: 'iPad Pro 12.9', category: 'Tablet', price: 899 }
76
+ ].filter(p => p.text.toLowerCase().includes(keyword.toLowerCase()));
77
+
78
+ return {
79
+ list: mockProducts,
80
+ hasMore: false
81
+ };
82
+ };
83
+
84
+ const handleUserChange = (user: User): void => {
85
+ selectedUser = user;
86
+ console.log('Selected user:', user);
87
+ };
88
+
89
+ const handleProductChange = (product: Product): void => {
90
+ selectedProduct = product;
91
+ console.log('Selected product:', product);
92
+ };
93
+ </script>
94
+
95
+ <!-- User search selection -->
96
+ <InputOptionsSelect
97
+ placeholder="Search for users..."
98
+ lazyLoader={searchUsers}
99
+ keyField="id"
100
+ textField="name"
101
+ onChange={handleUserChange}
102
+ />
103
+
104
+ <!-- Product search selection -->
105
+ <InputOptionsSelect
106
+ placeholder="Search for products..."
107
+ lazyLoader={searchProducts}
108
+ keyField="code"
109
+ textField="text"
110
+ onChange={handleProductChange}
111
+ />
112
+ ```
113
+
114
+ ## Advanced Usage
115
+
116
+ ### Custom Option Rendering
117
+ ```svelte
118
+ <script lang="ts">
119
+ import UserItemRenderer from './UserItemRenderer.svelte';
120
+
121
+ const searchUsersWithDetails: LazyLoader = async (keyword: string, pageNo: number) => {
122
+ const response = await fetch(`/api/users/search-detailed?q=${keyword}&page=${pageNo}`);
123
+ return response.json();
124
+ };
125
+ </script>
126
+
127
+ <InputOptionsSelect
128
+ placeholder="Search users"
129
+ lazyLoader={searchUsersWithDetails}
130
+ keyField="id"
131
+ textField="name"
132
+ itemRender={UserItemRenderer}
133
+ onChange={handleUserChange}
134
+ />
135
+
136
+ <!-- UserItemRenderer.svelte -->
137
+ <script lang="ts">
138
+ export let item: User;
139
+ </script>
140
+
141
+ <div class="user-item">
142
+ <div class="user-avatar">
143
+ <img src={item.avatar} alt={item.name} />
144
+ </div>
145
+ <div class="user-info">
146
+ <div class="user-name">{item.name}</div>
147
+ <div class="user-email">{item.email}</div>
148
+ <div class="user-department">{item.department}</div>
149
+ </div>
150
+ </div>
151
+ ```
152
+
153
+ ### Search with Caching
154
+ ```svelte
155
+ <script lang="ts">
156
+ interface SearchCache {
157
+ [key: string]: {
158
+ data: any[];
159
+ timestamp: number;
160
+ };
161
+ }
162
+
163
+ let searchCache: SearchCache = {};
164
+ const cacheTimeout = 5 * 60 * 1000; // 5 minute cache
165
+
166
+ const cachedSearchLoader: LazyLoader = async (keyword: string, pageNo: number) => {
167
+ const cacheKey = `${keyword}-${pageNo}`;
168
+ const cached = searchCache[cacheKey];
169
+
170
+ // Check cache
171
+ if (cached && Date.now() - cached.timestamp < cacheTimeout) {
172
+ console.log('Using cached data');
173
+ return {
174
+ list: cached.data,
175
+ hasMore: false
176
+ };
177
+ }
178
+
179
+ // Fetch from API
180
+ const response = await fetch(`/api/search?q=${keyword}&page=${pageNo}`);
181
+ const result = await response.json();
182
+
183
+ // Cache result
184
+ searchCache[cacheKey] = {
185
+ data: result.list,
186
+ timestamp: Date.now()
187
+ };
188
+
189
+ return result;
190
+ };
191
+ </script>
192
+ ```
193
+
194
+ ## Best Practices
195
+
196
+ ### 1. Debounced Search
197
+ The component internally implements debouncing with a default delay of 500ms before executing search.
198
+
199
+ ### 2. Error Handling
200
+ ```svelte
201
+ <script lang="ts">
202
+ const robustSearchLoader: LazyLoader = async (keyword: string, pageNo: number) => {
203
+ try {
204
+ const response = await fetch(`/api/search?q=${keyword}&page=${pageNo}`);
205
+
206
+ if (!response.ok) {
207
+ throw new Error(`Search failed: ${response.status}`);
208
+ }
209
+
210
+ return await response.json();
211
+ } catch (error) {
212
+ console.error('Search error:', error);
213
+ return {
214
+ list: [],
215
+ hasMore: false
216
+ };
217
+ }
218
+ };
219
+ </script>
220
+ ```
221
+
222
+ ### 3. Paginated Loading
223
+ ```svelte
224
+ <script lang="ts">
225
+ const paginatedLoader: LazyLoader = async (keyword: string, pageNo: number) => {
226
+ const pageSize = 20;
227
+ const response = await fetch(
228
+ `/api/search?q=${keyword}&page=${pageNo}&size=${pageSize}`
229
+ );
230
+
231
+ const data = await response.json();
232
+
233
+ return {
234
+ list: data.items,
235
+ hasMore: data.total > pageNo * pageSize
236
+ };
237
+ };
238
+ </script>
239
+ ```
@@ -0,0 +1,389 @@
1
+ # LookupEditor Component
2
+
3
+ Lookup editor component that performs complex lookup and selection operations through modal dialogs.
4
+
5
+ ## Type Definitions
6
+
7
+ ```typescript
8
+ type OnActionHandler = () => void;
9
+ ```
10
+
11
+ ## Properties
12
+
13
+ | Property | Type | Default | Description |
14
+ |----------|------|---------|-------------|
15
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Appearance variant |
16
+ | `disabled` | `boolean` | `false` | Whether disabled |
17
+ | `readonly` | `boolean` | `false` | Whether read-only |
18
+ | `compact` | `boolean` | `false` | Whether compact mode |
19
+ | `mandatory` | `boolean` | `false` | Whether required |
20
+ | `value` | `any` | `null` | Selected value |
21
+ | `text` | `string` | `''` | Display text |
22
+ | `placeholder` | `string` | `''` | Placeholder text |
23
+ | `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode |
24
+ | `style` | `string` | `''` | Custom styles |
25
+ | `onChange` | `OnChangeHandler<any>` | - | Value change callback |
26
+ | `onAction` | `OnActionHandler` | - | Lookup action callback |
27
+
28
+ ## Usage Examples
29
+
30
+ ```svelte
31
+ <script lang="ts">
32
+ import LookupEditor from '@ticatec/uniface-element/LookupEditor';
33
+ import CustomerLookupModal from './CustomerLookupModal.svelte';
34
+ import ProductLookupModal from './ProductLookupModal.svelte';
35
+
36
+ interface Customer {
37
+ id: string;
38
+ name: string;
39
+ code: string;
40
+ email: string;
41
+ }
42
+
43
+ interface Product {
44
+ id: string;
45
+ name: string;
46
+ price: number;
47
+ category: string;
48
+ }
49
+
50
+ let selectedCustomer: string | null = null;
51
+ let customerText: string = '';
52
+ let selectedProduct: string | null = null;
53
+ let productText: string = '';
54
+ let showCustomerModal: boolean = false;
55
+ let showProductModal: boolean = false;
56
+
57
+ // Customer lookup
58
+ const handleCustomerLookup = (): void => {
59
+ showCustomerModal = true;
60
+ };
61
+
62
+ const handleCustomerSelect = (customer: Customer): void => {
63
+ selectedCustomer = customer.id;
64
+ customerText = `${customer.name} (${customer.code})`;
65
+ showCustomerModal = false;
66
+ };
67
+
68
+ const handleCustomerChange = (value: any): void => {
69
+ selectedCustomer = value;
70
+ };
71
+
72
+ // Product lookup
73
+ const handleProductLookup = (): void => {
74
+ showProductModal = true;
75
+ };
76
+
77
+ const handleProductSelect = (product: Product): void => {
78
+ selectedProduct = product.id;
79
+ productText = `${product.name} - $${product.price}`;
80
+ showProductModal = false;
81
+ };
82
+
83
+ const handleProductChange = (value: any): void => {
84
+ selectedProduct = value;
85
+ };
86
+ </script>
87
+
88
+ <!-- Customer lookup -->
89
+ <LookupEditor
90
+ placeholder="Please select customer"
91
+ bind:value={selectedCustomer}
92
+ bind:text={customerText}
93
+ onAction={handleCustomerLookup}
94
+ onChange={handleCustomerChange}
95
+ />
96
+
97
+ <!-- Product lookup -->
98
+ <LookupEditor
99
+ placeholder="Please select product"
100
+ mandatory={true}
101
+ bind:value={selectedProduct}
102
+ bind:text={productText}
103
+ onAction={handleProductLookup}
104
+ onChange={handleProductChange}
105
+ />
106
+
107
+ <!-- Customer lookup modal -->
108
+ {#if showCustomerModal}
109
+ <CustomerLookupModal
110
+ onSelect={handleCustomerSelect}
111
+ onClose={() => showCustomerModal = false}
112
+ />
113
+ {/if}
114
+
115
+ <!-- Product lookup modal -->
116
+ {#if showProductModal}
117
+ <ProductLookupModal
118
+ onSelect={handleProductSelect}
119
+ onClose={() => showProductModal = false}
120
+ />
121
+ {/if}
122
+ ```
123
+
124
+ ## Advanced Usage
125
+
126
+ ### Multi-step Lookup Flow
127
+ ```svelte
128
+ <script lang="ts">
129
+ interface Supplier {
130
+ id: string;
131
+ name: string;
132
+ country: string;
133
+ }
134
+
135
+ interface SupplierProduct {
136
+ id: string;
137
+ name: string;
138
+ supplier_id: string;
139
+ price: number;
140
+ }
141
+
142
+ let selectedSupplier: string | null = null;
143
+ let supplierText: string = '';
144
+ let selectedSupplierProduct: string | null = null;
145
+ let supplierProductText: string = '';
146
+ let showSupplierModal: boolean = false;
147
+ let showSupplierProductModal: boolean = false;
148
+
149
+ const handleSupplierLookup = (): void => {
150
+ showSupplierModal = true;
151
+ };
152
+
153
+ const handleSupplierSelect = (supplier: Supplier): void => {
154
+ selectedSupplier = supplier.id;
155
+ supplierText = `${supplier.name} (${supplier.country})`;
156
+ showSupplierModal = false;
157
+
158
+ // Reset supplier product selection
159
+ selectedSupplierProduct = null;
160
+ supplierProductText = '';
161
+ };
162
+
163
+ const handleSupplierProductLookup = (): void => {
164
+ if (!selectedSupplier) {
165
+ alert('Please select supplier first');
166
+ return;
167
+ }
168
+ showSupplierProductModal = true;
169
+ };
170
+
171
+ const handleSupplierProductSelect = (product: SupplierProduct): void => {
172
+ selectedSupplierProduct = product.id;
173
+ supplierProductText = `${product.name} - $${product.price}`;
174
+ showSupplierProductModal = false;
175
+ };
176
+ </script>
177
+
178
+ <div class="lookup-flow">
179
+ <div class="form-field">
180
+ <label>Supplier:</label>
181
+ <LookupEditor
182
+ placeholder="Please select supplier"
183
+ bind:value={selectedSupplier}
184
+ bind:text={supplierText}
185
+ onAction={handleSupplierLookup}
186
+ />
187
+ </div>
188
+
189
+ <div class="form-field">
190
+ <label>Supplier Product:</label>
191
+ <LookupEditor
192
+ placeholder="Please select product"
193
+ disabled={!selectedSupplier}
194
+ bind:value={selectedSupplierProduct}
195
+ bind:text={supplierProductText}
196
+ onAction={handleSupplierProductLookup}
197
+ />
198
+ </div>
199
+ </div>
200
+ ```
201
+
202
+ ### Lookup with Caching
203
+ ```svelte
204
+ <script lang="ts">
205
+ interface CacheEntry<T> {
206
+ data: T;
207
+ timestamp: number;
208
+ }
209
+
210
+ class LookupCache {
211
+ private cache = new Map<string, CacheEntry<any>>();
212
+ private ttl = 5 * 60 * 1000; // 5 minute cache
213
+
214
+ get<T>(key: string): T | null {
215
+ const entry = this.cache.get(key);
216
+ if (!entry) return null;
217
+
218
+ if (Date.now() - entry.timestamp > this.ttl) {
219
+ this.cache.delete(key);
220
+ return null;
221
+ }
222
+
223
+ return entry.data;
224
+ }
225
+
226
+ set<T>(key: string, data: T): void {
227
+ this.cache.set(key, {
228
+ data,
229
+ timestamp: Date.now()
230
+ });
231
+ }
232
+
233
+ clear(): void {
234
+ this.cache.clear();
235
+ }
236
+ }
237
+
238
+ const cache = new LookupCache();
239
+
240
+ let selectedUser: string | null = null;
241
+ let userText: string = '';
242
+ let showUserModal: boolean = false;
243
+
244
+ const handleUserLookup = (): void => {
245
+ // Check cache
246
+ const cachedUsers = cache.get('users');
247
+ if (cachedUsers) {
248
+ console.log('Using cached user data');
249
+ }
250
+
251
+ showUserModal = true;
252
+ };
253
+
254
+ const handleUserSelect = (user: any): void => {
255
+ selectedUser = user.id;
256
+ userText = `${user.name} (${user.email})`;
257
+
258
+ // Cache user data
259
+ cache.set(`user:${user.id}`, user);
260
+
261
+ showUserModal = false;
262
+ };
263
+ </script>
264
+ ```
265
+
266
+ ### External API Integration
267
+ ```svelte
268
+ <script lang="ts">
269
+ interface ApiResponse<T> {
270
+ data: T[];
271
+ total: number;
272
+ page: number;
273
+ }
274
+
275
+ interface ApiUser {
276
+ id: number;
277
+ name: string;
278
+ email: string;
279
+ department: string;
280
+ }
281
+
282
+ let selectedApiUser: number | null = null;
283
+ let apiUserText: string = '';
284
+ let showApiUserModal: boolean = false;
285
+ let isLoading: boolean = false;
286
+
287
+ const searchUsers = async (query: string, page: number = 1): Promise<ApiResponse<ApiUser>> => {
288
+ const response = await fetch(`/api/users/search?q=${encodeURIComponent(query)}&page=${page}`);
289
+ if (!response.ok) {
290
+ throw new Error('Failed to search users');
291
+ }
292
+ return response.json();
293
+ };
294
+
295
+ const handleApiUserLookup = (): void => {
296
+ showApiUserModal = true;
297
+ };
298
+
299
+ const handleApiUserSelect = async (userId: number): Promise<void> => {
300
+ isLoading = true;
301
+ try {
302
+ const response = await fetch(`/api/users/${userId}`);
303
+ const user: ApiUser = await response.json();
304
+
305
+ selectedApiUser = user.id;
306
+ apiUserText = `${user.name} - ${user.department}`;
307
+ showApiUserModal = false;
308
+ } catch (error) {
309
+ console.error('Failed to fetch user details:', error);
310
+ } finally {
311
+ isLoading = false;
312
+ }
313
+ };
314
+ </script>
315
+
316
+ <LookupEditor
317
+ placeholder="Please select API user"
318
+ disabled={isLoading}
319
+ bind:value={selectedApiUser}
320
+ bind:text={apiUserText}
321
+ onAction={handleApiUserLookup}
322
+ />
323
+
324
+ {#if isLoading}
325
+ <div class="loading-indicator">Loading...</div>
326
+ {/if}
327
+ ```
328
+
329
+ ## Best Practices
330
+
331
+ ### 1. Provide Clear Display Text
332
+ ```typescript
333
+ const formatDisplayText = (item: any): string => {
334
+ return `${item.name} (${item.code}) - ${item.category}`;
335
+ };
336
+ ```
337
+
338
+ ### 2. Handle Required Validation
339
+ ```svelte
340
+ <script lang="ts">
341
+ let value: string | null = null;
342
+ let error: string = '';
343
+
344
+ const validate = (): boolean => {
345
+ if (!value) {
346
+ error = 'This field is required';
347
+ return false;
348
+ }
349
+ error = '';
350
+ return true;
351
+ };
352
+ </script>
353
+
354
+ <LookupEditor
355
+ mandatory={true}
356
+ bind:value={value}
357
+ onAction={handleLookup}
358
+ />
359
+ {#if error}
360
+ <div class="error-message">{error}</div>
361
+ {/if}
362
+ ```
363
+
364
+ ### 3. Responsive Modal Design
365
+ ```svelte
366
+ <script lang="ts">
367
+ import { onMount } from 'svelte';
368
+
369
+ let isMobile: boolean = false;
370
+
371
+ const checkMobile = (): void => {
372
+ isMobile = window.innerWidth < 768;
373
+ };
374
+
375
+ onMount(() => {
376
+ checkMobile();
377
+ window.addEventListener('resize', checkMobile);
378
+ return () => window.removeEventListener('resize', checkMobile);
379
+ });
380
+ </script>
381
+
382
+ {#if showModal}
383
+ <LookupModal
384
+ fullscreen={isMobile}
385
+ onSelect={handleSelect}
386
+ onClose={() => showModal = false}
387
+ />
388
+ {/if}
389
+ ```