@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,1156 @@
1
+ # DateRange Component
2
+
3
+ A date range selector component that allows users to select a start and end date through an intuitive dual calendar interface, commonly used for filtering data by date periods such as reporting ranges, booking periods, or event schedules.
4
+
5
+ ## Overview
6
+
7
+ The DateRange component provides a comprehensive date selection experience with dual calendar displays, flexible date formatting, and robust validation. It features readonly input fields that open a popover with side-by-side calendars for easy range selection. The component supports various date formats, minimum/maximum date constraints, and seamless integration with form validation systems.
8
+
9
+ ## Installation
10
+
11
+ ```typescript
12
+ import DateRange from '@ticatec/uniface-element/DateRange';
13
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
14
+ ```
15
+
16
+ ## Basic Usage
17
+
18
+ ```svelte
19
+ <script lang="ts">
20
+ import DateRange from '@ticatec/uniface-element/DateRange';
21
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
22
+
23
+ let fromDate: UniDate = null;
24
+ let toDate: UniDate = null;
25
+ </script>
26
+
27
+ <DateRange
28
+ bind:fromValue={fromDate}
29
+ bind:toValue={toDate}
30
+ variant="outlined"
31
+ />
32
+ ```
33
+
34
+ ## Properties
35
+
36
+ | Property | Type | Default | Description |
37
+ |----------|------|---------|-------------|
38
+ | `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Visual styling variant |
39
+ | `compact` | `boolean` | `false` | Enable compact layout for dense forms |
40
+ | `class` | `string` | `''` | Additional CSS class names |
41
+ | `style` | `string` | `''` | Custom inline styles |
42
+ | `fromValue` | `UniDate` | `null` | Start date (bindable) |
43
+ | `toValue` | `UniDate` | `null` | End date (bindable) |
44
+ | `format` | `string` | `"YYYY-MM-DD"` | Date display format (dayjs format) |
45
+ | `min` | `string \| Date \| null` | `null` | Minimum selectable date |
46
+ | `max` | `string \| Date \| null` | `null` | Maximum selectable date |
47
+
48
+ ## Type Definitions
49
+
50
+ ```typescript
51
+ /**
52
+ * Flexible date type supporting multiple formats
53
+ */
54
+ type UniDate = dayjs.Dayjs | Date | string | null;
55
+ ```
56
+
57
+ ## Features
58
+
59
+ - **Dual Calendar Interface**: Side-by-side calendar view for intuitive range selection
60
+ - **Flexible Date Types**: Supports Date objects, strings, and dayjs instances
61
+ - **Custom Formatting**: Configurable date display format using dayjs patterns
62
+ - **Range Validation**: Automatic validation ensuring from date ≤ to date
63
+ - **Min/Max Constraints**: Optional date boundaries to restrict selection
64
+ - **Popover Calendar**: Clean calendar popup with integrated date picker
65
+ - **Clear Functionality**: Built-in clear action when dates are selected
66
+ - **Readonly Inputs**: Prevents manual typing for consistent date format
67
+
68
+ ## Usage Examples
69
+
70
+ ### Reporting Date Range Selector
71
+
72
+ ```svelte
73
+ <script lang="ts">
74
+ import DateRange from '@ticatec/uniface-element/DateRange';
75
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
76
+ import dayjs from 'dayjs';
77
+
78
+ let reportFrom: UniDate = dayjs().subtract(30, 'day');
79
+ let reportTo: UniDate = dayjs();
80
+
81
+ // Sales data for demo
82
+ let salesData = [
83
+ { date: '2024-03-01', sales: 12500, orders: 45 },
84
+ { date: '2024-03-02', sales: 8900, orders: 32 },
85
+ { date: '2024-03-03', sales: 15600, orders: 58 },
86
+ { date: '2024-03-04', sales: 11200, orders: 41 },
87
+ { date: '2024-03-05', sales: 9800, orders: 35 }
88
+ ];
89
+
90
+ let filteredData = [];
91
+ let totalSales = 0;
92
+ let totalOrders = 0;
93
+
94
+ // Filter data based on selected date range
95
+ function filterSalesData() {
96
+ if (!reportFrom || !reportTo) {
97
+ filteredData = salesData;
98
+ } else {
99
+ const fromDate = dayjs(reportFrom);
100
+ const toDate = dayjs(reportTo);
101
+
102
+ filteredData = salesData.filter(item => {
103
+ const itemDate = dayjs(item.date);
104
+ return itemDate.isBetween(fromDate, toDate, 'day', '[]');
105
+ });
106
+ }
107
+
108
+ // Calculate totals
109
+ totalSales = filteredData.reduce((sum, item) => sum + item.sales, 0);
110
+ totalOrders = filteredData.reduce((sum, item) => sum + item.orders, 0);
111
+ }
112
+
113
+ // Reactive filtering
114
+ $: {
115
+ reportFrom, reportTo;
116
+ filterSalesData();
117
+ }
118
+
119
+ // Quick date range presets
120
+ function setDateRange(days: number) {
121
+ reportFrom = dayjs().subtract(days, 'day');
122
+ reportTo = dayjs();
123
+ }
124
+
125
+ function setThisMonth() {
126
+ reportFrom = dayjs().startOf('month');
127
+ reportTo = dayjs().endOf('month');
128
+ }
129
+
130
+ function setLastMonth() {
131
+ reportFrom = dayjs().subtract(1, 'month').startOf('month');
132
+ reportTo = dayjs().subtract(1, 'month').endOf('month');
133
+ }
134
+ </script>
135
+
136
+ <div class="sales-report">
137
+ <header class="report-header">
138
+ <h2>Sales Report Dashboard</h2>
139
+ <p>Select a date range to view sales analytics</p>
140
+ </header>
141
+
142
+ <div class="date-controls">
143
+ <div class="date-range-section">
144
+ <label>Report Period:</label>
145
+ <DateRange
146
+ bind:fromValue={reportFrom}
147
+ bind:toValue={reportTo}
148
+ variant="outlined"
149
+ format="MMM DD, YYYY"
150
+ style="width: 320px;"
151
+ />
152
+ </div>
153
+
154
+ <div class="quick-presets">
155
+ <label>Quick Presets:</label>
156
+ <div class="preset-buttons">
157
+ <button class="preset-btn" on:click={() => setDateRange(7)}>Last 7 days</button>
158
+ <button class="preset-btn" on:click={() => setDateRange(30)}>Last 30 days</button>
159
+ <button class="preset-btn" on:click={setThisMonth}>This Month</button>
160
+ <button class="preset-btn" on:click={setLastMonth}>Last Month</button>
161
+ </div>
162
+ </div>
163
+ </div>
164
+
165
+ <div class="report-summary">
166
+ <div class="summary-card">
167
+ <h3>Total Sales</h3>
168
+ <div class="metric-value">${totalSales.toLocaleString()}</div>
169
+ </div>
170
+ <div class="summary-card">
171
+ <h3>Total Orders</h3>
172
+ <div class="metric-value">{totalOrders}</div>
173
+ </div>
174
+ <div class="summary-card">
175
+ <h3>Average Order</h3>
176
+ <div class="metric-value">
177
+ ${totalOrders > 0 ? (totalSales / totalOrders).toFixed(2) : '0.00'}
178
+ </div>
179
+ </div>
180
+ </div>
181
+
182
+ <div class="data-table">
183
+ <h3>Daily Breakdown ({filteredData.length} days)</h3>
184
+ {#if filteredData.length > 0}
185
+ <table>
186
+ <thead>
187
+ <tr>
188
+ <th>Date</th>
189
+ <th>Sales</th>
190
+ <th>Orders</th>
191
+ <th>Avg Order</th>
192
+ </tr>
193
+ </thead>
194
+ <tbody>
195
+ {#each filteredData as item}
196
+ <tr>
197
+ <td>{dayjs(item.date).format('MMM DD, YYYY')}</td>
198
+ <td>${item.sales.toLocaleString()}</td>
199
+ <td>{item.orders}</td>
200
+ <td>${(item.sales / item.orders).toFixed(2)}</td>
201
+ </tr>
202
+ {/each}
203
+ </tbody>
204
+ </table>
205
+ {:else}
206
+ <div class="no-data">
207
+ <p>No sales data available for the selected date range.</p>
208
+ </div>
209
+ {/if}
210
+ </div>
211
+ </div>
212
+
213
+ <style>
214
+ .sales-report {
215
+ max-width: 900px;
216
+ margin: 0 auto;
217
+ padding: 20px;
218
+ }
219
+
220
+ .report-header {
221
+ text-align: center;
222
+ margin-bottom: 30px;
223
+ }
224
+
225
+ .report-header h2 {
226
+ color: #333;
227
+ margin: 0 0 8px 0;
228
+ }
229
+
230
+ .report-header p {
231
+ color: #666;
232
+ margin: 0;
233
+ }
234
+
235
+ .date-controls {
236
+ display: flex;
237
+ flex-wrap: wrap;
238
+ gap: 30px;
239
+ align-items: flex-end;
240
+ margin-bottom: 30px;
241
+ padding: 20px;
242
+ background: #f8f9fa;
243
+ border-radius: 8px;
244
+ }
245
+
246
+ .date-range-section,
247
+ .quick-presets {
248
+ flex: 1;
249
+ min-width: 280px;
250
+ }
251
+
252
+ .date-range-section label,
253
+ .quick-presets label {
254
+ display: block;
255
+ font-weight: 500;
256
+ margin-bottom: 8px;
257
+ color: #333;
258
+ }
259
+
260
+ .preset-buttons {
261
+ display: flex;
262
+ flex-wrap: wrap;
263
+ gap: 8px;
264
+ }
265
+
266
+ .preset-btn {
267
+ padding: 6px 12px;
268
+ background: #e9ecef;
269
+ border: 1px solid #ced4da;
270
+ border-radius: 4px;
271
+ cursor: pointer;
272
+ font-size: 0.875rem;
273
+ transition: all 0.2s;
274
+ }
275
+
276
+ .preset-btn:hover {
277
+ background: #007bff;
278
+ color: white;
279
+ border-color: #007bff;
280
+ }
281
+
282
+ .report-summary {
283
+ display: grid;
284
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
285
+ gap: 20px;
286
+ margin-bottom: 30px;
287
+ }
288
+
289
+ .summary-card {
290
+ background: white;
291
+ padding: 20px;
292
+ border-radius: 8px;
293
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
294
+ text-align: center;
295
+ }
296
+
297
+ .summary-card h3 {
298
+ margin: 0 0 12px 0;
299
+ color: #666;
300
+ font-size: 0.9rem;
301
+ text-transform: uppercase;
302
+ letter-spacing: 0.5px;
303
+ }
304
+
305
+ .metric-value {
306
+ font-size: 2rem;
307
+ font-weight: 700;
308
+ color: #007bff;
309
+ }
310
+
311
+ .data-table {
312
+ background: white;
313
+ border-radius: 8px;
314
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
315
+ overflow: hidden;
316
+ }
317
+
318
+ .data-table h3 {
319
+ margin: 0;
320
+ padding: 20px;
321
+ background: #f8f9fa;
322
+ border-bottom: 1px solid #dee2e6;
323
+ color: #333;
324
+ }
325
+
326
+ table {
327
+ width: 100%;
328
+ border-collapse: collapse;
329
+ }
330
+
331
+ th, td {
332
+ text-align: left;
333
+ padding: 12px 20px;
334
+ border-bottom: 1px solid #dee2e6;
335
+ }
336
+
337
+ th {
338
+ font-weight: 600;
339
+ color: #333;
340
+ background: #f8f9fa;
341
+ }
342
+
343
+ .no-data {
344
+ padding: 60px 20px;
345
+ text-align: center;
346
+ color: #666;
347
+ }
348
+
349
+ @media (max-width: 768px) {
350
+ .date-controls {
351
+ flex-direction: column;
352
+ align-items: stretch;
353
+ }
354
+
355
+ .preset-buttons {
356
+ justify-content: center;
357
+ }
358
+
359
+ .report-summary {
360
+ grid-template-columns: 1fr;
361
+ }
362
+
363
+ table {
364
+ font-size: 0.875rem;
365
+ }
366
+ }
367
+ </style>
368
+ ```
369
+
370
+ ### Event Booking Date Range
371
+
372
+ ```svelte
373
+ <script lang="ts">
374
+ import DateRange from '@ticatec/uniface-element/DateRange';
375
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
376
+ import dayjs from 'dayjs';
377
+
378
+ let checkInDate: UniDate = null;
379
+ let checkOutDate: UniDate = null;
380
+
381
+ // Hotel booking data
382
+ let availableRooms = [
383
+ { id: 1, type: 'Standard Room', price: 120, available: true },
384
+ { id: 2, type: 'Deluxe Room', price: 180, available: true },
385
+ { id: 3, type: 'Suite', price: 320, available: false },
386
+ { id: 4, type: 'Executive Room', price: 220, available: true }
387
+ ];
388
+
389
+ let selectedRoom = null;
390
+ let totalNights = 0;
391
+ let totalCost = 0;
392
+
393
+ // Calculate stay duration and cost
394
+ function calculateStay() {
395
+ if (checkInDate && checkOutDate) {
396
+ const checkin = dayjs(checkInDate);
397
+ const checkout = dayjs(checkOutDate);
398
+ totalNights = checkout.diff(checkin, 'day');
399
+
400
+ if (selectedRoom) {
401
+ totalCost = totalNights * selectedRoom.price;
402
+ }
403
+ } else {
404
+ totalNights = 0;
405
+ totalCost = 0;
406
+ }
407
+ }
408
+
409
+ // Reactive calculations
410
+ $: {
411
+ checkInDate, checkOutDate, selectedRoom;
412
+ calculateStay();
413
+ }
414
+
415
+ function selectRoom(room) {
416
+ selectedRoom = room;
417
+ }
418
+
419
+ function bookRoom() {
420
+ if (selectedRoom && checkInDate && checkOutDate) {
421
+ alert(`Booking confirmed!\nRoom: ${selectedRoom.type}\nCheck-in: ${dayjs(checkInDate).format('MMM DD, YYYY')}\nCheck-out: ${dayjs(checkOutDate).format('MMM DD, YYYY')}\nTotal: $${totalCost}`);
422
+ }
423
+ }
424
+ </script>
425
+
426
+ <div class="booking-system">
427
+ <header class="booking-header">
428
+ <h2>Hotel Room Booking</h2>
429
+ <p>Select your stay dates and choose a room</p>
430
+ </header>
431
+
432
+ <div class="booking-form">
433
+ <div class="date-selection">
434
+ <h3>Select Your Stay Dates</h3>
435
+ <DateRange
436
+ bind:fromValue={checkInDate}
437
+ bind:toValue={checkOutDate}
438
+ variant="outlined"
439
+ format="MMM DD, YYYY"
440
+ min={dayjs().format('YYYY-MM-DD')}
441
+ max={dayjs().add(1, 'year').format('YYYY-MM-DD')}
442
+ style="width: 350px;"
443
+ />
444
+
445
+ {#if totalNights > 0}
446
+ <div class="stay-info">
447
+ <p><strong>{totalNights}</strong> night{totalNights === 1 ? '' : 's'} stay</p>
448
+ <p>Check-in: {dayjs(checkInDate).format('dddd, MMM DD, YYYY')}</p>
449
+ <p>Check-out: {dayjs(checkOutDate).format('dddd, MMM DD, YYYY')}</p>
450
+ </div>
451
+ {/if}
452
+ </div>
453
+
454
+ {#if checkInDate && checkOutDate && totalNights > 0}
455
+ <div class="room-selection">
456
+ <h3>Available Rooms</h3>
457
+ <div class="rooms-grid">
458
+ {#each availableRooms as room}
459
+ <div
460
+ class="room-card"
461
+ class:selected={selectedRoom?.id === room.id}
462
+ class:unavailable={!room.available}
463
+ on:click={() => room.available && selectRoom(room)}
464
+ >
465
+ <div class="room-type">{room.type}</div>
466
+ <div class="room-price">${room.price}/night</div>
467
+ <div class="room-total">
468
+ {#if room.available}
469
+ Total: ${room.price * totalNights} for {totalNights} nights
470
+ {:else}
471
+ <span class="unavailable-text">Not Available</span>
472
+ {/if}
473
+ </div>
474
+ {#if selectedRoom?.id === room.id}
475
+ <div class="selected-indicator">✓ Selected</div>
476
+ {/if}
477
+ </div>
478
+ {/each}
479
+ </div>
480
+ </div>
481
+
482
+ {#if selectedRoom}
483
+ <div class="booking-summary">
484
+ <h3>Booking Summary</h3>
485
+ <div class="summary-details">
486
+ <div class="detail-row">
487
+ <span>Room Type:</span>
488
+ <span>{selectedRoom.type}</span>
489
+ </div>
490
+ <div class="detail-row">
491
+ <span>Check-in Date:</span>
492
+ <span>{dayjs(checkInDate).format('MMM DD, YYYY')}</span>
493
+ </div>
494
+ <div class="detail-row">
495
+ <span>Check-out Date:</span>
496
+ <span>{dayjs(checkOutDate).format('MMM DD, YYYY')}</span>
497
+ </div>
498
+ <div class="detail-row">
499
+ <span>Number of Nights:</span>
500
+ <span>{totalNights}</span>
501
+ </div>
502
+ <div class="detail-row">
503
+ <span>Rate per Night:</span>
504
+ <span>${selectedRoom.price}</span>
505
+ </div>
506
+ <div class="detail-row total">
507
+ <span>Total Cost:</span>
508
+ <span>${totalCost}</span>
509
+ </div>
510
+ </div>
511
+
512
+ <button class="book-btn" on:click={bookRoom}>
513
+ Book Room - ${totalCost}
514
+ </button>
515
+ </div>
516
+ {/if}
517
+ {/if}
518
+ </div>
519
+ </div>
520
+
521
+ <style>
522
+ .booking-system {
523
+ max-width: 800px;
524
+ margin: 0 auto;
525
+ padding: 20px;
526
+ }
527
+
528
+ .booking-header {
529
+ text-align: center;
530
+ margin-bottom: 30px;
531
+ }
532
+
533
+ .booking-header h2 {
534
+ color: #333;
535
+ margin: 0 0 8px 0;
536
+ }
537
+
538
+ .booking-header p {
539
+ color: #666;
540
+ margin: 0;
541
+ }
542
+
543
+ .booking-form {
544
+ display: flex;
545
+ flex-direction: column;
546
+ gap: 30px;
547
+ }
548
+
549
+ .date-selection {
550
+ background: white;
551
+ padding: 25px;
552
+ border-radius: 8px;
553
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
554
+ }
555
+
556
+ .date-selection h3 {
557
+ margin: 0 0 20px 0;
558
+ color: #333;
559
+ }
560
+
561
+ .stay-info {
562
+ margin-top: 20px;
563
+ padding: 16px;
564
+ background: #e3f2fd;
565
+ border-radius: 6px;
566
+ }
567
+
568
+ .stay-info p {
569
+ margin: 4px 0;
570
+ color: #1976d2;
571
+ }
572
+
573
+ .room-selection {
574
+ background: white;
575
+ padding: 25px;
576
+ border-radius: 8px;
577
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
578
+ }
579
+
580
+ .room-selection h3 {
581
+ margin: 0 0 20px 0;
582
+ color: #333;
583
+ }
584
+
585
+ .rooms-grid {
586
+ display: grid;
587
+ grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
588
+ gap: 16px;
589
+ }
590
+
591
+ .room-card {
592
+ padding: 20px;
593
+ border: 2px solid #e9ecef;
594
+ border-radius: 8px;
595
+ cursor: pointer;
596
+ transition: all 0.2s;
597
+ position: relative;
598
+ }
599
+
600
+ .room-card:hover:not(.unavailable) {
601
+ border-color: #007bff;
602
+ transform: translateY(-2px);
603
+ box-shadow: 0 4px 8px rgba(0,123,255,0.15);
604
+ }
605
+
606
+ .room-card.selected {
607
+ border-color: #007bff;
608
+ background: #f0f8ff;
609
+ }
610
+
611
+ .room-card.unavailable {
612
+ opacity: 0.5;
613
+ cursor: not-allowed;
614
+ background: #f8f9fa;
615
+ }
616
+
617
+ .room-type {
618
+ font-size: 1.2rem;
619
+ font-weight: 600;
620
+ color: #333;
621
+ margin-bottom: 8px;
622
+ }
623
+
624
+ .room-price {
625
+ font-size: 1.1rem;
626
+ font-weight: 500;
627
+ color: #007bff;
628
+ margin-bottom: 8px;
629
+ }
630
+
631
+ .room-total {
632
+ font-size: 0.9rem;
633
+ color: #666;
634
+ }
635
+
636
+ .unavailable-text {
637
+ color: #dc3545;
638
+ font-weight: 500;
639
+ }
640
+
641
+ .selected-indicator {
642
+ position: absolute;
643
+ top: 10px;
644
+ right: 10px;
645
+ background: #28a745;
646
+ color: white;
647
+ padding: 4px 8px;
648
+ border-radius: 4px;
649
+ font-size: 0.75rem;
650
+ font-weight: 500;
651
+ }
652
+
653
+ .booking-summary {
654
+ background: white;
655
+ padding: 25px;
656
+ border-radius: 8px;
657
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
658
+ }
659
+
660
+ .booking-summary h3 {
661
+ margin: 0 0 20px 0;
662
+ color: #333;
663
+ }
664
+
665
+ .summary-details {
666
+ margin-bottom: 20px;
667
+ }
668
+
669
+ .detail-row {
670
+ display: flex;
671
+ justify-content: space-between;
672
+ padding: 8px 0;
673
+ border-bottom: 1px solid #f0f0f0;
674
+ }
675
+
676
+ .detail-row.total {
677
+ font-weight: 600;
678
+ font-size: 1.1rem;
679
+ color: #333;
680
+ border-bottom: 2px solid #007bff;
681
+ margin-top: 10px;
682
+ }
683
+
684
+ .book-btn {
685
+ width: 100%;
686
+ padding: 12px 24px;
687
+ background: #28a745;
688
+ color: white;
689
+ border: none;
690
+ border-radius: 6px;
691
+ font-size: 1.1rem;
692
+ font-weight: 600;
693
+ cursor: pointer;
694
+ transition: background-color 0.2s;
695
+ }
696
+
697
+ .book-btn:hover {
698
+ background: #218838;
699
+ }
700
+
701
+ @media (max-width: 768px) {
702
+ .rooms-grid {
703
+ grid-template-columns: 1fr;
704
+ }
705
+
706
+ .detail-row {
707
+ font-size: 0.9rem;
708
+ }
709
+ }
710
+ </style>
711
+ ```
712
+
713
+ ### Advanced Search Filters
714
+
715
+ ```svelte
716
+ <script lang="ts">
717
+ import DateRange from '@ticatec/uniface-element/DateRange';
718
+ import type { UniDate } from '@ticatec/uniface-element/DateRange';
719
+ import dayjs from 'dayjs';
720
+
721
+ // Search criteria
722
+ let createdFrom: UniDate = null;
723
+ let createdTo: UniDate = null;
724
+ let modifiedFrom: UniDate = null;
725
+ let modifiedTo: UniDate = null;
726
+
727
+ // Mock document data
728
+ let allDocuments = [
729
+ { id: 1, title: 'Project Proposal', type: 'Document', created: '2024-02-15', modified: '2024-03-01', status: 'Draft' },
730
+ { id: 2, title: 'Budget Report', type: 'Spreadsheet', created: '2024-02-20', modified: '2024-02-28', status: 'Final' },
731
+ { id: 3, title: 'Meeting Notes', type: 'Document', created: '2024-03-01', modified: '2024-03-05', status: 'Draft' },
732
+ { id: 4, title: 'Contract Template', type: 'Template', created: '2024-01-10', modified: '2024-02-15', status: 'Final' },
733
+ { id: 5, title: 'Marketing Plan', type: 'Presentation', created: '2024-03-05', modified: '2024-03-10', status: 'Review' }
734
+ ];
735
+
736
+ let filteredDocuments = [];
737
+
738
+ // Filter documents based on date ranges
739
+ function filterDocuments() {
740
+ filteredDocuments = allDocuments.filter(doc => {
741
+ let matchesCreated = true;
742
+ let matchesModified = true;
743
+
744
+ // Check created date range
745
+ if (createdFrom || createdTo) {
746
+ const createdDate = dayjs(doc.created);
747
+ if (createdFrom && createdDate.isBefore(dayjs(createdFrom))) {
748
+ matchesCreated = false;
749
+ }
750
+ if (createdTo && createdDate.isAfter(dayjs(createdTo))) {
751
+ matchesCreated = false;
752
+ }
753
+ }
754
+
755
+ // Check modified date range
756
+ if (modifiedFrom || modifiedTo) {
757
+ const modifiedDate = dayjs(doc.modified);
758
+ if (modifiedFrom && modifiedDate.isBefore(dayjs(modifiedFrom))) {
759
+ matchesModified = false;
760
+ }
761
+ if (modifiedTo && modifiedDate.isAfter(dayjs(modifiedTo))) {
762
+ matchesModified = false;
763
+ }
764
+ }
765
+
766
+ return matchesCreated && matchesModified;
767
+ });
768
+ }
769
+
770
+ // Reactive filtering
771
+ $: {
772
+ createdFrom, createdTo, modifiedFrom, modifiedTo;
773
+ filterDocuments();
774
+ }
775
+
776
+ function clearAllFilters() {
777
+ createdFrom = null;
778
+ createdTo = null;
779
+ modifiedFrom = null;
780
+ modifiedTo = null;
781
+ }
782
+
783
+ function setRecentFilter() {
784
+ createdFrom = dayjs().subtract(30, 'day');
785
+ createdTo = dayjs();
786
+ }
787
+
788
+ function exportResults() {
789
+ console.log('Exported documents:', filteredDocuments);
790
+ alert(`Exported ${filteredDocuments.length} documents`);
791
+ }
792
+ </script>
793
+
794
+ <div class="advanced-search">
795
+ <header class="search-header">
796
+ <h2>Document Search & Filter</h2>
797
+ <p>Use date ranges to find documents by creation and modification dates</p>
798
+ </header>
799
+
800
+ <div class="filter-panel">
801
+ <div class="filter-section">
802
+ <h3>Creation Date Range</h3>
803
+ <DateRange
804
+ bind:fromValue={createdFrom}
805
+ bind:toValue={createdTo}
806
+ variant="outlined"
807
+ format="MMM DD, YYYY"
808
+ compact={true}
809
+ style="width: 300px;"
810
+ />
811
+ </div>
812
+
813
+ <div class="filter-section">
814
+ <h3>Modification Date Range</h3>
815
+ <DateRange
816
+ bind:fromValue={modifiedFrom}
817
+ bind:toValue={modifiedTo}
818
+ variant="outlined"
819
+ format="MMM DD, YYYY"
820
+ compact={true}
821
+ style="width: 300px;"
822
+ />
823
+ </div>
824
+
825
+ <div class="filter-actions">
826
+ <button class="action-btn secondary" on:click={setRecentFilter}>Last 30 Days</button>
827
+ <button class="action-btn secondary" on:click={clearAllFilters}>Clear All</button>
828
+ {#if filteredDocuments.length > 0}
829
+ <button class="action-btn primary" on:click={exportResults}>Export ({filteredDocuments.length})</button>
830
+ {/if}
831
+ </div>
832
+ </div>
833
+
834
+ <div class="results-section">
835
+ <div class="results-header">
836
+ <h3>Search Results</h3>
837
+ <span class="result-count">{filteredDocuments.length} of {allDocuments.length} documents</span>
838
+ </div>
839
+
840
+ <div class="documents-list">
841
+ {#if filteredDocuments.length > 0}
842
+ {#each filteredDocuments as doc}
843
+ <div class="document-card">
844
+ <div class="doc-header">
845
+ <div class="doc-title">{doc.title}</div>
846
+ <div class="doc-type">{doc.type}</div>
847
+ </div>
848
+ <div class="doc-dates">
849
+ <div class="date-info">
850
+ <span class="date-label">Created:</span>
851
+ <span class="date-value">{dayjs(doc.created).format('MMM DD, YYYY')}</span>
852
+ </div>
853
+ <div class="date-info">
854
+ <span class="date-label">Modified:</span>
855
+ <span class="date-value">{dayjs(doc.modified).format('MMM DD, YYYY')}</span>
856
+ </div>
857
+ </div>
858
+ <div class="doc-status">
859
+ <span class="status-badge status-{doc.status.toLowerCase()}">{doc.status}</span>
860
+ </div>
861
+ </div>
862
+ {/each}
863
+ {:else}
864
+ <div class="no-results">
865
+ <h4>No documents found</h4>
866
+ <p>Try adjusting your date range filters or clear all filters to see more results.</p>
867
+ </div>
868
+ {/if}
869
+ </div>
870
+ </div>
871
+ </div>
872
+
873
+ <style>
874
+ .advanced-search {
875
+ max-width: 1000px;
876
+ margin: 0 auto;
877
+ padding: 20px;
878
+ }
879
+
880
+ .search-header {
881
+ text-align: center;
882
+ margin-bottom: 30px;
883
+ }
884
+
885
+ .search-header h2 {
886
+ color: #333;
887
+ margin: 0 0 8px 0;
888
+ }
889
+
890
+ .search-header p {
891
+ color: #666;
892
+ margin: 0;
893
+ }
894
+
895
+ .filter-panel {
896
+ background: #f8f9fa;
897
+ padding: 25px;
898
+ border-radius: 8px;
899
+ margin-bottom: 30px;
900
+ display: flex;
901
+ flex-wrap: wrap;
902
+ gap: 25px;
903
+ align-items: flex-end;
904
+ }
905
+
906
+ .filter-section {
907
+ flex: 1;
908
+ min-width: 280px;
909
+ }
910
+
911
+ .filter-section h3 {
912
+ margin: 0 0 12px 0;
913
+ color: #333;
914
+ font-size: 1rem;
915
+ }
916
+
917
+ .filter-actions {
918
+ display: flex;
919
+ flex-wrap: wrap;
920
+ gap: 10px;
921
+ align-items: center;
922
+ }
923
+
924
+ .action-btn {
925
+ padding: 8px 16px;
926
+ border: none;
927
+ border-radius: 4px;
928
+ cursor: pointer;
929
+ font-size: 0.875rem;
930
+ font-weight: 500;
931
+ transition: all 0.2s;
932
+ }
933
+
934
+ .action-btn.primary {
935
+ background: #007bff;
936
+ color: white;
937
+ }
938
+
939
+ .action-btn.primary:hover {
940
+ background: #0056b3;
941
+ }
942
+
943
+ .action-btn.secondary {
944
+ background: #6c757d;
945
+ color: white;
946
+ }
947
+
948
+ .action-btn.secondary:hover {
949
+ background: #5a6268;
950
+ }
951
+
952
+ .results-section {
953
+ background: white;
954
+ border-radius: 8px;
955
+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
956
+ overflow: hidden;
957
+ }
958
+
959
+ .results-header {
960
+ display: flex;
961
+ justify-content: space-between;
962
+ align-items: center;
963
+ padding: 20px 25px;
964
+ background: #f8f9fa;
965
+ border-bottom: 1px solid #dee2e6;
966
+ }
967
+
968
+ .results-header h3 {
969
+ margin: 0;
970
+ color: #333;
971
+ }
972
+
973
+ .result-count {
974
+ color: #666;
975
+ font-size: 0.9rem;
976
+ }
977
+
978
+ .documents-list {
979
+ padding: 20px;
980
+ }
981
+
982
+ .document-card {
983
+ border: 1px solid #e9ecef;
984
+ border-radius: 6px;
985
+ padding: 16px;
986
+ margin-bottom: 12px;
987
+ transition: all 0.2s;
988
+ }
989
+
990
+ .document-card:hover {
991
+ border-color: #007bff;
992
+ box-shadow: 0 2px 4px rgba(0,123,255,0.15);
993
+ }
994
+
995
+ .doc-header {
996
+ display: flex;
997
+ justify-content: space-between;
998
+ align-items: center;
999
+ margin-bottom: 12px;
1000
+ }
1001
+
1002
+ .doc-title {
1003
+ font-weight: 600;
1004
+ color: #333;
1005
+ font-size: 1.1rem;
1006
+ }
1007
+
1008
+ .doc-type {
1009
+ background: #e9ecef;
1010
+ color: #495057;
1011
+ padding: 4px 8px;
1012
+ border-radius: 4px;
1013
+ font-size: 0.75rem;
1014
+ font-weight: 500;
1015
+ }
1016
+
1017
+ .doc-dates {
1018
+ display: flex;
1019
+ gap: 20px;
1020
+ margin-bottom: 12px;
1021
+ }
1022
+
1023
+ .date-info {
1024
+ font-size: 0.875rem;
1025
+ }
1026
+
1027
+ .date-label {
1028
+ color: #666;
1029
+ margin-right: 6px;
1030
+ }
1031
+
1032
+ .date-value {
1033
+ color: #333;
1034
+ font-weight: 500;
1035
+ }
1036
+
1037
+ .status-badge {
1038
+ padding: 4px 8px;
1039
+ border-radius: 12px;
1040
+ font-size: 0.75rem;
1041
+ font-weight: 500;
1042
+ }
1043
+
1044
+ .status-draft {
1045
+ background: #fff3cd;
1046
+ color: #856404;
1047
+ }
1048
+
1049
+ .status-final {
1050
+ background: #d4edda;
1051
+ color: #155724;
1052
+ }
1053
+
1054
+ .status-review {
1055
+ background: #cce5ff;
1056
+ color: #004085;
1057
+ }
1058
+
1059
+ .no-results {
1060
+ text-align: center;
1061
+ padding: 60px 20px;
1062
+ color: #666;
1063
+ }
1064
+
1065
+ .no-results h4 {
1066
+ margin: 0 0 12px 0;
1067
+ color: #333;
1068
+ }
1069
+
1070
+ @media (max-width: 768px) {
1071
+ .filter-panel {
1072
+ flex-direction: column;
1073
+ align-items: stretch;
1074
+ }
1075
+
1076
+ .filter-actions {
1077
+ justify-content: center;
1078
+ }
1079
+
1080
+ .doc-header {
1081
+ flex-direction: column;
1082
+ align-items: flex-start;
1083
+ gap: 8px;
1084
+ }
1085
+
1086
+ .doc-dates {
1087
+ flex-direction: column;
1088
+ gap: 4px;
1089
+ }
1090
+ }
1091
+ </style>
1092
+ ```
1093
+
1094
+ ## Styling
1095
+
1096
+ The DateRange component uses the following CSS classes:
1097
+
1098
+ ```css
1099
+ .uniface-range-editor {
1100
+ /* Main range container */
1101
+ display: flex;
1102
+ align-items: center;
1103
+ gap: 8px;
1104
+ }
1105
+
1106
+ .uniface-range-editor .calendar-icon {
1107
+ /* Calendar trigger icon */
1108
+ cursor: pointer;
1109
+ opacity: 0.7;
1110
+ transition: opacity 0.2s;
1111
+ }
1112
+
1113
+ .uniface-range-editor .calendar-icon:hover {
1114
+ opacity: 1;
1115
+ }
1116
+
1117
+ /* Calendar popover styling */
1118
+ .calendar-popover {
1119
+ /* Calendar popup container */
1120
+ background: white;
1121
+ border-radius: 8px;
1122
+ box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
1123
+ padding: 16px;
1124
+ }
1125
+ ```
1126
+
1127
+ ## API Reference
1128
+
1129
+ ### DateRange Component Props
1130
+
1131
+ ```typescript
1132
+ interface DateRangeProps {
1133
+ variant?: '' | 'plain' | 'outlined' | 'filled'; // Visual styling variant
1134
+ compact?: boolean; // Compact layout mode
1135
+ class?: string; // CSS class names
1136
+ style?: string; // Custom inline styles
1137
+ fromValue: UniDate; // Start date value
1138
+ toValue: UniDate; // End date value
1139
+ format?: string; // Date display format
1140
+ min?: string | Date | null; // Minimum selectable date
1141
+ max?: string | Date | null; // Maximum selectable date
1142
+ }
1143
+ ```
1144
+
1145
+ ## Best Practices
1146
+
1147
+ 1. **Date Validation** - Always validate that the from date is before or equal to the to date
1148
+ 2. **Format Consistency** - Use consistent date formats throughout your application
1149
+ 3. **Min/Max Bounds** - Set appropriate date boundaries for your use case
1150
+ 4. **User Feedback** - Provide clear visual feedback for selected date ranges
1151
+ 5. **Mobile Support** - Test calendar interaction on touch devices
1152
+ 6. **Accessibility** - Ensure calendar navigation works with keyboard
1153
+ 7. **Timezone Handling** - Be explicit about timezone handling in your application
1154
+ 8. **Clear Functionality** - Allow users to easily clear date selections
1155
+ 9. **Performance** - Debounce filtering operations that depend on date ranges
1156
+ 10. **Localization** - Consider date format preferences for international users