@scalar/api-reference
Version:
Generate beautiful API references from OpenAPI documents
115 lines (114 loc) • 5.07 kB
JavaScript
import { useSearchIndex } from "../hooks/useSearchIndex.js";
import SearchResult_default from "./SearchResult.vue.js";
import { Fragment, computed, createBlock, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, isRef, openBlock, ref, renderList, toDisplayString, unref, watch, withCtx, withKeys, withModifiers } from "vue";
import { ScalarModal, ScalarSearchInput, ScalarSearchResultList } from "@scalar/components";
import { nanoid } from "nanoid";
//#region src/features/Search/components/SearchModal.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = {
class: "mb-0 flex flex-col",
role: "search"
};
var SearchModal_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
__name: "SearchModal",
props: {
modalState: {},
document: {},
eventBus: {}
},
setup(__props) {
const props = __props;
/** Base id for the search form */
const id = nanoid();
/** An id for the results listbox */
const listboxId = `${id}-search-result`;
/** An id for the results instructions */
const instructionsId = `${id}-search-instructions`;
const { query, results } = useSearchIndex(() => props.document);
const selectedIndex = ref(void 0);
/** Clear the query value when the modal is opened */
watch(() => props.modalState.open, (open) => {
if (open) query.value = "";
});
/** Keyboard navigation */
const navigateSearchResults = (direction) => {
const offset = direction === "up" ? -1 : 1;
const length = results.value.length;
if (typeof selectedIndex.value === "number") selectedIndex.value = (selectedIndex.value + offset + length) % length;
else selectedIndex.value = offset === -1 ? length - 1 : 0;
};
/** Handle the selection of a search result */
function handleSelect(idx) {
if (typeof idx !== "number" || !results.value[idx]) return;
const result = results.value[idx];
props.modalState.hide();
props.eventBus.emit("scroll-to:nav-item", { id: result.item.id });
}
/**
* Active descendant id for the search input
* NOTE: Result items MUST share this id for the aria-activedescendant attribute to work correctly
*/
const activeDescendantId = computed(() => {
const selectedResult = results.value[selectedIndex.value ?? -1];
return selectedResult ? `search-result-${selectedResult.item.id}` : void 0;
});
return (_ctx, _cache) => {
return openBlock(), createBlock(unref(ScalarModal), {
"aria-label": "Reference Search",
state: __props.modalState,
variant: "search"
}, {
default: withCtx(() => [
createElementVNode("div", _hoisted_1, [createVNode(unref(ScalarSearchInput), {
modelValue: unref(query),
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => isRef(query) ? query.value = $event : null),
"aria-activedescendant": activeDescendantId.value,
"aria-autocomplete": "list",
"aria-controls": listboxId,
"aria-describedby": instructionsId,
role: "combobox",
onBlur: _cache[1] || (_cache[1] = ($event) => selectedIndex.value = void 0),
onKeydown: [
_cache[2] || (_cache[2] = withKeys(withModifiers(($event) => navigateSearchResults("down"), ["stop", "prevent"]), ["down"])),
_cache[3] || (_cache[3] = withKeys(withModifiers(() => handleSelect(selectedIndex.value), ["stop", "prevent"]), ["enter"])),
_cache[4] || (_cache[4] = withKeys(withModifiers(($event) => navigateSearchResults("up"), ["stop", "prevent"]), ["up"]))
]
}, null, 8, ["modelValue", "aria-activedescendant"])]),
createVNode(unref(ScalarSearchResultList), {
id: listboxId,
"aria-label": "Reference Search Results",
class: "custom-scroll px-1 pb-1",
noResults: !unref(results).length
}, {
query: withCtx(() => [createTextVNode(toDisplayString(unref(query)), 1)]),
default: withCtx(() => [(openBlock(true), createElementBlock(Fragment, null, renderList(unref(results), (result, idx) => {
return openBlock(), createBlock(SearchResult_default, {
id: `search-result-${result.item.id}`,
key: result.refIndex,
isSelected: selectedIndex.value === idx,
result,
onClick: withModifiers(() => handleSelect(idx), ["prevent"])
}, null, 8, [
"id",
"isSelected",
"result",
"onClick"
]);
}), 128))]),
_: 1
}, 8, ["noResults"]),
createElementVNode("div", {
id: instructionsId,
class: "ref-search-meta"
}, [..._cache[5] || (_cache[5] = [createElementVNode("span", {
"aria-hidden": "true",
class: "contents"
}, [createElementVNode("span", null, "↑↓ Navigate"), createElementVNode("span", null, "⏎ Select")], -1), createElementVNode("span", { class: "sr-only" }, " Press up arrow / down arrow to navigate, enter to select, type to filter results ", -1)])])
]),
_: 1
}, 8, ["state"]);
};
}
});
//#endregion
export { SearchModal_vue_vue_type_script_setup_true_lang_default as default };
//# sourceMappingURL=SearchModal.vue.script.js.map