fix(ui): truncate long searchable select labels
This commit is contained in:
parent
fb2a04660b
commit
ba12720e7e
|
|
@ -913,9 +913,9 @@ watch(
|
|||
content-class="w-[var(--reka-popover-trigger-width)]"
|
||||
>
|
||||
<template #option-label="{ option, label }">
|
||||
<div class="flex items-center gap-2">
|
||||
<DatabaseIcon :db-type="connectionIconType(option)" class="w-3.5 h-3.5" />
|
||||
{{ label }}
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<DatabaseIcon :db-type="connectionIconType(option)" class="h-3.5 w-3.5 shrink-0" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
|
@ -999,9 +999,9 @@ watch(
|
|||
content-class="w-[var(--reka-popover-trigger-width)]"
|
||||
>
|
||||
<template #option-label="{ option, label }">
|
||||
<div class="flex items-center gap-2">
|
||||
<DatabaseIcon :db-type="connectionIconType(option)" class="w-3.5 h-3.5" />
|
||||
{{ label }}
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<DatabaseIcon :db-type="connectionIconType(option)" class="h-3.5 w-3.5 shrink-0" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
|
|
|||
|
|
@ -267,9 +267,9 @@ async function fetchDbVersion(connectionId: string, database: string, schema: st
|
|||
content-class="w-[var(--reka-popover-trigger-width)]"
|
||||
>
|
||||
<template #option-label="{ option, label }">
|
||||
<div class="flex items-center gap-2">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.driver_profile || sqlConnections.find((c) => c.id === option)?.db_type || 'mysql'" class="w-3.5 h-3.5" />
|
||||
{{ label }}
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.driver_profile || sqlConnections.find((c) => c.id === option)?.db_type || 'mysql'" class="h-3.5 w-3.5 shrink-0" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
|
@ -351,9 +351,9 @@ async function fetchDbVersion(connectionId: string, database: string, schema: st
|
|||
content-class="w-[var(--reka-popover-trigger-width)]"
|
||||
>
|
||||
<template #option-label="{ option, label }">
|
||||
<div class="flex items-center gap-2">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.driver_profile || sqlConnections.find((c) => c.id === option)?.db_type || 'mysql'" class="w-3.5 h-3.5" />
|
||||
{{ label }}
|
||||
<div class="flex min-w-0 items-center gap-2">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.driver_profile || sqlConnections.find((c) => c.id === option)?.db_type || 'mysql'" class="h-3.5 w-3.5 shrink-0" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
|
|
|||
|
|
@ -380,9 +380,9 @@ function getConnectionName(id: string) {
|
|||
content-class="w-[var(--reka-popover-trigger-width)]"
|
||||
>
|
||||
<template #option-label="{ option, label }">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.db_type ?? 'mysql'" class="w-3.5 h-3.5" />
|
||||
{{ label }}
|
||||
<div class="flex min-w-0 items-center gap-1.5">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.db_type ?? 'mysql'" class="h-3.5 w-3.5 shrink-0" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
|
@ -443,9 +443,9 @@ function getConnectionName(id: string) {
|
|||
content-class="w-[var(--reka-popover-trigger-width)]"
|
||||
>
|
||||
<template #option-label="{ option, label }">
|
||||
<div class="flex items-center gap-1.5">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.db_type ?? 'mysql'" class="w-3.5 h-3.5" />
|
||||
{{ label }}
|
||||
<div class="flex min-w-0 items-center gap-1.5">
|
||||
<DatabaseIcon :db-type="sqlConnections.find((c) => c.id === option)?.db_type ?? 'mysql'" class="h-3.5 w-3.5 shrink-0" />
|
||||
<span class="min-w-0 flex-1 truncate">{{ label }}</span>
|
||||
</div>
|
||||
</template>
|
||||
</SearchableSelect>
|
||||
|
|
|
|||
|
|
@ -273,9 +273,12 @@ function handleKeydown(event: KeyboardEvent) {
|
|||
<Check :class="cn('absolute inset-0 h-3.5 w-3.5', option !== modelValue ? 'opacity-0' : clearSelectedOption ? 'opacity-100 group-hover:opacity-0 group-focus-visible:opacity-0' : 'opacity-100')" />
|
||||
<X v-if="clearSelectedOption && option === modelValue" class="absolute inset-0 h-3.5 w-3.5 opacity-0 group-hover:opacity-100 group-focus-visible:opacity-100" />
|
||||
</span>
|
||||
<slot name="option-label" :option="option" :label="displayName?.(option)">
|
||||
<span class="truncate">{{ displayName?.(option) }}</span>
|
||||
</slot>
|
||||
<!-- Keep custom labels inside the flex row so long content cannot overlap adjacent UI. -->
|
||||
<div class="dbx-searchable-select-option-label min-w-0 flex-1 overflow-hidden">
|
||||
<slot name="option-label" :option="option" :label="displayName?.(option)">
|
||||
<span class="block truncate">{{ displayName?.(option) }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
v-if="canSelectCustom"
|
||||
|
|
@ -292,9 +295,11 @@ function handleKeydown(event: KeyboardEvent) {
|
|||
@click="selectCustomOption"
|
||||
>
|
||||
<Check class="h-3.5 w-3.5 shrink-0 opacity-0" />
|
||||
<slot name="custom-option-label" :value="customOptionValue">
|
||||
<span class="truncate">{{ customOptionValue }}</span>
|
||||
</slot>
|
||||
<div class="dbx-searchable-select-option-label min-w-0 flex-1 overflow-hidden">
|
||||
<slot name="custom-option-label" :value="customOptionValue">
|
||||
<span class="block truncate">{{ customOptionValue }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
</button>
|
||||
</template>
|
||||
<button
|
||||
|
|
@ -312,9 +317,11 @@ function handleKeydown(event: KeyboardEvent) {
|
|||
@click="selectCustomOption"
|
||||
>
|
||||
<Check class="h-3.5 w-3.5 shrink-0 opacity-0" />
|
||||
<slot name="custom-option-label" :value="customOptionValue">
|
||||
<span class="truncate">{{ customOptionValue }}</span>
|
||||
</slot>
|
||||
<div class="dbx-searchable-select-option-label min-w-0 flex-1 overflow-hidden">
|
||||
<slot name="custom-option-label" :value="customOptionValue">
|
||||
<span class="block truncate">{{ customOptionValue }}</span>
|
||||
</slot>
|
||||
</div>
|
||||
</button>
|
||||
<div v-else class="px-2 py-2 text-sm text-muted-foreground">
|
||||
{{ emptyText }}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,21 @@
|
|||
import { readFileSync } from "node:fs";
|
||||
import { describe, expect, it } from "vitest";
|
||||
|
||||
const searchableSelectSource = readFileSync(new URL("../../../components/ui/searchable-select/SearchableSelect.vue", import.meta.url), "utf8");
|
||||
const dataTransferDialogSource = readFileSync(new URL("../../../components/transfer/DataTransferDialog.vue", import.meta.url), "utf8");
|
||||
|
||||
describe("SearchableSelect layout", () => {
|
||||
it("keeps slotted option labels inside a shrinkable overflow boundary", () => {
|
||||
const labelBoundaries = searchableSelectSource.match(/dbx-searchable-select-option-label min-w-0 flex-1 overflow-hidden/g) ?? [];
|
||||
|
||||
expect(labelBoundaries).toHaveLength(3);
|
||||
});
|
||||
|
||||
it("truncates long data transfer connection labels without shrinking their icons", () => {
|
||||
const truncatedConnectionLabels = dataTransferDialogSource.match(/<span class="min-w-0 flex-1 truncate">\{\{ label \}\}<\/span>/g) ?? [];
|
||||
const fixedConnectionIcons = dataTransferDialogSource.match(/class="h-3\.5 w-3\.5 shrink-0"/g) ?? [];
|
||||
|
||||
expect(truncatedConnectionLabels).toHaveLength(2);
|
||||
expect(fixedConnectionIcons).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
Loading…
Reference in New Issue