<div class="flex flex-col w-full gap-y-1">
<div x-data="initDatePicker()" class="input-wrapper flex flex-col relative w-full ">
<input type="text" x-model="value" @click="showDatepicker = !showDatepicker" @keydown="onInputKeydown($event)" @paste="$event.preventDefault()" autocomplete="off" class="form-input w-full peer
" placeholder="">
<div class="input-svg calendar">
<div type="button" @click="showDatepicker = true">
<svg class=" shrink-0" width="16" height="16" stroke="currentColor" stroke-width="1.5" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path d="M6.75 3v2.25M17.25 3v2.25M3 18.75V7.5a2.25 2.25 0 0 1 2.25-2.25h13.5A2.25 2.25 0 0 1 21 7.5v11.25m-18 0A2.25 2.25 0 0 0 5.25 21h13.5A2.25 2.25 0 0 0 21 18.75m-18 0v-7.5A2.25 2.25 0 0 1 5.25 9h13.5A2.25 2.25 0 0 1 21 11.25v7.5m-9-6h.008v.008H12v-.008ZM12 15h.008v.008H12V15Zm0 2.25h.008v.008H12v-.008ZM9.75 15h.008v.008H9.75V15Zm0 2.25h.008v.008H9.75v-.008ZM7.5 15h.008v.008H7.5V15Zm0 2.25h.008v.008H7.5v-.008Zm6.75-4.5h.008v.008h-.008v-.008Zm0 2.25h.008v.008h-.008V15Zm0 2.25h.008v.008h-.008v-.008Zm2.25-4.5h.008v.008H16.5v-.008Zm0 2.25h.008v.008H16.5V15Z" stroke="currentColor" stroke-width="1.5" fill="none" />
</svg>
</div>
</div>
<div class="absolute left-0 top-full p-3 bg-white rounded-lg shadow calendar-window z-30" x-cloak x-transition x-show="showDatepicker" @click.outside="showDatepicker = false" @keydown="onCalendarKeydown($event)">
<div class="flex justify-between items-center mb-2">
<div>
<select name="datepicker_month" x-model="month" class="text-sm rounded border-gray-300" @change="goToMonth(month)">
<template x-for="(monthName, index) in labels.monthNames">
<option :value="index" x-text="monthName"></option>
</template>
</select>
<select name="datepicker_year" x-model="year" class="text-sm rounded border-gray-300" @change="recalcDaysGrid()">
<template x-for="option in yearRange">
<option :value="option" x-text="option"></option>
</template>
</select>
</div>
<div class="min-w-16">
<button type="button" class="inline-flex p-1 rounded transition-colors cursor-pointer hover:bg-gray-100" :class="{'cursor-not-allowed opacity-25': isFirstMonth()}" :disabled="isFirstMonth()" :title="labels.prevText" @click="goToMonth(month - 1)">
<svg class=" shrink-0" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.7803 5.22431C12.0732 5.5172 12.0732 5.99208 11.7803 6.28497L8.06066 10.0046L11.7803 13.7243C12.0732 14.0172 12.0732 14.4921 11.7803 14.785C11.4874 15.0779 11.0126 15.0779 10.7197 14.785L6.46967 10.535C6.17678 10.2421 6.17678 9.7672 6.46967 9.47431L10.7197 5.22431C11.0126 4.93142 11.4874 4.93142 11.7803 5.22431Z" fill="currentColor" />
</svg> <span class="sr-only" x-text="labels.prevText"></span>
</button>
<button type="button" class="inline-flex p-1 rounded transition-colors cursor-pointer hover:bg-gray-100" :class="{'cursor-not-allowed opacity-25': isLastMonth() }" :disabled="isLastMonth()" :title="labels.nextText" @click="goToMonth(month + 1)">
<svg class=" shrink-0" width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">
<path fill-rule="evenodd" clip-rule="evenodd" d="M8.21967 5.21967C8.51256 4.92678 8.98744 4.92678 9.28033 5.21967L13.5303 9.46967C13.8232 9.76256 13.8232 10.2374 13.5303 10.5303L9.28033 14.7803C8.98744 15.0732 8.51256 15.0732 8.21967 14.7803C7.92678 14.4874 7.92678 14.0126 8.21967 13.7197L11.9393 10L8.21967 6.28033C7.92678 5.98744 7.92678 5.51256 8.21967 5.21967Z" fill="currentColor" />
</svg> <span class="sr-only" x-text="labels.nextText"></span>
</button>
</div>
</div>
<div class="grid grid-cols-7 -mx-1">
<template x-for="(day, index) in labels.dayNamesShort" :key="index">
<div class="p-0.5">
<div x-text="day" class="text-gray-800 font-medium text-center text-xs h-6 flex items-centerjustify-center">
</div>
</div>
</template>
<template x-for="(date, dateIndex) in dayNumbers" :key="dateIndex">
<button type="button" class="p-1" :style="getDayStyle(date)" @click="if (canSelectDate(date)) { setDate(date) }">
<div x-text="date" class="text-center text-sm rounded-full transition-colors flex items-center justify-center h-8" :class="{
'cursor-pointer hover:bg-gray-100 hover:text-black': canSelectDate(date),
'bg-brand text-white': isToday(date),
'text-gray-500': isInFuture(date)
}"></div>
</button>
</template>
</div>
<button class="p-2 w-full text-sm text-center rounded border border-gray-300 hover:bg-gray-100" x-text="labels.currentText" @click.prevent="goToday()"></button>
</div>
</div>
</div>
<script>
// script from vendor/hyva-themes/magento2-default-theme/Magento_Customer/templates/widget/dob.phtml
function initDatePicker() {
const format = 'dd/MM/y';
const firstDayOfWeek = '1';
const labelsConfig = {
"closeText": "Termin\u00e9",
"prevText": "Pr\u00e9c",
"nextText": "Suivant",
"currentText": "Aujourd'hui",
"monthNames": ["janvier", "f\u00e9vrier", "mars", "avril", "mai", "juin", "juillet", "ao\u00fbt", "septembre", "octobre", "novembre", "d\u00e9cembre"],
"monthNamesShort": ["janv.", "f\u00e9vr.", "mars", "avr.", "mai", "juin", "juil.", "ao\u00fbt", "sept.", "oct.", "nov.", "d\u00e9c."],
"dayNames": ["dimanche", "lundi", "mardi", "mercredi", "jeudi", "vendredi", "samedi"],
"dayNamesShort": ["dim.", "lun.", "mar.", "mer.", "jeu.", "ven.", "sam."],
"dayNamesMin": ["di", "lu", "ma", "me", "je", "ve", "sa"]
};
return {
showDatepicker: false,
value: '',
month: '',
year: '',
today: new Date(),
dayNumbers: [],
yearRange: [],
labels: labelsConfig,
dateFormatter: DateFormatter(format),
calendarWindow: null,
init() {
const today = new Date();
this.initYearsRange();
this.correctWeeks();
this.$nextTick(() => {
this.month = today.getMonth();
this.year = today.getFullYear();
this.recalcDaysGrid();
this.calendarWindow = this.$root.querySelector('.calendar-window');
});
},
initYearsRange() {
const today = new Date();
const thisYear = today.getFullYear();
const minimalYear = thisYear - 120;
const range = [];
for (let year = thisYear; year >= minimalYear; year--) {
range.unshift(year);
}
this.yearRange = range;
},
correctWeeks() {
if (firstDayOfWeek > 0) {
this.labels.dayNames = [
...this.labels.dayNames.slice(firstDayOfWeek),
...this.labels.dayNames.slice(0, firstDayOfWeek)
];
this.labels.dayNamesShort = [
...this.labels.dayNamesShort.slice(firstDayOfWeek),
...this.labels.dayNamesShort.slice(0, firstDayOfWeek)
];
}
},
isToday(date) {
const today = new Date();
const d = new Date(this.year, this.month, date);
return today.toDateString() === d.toDateString();
},
setDate(date) {
const selectedDate = new Date(this.year, this.month, date);
this.value = this.dateFormatter.format(selectedDate);
this.showDatepicker = false;
},
recalcDaysGrid() {
const daysInMonth = new Date(this.year, this.month + 1, 0).getDate();
const dayNumbers = [];
for (let i = 1; i <= daysInMonth; i++) {
dayNumbers.push(i);
}
this.dayNumbers = dayNumbers;
},
getDayStyle(day) {
const firstDayInWeek = this.correctDayOfWeek(new Date(this.year, this.month).getDay());
if (day.toString() === "1") {
return `grid-column-start: ${firstDayInWeek + 1}`;
}
return '';
},
correctDayOfWeek(day) {
let corrected = day - firstDayOfWeek;
if (corrected < 0) {
corrected += 7;
}
return corrected;
},
goToMonth(month) {
const date = new Date(this.year, this.month);
date.setMonth(month);
this.month = date.getMonth();
this.year = date.getFullYear();
this.recalcDaysGrid();
},
goToday() {
this.year = this.today.getFullYear();
this.month = this.today.getMonth();
this.recalcDaysGrid();
},
isInFuture(date) {
const today = new Date();
return this.year === today.getFullYear() &&
this.month === today.getMonth() &&
date > today.getDate()
},
isFirstMonth() {
return this.year === this.yearRange[0] && this.month === 0;
},
isLastMonth() {
return this.year === this.yearRange[this.yearRange.length - 1] &&
this.month === this.today.getMonth()
},
canSelectDate(date) {
return !this.isToday(date) && !this.isInFuture(date)
},
onInputKeydown(evt) {
const keyCode = evt.code;
if (keyCode === "Escape") {
this.showDatepicker = false;
}
if (keyCode === "Tab") {
return;
}
if (keyCode === "Enter") {
evt.preventDefault();
this.showDatepicker = true;
hyva.trapFocus(this.calendarWindow);
}
if (keyCode !== "Enter") {
evt.preventDefault();
}
},
onCalendarKeydown(evt) {
const keyCode = evt.code;
if (keyCode === "Escape") {
hyva.releaseFocus(this.calendarWindow);
this.showDatepicker = false;
}
}
}
}
function DateFormatter(template) {
return {
template: template,
map: {
'd': {
day: 'numeric'
},
'dd': {
day: '2-digit'
},
'D': {
weekday: 'short'
},
'DD': {
weekday: 'long'
},
'E': {
weekday: 'short'
},
'EE': {
weekday: 'short'
},
'EEE': {
weekday: 'short'
},
'EEEE': {
weekday: 'long'
},
'M': {
month: '2-digit'
},
'MM': {
month: '2-digit'
},
'MMM': {
month: 'short'
},
'MMMM': {
month: 'long'
},
'm': {
month: 'numeric'
},
'mm': {
month: '2-digit'
},
'y': {
year: 'numeric'
},
'Y': {
year: 'numeric'
},
'yy': {
year: 'numeric'
},
'yyyy': {
year: 'numeric'
}
},
format(date) {
const parsedFormat = template.match(new RegExp(/([mM]+)|([dD]+)|([yY]+)/g));
const options = parsedFormat.reduce((accumulator, match) => {
if (this.map[match]) {
return {
...accumulator,
...this.map[match]
}
}
return accumulator;
}, {})
const dateData = Intl.DateTimeFormat('en-US', options).formatToParts(date);
return parsedFormat.reduce((result, valueTemplate) => {
const dateItem = dateData.find(item => item.type === Object.keys(this.map[valueTemplate])[0]);
if (dateItem) {
return result.replace(valueTemplate, dateItem.value);
}
return result;
}, this.template);
}
}
}
</script>
{% set floating_label_input_class = label_floating is defined and label_floating ?
'peer-focus:block peer-placeholder-shown:hidden' : 'hidden' %}
<div class="flex flex-col w-full gap-y-1">
<div x-data="initDatePicker()" class="input-wrapper flex flex-col relative w-full {{ color is defined ? color : '' }} {{ label_floating is defined and label_floating ? 'floating-label' : '' }}">
<input type="text"
x-model="value"
@click="showDatepicker = !showDatepicker"
@keydown="onInputKeydown($event)"
@paste="$event.preventDefault()"
autocomplete="off"
class="form-input w-full peer
{{ required is defined and required ? 'required' }}"
placeholder=""
{{ name is defined and name ? 'name="' ~ name ~ '"' }}
{{ id is defined and id ? 'id="' ~ id ~ '"' }}
{{ required is defined and required ? 'required' }}
{{ input_attribute }}
>
<div class="input-svg calendar">
<div type="button" @click="showDatepicker = true">
{% render "@icons-heroicons--calendar-days-outline" with {
width: 16,
height: 16,
} %}
</div>
</div>
{% if label is defined and label %}
<div class="label-wrapper {{ not label_floating ? '-order-1 mb-2' : '' }}">
<label {{ id is defined and id ? 'for="' ~ id ~ '"' }}
class="flex flex-row items-center gap-2"
>
{% if label_icon_left is defined and label_icon_left.name %}
<div class="left-svg">
{% render "@icons-" ~ label_icon_left.name with {
width: 16,
height: 16,
} %}
</div>
{% endif %}
<span class="flex-grow">{{ label }}</span>
{% if required is defined and required %}
<div class="required text-error">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none">
<path d="M8.48605 7.23022L8.81938 7.03777L11.8608 5.28179C12.0734 5.15906 12.3452 5.23189 12.468 5.44446C12.5907 5.65704 12.5179 5.92886 12.3053 6.05159L9.26383 7.80757L8.9305 8.00002L9.26383 8.19247L12.3053 9.94845C12.5179 10.0712 12.5907 10.343 12.468 10.5556C12.3452 10.7681 12.0734 10.841 11.8608 10.7183L8.81938 8.96226L8.48605 8.76981V9.15471V12.6667C8.48605 12.9121 8.28706 13.1111 8.0416 13.1111C7.79614 13.1111 7.59716 12.9121 7.59716 12.6667V9.15472V8.76982L7.26382 8.96227L4.22237 10.7183L4.32568 10.8972L4.22237 10.7183C4.0098 10.841 3.73798 10.7681 3.61525 10.5556C3.49252 10.343 3.56536 10.0712 3.77793 9.94845L6.81938 8.19247L7.15272 8.00002L6.81938 7.80757L3.77794 6.05159L3.66964 6.23916L3.77794 6.05159C3.56536 5.92886 3.49253 5.65704 3.61526 5.44446C3.73799 5.23189 4.0098 5.15906 4.22238 5.28179L7.26382 7.03776L7.59716 7.23021V6.84531V3.33335C7.59716 3.08789 7.79614 2.88891 8.0416 2.88891C8.28706 2.88891 8.48605 3.08789 8.48605 3.33335V6.84532V7.23022Z"
fill="currentColor" stroke="currentColor" stroke-width="0.444444"/>
</svg>
</div>
{% endif %}
</label>
</div>
{% endif %}
<div class="absolute left-0 top-full p-3 bg-white rounded-lg shadow calendar-window z-30"
x-cloak
x-transition x-show="showDatepicker"
@click.outside="showDatepicker = false"
@keydown="onCalendarKeydown($event)"
>
<div class="flex justify-between items-center mb-2">
<div>
<select name="datepicker_month"
x-model="month"
class="text-sm rounded border-gray-300"
@change="goToMonth(month)"
>
<template x-for="(monthName, index) in labels.monthNames">
<option :value="index" x-text="monthName"></option>
</template>
</select>
<select name="datepicker_year"
x-model="year"
class="text-sm rounded border-gray-300"
@change="recalcDaysGrid()"
>
<template x-for="option in yearRange">
<option :value="option" x-text="option"></option>
</template>
</select>
</div>
<div class="min-w-16">
<button type="button"
class="inline-flex p-1 rounded transition-colors cursor-pointer hover:bg-gray-100"
:class="{'cursor-not-allowed opacity-25': isFirstMonth()}"
:disabled="isFirstMonth()"
:title="labels.prevText"
@click="goToMonth(month - 1)">
{% render "@icons-heroicons--chevron-left-mini" %}
<span class="sr-only" x-text="labels.prevText"></span>
</button>
<button
type="button"
class="inline-flex p-1 rounded transition-colors cursor-pointer hover:bg-gray-100"
:class="{'cursor-not-allowed opacity-25': isLastMonth() }"
:disabled="isLastMonth()"
:title="labels.nextText"
@click="goToMonth(month + 1)">
{% render "@icons-heroicons--chevron-right-mini" %}
<span class="sr-only" x-text="labels.nextText"></span>
</button>
</div>
</div>
<div class="grid grid-cols-7 -mx-1">
<template x-for="(day, index) in labels.dayNamesShort" :key="index">
<div class="p-0.5">
<div x-text="day"
class="text-gray-800 font-medium text-center text-xs h-6 flex items-centerjustify-center">
</div>
</div>
</template>
<template x-for="(date, dateIndex) in dayNumbers" :key="dateIndex">
<button type="button" class="p-1"
:style="getDayStyle(date)"
@click="if (canSelectDate(date)) { setDate(date) }"
>
<div x-text="date"
class="text-center text-sm rounded-full transition-colors flex items-center justify-center h-8"
:class="{
'cursor-pointer hover:bg-gray-100 hover:text-black': canSelectDate(date),
'bg-brand text-white': isToday(date),
'text-gray-500': isInFuture(date)
}"
></div>
</button>
</template>
</div>
<button class="p-2 w-full text-sm text-center rounded border border-gray-300 hover:bg-gray-100"
x-text="labels.currentText"
@click.prevent="goToday()"
></button>
</div>
</div>
{% if withHelper is defined and withHelper %}
{% render "@helper" %}
{% endif %}
</div>
<script>
// script from vendor/hyva-themes/magento2-default-theme/Magento_Customer/templates/widget/dob.phtml
function initDatePicker() {
const format = 'dd/MM/y';
const firstDayOfWeek = '1';
const labelsConfig = {"closeText":"Termin\u00e9","prevText":"Pr\u00e9c","nextText":"Suivant","currentText":"Aujourd'hui","monthNames":["janvier","f\u00e9vrier","mars","avril","mai","juin","juillet","ao\u00fbt","septembre","octobre","novembre","d\u00e9cembre"],"monthNamesShort":["janv.","f\u00e9vr.","mars","avr.","mai","juin","juil.","ao\u00fbt","sept.","oct.","nov.","d\u00e9c."],"dayNames":["dimanche","lundi","mardi","mercredi","jeudi","vendredi","samedi"],"dayNamesShort":["dim.","lun.","mar.","mer.","jeu.","ven.","sam."],"dayNamesMin":["di","lu","ma","me","je","ve","sa"]};
return {
showDatepicker: false,
value: '',
month: '',
year: '',
today: new Date(),
dayNumbers: [],
yearRange: [],
labels: labelsConfig,
dateFormatter: DateFormatter(format),
calendarWindow: null,
init() {
const today = new Date();
this.initYearsRange();
this.correctWeeks();
this.$nextTick(() => {
this.month = today.getMonth();
this.year = today.getFullYear();
this.recalcDaysGrid();
this.calendarWindow = this.$root.querySelector('.calendar-window');
});
},
initYearsRange() {
const today = new Date();
const thisYear = today.getFullYear();
const minimalYear = thisYear - 120;
const range = [];
for (let year = thisYear; year >= minimalYear; year--) {
range.unshift(year);
}
this.yearRange = range;
},
correctWeeks() {
if (firstDayOfWeek > 0) {
this.labels.dayNames = [
...this.labels.dayNames.slice(firstDayOfWeek),
...this.labels.dayNames.slice(0, firstDayOfWeek)
];
this.labels.dayNamesShort = [
...this.labels.dayNamesShort.slice(firstDayOfWeek),
...this.labels.dayNamesShort.slice(0, firstDayOfWeek)
];
}
},
isToday(date) {
const today = new Date();
const d = new Date(this.year, this.month, date);
return today.toDateString() === d.toDateString();
},
setDate(date) {
const selectedDate = new Date(this.year, this.month, date);
this.value = this.dateFormatter.format(selectedDate);
this.showDatepicker = false;
},
recalcDaysGrid() {
const daysInMonth = new Date(this.year, this.month + 1, 0).getDate();
const dayNumbers = [];
for (let i = 1; i <= daysInMonth; i++) {
dayNumbers.push(i);
}
this.dayNumbers = dayNumbers;
},
getDayStyle(day) {
const firstDayInWeek = this.correctDayOfWeek(new Date(this.year, this.month).getDay());
if (day.toString() === "1") {
return `grid-column-start: ${firstDayInWeek + 1}`;
}
return '';
},
correctDayOfWeek(day) {
let corrected = day - firstDayOfWeek;
if (corrected < 0) {
corrected += 7;
}
return corrected;
},
goToMonth(month) {
const date = new Date(this.year, this.month);
date.setMonth(month);
this.month = date.getMonth();
this.year = date.getFullYear();
this.recalcDaysGrid();
},
goToday() {
this.year = this.today.getFullYear();
this.month = this.today.getMonth();
this.recalcDaysGrid();
},
isInFuture(date) {
const today = new Date();
return this.year === today.getFullYear() &&
this.month === today.getMonth() &&
date > today.getDate()
},
isFirstMonth() {
return this.year === this.yearRange[0] && this.month === 0;
},
isLastMonth() {
return this.year === this.yearRange[this.yearRange.length - 1] &&
this.month === this.today.getMonth()
},
canSelectDate(date) {
return !this.isToday(date) && !this.isInFuture(date)
},
onInputKeydown(evt) {
const keyCode = evt.code;
if (keyCode === "Escape") {
this.showDatepicker = false;
}
if (keyCode === "Tab") {
return;
}
if (keyCode === "Enter") {
evt.preventDefault();
this.showDatepicker = true;
hyva.trapFocus(this.calendarWindow);
}
if (keyCode !== "Enter") {
evt.preventDefault();
}
},
onCalendarKeydown(evt) {
const keyCode = evt.code;
if (keyCode === "Escape") {
hyva.releaseFocus(this.calendarWindow);
this.showDatepicker = false;
}
}
}
}
function DateFormatter(template) {
return {
template: template,
map: {
'd' : { day: 'numeric' },
'dd': { day: '2-digit' },
'D' : { weekday: 'short' },
'DD': { weekday: 'long' },
'E' : { weekday: 'short' },
'EE' : { weekday: 'short' },
'EEE' : { weekday: 'short' },
'EEEE': { weekday: 'long' },
'M': { month: '2-digit' },
'MM': { month: '2-digit' },
'MMM' : { month: 'short' },
'MMMM': { month: 'long' },
'm' : { month : 'numeric'},
'mm': { month: '2-digit' },
'y': { year: 'numeric' },
'Y': { year: 'numeric' },
'yy': { year: 'numeric' },
'yyyy': { year: 'numeric' }
},
format(date) {
const parsedFormat = template.match(new RegExp(/([mM]+)|([dD]+)|([yY]+)/g));
const options = parsedFormat.reduce((accumulator, match) => {
if (this.map[match]) {
return {
...accumulator,
...this.map[match]
}
}
return accumulator;
}, {})
const dateData = Intl.DateTimeFormat('en-US', options).formatToParts(date);
return parsedFormat.reduce((result, valueTemplate) => {
const dateItem = dateData.find(item => item.type === Object.keys(this.map[valueTemplate])[0]);
if (dateItem) {
return result.replace(valueTemplate, dateItem.value);
}
return result;
}, this.template);
}
}
}
</script>
/* No context defined. */
No notes defined.