PluginProbe ʕ •ᴥ•ʔ
Booking for Appointments and Events Calendar – Amelia / 2.4.6
Booking for Appointments and Events Calendar – Amelia v2.4.6
2.4.7 2.4.6 2.4.5 2.4.4 2.4.3 2.4.2 2.4.1 2.4 trunk 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.15 1.2.16 1.2.17 1.2.18 1.2.19 1.2.2 1.2.20 1.2.21 1.2.22 1.2.23 1.2.24 1.2.25 1.2.26 1.2.27 1.2.28 1.2.29 1.2.3 1.2.30 1.2.31 1.2.32 1.2.33 1.2.34 1.2.35 1.2.36 1.2.37 1.2.38 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 2.0 2.0.1 2.0.2 2.1 2.1.1 2.1.2 2.1.3 2.2 2.2.1 2.3
ameliabooking / v3 / src / views / _components / datePicker / AmDatePicker.vue
ameliabooking / v3 / src / views / _components / datePicker Last commit date
AmDatePicker.vue 3 weeks ago
AmDatePicker.vue
1050 lines
1 <template>
2 <!-- Date Picker -->
3 <div class="am-date-picker__wrapper" :class="{ 'is-disabled': props.disabled }" :style="cssVars">
4 <div
5 class="am-date-picker__input"
6 :class="[`am-${props.type}`, { 'is-disabled': props.disabled }]"
7 aria-hidden="true"
8 @click="triggerCalendar"
9 >
10 <div v-if="props.type === 'date' && model" class="am-date-picker__input-date">
11 {{ getFrontedFormattedDate(moment(model).format('YYYY-MM-DD')) }}
12 </div>
13
14 <div v-if="props.type === 'daterange' && model[0]" class="am-date-picker__input-start">
15 {{ getFrontedFormattedDate(moment(model[0]).format('YYYY-MM-DD')) }}
16 </div>
17 <div v-if="props.type === 'daterange' && model[1]" class="am-date-picker__input-end">
18 {{ getFrontedFormattedDate(moment(model[1]).format('YYYY-MM-DD')) }}
19 </div>
20 </div>
21
22 <el-config-provider :locale="elementPlusTranslations(props.lang)">
23 <el-date-picker
24 :id="id"
25 ref="amDatePicker"
26 v-model="model"
27 :readonly="props.readonly"
28 :disabled="props.disabled"
29 :editable="props.editable"
30 :clearable="props.clearable"
31 :placeholder="props.placeholder"
32 :start-placeholder="props.startPlaceholder"
33 :end-placeholder="props.endPlaceholder"
34 :type="props.type"
35 :format="props.format"
36 :popper-class="datePickerPopperClass"
37 :popper-options="props.popperOptions"
38 :popper-style="cssVars"
39 :range-separator="props.rangeSeparator"
40 :default-value="props.defaultValue"
41 :default-time="props.defaultTime"
42 :value-format="props.valueFormat"
43 :unlink-panels="props.unlinkPanels"
44 :prefix-icon="props.prefixIcon"
45 :clear-icon="props.clearIcon"
46 :validate-event="props.validateEvent"
47 :disabled-date="disabledDate"
48 :shortcuts="props.shortcuts"
49 :cell-class-name="props.cellClassName"
50 :teleported="props.teleported"
51 :empty-values="props.emptyValues"
52 :value-on-clear="props.valueOnClear"
53 :fallback-placements="props.fallbackPlacements"
54 :placement="props.placement"
55 class="am-date-picker"
56 :aria-label="datePickerAriaLabel"
57 :class="[`am-date-picker--${size}`, { 'am-date-picker--disabled': props.disabled }]"
58 @keydown.capture="handleDatePickerKeydown"
59 @change="(eventValue) => $emit('change', eventValue)"
60 @blur="(e) => $emit('blur', e)"
61 @focus="(e) => $emit('focus', e)"
62 @clear="(e) => $emit('clear', e)"
63 @calendar-change="handleCalendarChange"
64 @panel-change="handlePanelChange"
65 @visible-change="handleVisibleChange"
66 >
67 </el-date-picker>
68 </el-config-provider>
69 </div>
70 <!-- /Date Picker -->
71 </template>
72
73 <script setup>
74 // * Import from Vue
75 import { computed, ref, toRefs, inject, markRaw, nextTick, onBeforeUnmount } from 'vue'
76
77 // * Libraries
78 import moment from 'moment'
79
80 // * Composables
81 import { useColorTransparency } from '../../../assets/js/common/colorManipulation'
82 import { elementPlusTranslations } from '../../../assets/js/common/translationsElementPlus'
83 import { getFrontedFormattedDate } from '../../../assets/js/common/date'
84 import IconComponent from '../icons/IconComponent.vue'
85
86 /**
87 * Component Props
88 */
89 const props = defineProps({
90 modelValue: {
91 type: [String, Array, Object, Number],
92 },
93 readonly: {
94 // * whether DatePicker is read only
95 type: Boolean,
96 default: false,
97 },
98 disabled: {
99 // * whether DatePicker is disabled
100 type: Boolean,
101 default: false,
102 },
103 size: {
104 // default / medium / small / mini / micro
105 type: String,
106 default: 'default',
107 validator(value) {
108 return ['default', 'medium', 'small', 'mini', 'micro'].includes(value)
109 },
110 },
111 editable: {
112 // * whether the input is editable
113 type: Boolean,
114 default: true,
115 },
116 clearable: {
117 // * whether the input is clearable and whether to show clear button
118 type: Boolean,
119 default: false,
120 },
121 placeholder: {
122 // * placeholder in non-range mode
123 type: String,
124 default: '',
125 },
126 startPlaceholder: {
127 // * placeholder in range mode
128 type: String,
129 },
130 endPlaceholder: {
131 // * placeholder in range mode
132 type: String,
133 },
134 type: {
135 // * type of the picker
136 type: String,
137 default: 'date',
138 validator(value) {
139 return [
140 'year',
141 'years',
142 'month',
143 'months',
144 'date',
145 'dates',
146 'datetime',
147 'week',
148 'datetimerange',
149 'daterange',
150 'monthrange',
151 'yearrange',
152 ].includes(value)
153 },
154 },
155 format: {
156 // * format of the displayed value in the input box
157 type: String,
158 },
159 popperClass: {
160 // * custom class name for DatePicker's dropdown
161 type: String,
162 default: '',
163 },
164 popperOptions: {
165 // * options for the popper.js instance
166 type: Object,
167 default: () => {},
168 },
169 rangeSeparator: {
170 // * separator between two date inputs in range mode
171 type: String,
172 default: '-',
173 },
174 defaultValue: {
175 // * optional, default date of the calendar
176 type: [String, Array, Object, Number],
177 },
178 defaultTime: {
179 // * optional, default time of the calendar
180 type: [String, Array, Object, Number],
181 },
182 valueFormat: {
183 // * optional, format of binding value. If not specified, the binding value will be a Date object
184 type: String,
185 },
186 id: {
187 // * same as id in native input
188 type: [String, Array],
189 },
190 name: {
191 // * same as name in native input
192 type: [String, Array],
193 },
194 unlinkPanels: {
195 // * whether to unlink the two panels in range mode
196 type: Boolean,
197 default: false,
198 },
199 prefixIcon: {
200 type: [String, Object, Function],
201 default: markRaw({
202 components: { IconComponent },
203 template: `<IconComponent icon="calendar"/>`,
204 }),
205 },
206 clearIcon: {
207 type: [String, Object, Function],
208 default: markRaw({
209 components: { IconComponent },
210 template: `<IconComponent icon="close"/>`,
211 }),
212 },
213 validateEvent: {
214 // * whether to trigger validation when the value changes
215 type: Boolean,
216 default: true,
217 },
218 disabledDate: {
219 // * a function determining if a date is disabled with that date as its parameter. Should return a Boolean
220 type: Function,
221 default: () => {},
222 },
223 shortcuts: {
224 // * an array of objects to set shortcut options
225 type: Array,
226 default: () => [],
227 },
228 cellClassName: {
229 // * a function determining the class name of a date cell with that date as its parameter. Should return a String
230 type: Function,
231 },
232 teleported: {
233 // * empty values of component
234 type: Boolean,
235 default: true,
236 },
237 emptyValues: {
238 // * whether to show empty values
239 type: [String, Array],
240 },
241 valueOnClear: {
242 // * clear return value
243 type: [String, Number, Boolean, Function],
244 default: '',
245 },
246 fallbackPlacements: {
247 // * list of possible positions for Tooltip, fallback placements for the popper.js instance
248 type: Array,
249 },
250 placement: {
251 // * position of the DatePicker's dropdown
252 type: String,
253 default: 'bottom',
254 validator(value) {
255 return [
256 'top',
257 'top-start',
258 'top-end',
259 'bottom',
260 'bottom-start',
261 'bottom-end',
262 'left',
263 'left-start',
264 'left-end',
265 'right',
266 'right-start',
267 'right-end',
268 ].includes(value)
269 },
270 },
271 lang: {
272 type: String,
273 default: '',
274 },
275 })
276
277 /**
278 * Component Emits
279 * */
280 const emits = defineEmits([
281 'update:modelValue',
282 'change',
283 'blur',
284 'focus',
285 'clear',
286 'calendar-change',
287 'panel-change',
288 'visible-change',
289 ])
290
291 /**
292 * Component model
293 */
294 let { modelValue } = toRefs(props)
295 let model = computed({
296 get: () => modelValue.value,
297 set: (val) => {
298 emits('update:modelValue', val)
299 },
300 })
301
302 /**
303 * Component reference
304 */
305 const amDatePicker = ref(null)
306 let accessibleDatePickerPanel = null
307
308 const accessibleDatePickerPopperClass = 'am-date-picker__popper'
309
310 let datePickerPopperClass = computed(() => {
311 return [props.popperClass, accessibleDatePickerPopperClass].filter(Boolean).join(' ')
312 })
313
314 let datePickerAriaLabel = computed(() => {
315 if (props.type === 'daterange') {
316 return (
317 [props.startPlaceholder, props.endPlaceholder].filter(Boolean).join(' - ') ||
318 props.placeholder ||
319 'Date range picker'
320 )
321 }
322
323 return props.placeholder || 'Date picker'
324 })
325
326 function triggerCalendar() {
327 if (amDatePicker.value) {
328 amDatePicker.value.focus()
329 amDatePicker.value.handleOpen()
330 }
331 }
332
333 function handleDatePickerKeydown(event) {
334 if (props.disabled || props.readonly) {
335 return
336 }
337
338 if (['Enter', ' ', 'ArrowDown'].includes(event.key)) {
339 event.preventDefault()
340 triggerCalendar()
341 }
342 }
343
344 function getDatePickerPanel() {
345 return document.querySelector(
346 `.${accessibleDatePickerPopperClass}:not([aria-hidden="true"]) .el-picker-panel`,
347 )
348 }
349
350 function isVisibleFocusableButton(button) {
351 return (
352 button instanceof HTMLButtonElement &&
353 !button.disabled &&
354 !button.classList.contains('is-disabled') &&
355 button.getClientRects().length > 0
356 )
357 }
358
359 function getMonthNavigationButtons() {
360 if (!accessibleDatePickerPanel) {
361 return []
362 }
363
364 return Array.from(
365 accessibleDatePickerPanel.querySelectorAll(
366 '.el-picker-panel__icon-btn.arrow-left, .el-picker-panel__icon-btn.arrow-right',
367 ),
368 ).filter(isVisibleFocusableButton)
369 }
370
371 function getPanelContentForElement(element) {
372 return (
373 element?.closest?.('.el-picker-panel__content') || element?.closest?.('.el-picker-panel__body')
374 )
375 }
376
377 function getAvailableDateCells() {
378 if (!accessibleDatePickerPanel) {
379 return []
380 }
381
382 return Array.from(
383 accessibleDatePickerPanel.querySelectorAll('td.available:not(.disabled)'),
384 ).filter((cell) => {
385 return cell instanceof HTMLElement && cell.getClientRects().length > 0
386 })
387 }
388
389 function getFocusedDateCellIndex(dateCells) {
390 const focusedCell = document.activeElement?.closest?.('td.available')
391
392 return dateCells.findIndex((cell) => cell === focusedCell)
393 }
394
395 function focusDateCell(dateCell) {
396 if (!dateCell) {
397 return
398 }
399
400 getAvailableDateCells().forEach((cell) => {
401 cell.setAttribute('tabindex', cell === dateCell ? '0' : '-1')
402 })
403
404 dateCell.focus()
405 }
406
407 function focusDateCellByOffset(offset) {
408 const dateCells = getAvailableDateCells()
409 const focusedIndex = getFocusedDateCellIndex(dateCells)
410 const nextIndex = Math.min(Math.max(focusedIndex + offset, 0), dateCells.length - 1)
411
412 focusDateCell(dateCells[nextIndex])
413 }
414
415 function focusDateCellByRowEdge(edge) {
416 const dateCells = getAvailableDateCells()
417 const focusedIndex = getFocusedDateCellIndex(dateCells)
418 const rowStartIndex = Math.floor(focusedIndex / 7) * 7
419 const nextIndex =
420 edge === 'start' ? rowStartIndex : Math.min(rowStartIndex + 6, dateCells.length - 1)
421
422 focusDateCell(dateCells[nextIndex])
423 }
424
425 function navigateMonth(direction) {
426 if (!accessibleDatePickerPanel) {
427 return
428 }
429
430 const arrowClass = direction === 'prev' ? 'arrow-left' : 'arrow-right'
431 const focusedContent = getPanelContentForElement(document.activeElement)
432 const focusedCell = document.activeElement?.closest?.('td.available')
433 const panelCells = focusedContent
434 ? getAvailableDateCells().filter((cell) => focusedContent.contains(cell))
435 : getAvailableDateCells()
436 const focusedIndex = focusedCell ? panelCells.indexOf(focusedCell) : -1
437 const focusedDay = focusedCell?.querySelector('.el-date-table-cell__text')?.textContent?.trim()
438 let button = focusedContent?.querySelector(`.el-picker-panel__icon-btn.${arrowClass}`)
439
440 if (!isVisibleFocusableButton(button)) {
441 if (focusedContent?.classList.contains('is-left')) {
442 button = accessibleDatePickerPanel.querySelector(
443 `.el-picker-panel__content.is-right .el-picker-panel__icon-btn.${arrowClass}`,
444 )
445 } else if (focusedContent?.classList.contains('is-right')) {
446 button = accessibleDatePickerPanel.querySelector(
447 `.el-picker-panel__content.is-left .el-picker-panel__icon-btn.${arrowClass}`,
448 )
449 } else {
450 button = accessibleDatePickerPanel.querySelector(`.el-picker-panel__icon-btn.${arrowClass}`)
451 }
452 }
453
454 if (!isVisibleFocusableButton(button)) {
455 return
456 }
457
458 button.click()
459 nextTick(() => {
460 setDateCellAccessibility()
461
462 const refreshedPanelCells = focusedContent
463 ? getAvailableDateCells().filter((cell) => focusedContent.contains(cell))
464 : getAvailableDateCells()
465
466 let replacementCell = focusedDay
467 ? refreshedPanelCells.find(
468 (cell) =>
469 cell.querySelector('.el-date-table-cell__text')?.textContent?.trim() === focusedDay,
470 )
471 : null
472
473 if (!replacementCell && focusedIndex >= 0) {
474 replacementCell = refreshedPanelCells[Math.min(focusedIndex, refreshedPanelCells.length - 1)]
475 }
476
477 if (!replacementCell) {
478 replacementCell =
479 refreshedPanelCells.find((cell) => cell.getAttribute('tabindex') === '0') ||
480 refreshedPanelCells[0]
481 }
482
483 focusDateCell(replacementCell)
484 })
485 }
486
487 function focusInitialPanelElement() {
488 const initialDateCell = getAvailableDateCells().find(
489 (cell) => cell.getAttribute('tabindex') === '0',
490 )
491
492 if (initialDateCell) {
493 focusDateCell(initialDateCell)
494 return
495 }
496
497 getMonthNavigationButtons()[0]?.focus()
498 }
499
500 function handleDateCellKeydown(event) {
501 if (event.key === 'Escape') {
502 event.preventDefault()
503 amDatePicker.value?.handleClose()
504 amDatePicker.value?.focus()
505 return
506 }
507
508 const focusedDateCell = event.target.closest?.('td.available')
509 if (!focusedDateCell) {
510 return
511 }
512
513 const keyActions = {
514 ArrowLeft: () => focusDateCellByOffset(-1),
515 ArrowRight: () => focusDateCellByOffset(1),
516 ArrowUp: () => focusDateCellByOffset(-7),
517 ArrowDown: () => focusDateCellByOffset(7),
518 Home: () => focusDateCellByRowEdge('start'),
519 End: () => focusDateCellByRowEdge('end'),
520 PageUp: () => navigateMonth('prev'),
521 PageDown: () => navigateMonth('next'),
522 }
523
524 if (event.key === 'Enter' || event.key === ' ') {
525 event.preventDefault()
526 focusedDateCell.click()
527 return
528 }
529
530 if (keyActions[event.key]) {
531 event.preventDefault()
532 keyActions[event.key]()
533 }
534 }
535
536 function setDateCellAccessibility() {
537 const dateCells = getAvailableDateCells()
538
539 dateCells.forEach((cell) => {
540 const isSelected =
541 cell.classList.contains('current') ||
542 cell.classList.contains('start-date') ||
543 cell.classList.contains('end-date')
544
545 cell.setAttribute('role', 'gridcell')
546 cell.setAttribute('aria-selected', isSelected ? 'true' : 'false')
547 cell.setAttribute('tabindex', isSelected ? '0' : '-1')
548 })
549
550 if (!dateCells.some((cell) => cell.getAttribute('tabindex') === '0')) {
551 dateCells[0]?.setAttribute('tabindex', '0')
552 }
553 }
554
555 function bindDatePickerPanelKeyboard() {
556 unbindDatePickerPanelKeyboard()
557
558 accessibleDatePickerPanel = getDatePickerPanel()
559
560 if (!accessibleDatePickerPanel) {
561 return false
562 }
563
564 setDateCellAccessibility()
565 accessibleDatePickerPanel.addEventListener('keydown', handleDateCellKeydown)
566 focusInitialPanelElement()
567
568 return true
569 }
570
571 function unbindDatePickerPanelKeyboard() {
572 accessibleDatePickerPanel?.removeEventListener('keydown', handleDateCellKeydown)
573 accessibleDatePickerPanel = null
574 }
575
576 function handleVisibleChange(visible) {
577 emits('visible-change', visible)
578
579 if (visible) {
580 nextTick(() => {
581 setTimeout(() => {
582 if (!bindDatePickerPanelKeyboard()) {
583 setTimeout(bindDatePickerPanelKeyboard, 50)
584 }
585 }, 0)
586 })
587 } else {
588 unbindDatePickerPanelKeyboard()
589 }
590 }
591
592 function handlePanelChange(value, mode, view) {
593 emits('panel-change', value, mode, view)
594
595 if (accessibleDatePickerPanel) {
596 nextTick(setDateCellAccessibility)
597 }
598 }
599
600 function handleCalendarChange(value) {
601 emits('calendar-change', value)
602
603 if (accessibleDatePickerPanel) {
604 nextTick(setDateCellAccessibility)
605 }
606 }
607
608 onBeforeUnmount(unbindDatePickerPanelKeyboard)
609
610 // * Colors block
611 let amColors = inject('amColors')
612
613 let cssVars = computed(() => {
614 return {
615 '--am-c-primary': amColors.value.colorPrimary,
616 '--am-c-inp-bgr': amColors.value.colorInpBgr,
617 '--am-c-inp-border': amColors.value.colorInpBorder,
618 '--am-c-inp-text': amColors.value.colorInpText,
619 '--am-c-inp-text-op03': useColorTransparency(amColors.value.colorInpText, 0.03),
620 '--am-c-inp-text-op05': useColorTransparency(amColors.value.colorInpText, 0.05),
621 '--am-c-inp-text-op40': useColorTransparency(amColors.value.colorInpText, 0.4),
622 '--am-c-inp-text-op60': useColorTransparency(amColors.value.colorInpText, 0.6),
623 '--am-c-inp-placeholder': amColors.value.colorInpPlaceHolder,
624 '--am-c-drop-bgr': amColors.value.colorDropBgr,
625 '--am-c-drop-text': amColors.value.colorDropText,
626 '--am-c-drop-text-op03': useColorTransparency(amColors.value.colorDropText, 0.03),
627 '--am-c-drop-text-op10': useColorTransparency(amColors.value.colorDropText, 0.1),
628 '--am-c-drop-text-op30': useColorTransparency(amColors.value.colorDropText, 0.3),
629 '--am-c-drop-text-op50': useColorTransparency(amColors.value.colorDropText, 0.5),
630 '--am-c-drop-text-op70': useColorTransparency(amColors.value.colorDropText, 0.7),
631 '--am-c-drop-text-op80': useColorTransparency(amColors.value.colorDropText, 0.8),
632 '--am-c-drop-border': amColors.value.colorDropBorder,
633 '--am-c-skeleton-op20': useColorTransparency(amColors.value.colorMainText, 0.2),
634 '--am-c-skeleton-op60': useColorTransparency(amColors.value.colorMainText, 0.6),
635 '--am-c-skeleton-sb-op20': useColorTransparency(amColors.value.colorSbText, 0.2),
636 '--am-c-skeleton-sb-op60': useColorTransparency(amColors.value.colorSbText, 0.6),
637 }
638 })
639 </script>
640
641 <style lang="scss">
642 @mixin am-datepicker-block {
643 // Date Picker
644 .am-date-picker {
645 &__wrapper {
646 --am-c-dpicker-bgr: var(--am-c-inp-bgr);
647 --am-c-dpicker-text: var(--am-c-inp-text);
648 --am-c-dpicker-border: var(--am-c-inp-border);
649 --am-c-dpicker-placeholder: var(--am-c-inp-placeholder);
650 --am-c-dpicker-shadow: var(--am-c-inp-text-op05);
651 --am-c-dpicker-rad: var(--am-c-inp-rad);
652 --am-fs-dpicker: var(--am-fs-inp);
653 --am-h-dpicker: 40px;
654 --am-padd-dpicker: 0 8px;
655
656 display: flex;
657 align-items: center;
658 position: relative;
659 width: 100%;
660 background-color: var(--am-c-dpicker-bgr);
661 border-radius: 4px;
662 border: none;
663 box-shadow: 0 2px 2px var(--am-c-dpicker-shadow);
664
665 &:hover:not(.is-disabled) {
666 --am-c-dpicker-border: var(--am-c-inp-text-op40);
667 }
668
669 &.is-disabled {
670 --am-c-dpicker-bgr: var(--am-c-inp-text-op03);
671 }
672 }
673
674 // size
675 &--default {
676 --am-h-dpicker: 40px;
677 }
678
679 &--medium {
680 --am-h-dpicker: 36px;
681 }
682
683 &--small {
684 --am-h-dpicker: 32px;
685 }
686
687 &--mini {
688 --am-h-dpicker: 28px;
689 }
690
691 &--micro {
692 --am-h-dpicker: 24px;
693 }
694
695 // Custom input display
696 &__input {
697 position: absolute;
698 top: 0;
699 height: 100%;
700 display: flex;
701 align-items: center;
702 justify-content: space-around;
703 cursor: text;
704 z-index: 1;
705
706 &.am-date {
707 left: 36px;
708 width: calc(100% - 36px);
709 }
710
711 &.am-daterange {
712 left: 32px;
713 width: calc(100% - 54px);
714 }
715
716 &.is-disabled {
717 --am-c-dpicker-text: var(--am-c-inp-text-op60);
718 cursor: not-allowed;
719 }
720
721 [class^='am-date-picker__input']^='am-date-picker__input'] {
722 height: 100%;
723 display: inline-flex;
724 align-items: center;
725 justify-content: center;
726 text-align: center;
727 color: var(--am-c-dpicker-text);
728 font-size: var(--am-fs-dpicker);
729 line-height: 24px;
730 background-color: transparent;
731 border-radius: 0;
732 }
733
734 .am-date-picker__input-date {
735 width: 100%;
736 text-align: left;
737 justify-content: flex-start;
738 }
739 }
740
741 // Date Editors
742 &.el-date-editor {
743 // Date Range Picker
744 &--daterange {
745 // Visual simulation of input display
746 &.el-input__wrapper {
747 width: 100%;
748 height: var(--am-h-dpicker);
749 background-color: transparent;
750 border: none;
751 box-shadow: 0 0 0 1px var(--am-c-dpicker-border);
752 padding: var(--am-padd-dpicker);
753 box-sizing: border-box;
754 transition: box-shadow 0.3s ease-in-out;
755 z-index: 2;
756
757 &:hover {
758 --am-c-dpicker-border: var(--am-c-inp-text-op40);
759 }
760
761 &.is-active:not(.is-disabled),
762 &.is-focus:not(.is-disabled) {
763 --am-c-dpicker-border: var(--am-c-primary);
764 }
765
766 &.is-disabled {
767 --am-c-dpicker-text: var(--am-c-inp-text-op60);
768 }
769 }
770
771 .el-range {
772 &-input {
773 color: transparent;
774 font-size: var(--am-fs-dpicker);
775 line-height: 24px;
776 border: none;
777 background: none;
778 border-radius: 0;
779 padding: 0;
780 margin: 0;
781 box-shadow: none;
782 }
783
784 &__icon {
785 color: var(--am-c-dpicker-text);
786 font-size: 24px;
787 line-height: 24px;
788 }
789
790 &-separator {
791 color: var(--am-c-dpicker-text);
792 font-size: var(--am-fs-dpicker);
793 line-height: 24px;
794 }
795 }
796 }
797
798 // Date Picker
799 &--date {
800 &.el-input {
801 width: 100%;
802 height: var(--am-h-dpicker);
803 background: none;
804 z-index: 2;
805
806 &--prefix {
807 --am-padd-dpicker: 0 12px 0 8px;
808 }
809
810 &--suffix {
811 --am-padd-dpicker: 0 8px 0 12px;
812 }
813
814 &--prefix,
815 &--suffix {
816 --am-padd-dpicker: 0 8px;
817 }
818
819 &.is-disabled {
820 .el-input__inner {
821 -webkit-text-fill-color: transparent;
822 }
823 }
824 }
825
826 .el-input {
827 &__wrapper {
828 width: 100%;
829 height: var(--am-h-dpicker);
830 gap: 0 4px;
831 background-color: transparent;
832 border: none;
833 box-shadow: 0 0 0 1px var(--am-c-dpicker-border);
834 padding: var(--am-padd-dpicker);
835 box-sizing: border-box;
836 transition: box-shadow 0.3s ease-in-out;
837
838 &.is-focus:not(.is-disabled),
839 &.is-active:not(.is-disabled) {
840 --am-c-dpicker-border: var(--am-c-primary);
841 }
842 }
843
844 &__inner {
845 color: transparent;
846 font-size: var(--am-fs-dpicker);
847 line-height: 24px;
848 border: none;
849 background: none;
850 border-radius: 0;
851 padding: 0;
852 margin: 0;
853 box-shadow: none;
854
855 // Placeholder
856 &::placeholder {
857 color: var(--am-c-dpicker-placeholder);
858 opacity: 1; /* Ensures it’s not transparent */
859 }
860 &::-webkit-input-placeholder {
861 /* Chrome, Safari */
862 color: var(--am-c-dpicker-placeholder);
863 }
864 &:-moz-placeholder {
865 /* Firefox 4-18 */
866 color: var(--am-c-dpicker-placeholder);
867 opacity: 1;
868 }
869 &::-moz-placeholder {
870 /* Firefox 19+ */
871 color: var(--am-c-dpicker-placeholder);
872 opacity: 1;
873 }
874 &:-ms-input-placeholder {
875 /* IE 10-11 */
876 color: var(--am-c-dpicker-placeholder);
877 }
878 }
879
880 &__prefix,
881 &__suffix {
882 font-size: 24px;
883 line-height: 1;
884 color: var(--am-c-dpicker-text);
885
886 * {
887 font-size: 24px;
888 line-height: 1;
889 color: var(--am-c-dpicker-text);
890 }
891
892 .am-icon-close {
893 font-size: 18px;
894 }
895 }
896 }
897 }
898 }
899 }
900 }
901
902 .el-picker-panel {
903 background-color: var(--am-c-drop-bgr);
904 color: var(--am-c-drop-text);
905 border: 1px solid var(--am-c-drop-border);
906
907 &__icon-btn {
908 color: var(--am-c-drop-text);
909
910 &:hover {
911 color: var(--am-c-btn-prim);
912 }
913
914 &:focus-visible {
915 outline: 2px solid var(--am-c-primary);
916 outline-offset: 2px;
917 border-radius: 4px;
918 }
919 }
920
921 &__content {
922 &.is-left {
923 border-right: 1px solid var(--am-c-drop-text-op10);
924 }
925 table,
926 table td,
927 table tr,
928 table tr:is(.el-date-table__row) {
929 border: none !important;
930 }
931 table tr:not(.el-date-table__row) th {
932 color: var(--am-c-drop-text-op70);
933 border: none !important;
934 border-bottom: 1px solid var(--am-c-drop-text-op10) !important;
935 }
936 table {
937 td.today .el-date-table-cell__text {
938 color: var(--am-c-drop-text);
939 }
940 td.current:not(.disabled) .el-date-table-cell__text {
941 background: var(--am-c-btn-prim);
942 }
943 td.available:hover > div > span {
944 background: var(--am-c-drop-text);
945 border-radius: 50%;
946 color: var(--am-c-drop-bgr);
947 }
948 td.available:focus {
949 outline: none;
950
951 .el-date-table-cell__text {
952 outline: 2px solid var(--am-c-primary);
953 outline-offset: 2px;
954 }
955 }
956 td.in-range > .el-date-table-cell {
957 background-color: var(--am-c-drop-text-op10);
958 }
959 td.in-range:hover > .el-date-table-cell {
960 background-color: var(--am-c-drop-text-op50);
961 }
962 td.end-date .el-date-table-cell__text,
963 td.start-date .el-date-table-cell__text {
964 color: var(--am-c-drop-bgr);
965 background-color: var(--am-c-drop-text-op80);
966 }
967 td.today.start-date .el-date-table-cell__text {
968 color: var(--am-c-drop-bgr);
969 }
970 td.prev-month,
971 td.next-month {
972 color: var(--am-c-drop-text-op30);
973 }
974
975 td.disabled .el-date-table-cell {
976 color: var(--am-c-drop-text-op30);
977 background-color: var(--am-c-drop-text-op03);
978 }
979 }
980 }
981
982 .d-arrow-left,
983 .d-arrow-right {
984 display: none;
985 }
986 }
987
988 .el-date-picker__header {
989 text-align: center;
990 margin: 12px;
991
992 .el-picker-panel__icon-btn {
993 padding: 0;
994 }
995
996 .el-date-picker {
997 padding: 0;
998 font-size: 12px;
999 color: #303133;
1000 cursor: pointer;
1001 margin-top: 8px;
1002 border-width: 0;
1003 border-style: initial;
1004 border-color: initial;
1005 border-image: initial;
1006 //background: transparent;
1007 outline: none;
1008
1009 &__prev-btn {
1010 float: left;
1011 }
1012
1013 &__next-btn {
1014 float: right;
1015 }
1016 &__prev-btn:focus,
1017 &__next-btn:focus {
1018 outline: 2px solid var(--am-c-primary);
1019 outline-offset: 2px;
1020 }
1021 }
1022 &-label:hover {
1023 color: var(--am-c-btn-prim);
1024 }
1025 }
1026
1027 .el-popper {
1028 &.el-picker__popper {
1029 &[data-popper-placement^='top']^='top'],
1030 &[data-popper-placement^='bottom']^='bottom'],
1031 &[data-popper-placement^='left']^='left'],
1032 &[data-popper-placement^='right']^='right'] {
1033 .el-popper__arrow {
1034 display: none;
1035 }
1036 }
1037 }
1038 }
1039
1040 // public
1041 .amelia-v2-booking #amelia-container {
1042 @include am-datepicker-block;
1043 }
1044
1045 // admin
1046 #amelia-app-backend-new #amelia-container {
1047 @include am-datepicker-block;
1048 }
1049 </style>
1050