feat: add component to enable scroll-into view (#451)
This commit is contained in:
parent
c1d1138742
commit
a18e5e2332
17
components/common/CommonScrollIntoView.vue
Normal file
17
components/common/CommonScrollIntoView.vue
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
<script setup lang="ts">
|
||||||
|
const { as = 'div', active } = defineProps<{ as: any; active: boolean }>()
|
||||||
|
const el = ref()
|
||||||
|
|
||||||
|
watch(() => active, (active) => {
|
||||||
|
const _el = unrefElement(el)
|
||||||
|
|
||||||
|
if (active && _el)
|
||||||
|
_el.scrollIntoView({ block: 'nearest', inline: 'start' })
|
||||||
|
})
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<component :is="as" ref="el">
|
||||||
|
<slot />
|
||||||
|
</component>
|
||||||
|
</template>
|
|
@ -1,14 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { SearchResult } from './types'
|
import type { SearchResult } from './types'
|
||||||
const props = defineProps<{ result: SearchResult; active: boolean }>()
|
defineProps<{ result: SearchResult; active: boolean }>()
|
||||||
|
|
||||||
const el = ref<HTMLElement>()
|
|
||||||
watch(() => props.active, (active) => {
|
|
||||||
const _el = unrefElement(el)
|
|
||||||
|
|
||||||
if (active && _el)
|
|
||||||
_el.scrollIntoView({ block: 'nearest', inline: 'start' })
|
|
||||||
})
|
|
||||||
|
|
||||||
const onActivate = () => {
|
const onActivate = () => {
|
||||||
(document.activeElement as HTMLElement).blur()
|
(document.activeElement as HTMLElement).blur()
|
||||||
|
@ -16,11 +8,11 @@ const onActivate = () => {
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<RouterLink ref="el" :to="result.to" py2 block px2 :aria-selected="active" :class="{ 'bg-active': active }" hover:bg-active @click="() => onActivate()">
|
<CommonScrollIntoView as="RouterLink" :active="active" :to="result.to" py2 block px2 :aria-selected="active" :class="{ 'bg-active': active }" hover:bg-active @click="() => onActivate()">
|
||||||
<SearchHashtagInfo v-if="result.type === 'hashtag'" :hashtag="result.hashtag" />
|
<SearchHashtagInfo v-if="result.type === 'hashtag'" :hashtag="result.hashtag" />
|
||||||
<AccountInfo v-else-if="result.type === 'account'" :account="result.account" />
|
<AccountInfo v-else-if="result.type === 'account'" :account="result.account" />
|
||||||
<div v-else-if="result.type === 'action'" text-center>
|
<div v-else-if="result.type === 'action'" text-center>
|
||||||
{{ result.action!.label }}
|
{{ result.action!.label }}
|
||||||
</div>
|
</div>
|
||||||
</RouterLink>
|
</CommonScrollIntoView>
|
||||||
</template>
|
</template>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
<script setup lang="ts">
|
<script setup lang="ts">
|
||||||
import type { Account } from 'masto'
|
import type { Account } from 'masto'
|
||||||
|
import CommonScrollIntoView from '../common/CommonScrollIntoView.vue'
|
||||||
|
|
||||||
const { items, command } = defineProps<{
|
const { items, command } = defineProps<{
|
||||||
items: Account[]
|
items: Account[]
|
||||||
|
@ -50,15 +51,16 @@ defineExpose({
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template v-if="items.length">
|
<template v-if="items.length">
|
||||||
<button
|
<CommonScrollIntoView
|
||||||
v-for="(item, index) in items"
|
v-for="(item, index) in items" :key="index"
|
||||||
:key="index"
|
:active="index === selectedIndex"
|
||||||
|
as="button"
|
||||||
:class="index === selectedIndex ? 'bg-active' : 'text-secondary'"
|
:class="index === selectedIndex ? 'bg-active' : 'text-secondary'"
|
||||||
block m0 w-full text-left px2 py1
|
block m0 w-full text-left px2 py1
|
||||||
@click="selectItem(index)"
|
@click="selectItem(index)"
|
||||||
>
|
>
|
||||||
<AccountInfo :account="item" />
|
<AccountInfo :account="item" />
|
||||||
</button>
|
</CommonScrollIntoView>
|
||||||
</template>
|
</template>
|
||||||
</div>
|
</div>
|
||||||
<div v-else />
|
<div v-else />
|
||||||
|
|
Loading…
Reference in a new issue