init component

This commit is contained in:
Robin COuret
2026-02-16 17:28:37 +01:00
parent 460c7a25e0
commit e0e50af706
4557 changed files with 666911 additions and 8 deletions

View File

@@ -0,0 +1,541 @@
import "../../../../src/components/pagination/pagination.sass";
import "../../../../src/components/dropdown/dropdown.sass";
import "../../../../src/components/form/datepicker/datepicker.sass";
import { useDisable, UseDisablePropsDefinition } from '../../../composables/disable';
import { useEqRef } from '../../../composables/eqRef';
import { useFieldData } from '../../../composables/fieldData';
import { getUseInputPropsDefinition } from '../../../composables/input/useInput';
import { useProxy } from '../../../composables/proxy/useProxy';
import { DEFAULT_DAY_NAMES, DEFAULT_MONTH_NAMES } from './shared';
import { addDays, eqSerialDate, isDate } from './utils';
import { BInput } from '../input/BInput';
import { isArrowDownEvent, isArrowLeftEvent, isArrowRightEvent, isArrowUpEvent, isEnterEvent, isEscEvent, isSpaceEvent } from '../../../utils/eventHelpers';
import { head, isNonEmpty, range } from 'fp-ts/lib/Array';
import { constant } from 'fp-ts/lib/function';
import { alt, chain, fromNullable, getEq, isNone, isSome, some } from 'fp-ts/lib/Option';
import { pipe } from 'fp-ts/lib/pipeable';
import BDropdown, { BDropdownPropsDefinition } from '../../dropdown/BDropdown';
import BDatepickerTable from './BDatepickerTable';
import BField from '../field/BField';
import { BSelect } from '../select/BSelect';
import { computed, onUnmounted, onMounted, defineAsyncComponent, defineComponent, h, shallowRef, watch, toRef } from 'vue';
import { constEmptyArray, isString, toggleListItem } from '../../../utils/helpers';
const DEFAULT_DATEPICKER_ICONS = {
previous: defineAsyncComponent(() => import('../../icons/angleLeft')),
next: defineAsyncComponent(() => import('../../icons/angleRight')),
calendar: defineAsyncComponent(() => import('../../icons/calendar'))
};
export function getDatepickerIcons(icons) {
return { ...DEFAULT_DATEPICKER_ICONS,
...icons
};
}
const BDatepickerPropsDefinition = { ...BDropdownPropsDefinition,
...UseDisablePropsDefinition,
...getUseInputPropsDefinition(),
modelValue: {
type: [Array, Date]
},
'onUpdate:modelValue': {
type: Function,
required: true
},
year: {
type: Number,
default: new Date().getFullYear()
},
'onUpdate:year': {
type: Function,
required: false
},
month: {
type: Number,
default: new Date().getMonth()
},
'onUpdate:month': {
type: Function,
required: false
},
dayNames: {
type: Array,
default: constant(DEFAULT_DAY_NAMES)
},
monthNames: {
type: Array,
default: constant(DEFAULT_MONTH_NAMES)
},
firstDayOfWeek: {
type: Number,
default: 0
},
events: {
type: Array,
default: constEmptyArray
},
minDate: {
type: Date,
required: false
},
maxDate: {
type: Date,
required: false
},
isDisabled: {
type: Boolean,
default: false
},
unselectableDates: {
type: Array,
default: constEmptyArray
},
unselectableDaysOfWeek: {
type: Array,
default: constEmptyArray
},
selectableDates: {
type: Object
},
showWeekNumber: {
type: Boolean,
default: false
},
isMultiple: {
type: Boolean,
default: false
},
placeholder: {
type: String
},
useMobileNative: {
type: Boolean,
default: false
},
position: {
type: String
},
indicators: {
type: String,
default: 'bars'
},
yearsRange: {
type: Array,
default: constant([-5, 3])
},
closeOnSelect: {
type: Boolean,
default: true
},
isReadonly: {
type: Boolean,
default: true
},
useNativeValidation: {
type: Boolean,
default: false
},
// openOnFocus: {
// type: Boolean as PropType<boolean>,
// default: true
// },
icons: {
type: Object,
default: constant(DEFAULT_DATEPICKER_ICONS)
}
};
function useNative(props) {
return props.useMobileNative && !props.isInline;
}
const useFormattedDate = Intl.DateTimeFormat('default', {
year: 'numeric',
month: 'numeric',
day: 'numeric'
}).format;
function useFormattedModelValue(modelValue) {
return Array.isArray(modelValue) ? modelValue.map(useFormattedDate).join(', ') : modelValue ? useFormattedDate(modelValue) : null;
}
function parseInputString(str) {
const splits = str.split(',').map(s => s.trim());
return splits.map(s => new Date(s)).filter(d => isDate(d) && !isNaN(d.getTime()));
}
function generateInput(props, context, data) {
const isMobile = useNative(props);
return h(BInput, {
max: props.maxDate ? useFormattedDate(props.maxDate) : null,
min: props.minDate ? useFormattedDate(props.minDate) : null,
autocomplete: 'off',
type: isMobile ? 'date' : 'text',
modelValue: useFormattedModelValue(data.modelValue.value),
'onUpdate:modelValue': val => {
data.modelValue.value = parseInputString(val);
},
placeholder: props.placeholder,
size: props.size,
icon: props.icons.calendar,
isRounded: props.isRounded,
isDisabled: props.isDisabled,
isReadonly: props.isReadonly,
isLoading: props.isLoading,
useNativeValidation: props.useNativeValidation // onFocus: () => {
// if (!isMobile && props.openOnFocus && toggle) {
// if (toggle.isOff.value) {
// console.log('focus-set-on')
// toggle.setOn();
// Date.now()
// }
// }
// }
});
}
function generateButton(props, data, isNext) {
return h('button', {
class: isNext ? 'pagination-next datepicker-next' : 'pagination-previous datepicker-previous',
disabled: data.isDisabled,
onClick: isNext ? data.nextMonth : data.previousMonth,
onKeydown: e => {
if (isEnterEvent(e) || isSpaceEvent(e)) {
e.preventDefault();
isNext ? data.nextMonth() : data.previousMonth();
}
}
}, [h(isNext ? props.icons.next : props.icons.previous, {
variant: 'is-link',
isThemeable: false
})]);
}
function generateYearSelect(props, data) {
return h(BSelect, {
items: data.years,
modelValue: data.year.value,
isDisabled: data.isDisabled,
size: props.size,
'onUpdate:modelValue': data.setYear
});
}
function generateMonthSelect(props, data) {
return h(BSelect, {
items: data.months,
isDisabled: data.isDisabled,
size: props.size,
modelValue: data.month.value,
'onUpdate:modelValue': data.setMonth
});
}
function generateSelects(props, data) {
return h('div', {
class: 'pagination-list'
}, [h(BField, {
class: 'is-marginless'
}, () => [generateMonthSelect(props, data), generateYearSelect(props, data)])]);
}
function generateDefaultHeaderContents(props, data) {
return h('div', {
class: ['pagination field is-centered', props.size]
}, [generateButton(props, data, false), generateSelects(props, data), generateButton(props, data, true)]);
}
function generateHeader(props, context, data) {
return h('header', {
class: 'datepicker-header'
}, context.slots.header ? context.slots.header(data) : [generateDefaultHeaderContents(props, data)]);
}
function generateDatepickerTable(props, context, data) {
return h(BDatepickerTable, {
modelValue: data.modelValue.value,
'onUpdate:modelValue': val => {
data.modelValue.value = val;
},
focusedDate: data.focusedDate.value,
'onUpdate:focusedDate': val => {
data.focusedDate.value = val;
},
dayNames: props.dayNames,
monthNames: props.monthNames,
firstDayOfWeek: props.firstDayOfWeek,
minDate: props.minDate,
maxDate: props.maxDate,
month: data.month.value,
year: data.year.value,
isDisabled: data.isDisabled,
unselectableDates: props.unselectableDates,
unselectableDaysOfWeek: props.unselectableDaysOfWeek,
selectableDates: props.selectableDates,
events: props.events,
indicators: props.indicators,
showWeekNumber: props.showWeekNumber
});
}
function generateFooter(context) {
return h('footer', {
class: 'datepicker-footer'
}, context.slots.footer && context.slots.footer());
}
function generateCalendar(props, context, data) {
return h('section', {
class: 'datepicker-content',
'aria-label': 'Datepicker calendar'
}, [generateDatepickerTable(props, context, data)]);
}
function generateDatepickerBody(props, context, data) {
const nodes = [generateHeader(props, context, data), generateCalendar(props, context, data)];
if (context.slots.footer) {
nodes.push(generateFooter(context));
}
return h('div', nodes);
}
function generateDropdown(props, context, data, dropdown) {
return h(BDropdown, {
ref: dropdown,
position: props.position,
isDisabled: props.isDisabled,
isInline: props.isInline
}, {
trigger: () => {
return generateInput(props, context, data);
},
default: () => generateDatepickerBody(props, context, data)
});
}
function getMonths(props, focusedMonth) {
return props.monthNames.map((month, index) => ({
value: index,
text: month,
isDisabled: false,
isSelected: focusedMonth === index
}));
}
function getYears(props, focusedYear) {
const currentYear = new Date().getFullYear();
return range(props.yearsRange[0], props.yearsRange[1]).map(inc => currentYear + inc).map(year => ({
value: year,
text: year.toString(),
isDisabled: false,
isSelected: focusedYear === year
}));
}
function getSetPreviousMonth(props, month, year) {
return e => {
if (e) {
e.preventDefault();
}
if (!props.isDisabled) {
if (month.value > 0) {
month.value = month.value - 1;
} else {
month.value = 11;
year.value = year.value - 1;
}
}
};
}
function getSetNextMonth(props, month, year) {
return e => {
if (e) {
e.preventDefault();
}
if (!props.isDisabled) {
const mv = month.value;
if (mv < 11) {
month.value = mv + 1;
} else {
month.value = 0;
year.value = year.value + 1;
}
}
};
}
function getSetMonth(monthRef) {
return month => {
if (isString(month)) {
const newVal = fromNullable(parseInt(month, 10));
if (isSome(newVal)) {
monthRef.value = newVal.value;
}
} else {
monthRef.value = month;
}
};
}
function getSetYear(yearRef) {
return year => {
if (isString(year)) {
const newVal = fromNullable(parseInt(year, 10));
if (isSome(newVal)) {
yearRef.value = newVal.value;
}
} else {
yearRef.value = year;
}
};
}
const toggleSerialDate = toggleListItem(eqSerialDate);
export default defineComponent({
name: 'b-datepicker',
props: BDatepickerPropsDefinition,
setup(props, context) {
const fieldData = useFieldData();
const isDisabled = useDisable(props);
const dropdown = shallowRef(null);
const internalValue = shallowRef(props.modelValue);
watch(() => props.modelValue, newVal => {
internalValue.value = newVal;
});
const modelValue = computed({
get() {
return internalValue.value;
},
set(val) {
if (!val) {
return;
}
if (Array.isArray(val) && props.isMultiple || isDate(val)) {
props['onUpdate:modelValue'](val);
internalValue.value = val;
} else if (props.isMultiple && isDate(val)) {
const newVal = toggleSerialDate(val, internalValue.value == undefined ? [] : Array.isArray(internalValue.value) ? internalValue.value : [internalValue.value]);
props['onUpdate:modelValue'](newVal);
internalValue.value = newVal;
} else if (Array.isArray(val) && isNonEmpty(val)) {
props['onUpdate:modelValue'](val[0]);
internalValue.value = val[0];
}
if (props.closeOnSelect) {
dropdown.value && dropdown.value.toggle.setOff();
}
}
});
const focusedDate = useEqRef(getEq(eqSerialDate))(pipe(fromNullable(props.modelValue), chain(v => Array.isArray(v) ? head(v) : some(v)), alt(() => some(new Date()))));
const {
value: month
} = useProxy(toRef(props, 'month'), toRef(props, 'onUpdate:month'));
const {
value: year
} = useProxy(toRef(props, 'year'), toRef(props, 'onUpdate:year'));
const nextMonth = getSetNextMonth(props, month, year);
const previousMonth = getSetPreviousMonth(props, month, year);
const setMonth = getSetMonth(month);
const setYear = getSetYear(year);
function onKeydown(e) {
if (dropdown.value === undefined || dropdown.value?.$el === undefined || !dropdown.value.$el.contains(e.target)) {
return;
}
if (isEscEvent(e)) {
dropdown.value && dropdown.value.toggle.setOff();
return;
}
const fd = pipe(focusedDate.value, alt(() => pipe(fromNullable(modelValue.value), chain(v => Array.isArray(v) ? head(v) : some(v)))));
if (isNone(fd)) {
return;
}
if (isEnterEvent(e) || isSpaceEvent(e)) {
e.preventDefault();
modelValue.value = fd.value;
} else if (isArrowUpEvent(e)) {
e.preventDefault();
focusedDate.value = some(addDays(fd.value, -7));
} else if (isArrowRightEvent(e)) {
e.preventDefault();
focusedDate.value = some(addDays(fd.value, 1));
} else if (isArrowDownEvent(e)) {
e.preventDefault();
focusedDate.value = some(addDays(fd.value, 7));
} else if (isArrowLeftEvent(e)) {
e.preventDefault();
focusedDate.value = some(addDays(fd.value, -1));
}
}
onMounted(() => {
if (typeof window !== 'undefined') {
document.addEventListener('keyup', onKeydown);
}
});
onUnmounted(() => {
if (typeof window !== 'undefined') {
document.removeEventListener('keyup', onKeydown);
}
});
watch(focusedDate, fd => {
const m = month.value;
const y = year.value;
if (isSome(fd)) {
const fdValue = fd.value;
const nMonth = fdValue.getMonth();
if (nMonth !== m) {
month.value = nMonth;
}
const nYear = fdValue.getFullYear();
if (nYear !== y) {
year.value = nYear;
}
}
}, {
immediate: true
});
return () => {
const data = {
modelValue,
month,
year,
isDisabled: isDisabled.value,
focusedDate: focusedDate,
nextMonth,
previousMonth,
setMonth,
setYear,
months: getMonths(props, month.value),
years: getYears(props, year.value)
};
return h('article', {
class: ['b-datepicker control', props.size, {
'is-expanded': props.isExpanded || fieldData.attrs.isExpanded.value
}]
}, [useNative(props) ? generateInput(props, context, data) : generateDropdown(props, context, data, dropdown)]);
};
}
});
//# sourceMappingURL=BDatepicker.js.map