Virtual list in property select

This commit is contained in:
andrewwallacespeckle
2025-08-21 16:18:27 +01:00
parent 626b15ab69
commit c5f2ed3afb
2 changed files with 52 additions and 25 deletions
@@ -154,7 +154,7 @@
<!-- Panel Extension - Portal target for additional content -->
<div
id="panel-extension"
class="absolute max-h-96 h-full empty:hidden z-30 w-64 top-1.5 bg-foundation border border-outline-2 rounded-lg overflow-hidden"
class="absolute max-h-[calc(100dvh-4rem)] empty:hidden z-30 w-64 top-1.5 bg-foundation border border-outline-2 rounded-lg overflow-hidden"
:style="`left: ${panelExtensionLeft}px`"
>
<PortalTarget name="panel-extension"></PortalTarget>
@@ -6,37 +6,50 @@
input-id="property-search"
/>
<div class="flex-1 overflow-y-auto overflow-x-hidden simple-scrollbar p-2">
<div class="flex flex-col">
<button
v-for="property in filteredOptions"
:key="property.value"
class="p-2 text-foreground rounded hover:bg-highlight-1 text-left flex items-center gap-2"
@click="$emit('selectProperty', property.value)"
>
<component
:is="getPropertyTypeDisplay(property.type).icon"
class="h-3 w-3 shrink-0"
:class="getPropertyTypeDisplay(property.type).classes"
/>
<div class="min-w-0 flex-1">
<div class="text-body-2xs font-medium text-foreground truncate">
{{ property.label }}
<div
v-bind="containerProps"
class="relative simple-scrollbar"
:style="{ height: containerHeight }"
>
<div
v-for="{ data: property, index } in list"
:key="`${index}-${property.value}`"
:style="{
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: `${itemHeight}px`,
transform: `translateY(${index * itemHeight}px)`
}"
>
<div class="px-1">
<button
class="w-full h-full py-1.5 px-2 text-foreground rounded hover:bg-highlight-1 text-left flex items-center gap-2"
@click="$emit('selectProperty', property.value)"
>
<component
:is="getPropertyTypeDisplay(property.type).icon"
class="h-3 w-3 shrink-0"
:class="getPropertyTypeDisplay(property.type).classes"
/>
<div class="min-w-0 flex-1">
<div class="text-body-2xs font-medium text-foreground truncate">
{{ property.label }}
</div>
<div class="text-body-3xs text-foreground-2 truncate -mt-0.5">
{{ property.parentPath || '-' }}
</div>
</div>
<div
v-if="property.parentPath"
class="text-body-3xs text-foreground-2 truncate -mt-1"
>
{{ property.parentPath }}
</div>
</div>
</button>
</button>
</div>
</div>
</div>
</div>
</template>
<script setup lang="ts">
import { useVirtualList } from '@vueuse/core'
import { useFilterUtilities } from '~~/lib/viewer/composables/filtering'
type PropertyOption = {
@@ -73,4 +86,18 @@ const filteredOptions = computed(() => {
option.type.toLowerCase().includes(searchTerm)
)
})
// Virtual list setup
const itemHeight = 42
const maxHeight = 300 // Maximum height for the container
const containerHeight = computed(() => {
const contentHeight = filteredOptions.value.length * itemHeight
return `${Math.min(contentHeight, maxHeight)}px`
})
const { list, containerProps } = useVirtualList(filteredOptions, {
itemHeight,
overscan: 5
})
</script>