const KEY_DELTA_MAP = { ArrowLeft: -1, ArrowUp: -1, ArrowRight: 1, ArrowDown: 1, } const FOCUSABLE_SELECTORS = [ 'input:not([type="hidden"]):not([disabled])', 'textarea:not([disabled])', 'select:not([disabled])', '.el-input__inner', '.el-input-number', '.el-select', '.el-tree-select', '[tabindex]:not([tabindex="-1"])', ] function focusControl(container) { if (!container) return const focus = (el) => { if (!el) return el.focus?.() if (el.select && !el.readOnly) { el.select() } } if (container.matches?.('input, textarea, select')) { focus(container) return } const directTarget = container.querySelector(FOCUSABLE_SELECTORS.join(', ')) if (directTarget) { focusControl(directTarget) return } focus(container) } function getFormItems(root) { const propItems = Array.from(root.querySelectorAll('[data-prop]')) if (propItems.length) { return propItems } return Array.from(root.querySelectorAll('.el-form-item')) } function createHandler(root) { return function handleKeyDown(event) { const delta = KEY_DELTA_MAP[event.key] if (!delta) return const currentItem = event.target.closest('[data-prop], .el-form-item') if (!currentItem || !root.contains(currentItem)) return const items = getFormItems(root) if (!items.length) return const currentIndex = items.indexOf(currentItem) if (currentIndex === -1) return event.preventDefault() event.stopPropagation() const nextIndex = (currentIndex + delta + items.length) % items.length const targetItem = items[nextIndex] if (targetItem) { focusControl(targetItem) } } } export default { mounted(el) { const handler = createHandler(el) el.__arrowNavigateHandler = handler el.addEventListener('keydown', handler, true) }, beforeUnmount(el) { if (el.__arrowNavigateHandler) { el.removeEventListener('keydown', el.__arrowNavigateHandler, true) delete el.__arrowNavigateHandler } }, }