150 lines
5.1 KiB
JavaScript
150 lines
5.1 KiB
JavaScript
import { defineComponent, ref, inject, computed, provide, readonly, toRef, unref, watch, nextTick, renderSlot } from 'vue';
|
|
import { useEventListener } from '@vueuse/core';
|
|
import { rovingFocusGroupProps, ROVING_FOCUS_COLLECTION_INJECTION_KEY as COLLECTION_INJECTION_KEY } from './roving-focus-group.mjs';
|
|
import { ROVING_FOCUS_GROUP_INJECTION_KEY } from './tokens.mjs';
|
|
import { getFocusIntent, reorderArray, focusFirst } from './utils.mjs';
|
|
import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
|
|
import { composeEventHandlers } from '../../../utils/dom/event.mjs';
|
|
|
|
const CURRENT_TAB_ID_CHANGE_EVT = "currentTabIdChange";
|
|
const ENTRY_FOCUS_EVT = "rovingFocusGroup.entryFocus";
|
|
const EVT_OPTS = { bubbles: false, cancelable: true };
|
|
const _sfc_main = defineComponent({
|
|
name: "ElRovingFocusGroupImpl",
|
|
inheritAttrs: false,
|
|
props: rovingFocusGroupProps,
|
|
emits: [CURRENT_TAB_ID_CHANGE_EVT, "entryFocus"],
|
|
setup(props, { emit }) {
|
|
var _a;
|
|
const currentTabbedId = ref(
|
|
(_a = props.currentTabId || props.defaultCurrentTabId) != null ? _a : null
|
|
);
|
|
const isBackingOut = ref(false);
|
|
const isClickFocus = ref(false);
|
|
const rovingFocusGroupRef = ref();
|
|
const { getItems } = inject(
|
|
COLLECTION_INJECTION_KEY,
|
|
void 0
|
|
);
|
|
const rovingFocusGroupRootStyle = computed(() => {
|
|
return [
|
|
{
|
|
outline: "none"
|
|
},
|
|
props.style
|
|
];
|
|
});
|
|
const onItemFocus = (tabbedId) => {
|
|
emit(CURRENT_TAB_ID_CHANGE_EVT, tabbedId);
|
|
};
|
|
const onItemShiftTab = () => {
|
|
isBackingOut.value = true;
|
|
};
|
|
const onMousedown = composeEventHandlers(
|
|
(e) => {
|
|
var _a2;
|
|
(_a2 = props.onMousedown) == null ? void 0 : _a2.call(props, e);
|
|
},
|
|
() => {
|
|
isClickFocus.value = true;
|
|
}
|
|
);
|
|
const onFocus = composeEventHandlers(
|
|
(e) => {
|
|
var _a2;
|
|
(_a2 = props.onFocus) == null ? void 0 : _a2.call(props, e);
|
|
},
|
|
(e) => {
|
|
const isKeyboardFocus = !unref(isClickFocus);
|
|
const { target, currentTarget } = e;
|
|
if (target === currentTarget && isKeyboardFocus && !unref(isBackingOut)) {
|
|
const entryFocusEvt = new Event(ENTRY_FOCUS_EVT, EVT_OPTS);
|
|
currentTarget == null ? void 0 : currentTarget.dispatchEvent(entryFocusEvt);
|
|
if (!entryFocusEvt.defaultPrevented) {
|
|
const items = getItems().filter((item) => item.focusable);
|
|
const activeItem = items.find((item) => item.active);
|
|
const currentItem = items.find(
|
|
(item) => item.id === unref(currentTabbedId)
|
|
);
|
|
const candidates = [activeItem, currentItem, ...items].filter(
|
|
Boolean
|
|
);
|
|
const candidateNodes = candidates.map((item) => item.ref);
|
|
focusFirst(candidateNodes);
|
|
}
|
|
}
|
|
isClickFocus.value = false;
|
|
}
|
|
);
|
|
const onBlur = composeEventHandlers(
|
|
(e) => {
|
|
var _a2;
|
|
(_a2 = props.onBlur) == null ? void 0 : _a2.call(props, e);
|
|
},
|
|
() => {
|
|
isBackingOut.value = false;
|
|
}
|
|
);
|
|
const handleEntryFocus = (...args) => {
|
|
emit("entryFocus", ...args);
|
|
};
|
|
const onKeydown = (e) => {
|
|
const focusIntent = getFocusIntent(e);
|
|
if (focusIntent) {
|
|
e.preventDefault();
|
|
const items = getItems().filter((item) => item.focusable);
|
|
let elements = items.map((item) => item.ref);
|
|
switch (focusIntent) {
|
|
case "last": {
|
|
elements.reverse();
|
|
break;
|
|
}
|
|
case "prev":
|
|
case "next": {
|
|
if (focusIntent === "prev") {
|
|
elements.reverse();
|
|
}
|
|
const currentIdx = elements.indexOf(e.currentTarget);
|
|
elements = props.loop ? reorderArray(elements, currentIdx + 1) : elements.slice(currentIdx + 1);
|
|
break;
|
|
}
|
|
}
|
|
nextTick(() => {
|
|
focusFirst(elements);
|
|
});
|
|
}
|
|
};
|
|
provide(ROVING_FOCUS_GROUP_INJECTION_KEY, {
|
|
currentTabbedId: readonly(currentTabbedId),
|
|
loop: toRef(props, "loop"),
|
|
tabIndex: computed(() => {
|
|
return unref(isBackingOut) ? -1 : 0;
|
|
}),
|
|
rovingFocusGroupRef,
|
|
rovingFocusGroupRootStyle,
|
|
orientation: toRef(props, "orientation"),
|
|
dir: toRef(props, "dir"),
|
|
onItemFocus,
|
|
onItemShiftTab,
|
|
onBlur,
|
|
onFocus,
|
|
onMousedown,
|
|
onKeydown
|
|
});
|
|
watch(
|
|
() => props.currentTabId,
|
|
(val) => {
|
|
currentTabbedId.value = val != null ? val : null;
|
|
}
|
|
);
|
|
useEventListener(rovingFocusGroupRef, ENTRY_FOCUS_EVT, handleEntryFocus);
|
|
}
|
|
});
|
|
function _sfc_render(_ctx, _cache, $props, $setup, $data, $options) {
|
|
return renderSlot(_ctx.$slots, "default");
|
|
}
|
|
var ElRovingFocusGroupImpl = /* @__PURE__ */ _export_sfc(_sfc_main, [["render", _sfc_render], ["__file", "/home/runner/work/element-plus/element-plus/packages/components/roving-focus-group/src/roving-focus-group-impl.vue"]]);
|
|
|
|
export { ElRovingFocusGroupImpl as default };
|
|
//# sourceMappingURL=roving-focus-group-impl.mjs.map
|