fix(ui): resolve transition key conflicts in reorderable lists

Add listKeyPrefix prop to ensure unique keys across list instances
Remove enter/leave transition styles to prevent animation glitches
This commit is contained in:
2026-05-01 12:49:08 +08:00
parent 239a2ec3b5
commit bd068ce2f6
3 changed files with 16 additions and 23 deletions

View File

@@ -5,10 +5,12 @@ const props = withDefaults(defineProps<{
items: T[];
itemKey: (item: T) => string | number;
itemLabel: (item: T) => string;
listKeyPrefix?: string;
disabled?: boolean;
handleLabel: (name: string) => string;
handleTitle: string;
}>(), {
listKeyPrefix: '',
disabled: false
});
@@ -28,6 +30,10 @@ function keyFor(item: T): string | number {
return props.itemKey(item);
}
function transitionKeyFor(item: T): string {
return props.listKeyPrefix ? `${props.listKeyPrefix}:${String(keyFor(item))}` : String(keyFor(item));
}
function sameKey(first: string | number, second: string | number): boolean {
return String(first) === String(second);
}
@@ -181,7 +187,7 @@ function handleKeydown(item: T, event: KeyboardEvent) {
<TransitionGroup name="reorderable-list" tag="ul" class="row-list reorderable-list">
<li
v-for="item in items"
:key="keyFor(item)"
:key="transitionKeyFor(item)"
class="reorderable-row"
:class="{
'is-dragging': draggingKey === keyFor(item),

View File

@@ -1061,24 +1061,8 @@ button:disabled,
bottom: -2px;
}
.reorderable-list-move,
.reorderable-list-enter-active,
.reorderable-list-leave-active {
transition:
opacity 0.18s ease,
transform 0.18s ease;
}
.reorderable-list-enter-from,
.reorderable-list-leave-to {
opacity: 0;
transform: translateY(6px);
}
.reorderable-list-leave-active {
position: absolute;
right: 0;
left: 0;
.reorderable-list-move {
transition: transform 0.18s ease;
}
.drag-handle {
@@ -1132,15 +1116,11 @@ button:disabled,
@media (prefers-reduced-motion: reduce) {
.reorderable-row,
.reorderable-list-move,
.reorderable-list-enter-active,
.reorderable-list-leave-active,
.drag-handle {
transition: none;
}
.reorderable-row.is-dragging,
.reorderable-list-enter-from,
.reorderable-list-leave-to,
.drag-handle:active {
transform: none;
}

View File

@@ -563,6 +563,7 @@ onMounted(() => {
:items="checklistRows"
:item-key="checklistKey"
:item-label="checklistLabel"
list-key-prefix="checklist"
:disabled="busy"
:handle-label="dragSortLabel"
:handle-title="t('pages.admin.dragSortTitle')"
@@ -611,6 +612,7 @@ onMounted(() => {
:items="configRows"
:item-key="configKey"
:item-label="configLabel"
:list-key-prefix="`config-${activeConfigType}`"
:disabled="busy"
:handle-label="dragSortLabel"
:handle-title="t('pages.admin.dragSortTitle')"
@@ -662,6 +664,7 @@ onMounted(() => {
:items="languageRows"
:item-key="languageKey"
:item-label="languageLabel"
list-key-prefix="languages"
:disabled="busy"
:handle-label="dragSortLabel"
:handle-title="t('pages.admin.dragSortTitle')"
@@ -690,6 +693,7 @@ onMounted(() => {
:items="pokemonRows"
:item-key="pokemonKey"
:item-label="pokemonLabel"
list-key-prefix="pokemon"
:disabled="busy"
:handle-label="dragSortLabel"
:handle-title="t('pages.admin.dragSortTitle')"
@@ -714,6 +718,7 @@ onMounted(() => {
:items="itemRows"
:item-key="itemKey"
:item-label="itemLabel"
list-key-prefix="items"
:disabled="busy"
:handle-label="dragSortLabel"
:handle-title="t('pages.admin.dragSortTitle')"
@@ -738,6 +743,7 @@ onMounted(() => {
:items="recipeRows"
:item-key="recipeKey"
:item-label="recipeLabel"
list-key-prefix="recipes"
:disabled="busy"
:handle-label="dragSortLabel"
:handle-title="t('pages.admin.dragSortTitle')"
@@ -762,6 +768,7 @@ onMounted(() => {
:items="habitatRows"
:item-key="habitatKey"
:item-label="habitatLabel"
list-key-prefix="habitats"
:disabled="busy"
:handle-label="dragSortLabel"
:handle-title="t('pages.admin.dragSortTitle')"