@mptw/skylens-ui 1.0.0

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 (143) hide show
  1. package/.editorconfig +12 -0
  2. package/.eslintrc.cjs +4 -0
  3. package/.nuxtrc +1 -0
  4. package/.playground/app.config.ts +5 -0
  5. package/.playground/nuxt.config.ts +3 -0
  6. package/README.md +73 -0
  7. package/app.config.ts +5 -0
  8. package/app.vue +3 -0
  9. package/assets/css/fonts/MEShPlus-font-icon.eot +0 -0
  10. package/assets/css/fonts/MEShPlus-font-icon.svg +186 -0
  11. package/assets/css/fonts/MEShPlus-font-icon.ttf +0 -0
  12. package/assets/css/fonts/MEShPlus-font-icon.woff +0 -0
  13. package/assets/css/icons.css +555 -0
  14. package/assets/css/layout.styl +98 -0
  15. package/assets/css/tailwind.css +3 -0
  16. package/assets/images/commons/app-logo-white.png +0 -0
  17. package/assets/images/commons/app-logo.png +0 -0
  18. package/assets/images/commons/empty-box.png +0 -0
  19. package/assets/images/commons/watermark.svg +15 -0
  20. package/components/SLAlertModal.vue +99 -0
  21. package/components/SLBreadcrumbs.vue +42 -0
  22. package/components/SLButton.vue +301 -0
  23. package/components/SLCalendarButton.vue +259 -0
  24. package/components/SLCalendarPopup.vue +832 -0
  25. package/components/SLCard.vue +118 -0
  26. package/components/SLChart.vue +181 -0
  27. package/components/SLCheckbox.vue +179 -0
  28. package/components/SLCircleButton.vue +95 -0
  29. package/components/SLCollapsableBlock.vue +116 -0
  30. package/components/SLCollapsableMulitPillSelect.vue +92 -0
  31. package/components/SLConfirmModal.vue +122 -0
  32. package/components/SLDateInput.vue +460 -0
  33. package/components/SLDatePicker.vue +143 -0
  34. package/components/SLDistributor.vue +30 -0
  35. package/components/SLDownloadButton.vue +410 -0
  36. package/components/SLDraggable.vue +151 -0
  37. package/components/SLDropdown.vue +277 -0
  38. package/components/SLDropdownItem.vue +31 -0
  39. package/components/SLElementWithTitle.vue +181 -0
  40. package/components/SLEyeCheckbox.vue +162 -0
  41. package/components/SLFileInput.vue +101 -0
  42. package/components/SLGenderAgeSelect.vue +279 -0
  43. package/components/SLHeatMap.vue +151 -0
  44. package/components/SLHourRangeInput.vue +211 -0
  45. package/components/SLIOSSwitch.vue +235 -0
  46. package/components/SLIcon.vue +35 -0
  47. package/components/SLIconButton.vue +130 -0
  48. package/components/SLInfoTip.vue +221 -0
  49. package/components/SLInsightSitePage.vue +27 -0
  50. package/components/SLLegend.vue +76 -0
  51. package/components/SLLinearProgressBar.vue +35 -0
  52. package/components/SLLink.vue +162 -0
  53. package/components/SLLoading.vue +127 -0
  54. package/components/SLMapChart.vue +151 -0
  55. package/components/SLModal.vue +377 -0
  56. package/components/SLMonthCalendarButton.vue +378 -0
  57. package/components/SLMonthPicker.vue +151 -0
  58. package/components/SLMultiSelect.vue +121 -0
  59. package/components/SLNoData.vue +43 -0
  60. package/components/SLPageModal.vue +64 -0
  61. package/components/SLPagination.vue +192 -0
  62. package/components/SLPillCheckbox.vue +207 -0
  63. package/components/SLPillLabel.vue +101 -0
  64. package/components/SLPopupMenuButton.vue +158 -0
  65. package/components/SLProfileButton.vue +186 -0
  66. package/components/SLRadioButton.vue +97 -0
  67. package/components/SLRadioButtonGroup.vue +113 -0
  68. package/components/SLRadioGroup.vue +201 -0
  69. package/components/SLRangeInput.vue +209 -0
  70. package/components/SLRegionsMapChart.vue +151 -0
  71. package/components/SLRightSider.vue +242 -0
  72. package/components/SLSearchInput.vue +87 -0
  73. package/components/SLSelect.vue +545 -0
  74. package/components/SLSelectAllToggle.vue +118 -0
  75. package/components/SLSiderbarNav.vue +394 -0
  76. package/components/SLSiderbarNavItem.vue +204 -0
  77. package/components/SLSitePage.vue +96 -0
  78. package/components/SLSkyInsightSitePage.vue +27 -0
  79. package/components/SLSortByDropdown.vue +189 -0
  80. package/components/SLSpinIcon.vue +24 -0
  81. package/components/SLStayRangeInput.vue +306 -0
  82. package/components/SLTab.vue +159 -0
  83. package/components/SLTable.vue +409 -0
  84. package/components/SLTableTooltip.vue +111 -0
  85. package/components/SLTabs.vue +388 -0
  86. package/components/SLTextInput.vue +362 -0
  87. package/components/SLTextarea.vue +134 -0
  88. package/components/SLToast.vue +71 -0
  89. package/components/SLToggleButton.vue +78 -0
  90. package/components/SLTwoLayerMultiSelect.vue +428 -0
  91. package/components/SLTwoLayerSelect.vue +265 -0
  92. package/components/SLWarnModal.vue +75 -0
  93. package/interface/IDateRange.ts +5 -0
  94. package/interface/IHourRange.ts +4 -0
  95. package/interface/IInputOption.ts +6 -0
  96. package/interface/ILegendItem.ts +7 -0
  97. package/interface/IPopupMenuButton.ts +5 -0
  98. package/interface/IStayRange.ts +15 -0
  99. package/interface/ITableField.ts +19 -0
  100. package/interface/IWeb.ts +5 -0
  101. package/interface/NavConfigType.ts +14 -0
  102. package/interface/commons.ts +7 -0
  103. package/models/DateRange.ts +21 -0
  104. package/nuxt.config.ts +22 -0
  105. package/package.json +52 -0
  106. package/plugins/googlemaps.ts +17 -0
  107. package/plugins/v-calendar.ts +5 -0
  108. package/public/assets/files/taiwan-regions.json +7 -0
  109. package/public/assets/files/taiwan.json +24 -0
  110. package/public/assets/images/commons/default-favico.png +0 -0
  111. package/public/assets/images/dashboard/closure-button-icon.png +0 -0
  112. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-disabled.png +0 -0
  113. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-poi.png +0 -0
  114. package/public/assets/images/dashboard/dashboard-widget-bar-chart-icon-web.png +0 -0
  115. package/public/assets/images/dashboard/dashboard-widget-country-heatmap-chart-icon-disabled.png +0 -0
  116. package/public/assets/images/dashboard/dashboard-widget-country-heatmap-chart-icon.png +0 -0
  117. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-disabled.png +0 -0
  118. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-poi.png +0 -0
  119. package/public/assets/images/dashboard/dashboard-widget-geo-list-icon-web.png +0 -0
  120. package/public/assets/images/dashboard/dashboard-widget-heatmap-chart-icon-disabled.png +0 -0
  121. package/public/assets/images/dashboard/dashboard-widget-heatmap-chart-icon-web.png +0 -0
  122. package/public/assets/images/dashboard/dashboard-widget-line-chart-icon-disabled.png +0 -0
  123. package/public/assets/images/dashboard/dashboard-widget-line-chart-icon-poi.png +0 -0
  124. package/public/assets/images/dashboard/dashboard-widget-list-icon-disabled.png +0 -0
  125. package/public/assets/images/dashboard/dashboard-widget-list-icon-poi.png +0 -0
  126. package/public/assets/images/dashboard/dashboard-widget-list-icon-web.png +0 -0
  127. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-disabled.png +0 -0
  128. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-poi.png +0 -0
  129. package/public/assets/images/dashboard/dashboard-widget-pie-chart-icon-web.png +0 -0
  130. package/public/assets/images/dashboard/drag-hint-icon.svg +3 -0
  131. package/public/assets/images/dashboard/extend-button-icon.png +0 -0
  132. package/public/assets/images/dashboard/map-list-chart-icon.svg +17 -0
  133. package/public/assets/images/dashboard/map-marker-chart-icon.svg +32 -0
  134. package/public/assets/images/dashboard/pie-chart-icon.svg +4 -0
  135. package/public/assets/images/dashboard/poi-gender-age-chart-icon.svg +20 -0
  136. package/public/assets/images/dashboard/poi-nav-icon.png +0 -0
  137. package/public/assets/images/dashboard/web-gender-age-chart-icon.svg +20 -0
  138. package/public/assets/images/dashboard/web-nav-icon.png +0 -0
  139. package/tailwind.config.js +300 -0
  140. package/tsconfig.json +8 -0
  141. package/utils/constants.ts +160 -0
  142. package/utils/generateSheet.ts +36 -0
  143. package/utils/index.ts +539 -0
@@ -0,0 +1,92 @@
1
+ <template lang="pug">
2
+ .collapsable-multi-pill-select
3
+ a(
4
+ href="javascript:;"
5
+ :class="{ active: showIndustryTypes }"
6
+ @click="onClickedToggleIndustryTypes"
7
+ ).toggle-button
8
+ span 篩選產業類別
9
+ SLIcon(icon="caret-down").toggle-icon
10
+ .pills
11
+ SLPillCheckbox(
12
+ v-for="option in filteredOptions"
13
+ :modelValue="modelValue"
14
+ :label="option.label"
15
+ :value="option.value"
16
+ :disabled="option.disabled"
17
+ color="primary"
18
+ icon="times"
19
+ @update:modelValue="onInputed"
20
+ :key="option.value"
21
+ )
22
+ </template>
23
+
24
+ <script lang="ts">
25
+ import type { PropType } from "vue";
26
+ import type IInputOption from "~ui/interface/IInputOption";
27
+
28
+ export default defineComponent({
29
+ name: "SLCollapsableMultiPillSelect",
30
+ components: {},
31
+ props: {
32
+ options: {
33
+ type: Array as PropType<Array<IInputOption>>,
34
+ default: () => [],
35
+ },
36
+ modelValue: {
37
+ type: Array,
38
+ default: () => [],
39
+ },
40
+ },
41
+ emits: ["update:modelValue"],
42
+ setup(props, { emit }) {
43
+ const { options, modelValue } = toRefs(props);
44
+
45
+ const showIndustryTypes = ref(false);
46
+
47
+ const filteredOptions = computed(() => {
48
+ if (!showIndustryTypes.value) {
49
+ return options.value.filter((option) =>
50
+ modelValue.value.includes(option.value)
51
+ );
52
+ }
53
+
54
+ return options.value;
55
+ });
56
+
57
+ function onClickedToggleIndustryTypes() {
58
+ showIndustryTypes.value = !showIndustryTypes.value;
59
+ }
60
+
61
+ function onInputed(newValue: any) {
62
+ emit("update:modelValue", newValue);
63
+ }
64
+
65
+ return {
66
+ showIndustryTypes,
67
+ filteredOptions,
68
+ onClickedToggleIndustryTypes,
69
+ onInputed,
70
+ };
71
+ },
72
+ });
73
+ </script>
74
+
75
+ <style lang="stylus">
76
+ .collapsable-multi-pill-select
77
+ .toggle-button
78
+ @apply inline-flex items-center justify-between w-80 p-2 mb-2 border border-primary-light rounded text-base text-gray-2
79
+
80
+ &.active
81
+ .toggle-icon
82
+ @apply rotate-180
83
+
84
+ .toggle-icon
85
+ @apply transform origin-center
86
+
87
+ .pills
88
+ @apply s('-mx-1') mb-4 border-b border-primary-lighter
89
+
90
+ .pill-checkbox
91
+ @apply mx-1 mb-2
92
+ </style>
@@ -0,0 +1,122 @@
1
+ <template lang="pug">
2
+ SLModal(
3
+ :show="show"
4
+ :title="title"
5
+ :size="size"
6
+ :backdrop="true"
7
+ :close-button='closeButton'
8
+ :closeOnBackdrop="closeOnBackdrop"
9
+ :modalClass='allModalClass'
10
+ @update:show="onUpdatedShow"
11
+ )
12
+ slot
13
+ template(#footer)
14
+ slot(name="footer")
15
+ .confirm-modal-footer
16
+ SLButton(
17
+ :color="cancelButtonColor"
18
+ size="lg"
19
+ :title="cancelButtonTitle"
20
+ @click="onClickedCancel"
21
+ )
22
+ SLButton(
23
+ :color="confirmButtonColor"
24
+ size="lg"
25
+ :title="confirmButtonTitle"
26
+ :variant="confirmButtonVariant"
27
+ @click="onClickedConfirm"
28
+ )
29
+ </template>
30
+
31
+ <script lang="ts">
32
+ export default defineComponent({
33
+ name: "SLConfirmModal",
34
+ components: {},
35
+ props: {
36
+ show: {
37
+ type: Boolean,
38
+ default: false,
39
+ },
40
+ title: {
41
+ type: String,
42
+ default: "",
43
+ },
44
+ cancelButtonTitle: {
45
+ type: String,
46
+ default: "取消",
47
+ },
48
+ cancelButtonColor: {
49
+ type: String,
50
+ default: "cancel",
51
+ },
52
+ confirmButtonTitle: {
53
+ type: String,
54
+ default: "確定",
55
+ },
56
+ confirmButtonColor: {
57
+ type: String,
58
+ default: "primary",
59
+ },
60
+ confirmButtonVariant: {
61
+ type: String,
62
+ default: "outline",
63
+ validator: (value: string) => ["", "outline"].includes(value),
64
+ },
65
+ modalClass: {
66
+ type: String,
67
+ default: "",
68
+ },
69
+ size: {
70
+ type: String,
71
+ default: "xs",
72
+ },
73
+ closeButton: {
74
+ type: Boolean,
75
+ default: true,
76
+ },
77
+ closeOnBackdrop: {
78
+ type: Boolean,
79
+ default: false,
80
+ },
81
+ },
82
+ emits: ["update:show", "cancel", "confirm"],
83
+ setup(props, { emit }) {
84
+ const { modalClass } = toRefs(props);
85
+
86
+ const allModalClass = computed(() => {
87
+ const allClass = modalClass.value.split(" ");
88
+ allClass.push("confirm-modal");
89
+ return allClass.join(" ");
90
+ });
91
+
92
+ function onClickedCancel() {
93
+ emit("cancel");
94
+ emit("update:show", false);
95
+ }
96
+
97
+ function onClickedConfirm() {
98
+ emit("confirm");
99
+ }
100
+
101
+ function onUpdatedShow(value: boolean) {
102
+ emit("update:show", value);
103
+ }
104
+
105
+ return {
106
+ allModalClass,
107
+ onClickedCancel,
108
+ onClickedConfirm,
109
+ onUpdatedShow,
110
+ };
111
+ },
112
+ });
113
+ </script>
114
+
115
+ <style lang="stylus">
116
+ .confirm-modal
117
+ .modal-backdrop
118
+ @apply s('bg-white/40') backdrop-blur-5
119
+
120
+ &-footer
121
+ @apply flex justify-center space-x-4
122
+ </style>
@@ -0,0 +1,460 @@
1
+ <template lang="pug">
2
+ .date-input(
3
+ :class="dateInputClass"
4
+ )
5
+ label(v-if="label") {{ label }}
6
+ .form-control(
7
+ :class="{ 'is-invalid': isInvalid !== null && isInvalid, 'is-valid': isInvalid !== null && !isInvalid }"
8
+ ref="toggle"
9
+ )
10
+ .input-group(
11
+ :class="{ 'is-fill': !!modelValue }"
12
+ )
13
+ .input-group-prepend
14
+ SLIcon(icon="calendar")
15
+ .inputs
16
+ DatePicker(
17
+ :modelValue="startDate"
18
+ :mode='mode'
19
+ :is24hr='is24hr'
20
+ :min-date='minDate'
21
+ :max-date='maxDate'
22
+ :masks='dateMasks'
23
+ :attributes='attributes'
24
+ :popover='popover',
25
+ color='skylens-purple'
26
+ @update:modelValue="onUpdatedStartDate"
27
+ ref='startDatePickerComp'
28
+ )
29
+ template(#default="{ inputValue, inputEvents }")
30
+ input(
31
+ type="text"
32
+ :value="inputValue"
33
+ :placeholder="startDatePlaceholder"
34
+ :disabled="disabled"
35
+ v-on="inputEvents"
36
+ @focus="onFocusStartDate"
37
+ )
38
+ template(v-if='isRange')
39
+ .date-range-split -
40
+ DatePicker(
41
+ :modelValue="endDate"
42
+ :mode='mode'
43
+ :is24hr='is24hr'
44
+ :min-date='endMinDate'
45
+ :max-date='maxDate'
46
+ :masks='dateMasks'
47
+ :attributes='attributes'
48
+ :popover='popover'
49
+ color='skylens-purple'
50
+ @update:modelValue="onUpdatedEndDate"
51
+ ref='endDatePickerComp'
52
+ )
53
+ template(#default="{ inputValue, inputEvents }")
54
+ input(
55
+ type="text"
56
+ :value="inputValue"
57
+ :placeholder="endDatePlaceholder"
58
+ :disabled="disabled"
59
+ v-on="inputEvents"
60
+ @focus="onFocusEndDate"
61
+ )
62
+ SLIcon(icon="exclamation-triangle")
63
+ .input-info(v-if='info !== ""') {{ info }}
64
+ .invalid-feedback
65
+ slot(name="invalid-feedback") {{ invalidFeedback }}
66
+ </template>
67
+
68
+ <script lang="ts">
69
+ import type { PropType } from "vue";
70
+ import { DatePicker } from "v-calendar";
71
+ import "v-calendar/style.css";
72
+ import type { PopoverVisibility } from "v-calendar/dist/types/src/utils/popovers";
73
+ import { isDate, differenceInCalendarDays } from "date-fns";
74
+ import type IDateRange from "~ui/interface/IDateRange";
75
+
76
+ type DatePickerType = InstanceType<typeof DatePicker> & {
77
+ hidePopover: () => void;
78
+ };
79
+
80
+ export default defineComponent({
81
+ name: "DateInput",
82
+ components: { DatePicker },
83
+ props: {
84
+ label: {
85
+ type: String,
86
+ default: undefined,
87
+ },
88
+ inline: {
89
+ type: Boolean,
90
+ default: false,
91
+ },
92
+ modelValue: {
93
+ type: [Date, Object] as PropType<Date | IDateRange | null>,
94
+ default: null,
95
+ },
96
+ minDate: {
97
+ type: Date,
98
+ default: null,
99
+ },
100
+ maxDate: {
101
+ type: Date,
102
+ default: null,
103
+ },
104
+ startPlaceholder: {
105
+ type: String,
106
+ default: "",
107
+ },
108
+ endPlaceholder: {
109
+ type: String,
110
+ default: "",
111
+ },
112
+ isInvalid: {
113
+ type: Boolean,
114
+ default: false,
115
+ },
116
+ invalidFeedback: {
117
+ type: String,
118
+ default: "",
119
+ },
120
+ lazy: {
121
+ type: [Boolean, Number],
122
+ default: true,
123
+ },
124
+ isRange: {
125
+ type: Boolean,
126
+ default: true,
127
+ },
128
+ maxRangeDays: {
129
+ type: Number,
130
+ default: 0,
131
+ },
132
+ disabled: {
133
+ type: Boolean,
134
+ default: false,
135
+ },
136
+ mode: {
137
+ type: String,
138
+ default: "date",
139
+ validator: (val: string) => ["date", "dateTime", "time"].includes(val),
140
+ },
141
+ is24hr: {
142
+ type: Boolean,
143
+ default: true,
144
+ },
145
+ beReadonly: {
146
+ type: Boolean,
147
+ default: false,
148
+ },
149
+ info: {
150
+ type: String,
151
+ default: "",
152
+ },
153
+ size: {
154
+ type: String,
155
+ default: "",
156
+ validator: (val: string) => ["", "xs"].includes(val),
157
+ },
158
+ },
159
+ emits: ["update:modelValue"],
160
+ setup(props, { emit }) {
161
+ const {
162
+ inline,
163
+ modelValue,
164
+ isRange,
165
+ maxRangeDays,
166
+ is24hr,
167
+ minDate,
168
+ maxDate,
169
+ disabled,
170
+ mode,
171
+ startPlaceholder,
172
+ endPlaceholder,
173
+ beReadonly,
174
+ size,
175
+ } = toRefs(props);
176
+
177
+ const startDatePickerComp = shallowRef<DatePickerType | null>(null);
178
+ const endDatePickerComp = shallowRef<DatePickerType | null>(null);
179
+ const toggle = ref(null);
180
+ const startDate = ref<Date | null>(
181
+ isDate(modelValue.value)
182
+ ? (modelValue.value as Date)
183
+ : (modelValue.value as IDateRange)?.start || null
184
+ );
185
+ const endDate = ref<Date | null>(
186
+ isDate(modelValue.value)
187
+ ? null
188
+ : (modelValue.value as IDateRange)?.end || null
189
+ );
190
+
191
+ const dateInputClass = computed(() => {
192
+ const dateInputClass = [
193
+ {
194
+ inline: inline.value,
195
+ disabled: disabled.value,
196
+ readonly: beReadonly.value,
197
+ },
198
+ `date-input-${mode.value}`,
199
+ ];
200
+
201
+ if (isRange.value) {
202
+ dateInputClass.push("date-input-range");
203
+ }
204
+
205
+ if (size.value) {
206
+ dateInputClass.push(`date-input-${size.value}`);
207
+ }
208
+
209
+ return dateInputClass;
210
+ });
211
+ const dateMasks = computed(() => {
212
+ return {
213
+ input: "YYYY/MM/DD",
214
+ inputDateTime: "YYYY/MM/DD h:mm A",
215
+ inputDateTime24hr: "YYYY/MM/DD HH:mm",
216
+ inputTime: "h:mm A",
217
+ inputTime24hr: "HH:mm",
218
+ };
219
+ });
220
+ const attributes = computed(() => {
221
+ return [
222
+ {
223
+ bar: {
224
+ style: {
225
+ backgroundColor: "#BABBE1",
226
+ },
227
+ },
228
+ dates: [new Date()],
229
+ },
230
+ ];
231
+ });
232
+ const popover = computed(() => {
233
+ return beReadonly.value
234
+ ? false
235
+ : {
236
+ visibility: "click" as PopoverVisibility,
237
+ };
238
+ });
239
+ const endMinDate = computed(() => {
240
+ if (!isRange.value || !startDate.value) {
241
+ return minDate.value;
242
+ }
243
+
244
+ return startDate.value;
245
+ });
246
+ const startDatePlaceholder = computed(() => {
247
+ let startDatePlaceholder = "";
248
+
249
+ switch (mode.value) {
250
+ case "date":
251
+ startDatePlaceholder = "YYYY/MM/DD";
252
+ break;
253
+ case "dateTime":
254
+ startDatePlaceholder = `YYYY/MM/DD ${is24hr.value ? "HH" : "hh"}:mm`;
255
+ break;
256
+ default:
257
+ startDatePlaceholder = `${is24hr.value ? "HH" : "hh"}:mm`;
258
+ break;
259
+ }
260
+
261
+ return startPlaceholder.value || startDatePlaceholder;
262
+ });
263
+ const endDatePlaceholder = computed(() => {
264
+ let endDatePlaceholder = "";
265
+
266
+ switch (mode.value) {
267
+ case "date":
268
+ endDatePlaceholder = "YYYY/MM/DD";
269
+ break;
270
+ case "dateTime":
271
+ endDatePlaceholder = `YYYY/MM/DD ${is24hr.value ? "HH" : "hh"}:mm`;
272
+ break;
273
+ default:
274
+ endDatePlaceholder = `${is24hr.value ? "HH" : "hh"}:mm`;
275
+ break;
276
+ }
277
+
278
+ return endPlaceholder.value || endDatePlaceholder;
279
+ });
280
+
281
+ function onUpdatedStartDate(newValue: Date | null) {
282
+ if (!isRange.value) {
283
+ emit("update:modelValue", newValue);
284
+ return;
285
+ }
286
+
287
+ if (
288
+ endDate.value &&
289
+ newValue &&
290
+ (newValue > endDate.value ||
291
+ (maxRangeDays.value > 0 &&
292
+ Math.abs(differenceInCalendarDays(newValue, endDate.value)) >
293
+ maxRangeDays.value))
294
+ ) {
295
+ endDate.value = null;
296
+ }
297
+
298
+ emit("update:modelValue", {
299
+ start: newValue,
300
+ end: endDate.value,
301
+ });
302
+ }
303
+
304
+ function onUpdatedEndDate(newValue: Date | null) {
305
+ if (!isRange.value) return;
306
+
307
+ if (
308
+ startDate.value &&
309
+ newValue &&
310
+ (newValue < startDate.value ||
311
+ (maxRangeDays.value > 0 &&
312
+ Math.abs(differenceInCalendarDays(newValue, startDate.value)) >
313
+ maxRangeDays.value))
314
+ ) {
315
+ startDate.value = null;
316
+ }
317
+
318
+ emit("update:modelValue", {
319
+ start: startDate.value,
320
+ end: newValue,
321
+ });
322
+ }
323
+
324
+ function onFocusStartDate() {
325
+ if (endDatePickerComp.value) {
326
+ endDatePickerComp.value.hidePopover();
327
+ }
328
+ }
329
+
330
+ function onFocusEndDate() {
331
+ if (startDatePickerComp.value) {
332
+ startDatePickerComp.value.hidePopover();
333
+ }
334
+ }
335
+
336
+ watch(modelValue, () => {
337
+ startDate.value = isDate(modelValue.value)
338
+ ? (modelValue.value as Date)
339
+ : (modelValue.value as IDateRange)?.start || null;
340
+ endDate.value = isDate(modelValue.value)
341
+ ? null
342
+ : (modelValue.value as IDateRange)?.end || null;
343
+ });
344
+
345
+ return {
346
+ startDatePickerComp,
347
+ endDatePickerComp,
348
+ toggle,
349
+ startDate,
350
+ endDate,
351
+ dateInputClass,
352
+ dateMasks,
353
+ attributes,
354
+ popover,
355
+ endMinDate,
356
+ startDatePlaceholder,
357
+ endDatePlaceholder,
358
+ onUpdatedStartDate,
359
+ onUpdatedEndDate,
360
+ onFocusStartDate,
361
+ onFocusEndDate,
362
+ };
363
+ },
364
+ });
365
+ </script>
366
+
367
+ <style lang="stylus">
368
+ .date-input
369
+ &.date-input-xs
370
+ .input-group
371
+ &-prepend
372
+ @apply s('pl-2.75') pr-4 rounded-l-lg
373
+
374
+ .inputs
375
+ @apply pl-0 rounded-r-lg
376
+
377
+ .input-group
378
+ .inputs
379
+ div
380
+ input
381
+ @apply s('w-[5.875rem]') text-center
382
+
383
+ &.date-input-range.date-input-dateTime
384
+ .input-group
385
+ .inputs
386
+ div
387
+ input
388
+ @apply s('w-[10.5rem]')
389
+
390
+ &.inline
391
+ @apply flex
392
+
393
+ & > label
394
+ @apply flex-grow-0 flex-shrink-0 mb-0 mr-2 py-2 border-t border-b border-transparent
395
+
396
+ .form-control
397
+ @apply flex-grow
398
+
399
+ &.disabled, &.readonly
400
+ .input-group
401
+ .input-group-prepend, .inputs
402
+ @apply border-primary-light bg-bg
403
+
404
+
405
+ & > label
406
+ @apply mb-2 text-base leading-normal text-gray-2
407
+
408
+ .is-invalid
409
+ .input-group, .input-group.is-focus
410
+ .input-group-prepend
411
+ @apply border-danger-hover
412
+
413
+ .inputs
414
+ @apply border-danger-hover
415
+
416
+ .icon
417
+ @apply inline-block
418
+
419
+ .invalid-feedback
420
+ @apply block
421
+
422
+
423
+ .input-group
424
+ @apply flex flex-nowrap text-base leading-normal
425
+
426
+ &.is-focus
427
+ .input
428
+ @apply border-primary
429
+
430
+ &.is-fill, &.is-focus
431
+ .input
432
+ .float-label
433
+ @apply s('ml-1.5') s('-mt-2.25') py-0 s('px-0.5') bg-white text-primary text-xs transition-input-focus
434
+
435
+ &-prepend
436
+ @apply flex-grow-0 flex-shrink-0 flex items-center relative pl-4 pr-6 rounded-l border border-r-0 border-primary-light bg-white text-base leading-none
437
+
438
+ &:after
439
+ content ''
440
+ @apply block absolute top-2 s('right-1.75') bottom-2 w-px bg-primary
441
+
442
+ .inputs
443
+ @apply relative flex-grow flex items-center p-2 bg-white rounded-r border border-l-0 border-primary-light text-base text-gray-2
444
+
445
+ div
446
+ input
447
+ @apply w-full bg-transparent text-base text-gray-2 text-left placeholder-gray-4 s('focus:outline-none')
448
+
449
+ .date-range-split
450
+ @apply s('mx-0.5')
451
+
452
+ .icon
453
+ @apply absolute right-0 mr-2 text-danger-hover hidden
454
+
455
+ .input-info
456
+ @apply mt-1 text-xs text-gray-3
457
+
458
+ .invalid-feedback
459
+ @apply hidden text-danger text-xs
460
+ </style>