@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,688 @@
1
+ # NumberRange Component
2
+
3
+ A numeric range input component that allows users to specify a range between two numbers, commonly used for filtering data by numeric criteria such as price ranges, age ranges, or quantity filters.
4
+
5
+ ## Overview
6
+
7
+ The NumberRange component provides an intuitive interface for selecting numeric ranges with built-in validation, automatic range constraints, and clear functionality. It features two connected number inputs that intelligently validate against each other, ensuring the "from" value is always less than or equal to the "to" value. Perfect for search filters, data queries, and any application requiring numeric range selection.
8
+
9
+ ## Installation
10
+
11
+ ```typescript
12
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
13
+ import type { OnChangeHandler } from '@ticatec/uniface-element/NumberRange';
14
+ ```
15
+
16
+ ## Basic Usage
17
+
18
+ ```svelte
19
+ <script lang="ts">
20
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
21
+
22
+ let fromValue: number = 0;
23
+ let toValue: number = 100;
24
+ </script>
25
+
26
+ <NumberRange
27
+ bind:fromValue
28
+ bind:toValue
29
+ variant="outlined"
30
+ />
31
+ ```
32
+
33
+ ## Properties
34
+
35
+ | Property | Type | Default | Description |
36
+ |----------|------|---------|-------------|
37
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Visual styling variant |
38
+ | `compact` | `boolean` | `false` | Enable compact layout for dense forms |
39
+ | `class` | `string` | `''` | Additional CSS class names |
40
+ | `style` | `string` | `''` | Custom inline styles |
41
+ | `min` | `number \| null` | `null` | Global minimum allowed value |
42
+ | `max` | `number \| null` | `null` | Global maximum allowed value |
43
+ | `fromValue` | `number` | - | Starting value of the range (bindable) |
44
+ | `toValue` | `number` | - | Ending value of the range (bindable) |
45
+ | `allowNegative` | `boolean` | `false` | Allow negative numbers in inputs |
46
+
47
+ ## Features
48
+
49
+ - **Smart Validation**: Automatically validates range constraints (from ≤ to)
50
+ - **Cross-Field Limits**: The "from" value sets the maximum for "to", and "to" value sets minimum for "from"
51
+ - **Clear Functionality**: Built-in clear button that appears when values exist
52
+ - **Auto Focus**: Focuses the first input after clearing values
53
+ - **Negative Numbers**: Optional support for negative number ranges
54
+ - **Consistent Styling**: Matches other form components with variant support
55
+
56
+ ## Type Definitions
57
+
58
+ ```typescript
59
+ /**
60
+ * Change event handler type
61
+ */
62
+ type OnChangeHandler<T> = (value: T) => void;
63
+ ```
64
+
65
+ ## Usage Examples
66
+
67
+ ### Price Range Filter
68
+
69
+ ```svelte
70
+ <script lang="ts">
71
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
72
+
73
+ let minPrice: number = 0;
74
+ let maxPrice: number = 1000;
75
+
76
+ // Reactive statement to handle price range changes
77
+ $: if (minPrice !== undefined && maxPrice !== undefined) {
78
+ filterProductsByPrice(minPrice, maxPrice);
79
+ }
80
+
81
+ function filterProductsByPrice(min: number, max: number) {
82
+ console.log(`Filtering products between $${min} and $${max}`);
83
+ // Implement filtering logic here
84
+ }
85
+
86
+ function resetPriceFilter() {
87
+ minPrice = 0;
88
+ maxPrice = 1000;
89
+ }
90
+ </script>
91
+
92
+ <div class="price-filter">
93
+ <h3>Price Range</h3>
94
+
95
+ <NumberRange
96
+ bind:fromValue={minPrice}
97
+ bind:toValue={maxPrice}
98
+ variant="outlined"
99
+ min={0}
100
+ max={10000}
101
+ style="width: 300px;"
102
+ />
103
+
104
+ <div class="price-display">
105
+ <span class="price-label">
106
+ ${minPrice?.toLocaleString() || 0} - ${maxPrice?.toLocaleString() || 0}
107
+ </span>
108
+ </div>
109
+
110
+ <button class="reset-btn" on:click={resetPriceFilter}>
111
+ Reset Filter
112
+ </button>
113
+ </div>
114
+
115
+ <style>
116
+ .price-filter {
117
+ padding: 16px;
118
+ background: #f8f9fa;
119
+ border-radius: 8px;
120
+ max-width: 400px;
121
+ }
122
+
123
+ .price-filter h3 {
124
+ margin: 0 0 12px 0;
125
+ color: #333;
126
+ font-size: 1.1rem;
127
+ }
128
+
129
+ .price-display {
130
+ margin: 12px 0;
131
+ text-align: center;
132
+ }
133
+
134
+ .price-label {
135
+ font-weight: 500;
136
+ color: #007bff;
137
+ font-size: 1.1rem;
138
+ }
139
+
140
+ .reset-btn {
141
+ width: 100%;
142
+ padding: 8px 16px;
143
+ background: #6c757d;
144
+ color: white;
145
+ border: none;
146
+ border-radius: 4px;
147
+ cursor: pointer;
148
+ margin-top: 8px;
149
+ }
150
+
151
+ .reset-btn:hover {
152
+ background: #5a6268;
153
+ }
154
+ </style>
155
+ ```
156
+
157
+ ### Age Range Selector
158
+
159
+ ```svelte
160
+ <script lang="ts">
161
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
162
+
163
+ let minAge: number = 18;
164
+ let maxAge: number = 65;
165
+ let selectedProfiles = [];
166
+
167
+ // Function to filter user profiles by age
168
+ function filterProfilesByAge(min: number, max: number) {
169
+ // Mock profiles data
170
+ const allProfiles = [
171
+ { id: 1, name: 'Alice Johnson', age: 25 },
172
+ { id: 2, name: 'Bob Smith', age: 35 },
173
+ { id: 3, name: 'Carol Davis', age: 45 },
174
+ { id: 4, name: 'David Wilson', age: 28 },
175
+ { id: 5, name: 'Emma Brown', age: 52 }
176
+ ];
177
+
178
+ selectedProfiles = allProfiles.filter(profile =>
179
+ profile.age >= min && profile.age <= max
180
+ );
181
+ }
182
+
183
+ // Filter on initial load and when values change
184
+ $: filterProfilesByAge(minAge || 0, maxAge || 100);
185
+ </script>
186
+
187
+ <div class="age-filter-demo">
188
+ <div class="filter-section">
189
+ <h3>Filter by Age Range</h3>
190
+
191
+ <NumberRange
192
+ bind:fromValue={minAge}
193
+ bind:toValue={maxAge}
194
+ variant="filled"
195
+ min={16}
196
+ max={100}
197
+ style="width: 250px;"
198
+ compact={true}
199
+ />
200
+
201
+ <div class="age-summary">
202
+ <p>Showing profiles aged {minAge} to {maxAge} years</p>
203
+ <p class="result-count">{selectedProfiles.length} profiles found</p>
204
+ </div>
205
+ </div>
206
+
207
+ <div class="results-section">
208
+ <h4>Matching Profiles</h4>
209
+ {#if selectedProfiles.length > 0}
210
+ <div class="profiles-grid">
211
+ {#each selectedProfiles as profile}
212
+ <div class="profile-card">
213
+ <div class="profile-name">{profile.name}</div>
214
+ <div class="profile-age">Age: {profile.age}</div>
215
+ </div>
216
+ {/each}
217
+ </div>
218
+ {:else}
219
+ <p class="no-results">No profiles match the selected age range</p>
220
+ {/if}
221
+ </div>
222
+ </div>
223
+
224
+ <style>
225
+ .age-filter-demo {
226
+ max-width: 600px;
227
+ margin: 0 auto;
228
+ padding: 20px;
229
+ }
230
+
231
+ .filter-section {
232
+ background: #ffffff;
233
+ padding: 20px;
234
+ border-radius: 8px;
235
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
236
+ margin-bottom: 20px;
237
+ }
238
+
239
+ .filter-section h3 {
240
+ margin: 0 0 16px 0;
241
+ color: #333;
242
+ }
243
+
244
+ .age-summary {
245
+ margin-top: 12px;
246
+ padding: 12px;
247
+ background: #e3f2fd;
248
+ border-radius: 4px;
249
+ text-align: center;
250
+ }
251
+
252
+ .result-count {
253
+ font-weight: 600;
254
+ color: #1976d2;
255
+ margin: 4px 0 0 0;
256
+ }
257
+
258
+ .results-section h4 {
259
+ margin: 0 0 16px 0;
260
+ color: #333;
261
+ }
262
+
263
+ .profiles-grid {
264
+ display: grid;
265
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
266
+ gap: 12px;
267
+ }
268
+
269
+ .profile-card {
270
+ padding: 16px;
271
+ background: #f8f9fa;
272
+ border-radius: 6px;
273
+ border-left: 4px solid #007bff;
274
+ }
275
+
276
+ .profile-name {
277
+ font-weight: 500;
278
+ color: #333;
279
+ margin-bottom: 4px;
280
+ }
281
+
282
+ .profile-age {
283
+ color: #666;
284
+ font-size: 0.9rem;
285
+ }
286
+
287
+ .no-results {
288
+ text-align: center;
289
+ color: #666;
290
+ font-style: italic;
291
+ padding: 40px 20px;
292
+ }
293
+ </style>
294
+ ```
295
+
296
+ ### Inventory Range Query
297
+
298
+ ```svelte
299
+ <script lang="ts">
300
+ import NumberRange from '@ticatec/uniface-element/NumberRange';
301
+
302
+ let minQuantity: number = 0;
303
+ let maxQuantity: number = 500;
304
+
305
+ // Mock inventory data
306
+ let inventoryItems = [
307
+ { id: 'A001', name: 'Widget Alpha', quantity: 45, category: 'Electronics' },
308
+ { id: 'B002', name: 'Gadget Beta', quantity: 120, category: 'Tools' },
309
+ { id: 'C003', name: 'Device Gamma', quantity: 8, category: 'Electronics' },
310
+ { id: 'D004', name: 'Tool Delta', quantity: 300, category: 'Tools' },
311
+ { id: 'E005', name: 'Part Epsilon', quantity: 750, category: 'Parts' }
312
+ ];
313
+
314
+ let filteredItems = [];
315
+
316
+ function applyQuantityFilter() {
317
+ filteredItems = inventoryItems.filter(item =>
318
+ item.quantity >= (minQuantity || 0) &&
319
+ item.quantity <= (maxQuantity || Infinity)
320
+ );
321
+ }
322
+
323
+ // Apply filter when range changes
324
+ $: {
325
+ minQuantity, maxQuantity;
326
+ applyQuantityFilter();
327
+ }
328
+
329
+ function exportResults() {
330
+ const csvContent = [
331
+ 'ID,Name,Quantity,Category',
332
+ ...filteredItems.map(item =>
333
+ `${item.id},${item.name},${item.quantity},${item.category}`
334
+ )
335
+ ].join('\n');
336
+
337
+ console.log('Export data:', csvContent);
338
+ alert('Data exported to console');
339
+ }
340
+
341
+ // Predefined range presets
342
+ const presets = [
343
+ { label: 'Low Stock (0-50)', min: 0, max: 50 },
344
+ { label: 'Medium Stock (51-200)', min: 51, max: 200 },
345
+ { label: 'High Stock (201-500)', min: 201, max: 500 },
346
+ { label: 'Overstocked (500+)', min: 500, max: 1000 }
347
+ ];
348
+
349
+ function applyPreset(preset) {
350
+ minQuantity = preset.min;
351
+ maxQuantity = preset.max;
352
+ }
353
+ </script>
354
+
355
+ <div class="inventory-query">
356
+ <header class="query-header">
357
+ <h2>Inventory Quantity Filter</h2>
358
+ <p>Filter inventory items by quantity range</p>
359
+ </header>
360
+
361
+ <div class="filter-controls">
362
+ <div class="range-input-section">
363
+ <label>Quantity Range:</label>
364
+ <NumberRange
365
+ bind:fromValue={minQuantity}
366
+ bind:toValue={maxQuantity}
367
+ variant="outlined"
368
+ min={0}
369
+ max={1000}
370
+ style="width: 280px;"
371
+ />
372
+ </div>
373
+
374
+ <div class="presets-section">
375
+ <label>Quick Presets:</label>
376
+ <div class="preset-buttons">
377
+ {#each presets as preset}
378
+ <button
379
+ class="preset-btn"
380
+ on:click={() => applyPreset(preset)}
381
+ >
382
+ {preset.label}
383
+ </button>
384
+ {/each}
385
+ </div>
386
+ </div>
387
+ </div>
388
+
389
+ <div class="results-section">
390
+ <div class="results-header">
391
+ <h3>Results ({filteredItems.length} items)</h3>
392
+ {#if filteredItems.length > 0}
393
+ <button class="export-btn" on:click={exportResults}>
394
+ Export CSV
395
+ </button>
396
+ {/if}
397
+ </div>
398
+
399
+ <div class="results-table">
400
+ {#if filteredItems.length > 0}
401
+ <table>
402
+ <thead>
403
+ <tr>
404
+ <th>Item ID</th>
405
+ <th>Name</th>
406
+ <th>Quantity</th>
407
+ <th>Category</th>
408
+ <th>Status</th>
409
+ </tr>
410
+ </thead>
411
+ <tbody>
412
+ {#each filteredItems as item}
413
+ <tr>
414
+ <td class="item-id">{item.id}</td>
415
+ <td class="item-name">{item.name}</td>
416
+ <td class="item-quantity">{item.quantity}</td>
417
+ <td class="item-category">{item.category}</td>
418
+ <td class="item-status">
419
+ <span class="status-badge status-{item.quantity < 50 ? 'low' : item.quantity < 200 ? 'medium' : 'high'}">
420
+ {item.quantity < 50 ? 'Low' : item.quantity < 200 ? 'Medium' : 'High'}
421
+ </span>
422
+ </td>
423
+ </tr>
424
+ {/each}
425
+ </tbody>
426
+ </table>
427
+ {:else}
428
+ <div class="no-results">
429
+ <p>No inventory items found in the specified quantity range.</p>
430
+ <p class="suggestion">Try adjusting the range or using a preset filter.</p>
431
+ </div>
432
+ {/if}
433
+ </div>
434
+ </div>
435
+ </div>
436
+
437
+ <style>
438
+ .inventory-query {
439
+ max-width: 900px;
440
+ margin: 0 auto;
441
+ padding: 20px;
442
+ }
443
+
444
+ .query-header {
445
+ text-align: center;
446
+ margin-bottom: 30px;
447
+ }
448
+
449
+ .query-header h2 {
450
+ color: #333;
451
+ margin: 0 0 8px 0;
452
+ }
453
+
454
+ .query-header p {
455
+ color: #666;
456
+ margin: 0;
457
+ }
458
+
459
+ .filter-controls {
460
+ display: flex;
461
+ flex-wrap: wrap;
462
+ gap: 30px;
463
+ align-items: flex-end;
464
+ margin-bottom: 30px;
465
+ padding: 20px;
466
+ background: #f8f9fa;
467
+ border-radius: 8px;
468
+ }
469
+
470
+ .range-input-section,
471
+ .presets-section {
472
+ flex: 1;
473
+ min-width: 250px;
474
+ }
475
+
476
+ .range-input-section label,
477
+ .presets-section label {
478
+ display: block;
479
+ font-weight: 500;
480
+ margin-bottom: 8px;
481
+ color: #333;
482
+ }
483
+
484
+ .preset-buttons {
485
+ display: flex;
486
+ flex-wrap: wrap;
487
+ gap: 8px;
488
+ }
489
+
490
+ .preset-btn {
491
+ padding: 6px 12px;
492
+ background: #e9ecef;
493
+ border: 1px solid #ced4da;
494
+ border-radius: 4px;
495
+ cursor: pointer;
496
+ font-size: 0.875rem;
497
+ transition: all 0.2s;
498
+ }
499
+
500
+ .preset-btn:hover {
501
+ background: #dee2e6;
502
+ border-color: #adb5bd;
503
+ }
504
+
505
+ .results-section {
506
+ background: white;
507
+ border-radius: 8px;
508
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
509
+ overflow: hidden;
510
+ }
511
+
512
+ .results-header {
513
+ display: flex;
514
+ justify-content: space-between;
515
+ align-items: center;
516
+ padding: 20px;
517
+ background: #f8f9fa;
518
+ border-bottom: 1px solid #dee2e6;
519
+ }
520
+
521
+ .results-header h3 {
522
+ margin: 0;
523
+ color: #333;
524
+ }
525
+
526
+ .export-btn {
527
+ padding: 8px 16px;
528
+ background: #007bff;
529
+ color: white;
530
+ border: none;
531
+ border-radius: 4px;
532
+ cursor: pointer;
533
+ font-size: 0.875rem;
534
+ }
535
+
536
+ .export-btn:hover {
537
+ background: #0056b3;
538
+ }
539
+
540
+ .results-table {
541
+ padding: 20px;
542
+ }
543
+
544
+ table {
545
+ width: 100%;
546
+ border-collapse: collapse;
547
+ }
548
+
549
+ th, td {
550
+ text-align: left;
551
+ padding: 12px;
552
+ border-bottom: 1px solid #dee2e6;
553
+ }
554
+
555
+ th {
556
+ font-weight: 600;
557
+ color: #333;
558
+ background: #f8f9fa;
559
+ }
560
+
561
+ .item-id {
562
+ font-family: monospace;
563
+ font-weight: 500;
564
+ }
565
+
566
+ .item-quantity {
567
+ text-align: right;
568
+ font-weight: 500;
569
+ }
570
+
571
+ .status-badge {
572
+ padding: 4px 8px;
573
+ border-radius: 12px;
574
+ font-size: 0.75rem;
575
+ font-weight: 500;
576
+ }
577
+
578
+ .status-low {
579
+ background: #ffebee;
580
+ color: #c62828;
581
+ }
582
+
583
+ .status-medium {
584
+ background: #fff3e0;
585
+ color: #ef6c00;
586
+ }
587
+
588
+ .status-high {
589
+ background: #e8f5e8;
590
+ color: #2e7d32;
591
+ }
592
+
593
+ .no-results {
594
+ text-align: center;
595
+ padding: 60px 20px;
596
+ color: #666;
597
+ }
598
+
599
+ .suggestion {
600
+ font-size: 0.9rem;
601
+ color: #888;
602
+ margin-top: 8px;
603
+ }
604
+
605
+ @media (max-width: 768px) {
606
+ .filter-controls {
607
+ flex-direction: column;
608
+ align-items: stretch;
609
+ }
610
+
611
+ .preset-buttons {
612
+ justify-content: center;
613
+ }
614
+
615
+ .results-header {
616
+ flex-direction: column;
617
+ gap: 12px;
618
+ align-items: stretch;
619
+ }
620
+
621
+ table {
622
+ font-size: 0.875rem;
623
+ }
624
+
625
+ th, td {
626
+ padding: 8px;
627
+ }
628
+ }
629
+ </style>
630
+ ```
631
+
632
+ ## Styling
633
+
634
+ The NumberRange component uses the following CSS classes:
635
+
636
+ ```css
637
+ .uniface-range-editor {
638
+ /* Main range container */
639
+ display: flex;
640
+ align-items: center;
641
+ gap: 8px;
642
+ }
643
+
644
+ .uniface-range-editor .range-divider {
645
+ /* Divider between from/to inputs */
646
+ color: var(--uniface-editor-border-color, #dee2e6);
647
+ }
648
+
649
+ .uniface-range-editor .action-icon {
650
+ /* Clear button styling */
651
+ cursor: pointer;
652
+ opacity: 0.6;
653
+ transition: opacity 0.2s;
654
+ }
655
+
656
+ .uniface-range-editor .action-icon:hover {
657
+ opacity: 1;
658
+ }
659
+ ```
660
+
661
+ ## API Reference
662
+
663
+ ### NumberRange Component Props
664
+
665
+ ```typescript
666
+ interface NumberRangeProps {
667
+ variant?: '' | 'plain' | 'outlined' | 'filled'; // Visual styling variant
668
+ compact?: boolean; // Compact layout mode
669
+ class?: string; // CSS class names
670
+ style?: string; // Custom inline styles
671
+ min?: number | null; // Global minimum value
672
+ max?: number | null; // Global maximum value
673
+ fromValue: number; // Range start value
674
+ toValue: number; // Range end value
675
+ allowNegative?: boolean; // Allow negative numbers
676
+ }
677
+ ```
678
+
679
+ ## Best Practices
680
+
681
+ 1. **Validation** - Always bind both `fromValue` and `toValue` for proper range validation
682
+ 2. **Limits** - Set appropriate `min` and `max` values to guide user input
683
+ 3. **User Feedback** - Provide clear indication of selected range values
684
+ 4. **Accessibility** - Ensure sufficient color contrast and keyboard navigation
685
+ 5. **Mobile Support** - Test input behavior on touch devices
686
+ 6. **Data Types** - Handle undefined/null values gracefully in reactive statements
687
+ 7. **Performance** - Debounce filtering operations for large datasets
688
+ 8. **Clear Functionality** - Rely on built-in clear button for consistent UX