fix: wrapper deleted

This commit is contained in:
Jin Yi
2025-08-29 14:54:52 +09:00
parent 3de318f3df
commit 0ab9af78d1
3 changed files with 126 additions and 132 deletions

View File

@@ -200,8 +200,8 @@ export const MultipleSelectors: Story = {
</div> </div>
<div class="p-4 bg-gray-50 dark-theme:bg-zinc-800 rounded"> <div class="p-4 bg-gray-50 dark-theme:bg-zinc-800 rounded">
<h4 class="font-medium mb-2">Current Selection:</h4> <h4 class="font-medium mt-0">Current Selection:</h4>
<div class="space-y-1 text-sm"> <div class="flex flex-col text-sm">
<p>Frameworks: {{ selectedFrameworks.length > 0 ? selectedFrameworks.map(s => s.name).join(', ') : 'None' }}</p> <p>Frameworks: {{ selectedFrameworks.length > 0 ? selectedFrameworks.map(s => s.name).join(', ') : 'None' }}</p>
<p>Projects: {{ selectedProjects.length > 0 ? selectedProjects.map(s => s.name).join(', ') : 'None' }}</p> <p>Projects: {{ selectedProjects.length > 0 ? selectedProjects.map(s => s.name).join(', ') : 'None' }}</p>
<p>Tags: {{ selectedTags.length > 0 ? selectedTags.map(s => s.name).join(', ') : 'None' }}</p> <p>Tags: {{ selectedTags.length > 0 ? selectedTags.map(s => s.name).join(', ') : 'None' }}</p>

View File

@@ -1,96 +1,92 @@
<template> <template>
<div class="relative inline-block"> <MultiSelect
<MultiSelect v-model="selectedItems"
v-model="selectedItems" :options="options"
:options="options" option-label="name"
option-label="name" unstyled
unstyled :placeholder="label"
:placeholder="label" :max-selected-labels="0"
:max-selected-labels="0" :pt="pt"
:pt="pt" >
<template
v-if="showSearchBox || showSelectedCount || showClearButton"
#header
> >
<template <div class="p-2 flex flex-col pb-0">
v-if="showSearchBox || showSelectedCount || showClearButton" <SearchBox
#header v-if="showSearchBox"
> v-model="searchQuery"
<div class="p-2 flex flex-col pb-0"> :class="showSelectedCount || showClearButton ? 'mb-2' : ''"
<SearchBox :has-border="true"
v-if="showSearchBox" :place-holder="searchPlaceholder"
v-model="searchQuery" />
:class="showSelectedCount || showClearButton ? 'mb-2' : ''" <div
:has-border="true" v-if="showSelectedCount || showClearButton"
:place-holder="searchPlaceholder" class="mt-2 flex items-center justify-between"
>
<span
v-if="showSelectedCount"
class="text-sm text-neutral-400 dark-theme:text-zinc-500 px-1"
>
{{
selectedCount > 0
? $t('g.itemsSelected', { selectedCount })
: $t('g.itemSelected', { selectedCount })
}}
</span>
<TextButton
v-if="showClearButton"
:label="$t('g.clearAll')"
type="transparent"
size="fit-content"
class="text-sm !text-blue-500 !dark-theme:text-blue-600"
@click.stop="selectedItems = []"
/> />
<div
v-if="showSelectedCount || showClearButton"
class="mt-2 flex items-center justify-between"
>
<span
v-if="showSelectedCount"
class="text-sm text-neutral-400 dark-theme:text-zinc-500 px-1"
>
{{
selectedCount > 0
? $t('g.itemsSelected', { selectedCount })
: $t('g.itemSelected', { selectedCount })
}}
</span>
<TextButton
v-if="showClearButton"
:label="$t('g.clearAll')"
type="transparent"
size="fit-content"
class="text-sm !text-blue-500 !dark-theme:text-blue-600"
@click.stop="selectedItems = []"
/>
</div>
<div class="mt-4 h-px bg-zinc-200 dark-theme:bg-zinc-700"></div>
</div> </div>
</template> <div class="mt-4 h-px bg-zinc-200 dark-theme:bg-zinc-700"></div>
</div>
</template>
<!-- Trigger value (keep text scale identical) --> <!-- Trigger value (keep text scale identical) -->
<template #value> <template #value>
<span class="text-sm text-zinc-700 dark-theme:text-gray-200"> <span class="text-sm text-zinc-700 dark-theme:text-gray-200">
{{ label }} {{ label }}
</span> </span>
</template> <span
v-if="selectedCount > 0"
class="pointer-events-none absolute -right-2 -top-2 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-blue-400 dark-theme:bg-blue-500 text-xs font-semibold text-white"
>
{{ selectedCount }}
</span>
</template>
<!-- Chevron size identical to current --> <!-- Chevron size identical to current -->
<template #dropdownicon> <template #dropdownicon>
<i-lucide:chevron-down class="text-lg text-neutral-400" /> <i-lucide:chevron-down class="text-lg text-neutral-400" />
</template> </template>
<!-- Custom option row: square checkbox + label (unchanged layout/colors) --> <!-- Custom option row: square checkbox + label (unchanged layout/colors) -->
<template #option="slotProps"> <template #option="slotProps">
<div class="flex items-center gap-2"> <div class="flex items-center gap-2">
<div <div
class="flex h-4 w-4 p-0.5 flex-shrink-0 items-center justify-center rounded border-[3px] transition-all duration-200" class="flex h-4 w-4 p-0.5 flex-shrink-0 items-center justify-center rounded border-[3px] transition-all duration-200"
:class=" :class="
slotProps.selected slotProps.selected
? 'border-blue-400 bg-blue-400 dark-theme:border-blue-500 dark-theme:bg-blue-500' ? 'border-blue-400 bg-blue-400 dark-theme:border-blue-500 dark-theme:bg-blue-500'
: 'border-neutral-300 dark-theme:border-zinc-600 bg-neutral-100 dark-theme:bg-zinc-700' : 'border-neutral-300 dark-theme:border-zinc-600 bg-neutral-100 dark-theme:bg-zinc-700'
" "
> >
<i-lucide:check <i-lucide:check
v-if="slotProps.selected" v-if="slotProps.selected"
class="text-xs text-bold text-white" class="text-xs text-bold text-white"
/> />
</div>
<Button class="border-none outline-none bg-transparent" unstyled>{{
slotProps.option.name
}}</Button>
</div> </div>
</template> <Button class="border-none outline-none bg-transparent" unstyled>{{
</MultiSelect> slotProps.option.name
}}</Button>
<!-- Selected count badge --> </div>
<div </template>
v-if="selectedCount > 0" </MultiSelect>
class="pointer-events-none absolute -right-2 -top-2 z-10 flex h-5 w-5 items-center justify-center rounded-full bg-blue-400 dark-theme:bg-blue-500 text-xs font-semibold text-white"
>
{{ selectedCount }}
</div>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -138,7 +134,7 @@ const selectedCount = computed(() => selectedItems.value.length)
const pt = computed(() => ({ const pt = computed(() => ({
root: ({ props }: MultiSelectPassThroughMethodOptions) => ({ root: ({ props }: MultiSelectPassThroughMethodOptions) => ({
class: [ class: [
'relative inline-flex cursor-pointer select-none w-full', 'relative inline-flex cursor-pointer select-none',
'rounded-lg bg-white dark-theme:bg-zinc-800 text-neutral dark-theme:text-white', 'rounded-lg bg-white dark-theme:bg-zinc-800 text-neutral dark-theme:text-white',
'transition-all duration-200 ease-in-out', 'transition-all duration-200 ease-in-out',
'border-[2.5px] border-solid', 'border-[2.5px] border-solid',

View File

@@ -1,49 +1,47 @@
<template> <template>
<div class="relative inline-flex items-center"> <Select
<Select v-model="selectedItem"
v-model="selectedItem" :options="options"
:options="options" option-label="name"
option-label="name" option-value="value"
option-value="value" unstyled
unstyled :placeholder="label"
:placeholder="label" :pt="pt"
:pt="pt" >
> <!-- Trigger value -->
<!-- Trigger value --> <template #value="slotProps">
<template #value="slotProps"> <div class="flex items-center gap-2 text-sm">
<div class="flex items-center gap-2 text-sm"> <slot name="icon" />
<slot name="icon" /> <span
<span v-if="slotProps.value !== null && slotProps.value !== undefined"
v-if="slotProps.value !== null && slotProps.value !== undefined" class="text-zinc-700 dark-theme:text-gray-200"
class="text-zinc-700 dark-theme:text-gray-200" >
> {{ getLabel(slotProps.value) }}
{{ getLabel(slotProps.value) }} </span>
</span> <span v-else class="text-zinc-700 dark-theme:text-gray-200">
<span v-else class="text-zinc-700 dark-theme:text-gray-200"> {{ label }}
{{ label }} </span>
</span> </div>
</div> </template>
</template>
<!-- Trigger caret --> <!-- Trigger caret -->
<template #dropdownicon> <template #dropdownicon>
<i-lucide:chevron-down <i-lucide:chevron-down
class="text-base text-neutral-400 dark-theme:text-gray-300" class="text-base text-neutral-400 dark-theme:text-gray-300"
/>
</template>
<!-- Option row -->
<template #option="{ option, selected }">
<div class="flex items-center justify-between gap-3 w-full">
<span class="truncate">{{ option.name }}</span>
<i-lucide:check
v-if="selected"
class="text-neutral-900 dark-theme:text-white"
/> />
</template> </div>
</template>
<!-- Option row --> </Select>
<template #option="{ option, selected }">
<div class="flex items-center justify-between gap-3 w-full">
<span class="truncate">{{ option.name }}</span>
<i-lucide:check
v-if="selected"
class="text-neutral-900 dark-theme:text-white"
/>
</div>
</template>
</Select>
</div>
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
@@ -77,7 +75,7 @@ const pt = computed(() => ({
}: SelectPassThroughMethodOptions<{ name: string; value: string }>) => ({ }: SelectPassThroughMethodOptions<{ name: string; value: string }>) => ({
class: [ class: [
// container // container
'relative inline-flex w-full cursor-pointer select-none items-center', 'relative inline-flex cursor-pointer select-none items-center',
// trigger surface // trigger surface
'rounded-md', 'rounded-md',
'bg-transparent text-neutral dark-theme:text-white', 'bg-transparent text-neutral dark-theme:text-white',