139 lines
4.8 KiB
TypeScript
139 lines
4.8 KiB
TypeScript
/**
|
|
* useColunasOrdenacao
|
|
* Composable que encapsula a lógica de drag-and-drop e sincronização de estado
|
|
* do modal de configuração de colunas da EliTabela.
|
|
*
|
|
* Responsável por:
|
|
* - Sincronizar colunas visíveis/invisíveis com a configuração persistida
|
|
* - Aplicar ordem salva e adicionar novas colunas ao final
|
|
* - Gerenciar eventos de arrastar-e-soltar entre as duas listas
|
|
*
|
|
* Extraído de `EliTabelaModalColunas.vue` para manter o componente abaixo de 250 linhas.
|
|
*/
|
|
import { type Ref, ref, watch } from "vue"
|
|
import type { EliTabelaColunasConfig } from "./colunasStorage"
|
|
import type { tipoEliColuna } from "./types-eli-tabela"
|
|
|
|
type OrigemLista = "visiveis" | "invisiveis"
|
|
|
|
interface UseColunasOrdenacaoOptions {
|
|
aberto: Ref<boolean>
|
|
rotulosColunas: Ref<string[]>
|
|
configInicial: Ref<EliTabelaColunasConfig>
|
|
// biome-ignore lint/suspicious/noExplicitAny: colunas genéricas — tipo parametrizado no pai
|
|
colunas: Ref<tipoEliColuna<any>[]>
|
|
}
|
|
|
|
/**
|
|
* Composable de drag-and-drop para reordenação e alternância de visibilidade de colunas.
|
|
* Sincroniza automaticamente quando `aberto`, `rotulosColunas`, `configInicial` ou `colunas` mudam.
|
|
*
|
|
* @param options.aberto - Ref que controla se o modal está aberto (gatilho de sincronização)
|
|
* @param options.rotulosColunas - Ref com todos os rótulos de colunas da tabela
|
|
* @param options.configInicial - Ref com a configuração persistida (visíveis + invisíveis)
|
|
* @param options.colunas - Ref com a definição completa das colunas (para ler `visivel: false` padrão)
|
|
* @returns Estado reativo e handlers de drag-and-drop prontos para o template
|
|
*/
|
|
export function useColunasOrdenacao({
|
|
aberto,
|
|
rotulosColunas,
|
|
configInicial,
|
|
colunas,
|
|
}: UseColunasOrdenacaoOptions) {
|
|
const visiveisLocal = ref<string[]>([])
|
|
const invisiveisLocal = ref<string[]>([])
|
|
const itemSendoArrastado = ref<string | null>(null)
|
|
|
|
function sincronizarEstado() {
|
|
const todos = rotulosColunas.value
|
|
const configTemDados =
|
|
(configInicial.value.visiveis?.length ?? 0) > 0 ||
|
|
(configInicial.value.invisiveis?.length ?? 0) > 0
|
|
|
|
const invisiveisPadraoSet = new Set(
|
|
colunas.value.filter((c) => c.visivel === false).map((c) => c.rotulo),
|
|
)
|
|
const invisiveisSet = configTemDados
|
|
? new Set(configInicial.value.invisiveis ?? [])
|
|
: invisiveisPadraoSet
|
|
|
|
const baseVisiveis = todos.filter((r) => !invisiveisSet.has(r))
|
|
const ordemSalva = configInicial.value.visiveis ?? []
|
|
const setVis = new Set(baseVisiveis)
|
|
const ordenadas: string[] = []
|
|
|
|
for (const r of ordemSalva) {
|
|
if (setVis.has(r)) ordenadas.push(r)
|
|
}
|
|
for (const r of baseVisiveis) {
|
|
if (!ordenadas.includes(r)) ordenadas.push(r)
|
|
}
|
|
|
|
visiveisLocal.value = ordenadas
|
|
invisiveisLocal.value = todos.filter((r) => invisiveisSet.has(r))
|
|
}
|
|
|
|
watch(
|
|
() => [aberto.value, rotulosColunas.value, configInicial.value, colunas.value] as const,
|
|
() => {
|
|
if (aberto.value) sincronizarEstado()
|
|
},
|
|
{ deep: true, immediate: true },
|
|
)
|
|
|
|
function onDragStart(e: DragEvent, rotulo: string) {
|
|
itemSendoArrastado.value = rotulo
|
|
if (e.dataTransfer) {
|
|
e.dataTransfer.setData("text/plain", rotulo)
|
|
e.dataTransfer.effectAllowed = "move"
|
|
}
|
|
}
|
|
|
|
function onDragEnd() {
|
|
itemSendoArrastado.value = null
|
|
}
|
|
|
|
function onDragOverItem(alvoRotulo: string, destino: OrigemLista) {
|
|
const draggedRotulo = itemSendoArrastado.value
|
|
if (!draggedRotulo || draggedRotulo === alvoRotulo) return
|
|
|
|
const origemVisIdx = visiveisLocal.value.indexOf(draggedRotulo)
|
|
const origemInvIdx = invisiveisLocal.value.indexOf(draggedRotulo)
|
|
const origem = origemVisIdx >= 0 ? "visiveis" : origemInvIdx >= 0 ? "invisiveis" : null
|
|
if (!origem) return
|
|
|
|
const origemArr = origem === "visiveis" ? visiveisLocal.value : invisiveisLocal.value
|
|
const destinoArr = destino === "visiveis" ? visiveisLocal.value : invisiveisLocal.value
|
|
|
|
const dragIdx = origemArr.indexOf(draggedRotulo)
|
|
const alvoIdx = destinoArr.indexOf(alvoRotulo)
|
|
|
|
origemArr.splice(dragIdx, 1)
|
|
destinoArr.splice(alvoIdx, 0, draggedRotulo)
|
|
}
|
|
|
|
function onDragOverLista(destino: OrigemLista) {
|
|
const draggedRotulo = itemSendoArrastado.value
|
|
if (!draggedRotulo) return
|
|
|
|
const destinoArr = destino === "visiveis" ? visiveisLocal.value : invisiveisLocal.value
|
|
if (destinoArr[destinoArr.length - 1] === draggedRotulo) return
|
|
|
|
const origemVisIdx = visiveisLocal.value.indexOf(draggedRotulo)
|
|
const origemInvIdx = invisiveisLocal.value.indexOf(draggedRotulo)
|
|
if (origemVisIdx >= 0) visiveisLocal.value.splice(origemVisIdx, 1)
|
|
if (origemInvIdx >= 0) invisiveisLocal.value.splice(origemInvIdx, 1)
|
|
|
|
destinoArr.push(draggedRotulo)
|
|
}
|
|
|
|
return {
|
|
visiveisLocal,
|
|
invisiveisLocal,
|
|
itemSendoArrastado,
|
|
onDragStart,
|
|
onDragEnd,
|
|
onDragOverItem,
|
|
onDragOverLista,
|
|
}
|
|
}
|