diff --git a/index.d.ts b/index.d.ts index 1d21896..42f83ad 100644 --- a/index.d.ts +++ b/index.d.ts @@ -10,7 +10,8 @@ type EmitEvents = | 'open' | 'focus' | 'blur' - | 'internalModelChange'; + | 'internalModelChange' + | 'recalculatePosition'; interface Vue3DatePicker { uid?: string; @@ -156,7 +157,7 @@ interface Vue3DatePicker { noHoursOverlay?: boolean; noMinutesOverlay?: boolean; noSecondsOverlay?: boolean; - altPosition?: boolean; + altPosition?: boolean | ((el: HTMLElement | undefined) => { top: string; left: string; transform: string }); disabledWeekDays?: number[] | string[]; allowedDates?: string[] | Date[]; showNowButton?: boolean; diff --git a/src/Vue3DatePicker/Vue3DatePicker.vue b/src/Vue3DatePicker/Vue3DatePicker.vue index 8e3928f..9f7109d 100644 --- a/src/Vue3DatePicker/Vue3DatePicker.vue +++ b/src/Vue3DatePicker/Vue3DatePicker.vue @@ -151,6 +151,7 @@ IMarker, ITransition, IDisableDates, + AltPosition, } from './interfaces'; import { getDefaultPattern, isValidTime } from './utils/date-utils'; import { getDefaultTextInputOptions, getDefaultFilters, mergeDefaultTransitions } from './utils/util'; @@ -169,6 +170,7 @@ 'focus', 'blur', 'internalModelChange', + 'recalculatePosition', ]); const props = defineProps({ uid: { type: String as PropType, default: null }, @@ -245,7 +247,7 @@ noHoursOverlay: { type: Boolean as PropType, default: false }, noMinutesOverlay: { type: Boolean as PropType, default: false }, noSecondsOverlay: { type: Boolean as PropType, default: false }, - altPosition: { type: Boolean as PropType, default: false }, + altPosition: { type: [Boolean, Function] as PropType, default: false }, allowedDates: { type: Array as PropType, default: () => [] }, showNowButton: { type: Boolean as PropType, default: false }, nowButtonLabel: { type: String as PropType, default: 'Now' }, @@ -305,6 +307,7 @@ props.altPosition, dpMenuRef, inputRef, + emit, ); const { internalModelValue, inputValue, parseExternalModelValue, emitModelValue, checkBeforeEmit } = diff --git a/src/Vue3DatePicker/components/composition/position.ts b/src/Vue3DatePicker/components/composition/position.ts index bea792f..995c7a1 100644 --- a/src/Vue3DatePicker/components/composition/position.ts +++ b/src/Vue3DatePicker/components/composition/position.ts @@ -1,5 +1,5 @@ import { ref, Ref } from 'vue'; -import { OpenPosition } from '../../interfaces'; +import { AltPosition, OpenPosition, VueEmit } from '../../interfaces'; import { unrefElement } from '../../utils/util'; interface IUsePosition { @@ -16,9 +16,10 @@ type ComponentRef = Ref; */ export const usePosition = ( openPosition: OpenPosition, - altPosition: boolean, + altPosition: AltPosition, menuRef: ComponentRef, inputRef: ComponentRef, + emit: VueEmit, ): IUsePosition => { const menuPosition = ref({ top: '0', left: '0', transform: 'none' }); const openOnTop = ref(false); @@ -55,7 +56,9 @@ export const usePosition = ( */ const setMenuPosition = (recalculate = true): void => { const el = unrefElement(inputRef); - if (el) { + if (altPosition && typeof altPosition !== 'boolean') { + menuPosition.value = altPosition(el); + } else if (el) { const { left, width, height } = el.getBoundingClientRect(); const { top: offset } = altPosition ? getOffsetAlt(el) : getOffset(el); const position = { top: `${height + offset + diagonal}px`, left: '', transform: 'none' }; @@ -112,6 +115,7 @@ export const usePosition = ( } } } + emit('recalculatePosition'); }; return { openOnTop, menuPosition, setMenuPosition, recalculatePosition }; diff --git a/src/Vue3DatePicker/interfaces.ts b/src/Vue3DatePicker/interfaces.ts index bebc8c4..ddc0ba0 100644 --- a/src/Vue3DatePicker/interfaces.ts +++ b/src/Vue3DatePicker/interfaces.ts @@ -142,3 +142,5 @@ export interface ITransition { } export type IDisableDates = (date: Date) => boolean; export type ITimeType = 'hours' | 'minutes' | 'seconds'; + +export type AltPosition = boolean | ((el: HTMLElement | undefined) => { top: string; left: string; transform: string });