forked from
npmx.dev/npmx.dev
[READ-ONLY]
a fast, modern browser for the npm registry
1<script setup lang="ts">
2import type { SelectBaseProps } from './Base.vue'
3
4const SELECT_FIELD_SIZES = {
5 sm: 'text-xs py-1.75 ps-2 pe-6 rounded-md',
6 md: 'text-sm py-2.25 ps-3 pe-9 rounded-lg',
7 lg: 'text-base py-4 ps-6 pe-15 rounded-xl',
8}
9const SELECT_FIELD_ICON_SIZES = {
10 sm: 'inset-ie-2 size-[0.75rem]',
11 md: 'inset-ie-3 size-[1rem]',
12 lg: 'inset-ie-5 size-[1.5rem]',
13}
14const SELECT_FIELD_LABEL_SIZES = {
15 sm: 'text-2xs',
16 md: 'text-xs',
17 lg: 'text-sm',
18}
19
20const model = defineModel<string | undefined>({ default: undefined })
21
22export interface SelectFieldProps extends SelectBaseProps {
23 items: { label: string; value: string; disabled?: boolean }[]
24 size?: keyof typeof SELECT_FIELD_SIZES
25 selectAttrs?: Omit<SelectBaseProps, 'size' | 'id'> &
26 Record<string, string | number | boolean | undefined>
27 label?: string
28 labelAttrs?: Record<string, string | number | boolean | undefined>
29 /** Visually hide label */
30 hiddenLabel?: boolean
31 id: string
32 /** Render select full width */
33 block?: boolean
34}
35
36const props = withDefaults(defineProps<SelectFieldProps>(), {
37 size: 'md',
38})
39</script>
40
41<template>
42 <div class="group/select">
43 <label
44 v-if="label"
45 :for="id"
46 v-bind="labelAttrs"
47 class="block mb-1 font-mono text-fg-subtle tracking-wide uppercase"
48 :class="[hiddenLabel ? 'sr-only' : '', SELECT_FIELD_LABEL_SIZES[size]]"
49 >{{ label }}</label
50 >
51 <div class="relative" :class="[block ? 'w-full' : 'w-fit']">
52 <SelectBase
53 :disabled="disabled"
54 size="none"
55 class="appearance-none group-hover/select:border-fg-muted"
56 :class="[SELECT_FIELD_SIZES[size], block ? 'w-full' : 'w-fit']"
57 v-model="model"
58 v-bind="selectAttrs"
59 :id="id"
60 >
61 <option
62 v-for="item in items"
63 :key="item.value"
64 :value="item.value"
65 :disabled="item.disabled"
66 >
67 {{ item.label }}
68 </option>
69 </SelectBase>
70 <span
71 aria-hidden="true"
72 class="block i-lucide:chevron-down absolute top-1/2 -translate-y-1/2 text-fg-subtle pointer-events-none group-hover/select:text-fg group-focus-within/select:text-fg"
73 :class="[SELECT_FIELD_ICON_SIZES[size]]"
74 />
75 </div>
76 </div>
77</template>