feat: suporte para selecionar campos na tabela
This commit is contained in:
parent
7dc071373a
commit
0886fd5c3e
16 changed files with 5867 additions and 4684 deletions
9715
dist/eli-vue.es.js
vendored
9715
dist/eli-vue.es.js
vendored
File diff suppressed because one or more lines are too long
99
dist/eli-vue.umd.js
vendored
99
dist/eli-vue.umd.js
vendored
File diff suppressed because one or more lines are too long
|
|
@ -11,6 +11,11 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<tipoEliTabelaConsulta<any>>;
|
||||
required: true;
|
||||
};
|
||||
/** Array de itens selecionados (v-model:selecionados) */
|
||||
selecionados: {
|
||||
type: PropType<unknown[]>;
|
||||
default: () => never[];
|
||||
};
|
||||
}>, {
|
||||
isDev: boolean;
|
||||
tabela: import("vue").ComputedRef<tipoEliTabelaConsulta<any>>;
|
||||
|
|
@ -77,6 +82,12 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
temColunasInvisiveis: import("vue").ComputedRef<boolean>;
|
||||
colunasInvisiveisEfetivas: import("vue").ComputedRef<tipoEliColuna<any>[]>;
|
||||
linhasExpandidas: import("vue").Ref<Record<number, boolean>, Record<number, boolean>>;
|
||||
mostrarSelecao: import("vue").ComputedRef<boolean>;
|
||||
isSelecionado: (linha: unknown) => boolean;
|
||||
alternarSelecao: (linha: unknown) => void;
|
||||
todosSelecionados: import("vue").ComputedRef<boolean>;
|
||||
algunsSelecionados: import("vue").ComputedRef<boolean>;
|
||||
alternarSelecaoTodos: (forcarMarcar?: boolean) => void;
|
||||
abrirModalColunas: () => void;
|
||||
abrirModalFiltro: () => void;
|
||||
fecharModalColunas: () => void;
|
||||
|
|
@ -129,13 +140,22 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
top: number;
|
||||
left: number;
|
||||
}>;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, "update:selecionados"[], "update:selecionados", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
/** Configuração principal da tabela (colunas, consulta e ações) */
|
||||
tabela: {
|
||||
type: PropType<tipoEliTabelaConsulta<any>>;
|
||||
required: true;
|
||||
};
|
||||
}>> & Readonly<{}>, {}, {}, {
|
||||
/** Array de itens selecionados (v-model:selecionados) */
|
||||
selecionados: {
|
||||
type: PropType<unknown[]>;
|
||||
default: () => never[];
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onUpdate:selecionados"?: ((...args: any[]) => any) | undefined;
|
||||
}>, {
|
||||
selecionados: unknown[];
|
||||
}, {}, {
|
||||
EliTabelaCabecalho: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||
exibirBusca: {
|
||||
type: BooleanConstructor;
|
||||
|
|
@ -366,6 +386,18 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<"asc" | "desc">;
|
||||
required: true;
|
||||
};
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
todosSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
algunsSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
}>, {
|
||||
ArrowUp: import("@lucide/vue").LucideIcon;
|
||||
ArrowDown: import("@lucide/vue").LucideIcon;
|
||||
|
|
@ -373,6 +405,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
emitAlternarOrdenacao: (chave: string) => void;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||
alternarOrdenacao(chave: string): boolean;
|
||||
"alternar-selecao-todos": () => true;
|
||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
colunas: {
|
||||
type: PropType<Array<tipoEliColuna<any>>>;
|
||||
|
|
@ -394,10 +427,26 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<"asc" | "desc">;
|
||||
required: true;
|
||||
};
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
todosSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
algunsSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onAlternar-selecao-todos"?: (() => any) | undefined;
|
||||
onAlternarOrdenacao?: ((chave: string) => any) | undefined;
|
||||
}>, {
|
||||
mostrarSelecao: boolean;
|
||||
colunaOrdenacao: string | null;
|
||||
todosSelecionados: boolean;
|
||||
algunsSelecionados: boolean;
|
||||
}, {}, {
|
||||
ArrowUp: import("@lucide/vue").LucideIcon;
|
||||
ArrowDown: import("@lucide/vue").LucideIcon;
|
||||
|
|
@ -443,6 +492,18 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<(indice: number) => void>;
|
||||
required: true;
|
||||
};
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
isSelecionado: {
|
||||
type: PropType<(linha: unknown) => boolean>;
|
||||
required: true;
|
||||
};
|
||||
alternarSelecao: {
|
||||
type: PropType<(linha: unknown) => void>;
|
||||
required: true;
|
||||
};
|
||||
}>, {
|
||||
ChevronRight: import("@lucide/vue").LucideIcon;
|
||||
ChevronDown: import("@lucide/vue").LucideIcon;
|
||||
|
|
@ -487,7 +548,21 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<(indice: number) => void>;
|
||||
required: true;
|
||||
};
|
||||
}>> & Readonly<{}>, {}, {}, {
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
isSelecionado: {
|
||||
type: PropType<(linha: unknown) => boolean>;
|
||||
required: true;
|
||||
};
|
||||
alternarSelecao: {
|
||||
type: PropType<(linha: unknown) => void>;
|
||||
required: true;
|
||||
};
|
||||
}>> & Readonly<{}>, {
|
||||
mostrarSelecao: boolean;
|
||||
}, {}, {
|
||||
EliTabelaCelula: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||
celula: {
|
||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
||||
|
|
@ -828,11 +903,13 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
}>, {
|
||||
visiveisLocal: import("vue").Ref<string[], string[]>;
|
||||
invisiveisLocal: import("vue").Ref<string[], string[]>;
|
||||
itemSendoArrastado: import("vue").Ref<string | null, string | null>;
|
||||
emitFechar: () => void;
|
||||
emitSalvar: () => void;
|
||||
onDragStart: (e: DragEvent, rotulo: string, origem: "visiveis" | "invisiveis", index: number) => void;
|
||||
onDropItem: (e: DragEvent, destino: "visiveis" | "invisiveis", index: number) => void;
|
||||
onDropLista: (e: DragEvent, destino: "visiveis" | "invisiveis", _index: number | null) => void;
|
||||
onDragStart: (e: DragEvent, rotulo: string) => void;
|
||||
onDragEnd: () => void;
|
||||
onDragOverItem: (alvoRotulo: string, destino: "visiveis" | "invisiveis") => void;
|
||||
onDragOverLista: (destino: "visiveis" | "invisiveis") => void;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||
fechar(): true;
|
||||
salvar(_config: EliTabelaColunasConfig): true;
|
||||
|
|
|
|||
|
|
@ -43,6 +43,18 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<(indice: number) => void>;
|
||||
required: true;
|
||||
};
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
isSelecionado: {
|
||||
type: PropType<(linha: unknown) => boolean>;
|
||||
required: true;
|
||||
};
|
||||
alternarSelecao: {
|
||||
type: PropType<(linha: unknown) => void>;
|
||||
required: true;
|
||||
};
|
||||
}>, {
|
||||
ChevronRight: import("@lucide/vue").LucideIcon;
|
||||
ChevronDown: import("@lucide/vue").LucideIcon;
|
||||
|
|
@ -87,7 +99,21 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<(indice: number) => void>;
|
||||
required: true;
|
||||
};
|
||||
}>> & Readonly<{}>, {}, {}, {
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
isSelecionado: {
|
||||
type: PropType<(linha: unknown) => boolean>;
|
||||
required: true;
|
||||
};
|
||||
alternarSelecao: {
|
||||
type: PropType<(linha: unknown) => void>;
|
||||
required: true;
|
||||
};
|
||||
}>> & Readonly<{}>, {
|
||||
mostrarSelecao: boolean;
|
||||
}, {}, {
|
||||
EliTabelaCelula: import("vue").DefineComponent<import("vue").ExtractPropTypes<{
|
||||
celula: {
|
||||
type: PropType<import("./types-eli-tabela").tipoComponenteCelula>;
|
||||
|
|
|
|||
|
|
@ -23,6 +23,18 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<"asc" | "desc">;
|
||||
required: true;
|
||||
};
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
todosSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
algunsSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
}>, {
|
||||
ArrowUp: import("@lucide/vue").LucideIcon;
|
||||
ArrowDown: import("@lucide/vue").LucideIcon;
|
||||
|
|
@ -30,6 +42,7 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
emitAlternarOrdenacao: (chave: string) => void;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||
alternarOrdenacao(chave: string): boolean;
|
||||
"alternar-selecao-todos": () => true;
|
||||
}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
|
||||
colunas: {
|
||||
type: PropType<Array<tipoEliColuna<any>>>;
|
||||
|
|
@ -51,10 +64,26 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
type: PropType<"asc" | "desc">;
|
||||
required: true;
|
||||
};
|
||||
mostrarSelecao: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
todosSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
algunsSelecionados: {
|
||||
type: BooleanConstructor;
|
||||
default: boolean;
|
||||
};
|
||||
}>> & Readonly<{
|
||||
"onAlternar-selecao-todos"?: (() => any) | undefined;
|
||||
onAlternarOrdenacao?: ((chave: string) => any) | undefined;
|
||||
}>, {
|
||||
mostrarSelecao: boolean;
|
||||
colunaOrdenacao: string | null;
|
||||
todosSelecionados: boolean;
|
||||
algunsSelecionados: boolean;
|
||||
}, {}, {
|
||||
ArrowUp: import("@lucide/vue").LucideIcon;
|
||||
ArrowDown: import("@lucide/vue").LucideIcon;
|
||||
|
|
|
|||
|
|
@ -24,11 +24,13 @@ declare const __VLS_export: import("vue").DefineComponent<import("vue").ExtractP
|
|||
}>, {
|
||||
visiveisLocal: import("vue").Ref<string[], string[]>;
|
||||
invisiveisLocal: import("vue").Ref<string[], string[]>;
|
||||
itemSendoArrastado: import("vue").Ref<string | null, string | null>;
|
||||
emitFechar: () => void;
|
||||
emitSalvar: () => void;
|
||||
onDragStart: (e: DragEvent, rotulo: string, origem: OrigemLista, index: number) => void;
|
||||
onDropItem: (e: DragEvent, destino: OrigemLista, index: number) => void;
|
||||
onDropLista: (e: DragEvent, destino: OrigemLista, _index: number | null) => void;
|
||||
onDragStart: (e: DragEvent, rotulo: string) => void;
|
||||
onDragEnd: () => void;
|
||||
onDragOverItem: (alvoRotulo: string, destino: OrigemLista) => void;
|
||||
onDragOverLista: (destino: OrigemLista) => void;
|
||||
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
|
||||
fechar(): true;
|
||||
salvar(_config: EliTabelaColunasConfig): true;
|
||||
|
|
|
|||
|
|
@ -72,6 +72,10 @@ export type tipoEliTabelaConsulta<T> = {
|
|||
nome: string;
|
||||
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
||||
mostrarCaixaDeBusca?: boolean;
|
||||
/** Habilita seleção múltipla (checkboxes) nas linhas da tabela. */
|
||||
mostrar_selecao?: boolean;
|
||||
/** Chave (ex: "id") para identificar unicamente a linha nas seleções entre páginas. */
|
||||
chave_selecao?: keyof T;
|
||||
/** Lista de colunas da tabela. */
|
||||
colunas: tipoEliColuna<T>[];
|
||||
/** Quantidade de registros solicitados por consulta (padrão `10`). */
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "eli-vue",
|
||||
"version": "0.1.128",
|
||||
"version": "0.1.144",
|
||||
"private": false,
|
||||
"main": "./dist/eli-vue.umd.js",
|
||||
"module": "./dist/eli-vue.es.js",
|
||||
|
|
|
|||
16
pnpm-lock.yaml
generated
16
pnpm-lock.yaml
generated
|
|
@ -19,7 +19,7 @@ importers:
|
|||
version: 1.11.19
|
||||
p-comuns:
|
||||
specifier: git+https://git2.idz.one/publico/_comuns.git
|
||||
version: git+https://git2.idz.one/publico/_comuns.git#64ddd6ad8af5e09a81d247fb1b23c2b05731d321(cross-fetch@4.1.0)(dayjs@1.11.19)(uuid@13.0.0)(zod@4.3.6)
|
||||
version: git+https://git2.idz.one/publico/_comuns.git#64ddd6ad8af5e09a81d247fb1b23c2b05731d321(cross-fetch@4.1.0)(dayjs@1.11.19)(uuid@13.0.0)(zod@4.4.3)
|
||||
p-respostas:
|
||||
specifier: git+https://git2.idz.one/publico/_respostas.git
|
||||
version: git+https://git2.idz.one/publico/_respostas.git#8c24d790ace7255404745dcbdf12c5396e8b9843(cross-fetch@4.1.0)(dayjs@1.11.19)(uuid@13.0.0)
|
||||
|
|
@ -27,8 +27,8 @@ importers:
|
|||
specifier: ^13.0.0
|
||||
version: 13.0.0
|
||||
zod:
|
||||
specifier: 4.3.6
|
||||
version: 4.3.6
|
||||
specifier: 4.4.3
|
||||
version: 4.4.3
|
||||
devDependencies:
|
||||
'@biomejs/biome':
|
||||
specifier: 2.4.12
|
||||
|
|
@ -837,8 +837,8 @@ packages:
|
|||
zod@4.1.4:
|
||||
resolution: {integrity: sha512-2YqJuWkU6IIK9qcE4k1lLLhyZ6zFw7XVRdQGpV97jEIZwTrscUw+DY31Xczd8nwaoksyJUIxCojZXwckJovWxA==}
|
||||
|
||||
zod@4.3.6:
|
||||
resolution: {integrity: sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==}
|
||||
zod@4.4.3:
|
||||
resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==}
|
||||
|
||||
snapshots:
|
||||
|
||||
|
|
@ -1315,12 +1315,12 @@ snapshots:
|
|||
uuid: 13.0.0
|
||||
zod: 4.1.4
|
||||
|
||||
p-comuns@git+https://git2.idz.one/publico/_comuns.git#64ddd6ad8af5e09a81d247fb1b23c2b05731d321(cross-fetch@4.1.0)(dayjs@1.11.19)(uuid@13.0.0)(zod@4.3.6):
|
||||
p-comuns@git+https://git2.idz.one/publico/_comuns.git#64ddd6ad8af5e09a81d247fb1b23c2b05731d321(cross-fetch@4.1.0)(dayjs@1.11.19)(uuid@13.0.0)(zod@4.4.3):
|
||||
dependencies:
|
||||
cross-fetch: 4.1.0
|
||||
dayjs: 1.11.19
|
||||
uuid: 13.0.0
|
||||
zod: 4.3.6
|
||||
zod: 4.4.3
|
||||
|
||||
p-respostas@git+https://git2.idz.one/publico/_respostas.git#8c24d790ace7255404745dcbdf12c5396e8b9843(cross-fetch@4.1.0)(dayjs@1.11.19)(uuid@13.0.0):
|
||||
dependencies:
|
||||
|
|
@ -1466,4 +1466,4 @@ snapshots:
|
|||
|
||||
zod@4.1.4: {}
|
||||
|
||||
zod@4.3.6: {}
|
||||
zod@4.4.3: {}
|
||||
|
|
|
|||
|
|
@ -11,6 +11,20 @@
|
|||
overflow: visible;
|
||||
}
|
||||
|
||||
/* Corrige o vazamento (pontas quadradas) do fundo dos th/td nas bordas arredondadas da tabela */
|
||||
.eli-tabela__table thead tr:first-child th:first-child {
|
||||
border-top-left-radius: 11px;
|
||||
}
|
||||
.eli-tabela__table thead tr:first-child th:last-child {
|
||||
border-top-right-radius: 11px;
|
||||
}
|
||||
.eli-tabela__table tbody tr:last-child td:first-child {
|
||||
border-bottom-left-radius: 11px;
|
||||
}
|
||||
.eli-tabela__table tbody tr:last-child td:last-child {
|
||||
border-bottom-right-radius: 11px;
|
||||
}
|
||||
|
||||
.eli-tabela__tbody {
|
||||
overflow: visible;
|
||||
}
|
||||
|
|
@ -66,7 +80,7 @@
|
|||
}
|
||||
|
||||
.eli-tabela__th-botao--ativo {
|
||||
color: rgba(37, 99, 235, 0.95);
|
||||
color: rgba(15, 23, 42, 0.85);
|
||||
}
|
||||
|
||||
.eli-tabela__th-texto {
|
||||
|
|
@ -395,3 +409,70 @@
|
|||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
|
||||
/* =========================================
|
||||
* Seleção (Checkboxes)
|
||||
* ========================================= */
|
||||
.eli-tabela__th--selecao,
|
||||
.eli-tabela__td--selecao {
|
||||
width: 48px;
|
||||
min-width: 48px;
|
||||
max-width: 48px;
|
||||
text-align: center;
|
||||
padding: 0 8px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.eli-tabela__checkbox {
|
||||
appearance: none;
|
||||
-webkit-appearance: none;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
cursor: pointer;
|
||||
border: 2px solid rgba(0, 0, 0, 0.54);
|
||||
border-radius: 2px;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
position: relative;
|
||||
transition: all 0.2s ease-in-out;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.eli-tabela__checkbox:hover {
|
||||
border-color: rgba(0, 0, 0, 0.87);
|
||||
}
|
||||
|
||||
.eli-tabela__checkbox:checked,
|
||||
.eli-tabela__checkbox:indeterminate {
|
||||
background-color: #1976d2;
|
||||
border-color: #1976d2;
|
||||
}
|
||||
|
||||
.eli-tabela__checkbox:checked::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
left: 4px;
|
||||
width: 4px;
|
||||
height: 9px;
|
||||
border: solid white;
|
||||
border-width: 0 2px 2px 0;
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
|
||||
.eli-tabela__checkbox:indeterminate::after {
|
||||
content: '';
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 2px;
|
||||
width: 8px;
|
||||
height: 2px;
|
||||
background-color: white;
|
||||
border-radius: 1px;
|
||||
}
|
||||
|
||||
.eli-tabela__checkbox:focus-visible {
|
||||
box-shadow: 0 0 0 2px rgba(25, 118, 210, 0.3);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -45,7 +45,11 @@
|
|||
:temColunasInvisiveis="temColunasInvisiveis"
|
||||
:colunaOrdenacao="colunaOrdenacao"
|
||||
:direcaoOrdenacao="direcaoOrdenacao"
|
||||
:mostrarSelecao="mostrarSelecao"
|
||||
:todosSelecionados="todosSelecionados"
|
||||
:algunsSelecionados="algunsSelecionados"
|
||||
@alternar-ordenacao="alternarOrdenacao"
|
||||
@alternar-selecao-todos="alternarSelecaoTodos"
|
||||
/>
|
||||
|
||||
<tbody v-if="carregando || Boolean(erro) || !linhas.length">
|
||||
|
|
@ -73,6 +77,9 @@
|
|||
:possuiAcoes="possuiAcoes"
|
||||
:toggleMenu="toggleMenu"
|
||||
:alternarLinhaExpandida="alternarLinhaExpandida"
|
||||
:mostrarSelecao="mostrarSelecao"
|
||||
:isSelecionado="isSelecionado"
|
||||
:alternarSelecao="alternarSelecao"
|
||||
/>
|
||||
</table>
|
||||
|
||||
|
|
@ -165,8 +172,14 @@ export default defineComponent({
|
|||
type: Object as PropType<tipoEliTabelaConsulta<any>>,
|
||||
required: true,
|
||||
},
|
||||
/** Array de itens selecionados (v-model:selecionados) */
|
||||
selecionados: {
|
||||
type: Array as PropType<unknown[]>,
|
||||
default: () => [],
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
emits: ["update:selecionados"],
|
||||
setup(props, { emit }) {
|
||||
/** Flag para habilitar elementos de debug */
|
||||
const isDev = import.meta.env.DEV
|
||||
/** Estados de carregamento/erro e dados retornados */
|
||||
|
|
@ -258,6 +271,84 @@ export default defineComponent({
|
|||
/** Alias reativo da prop tabela */
|
||||
const tabela = computed(() => props.tabela)
|
||||
|
||||
/** Seleção Múltipla */
|
||||
const mostrarSelecao = computed(() => Boolean(props.tabela.mostrar_selecao))
|
||||
const chaveSelecao = computed(
|
||||
() => props.tabela.chave_selecao as string | undefined,
|
||||
)
|
||||
|
||||
function obterChaveLinha(linha: unknown): unknown {
|
||||
if (chaveSelecao.value && linha && typeof linha === "object") {
|
||||
return (linha as Record<string, unknown>)[chaveSelecao.value]
|
||||
}
|
||||
return linha
|
||||
}
|
||||
|
||||
function isSelecionado(linha: unknown): boolean {
|
||||
const chave = obterChaveLinha(linha)
|
||||
if (chaveSelecao.value) {
|
||||
return props.selecionados.some((s) => obterChaveLinha(s) === chave)
|
||||
}
|
||||
return props.selecionados.includes(linha)
|
||||
}
|
||||
|
||||
function alternarSelecao(linha: unknown) {
|
||||
const atual = [...props.selecionados]
|
||||
const chave = obterChaveLinha(linha)
|
||||
|
||||
let index = -1
|
||||
if (chaveSelecao.value) {
|
||||
index = atual.findIndex((s) => obterChaveLinha(s) === chave)
|
||||
} else {
|
||||
index = atual.indexOf(linha)
|
||||
}
|
||||
|
||||
if (index === -1) {
|
||||
atual.push(linha)
|
||||
} else {
|
||||
atual.splice(index, 1)
|
||||
}
|
||||
emit("update:selecionados", atual)
|
||||
}
|
||||
|
||||
const todosSelecionados = computed(() => {
|
||||
if (linhasPaginadas.value.length === 0) return false
|
||||
return linhasPaginadas.value.every((linha) => isSelecionado(linha))
|
||||
})
|
||||
|
||||
const algunsSelecionados = computed(() => {
|
||||
if (linhasPaginadas.value.length === 0) return false
|
||||
return (
|
||||
linhasPaginadas.value.some((linha) => isSelecionado(linha)) &&
|
||||
!todosSelecionados.value
|
||||
)
|
||||
})
|
||||
|
||||
function alternarSelecaoTodos(forcarMarcar?: boolean) {
|
||||
const marcarTodos = forcarMarcar ?? !todosSelecionados.value
|
||||
let atual = [...props.selecionados]
|
||||
|
||||
if (marcarTodos) {
|
||||
// Adiciona os que faltam na página atual
|
||||
for (const linha of linhasPaginadas.value) {
|
||||
if (!isSelecionado(linha)) {
|
||||
atual.push(linha)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Remove os da página atual
|
||||
const chavesPagina = linhasPaginadas.value.map(obterChaveLinha)
|
||||
if (chaveSelecao.value) {
|
||||
atual = atual.filter(
|
||||
(s) => !chavesPagina.includes(obterChaveLinha(s)),
|
||||
)
|
||||
} else {
|
||||
atual = atual.filter((s) => !chavesPagina.includes(s))
|
||||
}
|
||||
}
|
||||
emit("update:selecionados", atual)
|
||||
}
|
||||
|
||||
/** Exibição da busca e ações do cabeçalho */
|
||||
const exibirBusca = computed(() =>
|
||||
Boolean(props.tabela.mostrarCaixaDeBusca),
|
||||
|
|
@ -859,6 +950,14 @@ export default defineComponent({
|
|||
colunasInvisiveisEfetivas,
|
||||
linhasExpandidas,
|
||||
|
||||
// selecao
|
||||
mostrarSelecao,
|
||||
isSelecionado,
|
||||
alternarSelecao,
|
||||
todosSelecionados,
|
||||
algunsSelecionados,
|
||||
alternarSelecaoTodos,
|
||||
|
||||
abrirModalColunas,
|
||||
abrirModalFiltro,
|
||||
fecharModalColunas,
|
||||
|
|
|
|||
|
|
@ -25,6 +25,17 @@
|
|||
</button>
|
||||
</td>
|
||||
|
||||
<td v-if="mostrarSelecao" class="eli-tabela__td eli-tabela__td--selecao" :key="`td-${i}-selecao`">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="eli-tabela__checkbox"
|
||||
:checked="isSelecionado(linha)"
|
||||
@change="alternarSelecao(linha)"
|
||||
@click.stop
|
||||
aria-label="Selecionar linha"
|
||||
/>
|
||||
</td>
|
||||
|
||||
<td
|
||||
v-for="(coluna, j) in colunas"
|
||||
:key="`td-${i}-${j}`"
|
||||
|
|
@ -63,7 +74,7 @@
|
|||
>
|
||||
<td
|
||||
class="eli-tabela__td eli-tabela__td--detalhes"
|
||||
:colspan="(temColunasInvisiveis ? 1 : 0) + colunas.length + (temAcoes ? 1 : 0)"
|
||||
:colspan="(temColunasInvisiveis ? 1 : 0) + (mostrarSelecao ? 1 : 0) + colunas.length + (temAcoes ? 1 : 0)"
|
||||
>
|
||||
<EliTabelaDetalhesLinha :linha="linha" :colunasInvisiveis="colunasInvisiveis" />
|
||||
</td>
|
||||
|
|
@ -131,6 +142,18 @@ export default defineComponent({
|
|||
type: Function as PropType<(indice: number) => void>,
|
||||
required: true,
|
||||
},
|
||||
mostrarSelecao: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
isSelecionado: {
|
||||
type: Function as PropType<(linha: unknown) => boolean>,
|
||||
required: true,
|
||||
},
|
||||
alternarSelecao: {
|
||||
type: Function as PropType<(linha: unknown) => void>,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
return {
|
||||
|
|
|
|||
|
|
@ -3,6 +3,17 @@
|
|||
<tr class="eli-tabela__tr eli-tabela__tr--header">
|
||||
<th v-if="temColunasInvisiveis" class="eli-tabela__th eli-tabela__th--expander" scope="col"></th>
|
||||
|
||||
<th v-if="mostrarSelecao" class="eli-tabela__th eli-tabela__th--selecao" scope="col">
|
||||
<input
|
||||
type="checkbox"
|
||||
class="eli-tabela__checkbox"
|
||||
:checked="todosSelecionados"
|
||||
:indeterminate="algunsSelecionados"
|
||||
@change="$emit('alternar-selecao-todos')"
|
||||
aria-label="Selecionar todos os itens da página"
|
||||
/>
|
||||
</th>
|
||||
|
||||
<th
|
||||
v-for="(coluna, idx) in colunas"
|
||||
:key="`th-${idx}`"
|
||||
|
|
@ -78,11 +89,24 @@ export default defineComponent({
|
|||
type: String as PropType<"asc" | "desc">,
|
||||
required: true,
|
||||
},
|
||||
mostrarSelecao: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
todosSelecionados: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
algunsSelecionados: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
emits: {
|
||||
alternarOrdenacao(chave: string) {
|
||||
return typeof chave === "string" && chave.length > 0
|
||||
},
|
||||
"alternar-selecao-todos": () => true,
|
||||
},
|
||||
setup(_props, { emit }) {
|
||||
// biome-ignore lint/suspicious/noExplicitAny: dynamic column
|
||||
|
|
|
|||
|
|
@ -1,74 +1,88 @@
|
|||
<template>
|
||||
<div v-if="aberto" class="eli-tabela-modal-colunas__overlay" role="presentation" @click.self="emitFechar">
|
||||
<div
|
||||
class="eli-tabela-modal-colunas__modal"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Configurar colunas"
|
||||
>
|
||||
<header class="eli-tabela-modal-colunas__header">
|
||||
<h3 class="eli-tabela-modal-colunas__titulo">Colunas</h3>
|
||||
<button type="button" class="eli-tabela-modal-colunas__fechar" aria-label="Fechar" @click="emitFechar">
|
||||
×
|
||||
</button>
|
||||
</header>
|
||||
<Teleport to="body">
|
||||
<div v-if="aberto" class="eli-tabela-modal-colunas__overlay" role="presentation" @click.self="emitFechar">
|
||||
<div
|
||||
class="eli-tabela-modal-colunas__modal"
|
||||
role="dialog"
|
||||
aria-modal="true"
|
||||
aria-label="Configurar colunas"
|
||||
>
|
||||
<header class="eli-tabela-modal-colunas__header">
|
||||
<h3 class="eli-tabela-modal-colunas__titulo">Colunas</h3>
|
||||
<button type="button" class="eli-tabela-modal-colunas__fechar" aria-label="Fechar" @click="emitFechar">
|
||||
×
|
||||
</button>
|
||||
</header>
|
||||
|
||||
<div class="eli-tabela-modal-colunas__conteudo">
|
||||
<div class="eli-tabela-modal-colunas__coluna">
|
||||
<div class="eli-tabela-modal-colunas__coluna-titulo">Visíveis</div>
|
||||
<div
|
||||
class="eli-tabela-modal-colunas__lista"
|
||||
@dragover.prevent
|
||||
@drop="(e) => onDropLista(e, 'visiveis', null)"
|
||||
>
|
||||
<div
|
||||
v-for="(rotulo, idx) in visiveisLocal"
|
||||
:key="`vis-${rotulo}`"
|
||||
class="eli-tabela-modal-colunas__item"
|
||||
draggable="true"
|
||||
@dragstart="(e) => onDragStart(e, rotulo, 'visiveis', idx)"
|
||||
@dragover.prevent
|
||||
@drop="(e) => onDropItem(e, 'visiveis', idx)"
|
||||
<div class="eli-tabela-modal-colunas__conteudo">
|
||||
<div class="eli-tabela-modal-colunas__coluna">
|
||||
<div class="eli-tabela-modal-colunas__coluna-titulo">Visíveis</div>
|
||||
<TransitionGroup
|
||||
name="list"
|
||||
tag="div"
|
||||
class="eli-tabela-modal-colunas__lista"
|
||||
@dragover.prevent="onDragOverLista('visiveis')"
|
||||
@drop="onDragEnd"
|
||||
>
|
||||
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
||||
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
||||
</div>
|
||||
<div
|
||||
v-for="rotulo in visiveisLocal"
|
||||
:key="`vis-${rotulo}`"
|
||||
class="eli-tabela-modal-colunas__item"
|
||||
:class="{
|
||||
'eli-tabela-modal-colunas__item--arrastando': itemSendoArrastado === rotulo
|
||||
}"
|
||||
draggable="true"
|
||||
@dragstart="onDragStart($event, rotulo)"
|
||||
@dragend="onDragEnd"
|
||||
@dragover.stop.prevent="onDragOverItem(rotulo, 'visiveis')"
|
||||
@drop.stop.prevent="onDragEnd"
|
||||
>
|
||||
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
||||
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
|
||||
<div class="eli-tabela-modal-colunas__coluna">
|
||||
<div class="eli-tabela-modal-colunas__coluna-titulo">Invisíveis</div>
|
||||
<TransitionGroup
|
||||
name="list"
|
||||
tag="div"
|
||||
class="eli-tabela-modal-colunas__lista"
|
||||
@dragover.prevent="onDragOverLista('invisiveis')"
|
||||
@drop="onDragEnd"
|
||||
>
|
||||
<div
|
||||
v-for="rotulo in invisiveisLocal"
|
||||
:key="`inv-${rotulo}`"
|
||||
class="eli-tabela-modal-colunas__item"
|
||||
:class="{
|
||||
'eli-tabela-modal-colunas__item--arrastando': itemSendoArrastado === rotulo
|
||||
}"
|
||||
draggable="true"
|
||||
@dragstart="onDragStart($event, rotulo)"
|
||||
@dragend="onDragEnd"
|
||||
@dragover.stop.prevent="onDragOverItem(rotulo, 'invisiveis')"
|
||||
@drop.stop.prevent="onDragEnd"
|
||||
>
|
||||
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
||||
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
||||
</div>
|
||||
</TransitionGroup>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="eli-tabela-modal-colunas__coluna">
|
||||
<div class="eli-tabela-modal-colunas__coluna-titulo">Invisíveis</div>
|
||||
<div
|
||||
class="eli-tabela-modal-colunas__lista"
|
||||
@dragover.prevent
|
||||
@drop="(e) => onDropLista(e, 'invisiveis', null)"
|
||||
>
|
||||
<div
|
||||
v-for="(rotulo, idx) in invisiveisLocal"
|
||||
:key="`inv-${rotulo}`"
|
||||
class="eli-tabela-modal-colunas__item"
|
||||
draggable="true"
|
||||
@dragstart="(e) => onDragStart(e, rotulo, 'invisiveis', idx)"
|
||||
@dragover.prevent
|
||||
@drop="(e) => onDropItem(e, 'invisiveis', idx)"
|
||||
>
|
||||
<span class="eli-tabela-modal-colunas__item-handle" aria-hidden="true">⋮⋮</span>
|
||||
<span class="eli-tabela-modal-colunas__item-texto">{{ rotulo }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<footer class="eli-tabela-modal-colunas__footer">
|
||||
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--sec" @click="emitFechar">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--prim" @click="emitSalvar">
|
||||
Salvar
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
|
||||
<footer class="eli-tabela-modal-colunas__footer">
|
||||
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--sec" @click="emitFechar">
|
||||
Cancelar
|
||||
</button>
|
||||
<button type="button" class="eli-tabela-modal-colunas__botao eli-tabela-modal-colunas__botao--prim" @click="emitSalvar">
|
||||
Salvar
|
||||
</button>
|
||||
</footer>
|
||||
</div>
|
||||
</div>
|
||||
</Teleport>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
|
|
@ -78,14 +92,6 @@ import type { tipoEliColuna } from "./types-eli-tabela"
|
|||
|
||||
type OrigemLista = "visiveis" | "invisiveis"
|
||||
|
||||
type DragPayload = {
|
||||
rotulo: string
|
||||
origem: OrigemLista
|
||||
index: number
|
||||
}
|
||||
|
||||
const DRAG_MIME = "application/x-eli-tabela-coluna"
|
||||
|
||||
export default defineComponent({
|
||||
name: "EliTabelaModalColunas",
|
||||
props: {
|
||||
|
|
@ -119,6 +125,8 @@ export default defineComponent({
|
|||
const visiveisLocal = ref<string[]>([])
|
||||
const invisiveisLocal = ref<string[]>([])
|
||||
|
||||
const itemSendoArrastado = ref<string | null>(null)
|
||||
|
||||
function sincronizarEstado() {
|
||||
const todos = props.rotulosColunas
|
||||
const configTemDados =
|
||||
|
|
@ -178,118 +186,66 @@ export default defineComponent({
|
|||
})
|
||||
}
|
||||
|
||||
function writeDragData(e: DragEvent, payload: DragPayload) {
|
||||
try {
|
||||
e.dataTransfer?.setData(DRAG_MIME, JSON.stringify(payload))
|
||||
e.dataTransfer?.setData("text/plain", payload.rotulo)
|
||||
if (e.dataTransfer) {
|
||||
e.dataTransfer.effectAllowed = "move"
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
function onDragStart(e: DragEvent, rotulo: string) {
|
||||
itemSendoArrastado.value = rotulo
|
||||
if (e.dataTransfer) {
|
||||
e.dataTransfer.setData("text/plain", rotulo)
|
||||
e.dataTransfer.effectAllowed = "move"
|
||||
}
|
||||
}
|
||||
|
||||
function readDragData(e: DragEvent): DragPayload | null {
|
||||
try {
|
||||
const raw = e.dataTransfer?.getData(DRAG_MIME)
|
||||
if (!raw) return null
|
||||
const parsed = JSON.parse(raw)
|
||||
if (
|
||||
!parsed ||
|
||||
typeof parsed.rotulo !== "string" ||
|
||||
(parsed.origem !== "visiveis" && parsed.origem !== "invisiveis")
|
||||
) {
|
||||
return null
|
||||
}
|
||||
return parsed as DragPayload
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
function onDragEnd() {
|
||||
itemSendoArrastado.value = null
|
||||
}
|
||||
|
||||
function removerDaOrigem(payload: DragPayload) {
|
||||
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 =
|
||||
payload.origem === "visiveis"
|
||||
? visiveisLocal.value
|
||||
: invisiveisLocal.value
|
||||
const idx = origemArr.indexOf(payload.rotulo)
|
||||
if (idx >= 0) origemArr.splice(idx, 1)
|
||||
}
|
||||
|
||||
function inserirNoDestino(
|
||||
destino: OrigemLista,
|
||||
rotulo: string,
|
||||
index: number | null,
|
||||
) {
|
||||
const arr =
|
||||
origem === "visiveis" ? visiveisLocal.value : invisiveisLocal.value
|
||||
const destinoArr =
|
||||
destino === "visiveis" ? visiveisLocal.value : invisiveisLocal.value
|
||||
// remove duplicatas
|
||||
const existing = arr.indexOf(rotulo)
|
||||
if (existing >= 0) arr.splice(existing, 1)
|
||||
|
||||
if (index === null || index < 0 || index > arr.length) {
|
||||
arr.push(rotulo)
|
||||
} else {
|
||||
arr.splice(index, 0, rotulo)
|
||||
}
|
||||
const dragIdx = origemArr.indexOf(draggedRotulo)
|
||||
const alvoIdx = destinoArr.indexOf(alvoRotulo)
|
||||
|
||||
origemArr.splice(dragIdx, 1)
|
||||
destinoArr.splice(alvoIdx, 0, draggedRotulo)
|
||||
}
|
||||
|
||||
function onDragStart(
|
||||
e: DragEvent,
|
||||
rotulo: string,
|
||||
origem: OrigemLista,
|
||||
index: number,
|
||||
) {
|
||||
writeDragData(e, { rotulo, origem, index })
|
||||
}
|
||||
function onDragOverLista(destino: OrigemLista) {
|
||||
const draggedRotulo = itemSendoArrastado.value
|
||||
if (!draggedRotulo) return
|
||||
|
||||
function onDropItem(e: DragEvent, destino: OrigemLista, index: number) {
|
||||
const payload = readDragData(e)
|
||||
if (!payload) return
|
||||
const destinoArr =
|
||||
destino === "visiveis" ? visiveisLocal.value : invisiveisLocal.value
|
||||
if (destinoArr[destinoArr.length - 1] === draggedRotulo) return
|
||||
|
||||
// remove da origem e insere no destino na posição do item
|
||||
removerDaOrigem(payload)
|
||||
inserirNoDestino(destino, payload.rotulo, index)
|
||||
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)
|
||||
|
||||
// garante que uma coluna não fique nos 2 lados
|
||||
if (destino === "visiveis") {
|
||||
const idxInv = invisiveisLocal.value.indexOf(payload.rotulo)
|
||||
if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1)
|
||||
} else {
|
||||
const idxVis = visiveisLocal.value.indexOf(payload.rotulo)
|
||||
if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1)
|
||||
}
|
||||
}
|
||||
|
||||
function onDropLista(
|
||||
e: DragEvent,
|
||||
destino: OrigemLista,
|
||||
_index: number | null,
|
||||
) {
|
||||
const payload = readDragData(e)
|
||||
if (!payload) return
|
||||
|
||||
removerDaOrigem(payload)
|
||||
inserirNoDestino(destino, payload.rotulo, null)
|
||||
|
||||
if (destino === "visiveis") {
|
||||
const idxInv = invisiveisLocal.value.indexOf(payload.rotulo)
|
||||
if (idxInv >= 0) invisiveisLocal.value.splice(idxInv, 1)
|
||||
} else {
|
||||
const idxVis = visiveisLocal.value.indexOf(payload.rotulo)
|
||||
if (idxVis >= 0) visiveisLocal.value.splice(idxVis, 1)
|
||||
}
|
||||
destinoArr.push(draggedRotulo)
|
||||
}
|
||||
|
||||
return {
|
||||
visiveisLocal,
|
||||
invisiveisLocal,
|
||||
itemSendoArrastado,
|
||||
emitFechar,
|
||||
emitSalvar,
|
||||
onDragStart,
|
||||
onDropItem,
|
||||
onDropLista,
|
||||
onDragEnd,
|
||||
onDragOverItem,
|
||||
onDragOverLista,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
@ -364,6 +320,8 @@ export default defineComponent({
|
|||
border-radius: 12px;
|
||||
padding: 10px;
|
||||
background: rgba(15, 23, 42, 0.01);
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.eli-tabela-modal-colunas__item {
|
||||
|
|
@ -376,6 +334,7 @@ export default defineComponent({
|
|||
background: #fff;
|
||||
cursor: grab;
|
||||
user-select: none;
|
||||
transition: box-shadow 0.15s, opacity 0.15s, transform 0.15s;
|
||||
}
|
||||
|
||||
.eli-tabela-modal-colunas__item + .eli-tabela-modal-colunas__item {
|
||||
|
|
@ -386,6 +345,31 @@ export default defineComponent({
|
|||
cursor: grabbing;
|
||||
}
|
||||
|
||||
.eli-tabela-modal-colunas__item--arrastando {
|
||||
opacity: 0.1;
|
||||
background: #f8fafc;
|
||||
border-style: dashed;
|
||||
}
|
||||
|
||||
/* Animações de reposicionamento e listas do Vue TransitionGroup */
|
||||
.list-move,
|
||||
.list-enter-active,
|
||||
.list-leave-active {
|
||||
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
|
||||
}
|
||||
|
||||
.list-enter-from,
|
||||
.list-leave-to {
|
||||
opacity: 0;
|
||||
transform: scale(0.95);
|
||||
}
|
||||
|
||||
.list-leave-active {
|
||||
/* position absolute para suavizar a animação de saída de outras listas */
|
||||
position: absolute;
|
||||
width: calc(100% - 20px);
|
||||
}
|
||||
|
||||
.eli-tabela-modal-colunas__item-handle {
|
||||
color: rgba(15, 23, 42, 0.55);
|
||||
font-size: 14px;
|
||||
|
|
|
|||
|
|
@ -93,6 +93,10 @@ export type tipoEliTabelaConsulta<T> = {
|
|||
nome: string
|
||||
/** Indica se a caixa de busca deve ser exibida acima da tabela. */
|
||||
mostrarCaixaDeBusca?: boolean
|
||||
/** Habilita seleção múltipla (checkboxes) nas linhas da tabela. */
|
||||
mostrar_selecao?: boolean
|
||||
/** Chave (ex: "id") para identificar unicamente a linha nas seleções entre páginas. */
|
||||
chave_selecao?: keyof T
|
||||
/** Lista de colunas da tabela. */
|
||||
colunas: tipoEliColuna<T>[]
|
||||
/** Quantidade de registros solicitados por consulta (padrão `10`). */
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@
|
|||
<h2>EliTabela</h2>
|
||||
|
||||
<!-- Exemplo: botão de ação "Novo" no cabeçalho que adiciona uma linha -->
|
||||
<EliTabela :tabela="tabelaOk" :key="versaoTabelaOk" />
|
||||
<div style="margin-bottom: 12px">
|
||||
<strong>Selecionados:</strong> {{ selecionados.map(s => s.empreendedor).join(', ') || 'Nenhum' }}
|
||||
</div>
|
||||
<EliTabela :tabela="tabelaOk" :key="versaoTabelaOk" v-model:selecionados="selecionados" />
|
||||
|
||||
<EliTabela :tabela="tabelaVazia" />
|
||||
|
||||
|
|
@ -97,6 +100,7 @@ export default defineComponent({
|
|||
]
|
||||
|
||||
const versaoTabelaOk = ref(0)
|
||||
const selecionados = ref<Linha[]>([])
|
||||
const mostrarModalCadastro = ref(false)
|
||||
const salvando = ref(false)
|
||||
const novoCadastro = ref({
|
||||
|
|
@ -175,6 +179,8 @@ export default defineComponent({
|
|||
nome: "ExemploPlaygroundData",
|
||||
registros_por_consulta: 10,
|
||||
mostrarCaixaDeBusca: true,
|
||||
mostrar_selecao: true,
|
||||
chave_selecao: "empreendedor",
|
||||
acoesTabela: [
|
||||
{
|
||||
posicao: "superior",
|
||||
|
|
@ -300,6 +306,7 @@ export default defineComponent({
|
|||
{
|
||||
chave: "empreendedor",
|
||||
rotulo: "Empreendedor",
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
filtro: (valor: unknown) =>
|
||||
criarFiltro26({
|
||||
// biome-ignore lint/suspicious/noExplicitAny: playground
|
||||
|
|
@ -310,7 +317,8 @@ export default defineComponent({
|
|||
{
|
||||
chave: "documento",
|
||||
rotulo: "Documento",
|
||||
filtro: (valor: unknown) =>
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
filtro: (valor: string) =>
|
||||
criarFiltro26({
|
||||
// biome-ignore lint/suspicious/noExplicitAny: playground
|
||||
documento: { like: valor as string } as any,
|
||||
|
|
@ -323,7 +331,8 @@ export default defineComponent({
|
|||
{
|
||||
chave: "email",
|
||||
rotulo: "E-mail",
|
||||
filtro: (valor: unknown) =>
|
||||
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
||||
filtro: (valor: string) =>
|
||||
criarFiltro26({
|
||||
// biome-ignore lint/suspicious/noExplicitAny: playground
|
||||
email: { like: valor as string } as any,
|
||||
|
|
@ -407,6 +416,7 @@ export default defineComponent({
|
|||
novoCadastro,
|
||||
salvarNovoCadastro,
|
||||
erroCadastro,
|
||||
selecionados,
|
||||
}
|
||||
},
|
||||
})
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue