UNPKG

@coreui/vue-pro

Version:

UI Components Library for Vue.js

160 lines (141 loc) 5.07 kB
import { defineComponent, h, onUpdated, PropType, ref, watch } from 'vue' import { useIsVisible } from '../../composables' import { getNextActiveElement, isRTL } from '../../utils' export interface Element { value: number | string label: number | string } const CTimePickerRollCol = defineComponent({ name: 'CTimePickerRollCol', props: { ariaLabel: String, columnIndex: Number, columnRefs: { type: Array as PropType<(HTMLElement | null)[]>, default: () => [], }, elements: { type: Array as PropType<Element[]>, required: true, }, selected: [Number, String, null], setColumnRef: Function as PropType<(index: number, el: HTMLElement | null) => void>, }, emits: ['click'], setup(props, { emit }) { const init = ref(true) const colRef = ref<HTMLElement>() const isVisible = useIsVisible(colRef) const scrollToSelectedElement = () => { const nodeEl = colRef.value?.querySelector('.selected') if (isVisible.value && nodeEl && nodeEl instanceof HTMLElement) { colRef.value?.scrollTo({ top: nodeEl.offsetTop, behavior: init.value ? 'instant' : 'smooth', }) } } watch(isVisible, () => { scrollToSelectedElement() if (isVisible.value) { init.value = false } }) watch(colRef, () => { if (props.columnIndex !== undefined && props.setColumnRef) { props.setColumnRef(props.columnIndex, colRef.value || null) } }, { immediate: true }) onUpdated(() => { scrollToSelectedElement() }) const moveFocusToNextColumn = () => { if (!props.columnRefs || props.columnIndex === undefined) return if (props.columnIndex < props.columnRefs.length - 1) { const column = props.columnRefs[props.columnIndex + 1] const focusableCell = column?.querySelector('.time-picker-roll-cell[tabindex="0"]') as HTMLElement focusableCell?.focus() } } const moveFocusToPreviousColumn = () => { if (!props.columnRefs || props.columnIndex === undefined) return if (props.columnIndex > 0) { const column = props.columnRefs[props.columnIndex - 1] const focusableCell = column?.querySelector('.time-picker-roll-cell[tabindex="0"]') as HTMLElement focusableCell?.focus() } } const handleKeyDown = (event: KeyboardEvent, value: number | string) => { if (event.code === 'Space' || event.key === 'Enter') { event.preventDefault() emit('click', value) moveFocusToNextColumn() return } if (colRef.value && (event.key === 'ArrowDown' || event.key === 'ArrowUp')) { event.preventDefault() const target = event.target as HTMLElement const items = [...colRef.value.querySelectorAll('.time-picker-roll-cell')] as HTMLElement[] getNextActiveElement(items, target, event.key === 'ArrowDown', true).focus() return } if (colRef.value && (event.key === 'Home' || event.key === 'End')) { event.preventDefault() const items = [...colRef.value.querySelectorAll('.time-picker-roll-cell')] as HTMLElement[] const index = event.key === 'Home' ? 0 : items.length - 1 items[index]?.focus() return } if (colRef.value && (event.key === 'ArrowLeft' || event.key === 'ArrowRight')) { event.preventDefault() const rtl = isRTL(colRef.value) const shouldGoLeft = (event.key === 'ArrowLeft' && !rtl) || (event.key === 'ArrowRight' && rtl) if (shouldGoLeft) { moveFocusToPreviousColumn() } else { moveFocusToNextColumn() } } } return () => h( 'div', { class: 'time-picker-roll-col', onFocusout: (event: FocusEvent) => { const currentTarget = event.currentTarget as HTMLElement const relatedTarget = event.relatedTarget as HTMLElement | null if (currentTarget && (!relatedTarget || !currentTarget.contains(relatedTarget))) { scrollToSelectedElement() } }, ref: colRef, role: 'listbox', 'aria-label': props.ariaLabel, }, props.elements.map((element, index) => { const isSelected = element.value === props.selected return h( 'div', { class: [ 'time-picker-roll-cell', { selected: isSelected, }, ], onClick: () => emit('click', element.value), onKeydown: (event: KeyboardEvent) => handleKeyDown(event, element.value), role: 'option', tabindex: isSelected ? 0 : props.selected ? -1 : index === 0 ? 0 : -1, 'aria-label': element.label.toString(), 'aria-selected': isSelected, }, element.label ) }) ) }, }) export { CTimePickerRollCol }