forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1<script setup lang="ts">
2withDefaults(
3 defineProps<{
4 inputClass?: string
5 }>(),
6 {
7 inputClass: 'inline sm:block',
8 },
9)
10
11const emit = defineEmits(['blur', 'focus'])
12const route = useRoute()
13const isSearchFocused = shallowRef(false)
14
15const showSearchBar = computed(() => {
16 return route.name !== 'index'
17})
18
19const { model: searchQuery, flushUpdateUrlQuery } = useGlobalSearch()
20
21function handleSubmit() {
22 flushUpdateUrlQuery()
23}
24
25// Expose focus method for parent components
26const inputRef = useTemplateRef('inputRef')
27function focus() {
28 inputRef.value?.focus()
29}
30defineExpose({ focus })
31</script>
32<template>
33 <search v-if="showSearchBar" :class="'flex-1 sm:max-w-md ' + inputClass">
34 <form method="GET" action="/search" class="relative" @submit.prevent="handleSubmit">
35 <label for="header-search" class="sr-only">
36 {{ $t('search.label') }}
37 </label>
38
39 <div class="relative group" :class="{ 'is-focused': isSearchFocused }">
40 <div class="search-box relative flex items-center">
41 <span
42 class="absolute inset-is-3 text-fg-subtle font-mono text-sm pointer-events-none transition-colors duration-200 motion-reduce:transition-none [.group:hover:not(:focus-within)_&]:text-fg/80 group-focus-within:text-accent z-1"
43 >
44 /
45 </span>
46
47 <InputBase
48 id="header-search"
49 ref="inputRef"
50 v-model="searchQuery"
51 type="search"
52 name="q"
53 :placeholder="$t('search.placeholder')"
54 no-correct
55 class="w-full min-w-25 ps-7"
56 @focus="isSearchFocused = true"
57 @blur="isSearchFocused = false"
58 size="small"
59 />
60 <button type="submit" class="sr-only">{{ $t('search.button') }}</button>
61 </div>
62 </div>
63 </form>
64 </search>
65</template>