@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.
- package/README.md +320 -1
- package/README_CN.md +392 -0
- package/dist/accordion/Accordion.svelte +1 -1
- package/dist/action-bar/ActionBar.svelte +7 -1
- package/dist/attachment-files/FileRender.svelte +1 -1
- package/dist/attachment-files/FileUploadBar.svelte +7 -6
- package/dist/attachment-files/FileUploadPanel.svelte +2 -2
- package/dist/base-calendar/DateContext.js +5 -4
- package/dist/base-calendar/YearPickupPanel.svelte +4 -4
- package/dist/card/Card.svelte +1 -1
- package/dist/card/Card.svelte.d.ts +1 -1
- package/dist/cascade-options-select/CascadeOptionSelect.svelte +2 -3
- package/dist/cascade-options-select/CascadeOptionSelect.svelte.d.ts +46 -1
- package/dist/cascade-options-select/CascadePanel.svelte +1 -1
- package/dist/checkbox/CheckBox.svelte +1 -1
- package/dist/color-picker/ColorPicker.svelte +9 -9
- package/dist/color-picker/ColorPicker.svelte.d.ts +0 -2
- package/dist/color-picker/ColorPickerPanel.svelte +11 -15
- package/dist/color-picker/ColorPickerPanel.svelte.d.ts +1 -1
- package/dist/common/CommonPicker.svelte +2 -2
- package/dist/common/CommonPicker.svelte.d.ts +1 -1
- package/dist/common/MouseClickHandler.d.ts +1 -1
- package/dist/common/Popover.svelte +28 -6
- package/dist/common/Popover.svelte.d.ts +9 -3
- package/dist/common/uniface-utils.js +6 -4
- package/dist/common-editor/CommonEditor.svelte +1 -1
- package/dist/common-editor/CommonEditor.svelte.d.ts +1 -1
- package/dist/common-editor/NumberInput.svelte +1 -1
- package/dist/common-editor/NumberInput.svelte.d.ts +1 -1
- package/dist/concise-data-table/ConciseListTable.svelte +7 -2
- package/dist/concise-data-table/ConciseListTable.svelte.d.ts +1 -0
- package/dist/concise-data-table/DataRow.svelte +1 -1
- package/dist/concise-data-table/TableOptions.d.ts +1 -1
- package/dist/data-table/DataTable.svelte +1 -1
- package/dist/data-table/parts/ActionsPanel.svelte +4 -3
- package/dist/data-table/parts/ActionsRow.svelte +3 -3
- package/dist/data-table/parts/ContentPanel.svelte +3 -2
- package/dist/data-table/parts/FixedColumnsPanel.svelte +0 -1
- package/dist/data-table/parts/FixedColumnsPanel.svelte.d.ts +1 -2
- package/dist/data-table/parts/FixedHeaderPanel.svelte +2 -2
- package/dist/data-table/parts/FixedRow.svelte +2 -1
- package/dist/data-table/parts/FixedRow.svelte.d.ts +1 -1
- package/dist/data-table/parts/HrefCell.svelte +23 -2
- package/dist/data-table/parts/PopupMenu.svelte +25 -2
- package/dist/data-table/parts/PopupMenu.svelte.d.ts +8 -1
- package/dist/date-picker/DatePicker.svelte +0 -1
- package/dist/date-picker/DateTimePicker.svelte +3 -3
- package/dist/date-picker/ScrollBar.svelte +4 -7
- package/dist/date-range/DateRangeEditor.svelte +1 -1
- package/dist/dialog/CommonDialog.svelte +8 -5
- package/dist/dialog/CommonDialog.svelte.d.ts +2 -1
- package/dist/dialog/Dialog.svelte +37 -12
- package/dist/dialog/Dialog.svelte.d.ts +4 -3
- package/dist/dialog/DialogBoard.svelte +11 -8
- package/dist/dialog/DialogWrapper.svelte +10 -0
- package/dist/{common-editor/DateInput.svelte.d.ts → dialog/DialogWrapper.svelte.d.ts} +6 -13
- package/dist/dialog/Dialogs.js +1 -1
- package/dist/dialog/ModalResult.d.ts +5 -0
- package/dist/dialog/ModalResult.js +5 -0
- package/dist/drawer/Drawer.svelte +1 -1
- package/dist/form-field/FormField.svelte +2 -1
- package/dist/form-field/FormField.svelte.d.ts +1 -0
- package/dist/form-panel/flex-row-form/FormContainer.svelte +1 -1
- package/dist/form-panel/grid-form/EmptyCell.svelte +8 -7
- package/dist/form-panel/grid-form/EmptyCell.svelte.d.ts +2 -2
- package/dist/form-panel/grid-form/GridField.svelte +1 -1
- package/dist/i18nRes/i18nRes.d.ts +2 -0
- package/dist/i18nRes/i18nRes.js +44 -0
- package/dist/i18nRes/index.d.ts +2 -0
- package/dist/i18nRes/index.js +2 -0
- package/dist/image-files/ImageFilesField.svelte +1 -1
- package/dist/indicator/IndicatorBoard.svelte +1 -1
- package/dist/inline-cell-editor/InvalidEditor.svelte +1 -0
- package/dist/input-options-select/InputOptionsSelect.svelte +6 -6
- package/dist/input-options-select/InputOptionsSelect.svelte.d.ts +1 -1
- package/dist/layout/flex/FlexBlock.svelte +1 -1
- package/dist/lookup-editor/LookupEditor.svelte +1 -1
- package/dist/memo-editor/MemoEditor.svelte +2 -2
- package/dist/message-box/IMessageBox.d.ts +2 -4
- package/dist/message-box/IMessageBox.js +4 -6
- package/dist/message-box/MessageBoxBoard.svelte +1 -3
- package/dist/options-multi-select/OptionsMultiSelect.svelte +1 -1
- package/dist/prompts-text-editor/PromptsTextEditor.svelte +2 -2
- package/dist/prompts-text-editor/PromptsTextEditor.svelte.d.ts +1 -1
- package/dist/property-editor/PropertyEditor.svelte +3 -3
- package/dist/text-editor/PasswordEditor.svelte +1 -1
- package/dist/transfer/Transfer.svelte +17 -12
- package/dist/transfer/Transfer.svelte.d.ts +0 -1
- package/dist/unit-number-editor/UnitNumberEditor.svelte +2 -2
- package/docs/buttons/cn/ActionBar.md +459 -0
- package/docs/buttons/cn/Button.md +228 -0
- package/docs/buttons/cn/IconButton.md +294 -0
- package/docs/buttons/cn/README.md +600 -0
- package/docs/buttons/cn/TextButton.md +163 -0
- package/docs/buttons/en/ActionBar.md +459 -0
- package/docs/buttons/en/Button.md +228 -0
- package/docs/buttons/en/IconButton.md +294 -0
- package/docs/buttons/en/README.md +600 -0
- package/docs/buttons/en/TextButton.md +163 -0
- package/docs/containers/cn/accordion.md +622 -0
- package/docs/containers/cn/box.md +445 -0
- package/docs/containers/cn/card.md +404 -0
- package/docs/containers/cn/page.md +576 -0
- package/docs/containers/cn/tabs.md +686 -0
- package/docs/containers/en/accordion.md +622 -0
- package/docs/containers/en/box.md +445 -0
- package/docs/containers/en/card.md +404 -0
- package/docs/containers/en/page.md +576 -0
- package/docs/containers/en/tabs.md +686 -0
- package/docs/data-display/cn/concise-data-table.md +731 -0
- package/docs/data-display/cn/listbox.md +786 -0
- package/docs/data-display/cn/treeview.md +863 -0
- package/docs/data-display/en/concise-data-table.md +732 -0
- package/docs/data-display/en/listbox.md +786 -0
- package/docs/data-display/en/treeview.md +863 -0
- package/docs/data-table/cn/README.md +596 -0
- package/docs/data-table/en/README.md +596 -0
- package/docs/dialog/cn/README.md +767 -0
- package/docs/dialog/en/README.md +767 -0
- package/docs/form/cn/README.md +847 -0
- package/docs/form/en/README.md +847 -0
- package/docs/form-components/cn/README.md +495 -0
- package/docs/form-components/cn/attachmentfilesfield.md +757 -0
- package/docs/form-components/cn/cascade-options-select.md +374 -0
- package/docs/form-components/cn/checkbox.md +58 -0
- package/docs/form-components/cn/date-picker.md +138 -0
- package/docs/form-components/cn/datetime-picker.md +228 -0
- package/docs/form-components/cn/group-checkbox.md +405 -0
- package/docs/form-components/cn/group-radiobox.md +525 -0
- package/docs/form-components/cn/imagefilesfield.md +651 -0
- package/docs/form-components/cn/input-options-select.md +250 -0
- package/docs/form-components/cn/lookup-editor.md +406 -0
- package/docs/form-components/cn/memoeditor.md +409 -0
- package/docs/form-components/cn/number-editor.md +261 -0
- package/docs/form-components/cn/options-multi-select.md +177 -0
- package/docs/form-components/cn/options-select.md +83 -0
- package/docs/form-components/cn/passwordeditor.md +538 -0
- package/docs/form-components/cn/prompts-text-editor.md +241 -0
- package/docs/form-components/cn/radiobutton.md +84 -0
- package/docs/form-components/cn/switch.md +178 -0
- package/docs/form-components/cn/text-editor.md +142 -0
- package/docs/form-components/cn/time-editor.md +159 -0
- package/docs/form-components/cn/unit-number-editor.md +164 -0
- package/docs/form-components/en/README.md +463 -0
- package/docs/form-components/en/attachmentfilesfield.md +757 -0
- package/docs/form-components/en/cascade-options-select.md +358 -0
- package/docs/form-components/en/checkbox.md +59 -0
- package/docs/form-components/en/date-picker.md +138 -0
- package/docs/form-components/en/datetime-picker.md +228 -0
- package/docs/form-components/en/group-checkbox.md +395 -0
- package/docs/form-components/en/group-radiobox.md +498 -0
- package/docs/form-components/en/imagefilesfield.md +651 -0
- package/docs/form-components/en/input-options-select.md +239 -0
- package/docs/form-components/en/lookup-editor.md +389 -0
- package/docs/form-components/en/memoeditor.md +409 -0
- package/docs/form-components/en/number-editor.md +249 -0
- package/docs/form-components/en/options-multi-select.md +177 -0
- package/docs/form-components/en/options-select.md +83 -0
- package/docs/form-components/en/passwordeditor.md +538 -0
- package/docs/form-components/en/prompts-text-editor.md +241 -0
- package/docs/form-components/en/radiobutton.md +84 -0
- package/docs/form-components/en/switch.md +180 -0
- package/docs/form-components/en/text-editor.md +142 -0
- package/docs/form-components/en/time-editor.md +159 -0
- package/docs/form-components/en/unit-number-editor.md +164 -0
- package/docs/form-layout/cn/criteria-field.md +652 -0
- package/docs/form-layout/cn/flex-form.md +454 -0
- package/docs/form-layout/cn/flex-row-form.md +542 -0
- package/docs/form-layout/cn/form-field.md +923 -0
- package/docs/form-layout/cn/grid-form.md +676 -0
- package/docs/form-layout/en/criteria-field.md +652 -0
- package/docs/form-layout/en/flex-form.md +454 -0
- package/docs/form-layout/en/flex-row-form.md +542 -0
- package/docs/form-layout/en/form-field.md +923 -0
- package/docs/form-layout/en/grid-form.md +676 -0
- package/docs/global/cn/README.md +534 -0
- package/docs/global/en/README.md +534 -0
- package/docs/layout/cn/classiclayout.md +460 -0
- package/docs/layout/cn/headerlayout.md +524 -0
- package/docs/layout/cn/sidebarlayout.md +263 -0
- package/docs/layout/en/classiclayout.md +951 -0
- package/docs/layout/en/headerlayout.md +524 -0
- package/docs/layout/en/sidebarlayout.md +262 -0
- package/docs/misc/cn/README.md +1217 -0
- package/docs/misc/en/README.md +1217 -0
- package/docs/navigation/cn/breadcrumb.md +291 -0
- package/docs/navigation/cn/navigator.md +322 -0
- package/docs/navigation/cn/navigatormenu.md +512 -0
- package/docs/navigation/cn/progressbar.md +199 -0
- package/docs/navigation/cn/progressstepbar.md +299 -0
- package/docs/navigation/en/breadcrumb.md +291 -0
- package/docs/navigation/en/navigator.md +322 -0
- package/docs/navigation/en/navigatormenu.md +512 -0
- package/docs/navigation/en/progressbar.md +199 -0
- package/docs/navigation/en/progressstepbar.md +299 -0
- package/docs/search-filters/cn/daterange.md +1156 -0
- package/docs/search-filters/cn/numberrange.md +688 -0
- package/docs/search-filters/cn/searchbox.md +1582 -0
- package/docs/search-filters/en/daterange.md +1156 -0
- package/docs/search-filters/en/numberrange.md +688 -0
- package/docs/search-filters/en/searchbox.md +1582 -0
- package/package.json +53 -13
- package/dist/common-editor/DateInput.svelte +0 -27
- package/dist/i18n_resources/index.d.ts +0 -3
- package/dist/i18n_resources/index.js +0 -3
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.d.ts +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_cn_resource.js +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.d.ts +0 -0
- /package/dist/{i18n_resources → i18nRes}/uniface_en_resource.js +0 -0
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
# DateTimePicker Component
|
|
2
|
+
|
|
3
|
+
Date and time picker component.
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
| Property | Type | Default | Description |
|
|
8
|
+
|----------|------|---------|-------------|
|
|
9
|
+
| `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Appearance variant |
|
|
10
|
+
| `disabled` | `boolean` | `false` | Whether disabled |
|
|
11
|
+
| `readonly` | `boolean` | `false` | Whether read-only |
|
|
12
|
+
| `compact` | `boolean` | `false` | Whether compact mode |
|
|
13
|
+
| `value` | `Date \| string \| null` | `null` | Date/time value |
|
|
14
|
+
| `format` | `string` | `'YYYY-MM-DD HH:mm'` | Date/time format |
|
|
15
|
+
| `placeholder` | `string` | `''` | Placeholder text |
|
|
16
|
+
| `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode |
|
|
17
|
+
| `minDateTime` | `Date \| string \| null` | `null` | Minimum date/time |
|
|
18
|
+
| `maxDateTime` | `Date \| string \| null` | `null` | Maximum date/time |
|
|
19
|
+
| `minuteStep` | `number` | `1` | Minute step |
|
|
20
|
+
| `locale` | `string` | `'en-US'` | Locale |
|
|
21
|
+
| `style` | `string` | `''` | Custom styles |
|
|
22
|
+
| `onChange` | `OnChangeHandler<Date>` | - | Value change callback |
|
|
23
|
+
|
|
24
|
+
## Usage Examples
|
|
25
|
+
|
|
26
|
+
```svelte
|
|
27
|
+
<script lang="ts">
|
|
28
|
+
import DateTimePicker from '@ticatec/uniface-element/DateTimePicker';
|
|
29
|
+
|
|
30
|
+
let appointmentTime: Date | null = null;
|
|
31
|
+
let eventStartTime: Date = new Date();
|
|
32
|
+
let eventEndTime: Date | null = null;
|
|
33
|
+
|
|
34
|
+
const handleAppointmentChange = (dateTime: Date): void => {
|
|
35
|
+
appointmentTime = dateTime;
|
|
36
|
+
console.log('Appointment time:', dateTime);
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
const handleEventStartChange = (dateTime: Date): void => {
|
|
40
|
+
eventStartTime = dateTime;
|
|
41
|
+
// Auto-set end time to 1 hour after start time
|
|
42
|
+
if (!eventEndTime) {
|
|
43
|
+
eventEndTime = new Date(dateTime.getTime() + 60 * 60 * 1000);
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const handleEventEndChange = (dateTime: Date): void => {
|
|
48
|
+
eventEndTime = dateTime;
|
|
49
|
+
};
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<!-- Appointment time selection -->
|
|
53
|
+
<DateTimePicker
|
|
54
|
+
placeholder="Please select appointment time"
|
|
55
|
+
minDateTime={new Date()}
|
|
56
|
+
minuteStep={15}
|
|
57
|
+
bind:value={appointmentTime}
|
|
58
|
+
onChange={handleAppointmentChange}
|
|
59
|
+
/>
|
|
60
|
+
|
|
61
|
+
<!-- Event start time -->
|
|
62
|
+
<DateTimePicker
|
|
63
|
+
placeholder="Please select start time"
|
|
64
|
+
bind:value={eventStartTime}
|
|
65
|
+
onChange={handleEventStartChange}
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
<!-- Event end time -->
|
|
69
|
+
<DateTimePicker
|
|
70
|
+
placeholder="Please select end time"
|
|
71
|
+
minDateTime={eventStartTime}
|
|
72
|
+
bind:value={eventEndTime}
|
|
73
|
+
onChange={handleEventEndChange}
|
|
74
|
+
/>
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Advanced Usage
|
|
78
|
+
|
|
79
|
+
### Meeting Room Booking
|
|
80
|
+
```svelte
|
|
81
|
+
<script lang="ts">
|
|
82
|
+
interface MeetingSlot {
|
|
83
|
+
start: Date;
|
|
84
|
+
end: Date;
|
|
85
|
+
duration: number; // minutes
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
let meetingStart: Date | null = null;
|
|
89
|
+
let meetingEnd: Date | null = null;
|
|
90
|
+
|
|
91
|
+
// Working hours constraints
|
|
92
|
+
const getWorkingHourLimits = (date: Date): { min: Date; max: Date } => {
|
|
93
|
+
const workStart = new Date(date);
|
|
94
|
+
workStart.setHours(9, 0, 0, 0);
|
|
95
|
+
|
|
96
|
+
const workEnd = new Date(date);
|
|
97
|
+
workEnd.setHours(18, 0, 0, 0);
|
|
98
|
+
|
|
99
|
+
return { min: workStart, max: workEnd };
|
|
100
|
+
};
|
|
101
|
+
|
|
102
|
+
const handleMeetingStartChange = (startTime: Date): void => {
|
|
103
|
+
meetingStart = startTime;
|
|
104
|
+
|
|
105
|
+
// Auto-set end time (default 1 hour later)
|
|
106
|
+
if (!meetingEnd) {
|
|
107
|
+
meetingEnd = new Date(startTime.getTime() + 60 * 60 * 1000);
|
|
108
|
+
}
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const calculateDuration = (start: Date | null, end: Date | null): number => {
|
|
112
|
+
if (!start || !end) return 0;
|
|
113
|
+
return Math.round((end.getTime() - start.getTime()) / (1000 * 60));
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
$: meetingDuration = calculateDuration(meetingStart, meetingEnd);
|
|
117
|
+
$: workingLimits = meetingStart ? getWorkingHourLimits(meetingStart) : null;
|
|
118
|
+
</script>
|
|
119
|
+
|
|
120
|
+
<div class="meeting-booking">
|
|
121
|
+
<div class="datetime-field">
|
|
122
|
+
<label>Meeting Start Time:</label>
|
|
123
|
+
<DateTimePicker
|
|
124
|
+
placeholder="Please select start time"
|
|
125
|
+
minDateTime={new Date()}
|
|
126
|
+
minuteStep={15}
|
|
127
|
+
bind:value={meetingStart}
|
|
128
|
+
onChange={handleMeetingStartChange}
|
|
129
|
+
/>
|
|
130
|
+
</div>
|
|
131
|
+
|
|
132
|
+
<div class="datetime-field">
|
|
133
|
+
<label>Meeting End Time:</label>
|
|
134
|
+
<DateTimePicker
|
|
135
|
+
placeholder="Please select end time"
|
|
136
|
+
minDateTime={meetingStart}
|
|
137
|
+
maxDateTime={workingLimits?.max}
|
|
138
|
+
minuteStep={15}
|
|
139
|
+
bind:value={meetingEnd}
|
|
140
|
+
/>
|
|
141
|
+
</div>
|
|
142
|
+
|
|
143
|
+
{#if meetingDuration > 0}
|
|
144
|
+
<div class="duration-info">
|
|
145
|
+
Meeting duration: {Math.floor(meetingDuration / 60)} hours {meetingDuration % 60} minutes
|
|
146
|
+
</div>
|
|
147
|
+
{/if}
|
|
148
|
+
|
|
149
|
+
{#if workingLimits && meetingEnd && meetingEnd > workingLimits.max}
|
|
150
|
+
<div class="warning">Warning: Meeting end time exceeds working hours</div>
|
|
151
|
+
{/if}
|
|
152
|
+
</div>
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Best Practices
|
|
156
|
+
|
|
157
|
+
### 1. Set Reasonable Time Ranges
|
|
158
|
+
```svelte
|
|
159
|
+
<script lang="ts">
|
|
160
|
+
// Appointments: only future times
|
|
161
|
+
const futureOnly = new Date();
|
|
162
|
+
futureOnly.setMinutes(futureOnly.getMinutes() + 30); // At least 30 minutes ahead
|
|
163
|
+
|
|
164
|
+
// Working hours: limit to weekday working hours
|
|
165
|
+
const isWorkingTime = (date: Date): boolean => {
|
|
166
|
+
const day = date.getDay();
|
|
167
|
+
const hour = date.getHours();
|
|
168
|
+
return day >= 1 && day <= 5 && hour >= 9 && hour <= 18;
|
|
169
|
+
};
|
|
170
|
+
</script>
|
|
171
|
+
|
|
172
|
+
<!-- Appointment system -->
|
|
173
|
+
<DateTimePicker
|
|
174
|
+
minDateTime={futureOnly}
|
|
175
|
+
minuteStep={30}
|
|
176
|
+
placeholder="Select appointment time"
|
|
177
|
+
/>
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### 2. Localization and Formatting
|
|
181
|
+
```svelte
|
|
182
|
+
<DateTimePicker
|
|
183
|
+
locale="en-US"
|
|
184
|
+
format="MM/DD/YYYY hh:mm A"
|
|
185
|
+
placeholder="Please select date and time"
|
|
186
|
+
/>
|
|
187
|
+
|
|
188
|
+
<DateTimePicker
|
|
189
|
+
locale="en-GB"
|
|
190
|
+
format="DD/MM/YYYY HH:mm"
|
|
191
|
+
placeholder="Select date and time"
|
|
192
|
+
/>
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### 3. Form Validation
|
|
196
|
+
```svelte
|
|
197
|
+
<script lang="ts">
|
|
198
|
+
let selectedDateTime: Date | null = null;
|
|
199
|
+
let error: string = '';
|
|
200
|
+
|
|
201
|
+
const validateDateTime = (dateTime: Date | null): void => {
|
|
202
|
+
if (!dateTime) {
|
|
203
|
+
error = 'Please select date and time';
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const now = new Date();
|
|
208
|
+
const minTime = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours later
|
|
209
|
+
|
|
210
|
+
if (dateTime < minTime) {
|
|
211
|
+
error = 'Please select time at least 24 hours from now';
|
|
212
|
+
return;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
error = '';
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
$: validateDateTime(selectedDateTime);
|
|
219
|
+
</script>
|
|
220
|
+
|
|
221
|
+
<DateTimePicker
|
|
222
|
+
bind:value={selectedDateTime}
|
|
223
|
+
onChange={validateDateTime}
|
|
224
|
+
/>
|
|
225
|
+
{#if error}
|
|
226
|
+
<div class="error-message">{error}</div>
|
|
227
|
+
{/if}
|
|
228
|
+
```
|
|
@@ -0,0 +1,395 @@
|
|
|
1
|
+
# GroupCheckBox Component
|
|
2
|
+
|
|
3
|
+
Checkbox group component that organizes multiple checkbox options together, supporting both bitwise operations and string delimiter value storage modes. Usually used for multi-selection scenarios, more convenient than using multiple individual CheckBox components.
|
|
4
|
+
|
|
5
|
+
## Properties
|
|
6
|
+
|
|
7
|
+
| Property | Type | Default | Description |
|
|
8
|
+
|----------|------|---------|-------------|
|
|
9
|
+
| `variant` | `'' \| 'plain' \| 'outlined' \| 'filled'` | `''` | Appearance variant |
|
|
10
|
+
| `disabled` | `boolean` | `false` | Whether disabled |
|
|
11
|
+
| `readonly` | `boolean` | `false` | Whether read-only |
|
|
12
|
+
| `compact` | `boolean` | `false` | Whether compact mode |
|
|
13
|
+
| `value` | `string \| number` | - | Selected value (string or bit value) |
|
|
14
|
+
| `bitBase` | `boolean` | `false` | Whether to use bitwise operation mode |
|
|
15
|
+
| `options` | `Array<any>` | - | Options array |
|
|
16
|
+
| `keyField` | `string` | `'code'` | Value field name |
|
|
17
|
+
| `textField` | `string` | `'text'` | Display field name |
|
|
18
|
+
| `delimiter` | `string` | `';'` | Delimiter for string mode |
|
|
19
|
+
| `displayMode` | `DisplayMode` | `DisplayMode.Edit` | Display mode |
|
|
20
|
+
| `item$style` | `string` | `''` | Style for individual checkbox |
|
|
21
|
+
| `disabledOptions` | `Array<string>` | `[]` | Disabled option values |
|
|
22
|
+
| `hideOptions` | `Array<string>` | `[]` | Hidden option values |
|
|
23
|
+
| `style` | `string` | `''` | Custom styles |
|
|
24
|
+
| `onChange` | `OnChangeHandler<string \| number>` | - | Value change callback |
|
|
25
|
+
|
|
26
|
+
## Usage Examples
|
|
27
|
+
|
|
28
|
+
```svelte
|
|
29
|
+
<script lang="ts">
|
|
30
|
+
import GroupCheckBox from '@ticatec/uniface-element/GroupCheckBox';
|
|
31
|
+
|
|
32
|
+
// Permission options
|
|
33
|
+
const permissions = [
|
|
34
|
+
{ code: 'read', text: 'Read Permission' },
|
|
35
|
+
{ code: 'write', text: 'Write Permission' },
|
|
36
|
+
{ code: 'delete', text: 'Delete Permission' },
|
|
37
|
+
{ code: 'admin', text: 'Admin Permission' }
|
|
38
|
+
];
|
|
39
|
+
|
|
40
|
+
// Hobby options
|
|
41
|
+
const hobbies = [
|
|
42
|
+
{ code: 'sports', text: 'Sports' },
|
|
43
|
+
{ code: 'music', text: 'Music' },
|
|
44
|
+
{ code: 'reading', text: 'Reading' },
|
|
45
|
+
{ code: 'travel', text: 'Travel' },
|
|
46
|
+
{ code: 'cooking', text: 'Cooking' }
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
let userPermissions = 0; // Using bitwise operations
|
|
50
|
+
let userHobbies = ''; // Using string delimiter
|
|
51
|
+
let userSkills = '';
|
|
52
|
+
|
|
53
|
+
const handlePermissionChange = (value: number) => {
|
|
54
|
+
userPermissions = value;
|
|
55
|
+
console.log('User permissions (bit value):', value);
|
|
56
|
+
|
|
57
|
+
// Parse bit value to see specific permissions
|
|
58
|
+
const selectedPermissions = [];
|
|
59
|
+
let bitValue = value;
|
|
60
|
+
let index = 0;
|
|
61
|
+
while (bitValue > 0) {
|
|
62
|
+
if (bitValue & 1) {
|
|
63
|
+
selectedPermissions.push(permissions[index].text);
|
|
64
|
+
}
|
|
65
|
+
bitValue >>= 1;
|
|
66
|
+
index++;
|
|
67
|
+
}
|
|
68
|
+
console.log('Selected permissions:', selectedPermissions);
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
const handleHobbiesChange = (value: string) => {
|
|
72
|
+
userHobbies = value;
|
|
73
|
+
console.log('User hobbies:', value);
|
|
74
|
+
};
|
|
75
|
+
</script>
|
|
76
|
+
|
|
77
|
+
<!-- Permission selection (bitwise mode) -->
|
|
78
|
+
<div class="form-group">
|
|
79
|
+
<label>User Permissions:</label>
|
|
80
|
+
<GroupCheckBox
|
|
81
|
+
options={permissions}
|
|
82
|
+
keyField="code"
|
|
83
|
+
textField="text"
|
|
84
|
+
bitBase={true}
|
|
85
|
+
bind:value={userPermissions}
|
|
86
|
+
onChange={handlePermissionChange}
|
|
87
|
+
/>
|
|
88
|
+
</div>
|
|
89
|
+
|
|
90
|
+
<!-- Hobby selection (string delimiter mode) -->
|
|
91
|
+
<div class="form-group">
|
|
92
|
+
<label>Interests:</label>
|
|
93
|
+
<GroupCheckBox
|
|
94
|
+
options={hobbies}
|
|
95
|
+
keyField="code"
|
|
96
|
+
textField="text"
|
|
97
|
+
delimiter=";"
|
|
98
|
+
bind:value={userHobbies}
|
|
99
|
+
onChange={handleHobbiesChange}
|
|
100
|
+
/>
|
|
101
|
+
</div>
|
|
102
|
+
|
|
103
|
+
<!-- Compact mode checkbox group -->
|
|
104
|
+
<div class="form-group">
|
|
105
|
+
<label>Skill Tags:</label>
|
|
106
|
+
<GroupCheckBox
|
|
107
|
+
options={[
|
|
108
|
+
{ code: 'js', text: 'JavaScript' },
|
|
109
|
+
{ code: 'ts', text: 'TypeScript' },
|
|
110
|
+
{ code: 'svelte', text: 'Svelte' },
|
|
111
|
+
{ code: 'vue', text: 'Vue.js' }
|
|
112
|
+
]}
|
|
113
|
+
keyField="code"
|
|
114
|
+
textField="text"
|
|
115
|
+
compact={true}
|
|
116
|
+
item$style="margin-right: 12px;"
|
|
117
|
+
bind:value={userSkills}
|
|
118
|
+
/>
|
|
119
|
+
</div>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Bitwise Mode Explanation
|
|
123
|
+
|
|
124
|
+
When `bitBase` is `true`, the component uses bitwise operations to store selection state:
|
|
125
|
+
- 1st option: bit value 1 (binary 0001)
|
|
126
|
+
- 2nd option: bit value 2 (binary 0010)
|
|
127
|
+
- 3rd option: bit value 4 (binary 0100)
|
|
128
|
+
- 4th option: bit value 8 (binary 1000)
|
|
129
|
+
|
|
130
|
+
When multiple options are selected, bit values are added together. For example, selecting the 1st and 3rd options gives value 1 + 4 = 5.
|
|
131
|
+
|
|
132
|
+
### Bitwise Utility Functions
|
|
133
|
+
|
|
134
|
+
```typescript
|
|
135
|
+
// Check if contains a specific permission
|
|
136
|
+
const hasPermission = (permissions: number, permission: string): boolean => {
|
|
137
|
+
const permissionIndex = permissionList.findIndex(p => p.code === permission);
|
|
138
|
+
return (permissions & (1 << permissionIndex)) !== 0;
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
// Add permission
|
|
142
|
+
const addPermission = (permissions: number, permission: string): number => {
|
|
143
|
+
const permissionIndex = permissionList.findIndex(p => p.code === permission);
|
|
144
|
+
return permissions | (1 << permissionIndex);
|
|
145
|
+
};
|
|
146
|
+
|
|
147
|
+
// Remove permission
|
|
148
|
+
const removePermission = (permissions: number, permission: string): number => {
|
|
149
|
+
const permissionIndex = permissionList.findIndex(p => p.code === permission);
|
|
150
|
+
return permissions & ~(1 << permissionIndex);
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
// Parse permission list
|
|
154
|
+
const parsePermissions = (permissions: number): string[] => {
|
|
155
|
+
const result = [];
|
|
156
|
+
let bitValue = permissions;
|
|
157
|
+
let index = 0;
|
|
158
|
+
while (bitValue > 0) {
|
|
159
|
+
if (bitValue & 1) {
|
|
160
|
+
result.push(permissionList[index].code);
|
|
161
|
+
}
|
|
162
|
+
bitValue >>= 1;
|
|
163
|
+
index++;
|
|
164
|
+
}
|
|
165
|
+
return result;
|
|
166
|
+
};
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
## Advanced Usage
|
|
170
|
+
|
|
171
|
+
### Dynamic Option Loading
|
|
172
|
+
```svelte
|
|
173
|
+
<script lang="ts">
|
|
174
|
+
import { onMount } from 'svelte';
|
|
175
|
+
|
|
176
|
+
let options = [];
|
|
177
|
+
let selectedValues = '';
|
|
178
|
+
let loading = true;
|
|
179
|
+
|
|
180
|
+
onMount(async () => {
|
|
181
|
+
try {
|
|
182
|
+
const response = await fetch('/api/categories');
|
|
183
|
+
options = await response.json();
|
|
184
|
+
} catch (error) {
|
|
185
|
+
console.error('Failed to load options:', error);
|
|
186
|
+
} finally {
|
|
187
|
+
loading = false;
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
|
|
191
|
+
const handleChange = (value: string) => {
|
|
192
|
+
selectedValues = value;
|
|
193
|
+
// Sync to server
|
|
194
|
+
saveUserPreferences(value);
|
|
195
|
+
};
|
|
196
|
+
</script>
|
|
197
|
+
|
|
198
|
+
{#if loading}
|
|
199
|
+
<div class="loading">Loading options...</div>
|
|
200
|
+
{:else}
|
|
201
|
+
<GroupCheckBox
|
|
202
|
+
{options}
|
|
203
|
+
keyField="id"
|
|
204
|
+
textField="name"
|
|
205
|
+
bind:value={selectedValues}
|
|
206
|
+
onChange={handleChange}
|
|
207
|
+
/>
|
|
208
|
+
{/if}
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### Conditional Disable and Hide
|
|
212
|
+
```svelte
|
|
213
|
+
<script lang="ts">
|
|
214
|
+
const features = [
|
|
215
|
+
{ code: 'basic', text: 'Basic Features' },
|
|
216
|
+
{ code: 'advanced', text: 'Advanced Features' },
|
|
217
|
+
{ code: 'premium', text: 'Premium Features' },
|
|
218
|
+
{ code: 'enterprise', text: 'Enterprise Features' }
|
|
219
|
+
];
|
|
220
|
+
|
|
221
|
+
let userLevel = 'basic'; // basic, premium, enterprise
|
|
222
|
+
let selectedFeatures = '';
|
|
223
|
+
|
|
224
|
+
// Dynamically set disabled options based on user level
|
|
225
|
+
$: disabledOptions = (() => {
|
|
226
|
+
switch (userLevel) {
|
|
227
|
+
case 'basic':
|
|
228
|
+
return ['advanced', 'premium', 'enterprise'];
|
|
229
|
+
case 'premium':
|
|
230
|
+
return ['enterprise'];
|
|
231
|
+
case 'enterprise':
|
|
232
|
+
return [];
|
|
233
|
+
default:
|
|
234
|
+
return ['advanced', 'premium', 'enterprise'];
|
|
235
|
+
}
|
|
236
|
+
})();
|
|
237
|
+
|
|
238
|
+
// Hide enterprise features (if not enterprise user)
|
|
239
|
+
$: hideOptions = userLevel !== 'enterprise' ? ['enterprise'] : [];
|
|
240
|
+
</script>
|
|
241
|
+
|
|
242
|
+
<div class="form-group">
|
|
243
|
+
<label>User Level:</label>
|
|
244
|
+
<select bind:value={userLevel}>
|
|
245
|
+
<option value="basic">Basic User</option>
|
|
246
|
+
<option value="premium">Premium User</option>
|
|
247
|
+
<option value="enterprise">Enterprise User</option>
|
|
248
|
+
</select>
|
|
249
|
+
</div>
|
|
250
|
+
|
|
251
|
+
<div class="form-group">
|
|
252
|
+
<label>Available Features:</label>
|
|
253
|
+
<GroupCheckBox
|
|
254
|
+
options={features}
|
|
255
|
+
keyField="code"
|
|
256
|
+
textField="text"
|
|
257
|
+
{disabledOptions}
|
|
258
|
+
hideOptions={hideOptions}
|
|
259
|
+
bind:value={selectedFeatures}
|
|
260
|
+
/>
|
|
261
|
+
</div>
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
### Select All/None Functionality
|
|
265
|
+
```svelte
|
|
266
|
+
<script lang="ts">
|
|
267
|
+
import CheckBox from '@ticatec/uniface-element/Checkbox';
|
|
268
|
+
|
|
269
|
+
const allOptions = [
|
|
270
|
+
{ code: 'option1', text: 'Option 1' },
|
|
271
|
+
{ code: 'option2', text: 'Option 2' },
|
|
272
|
+
{ code: 'option3', text: 'Option 3' },
|
|
273
|
+
{ code: 'option4', text: 'Option 4' }
|
|
274
|
+
];
|
|
275
|
+
|
|
276
|
+
let selectedValues = '';
|
|
277
|
+
|
|
278
|
+
// Check if all selected
|
|
279
|
+
$: isAllSelected = (() => {
|
|
280
|
+
if (!selectedValues) return false;
|
|
281
|
+
const selected = selectedValues.split(';');
|
|
282
|
+
return allOptions.every(option => selected.includes(option.code));
|
|
283
|
+
})();
|
|
284
|
+
|
|
285
|
+
// Check if partially selected
|
|
286
|
+
$: isIndeterminate = (() => {
|
|
287
|
+
if (!selectedValues) return false;
|
|
288
|
+
const selected = selectedValues.split(';');
|
|
289
|
+
return selected.length > 0 && selected.length < allOptions.length;
|
|
290
|
+
})();
|
|
291
|
+
|
|
292
|
+
const handleSelectAll = (checked: boolean) => {
|
|
293
|
+
if (checked) {
|
|
294
|
+
selectedValues = allOptions.map(opt => opt.code).join(';');
|
|
295
|
+
} else {
|
|
296
|
+
selectedValues = '';
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
const handleChange = (value: string) => {
|
|
301
|
+
selectedValues = value;
|
|
302
|
+
};
|
|
303
|
+
</script>
|
|
304
|
+
|
|
305
|
+
<div class="select-all-container">
|
|
306
|
+
<CheckBox
|
|
307
|
+
label="Select All"
|
|
308
|
+
value={isAllSelected}
|
|
309
|
+
indeterminate={isIndeterminate}
|
|
310
|
+
onChange={handleSelectAll}
|
|
311
|
+
/>
|
|
312
|
+
</div>
|
|
313
|
+
|
|
314
|
+
<GroupCheckBox
|
|
315
|
+
options={allOptions}
|
|
316
|
+
keyField="code"
|
|
317
|
+
textField="text"
|
|
318
|
+
bind:value={selectedValues}
|
|
319
|
+
onChange={handleChange}
|
|
320
|
+
/>
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Style Customization
|
|
324
|
+
|
|
325
|
+
```css
|
|
326
|
+
.form-group {
|
|
327
|
+
margin-bottom: 20px;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
.form-group label {
|
|
331
|
+
display: block;
|
|
332
|
+
margin-bottom: 8px;
|
|
333
|
+
font-weight: 500;
|
|
334
|
+
color: #333;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
.select-all-container {
|
|
338
|
+
padding: 8px 0;
|
|
339
|
+
border-bottom: 1px solid #e1e5e9;
|
|
340
|
+
margin-bottom: 12px;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.loading {
|
|
344
|
+
padding: 20px;
|
|
345
|
+
text-align: center;
|
|
346
|
+
color: #6c757d;
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/* Custom checkbox group styles */
|
|
350
|
+
.custom-checkbox-group {
|
|
351
|
+
display: grid;
|
|
352
|
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
|
353
|
+
gap: 12px;
|
|
354
|
+
padding: 16px;
|
|
355
|
+
background: #f8f9fa;
|
|
356
|
+
border-radius: 8px;
|
|
357
|
+
}
|
|
358
|
+
```
|
|
359
|
+
|
|
360
|
+
## Component Advantages
|
|
361
|
+
|
|
362
|
+
**Advantages over using individual CheckBox components:**
|
|
363
|
+
|
|
364
|
+
1. **Unified Management**: All related options managed in a single component
|
|
365
|
+
2. **Simplified Data Binding**: Only need to bind one value instead of multiple independent values
|
|
366
|
+
3. **Style Consistency**: All options have unified styling and spacing
|
|
367
|
+
4. **Dynamic Option Management**: Easy to show/hide, enable/disable specific options
|
|
368
|
+
5. **Bitwise Support**: Suitable for scenarios requiring bitwise operations like permission systems
|
|
369
|
+
6. **Better Semantics**: Clearly expresses the relationship between options
|
|
370
|
+
|
|
371
|
+
## Best Practices
|
|
372
|
+
|
|
373
|
+
### 1. Choose Appropriate Storage Mode
|
|
374
|
+
```svelte
|
|
375
|
+
<!-- Permission system: use bitwise operations -->
|
|
376
|
+
<GroupCheckBox bitBase={true} />
|
|
377
|
+
|
|
378
|
+
<!-- General multi-select: use string delimiter -->
|
|
379
|
+
<GroupCheckBox delimiter="," />
|
|
380
|
+
```
|
|
381
|
+
|
|
382
|
+
### 2. Provide Clear Labels
|
|
383
|
+
```svelte
|
|
384
|
+
<label>Please select your technology interests:</label>
|
|
385
|
+
<GroupCheckBox
|
|
386
|
+
options={techStack}
|
|
387
|
+
placeholder="Select tech stack"
|
|
388
|
+
/>
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
### 3. Use Compact Mode Appropriately
|
|
392
|
+
```svelte
|
|
393
|
+
<!-- Use compact mode when there are many options -->
|
|
394
|
+
<GroupCheckBox compact={true} />
|
|
395
|
+
```
|