.
This commit is contained in:
parent
99f8b5fb8e
commit
07047f9984
@ -1,12 +1,26 @@
|
|||||||
import { Button, Separator, Tooltip, TooltipContent, TooltipTrigger } from '@repo/shadcn-ui/components'
|
import {
|
||||||
import { cn } from '@repo/shadcn-ui/lib/utils'
|
Button,
|
||||||
import { Table } from "@tanstack/react-table"
|
Separator,
|
||||||
import { ArrowDownIcon, ArrowUpIcon, CopyPlusIcon, PlusIcon, ScanIcon, TrashIcon } from 'lucide-react'
|
Tooltip,
|
||||||
import React from 'react'
|
TooltipContent,
|
||||||
import { useTranslation } from "../../locales/i18n.ts"
|
TooltipTrigger,
|
||||||
import { DataTableViewOptions } from './data-table-view-options.tsx'
|
} from "@repo/shadcn-ui/components";
|
||||||
import { DataTableMeta } from './data-table.tsx'
|
import { cn } from "@repo/shadcn-ui/lib/utils";
|
||||||
|
import type { Table } from "@tanstack/react-table";
|
||||||
|
import {
|
||||||
|
ArrowDownIcon,
|
||||||
|
ArrowUpIcon,
|
||||||
|
CopyPlusIcon,
|
||||||
|
PlusIcon,
|
||||||
|
ScanIcon,
|
||||||
|
TrashIcon,
|
||||||
|
} from "lucide-react";
|
||||||
|
import React from "react";
|
||||||
|
|
||||||
|
import { useTranslation } from "../../locales/i18n.ts";
|
||||||
|
|
||||||
|
import type { DataTableMeta } from "./data-table.tsx";
|
||||||
|
import { DataTableViewOptions } from "./data-table-view-options.tsx";
|
||||||
|
|
||||||
interface DataTableToolbarProps<TData> {
|
interface DataTableToolbarProps<TData> {
|
||||||
table: Table<TData>;
|
table: Table<TData>;
|
||||||
@ -17,7 +31,7 @@ interface DataTableToolbarProps<TData> {
|
|||||||
export function DataTableToolbar<TData>({
|
export function DataTableToolbar<TData>({
|
||||||
table,
|
table,
|
||||||
showViewOptions = true,
|
showViewOptions = true,
|
||||||
className
|
className,
|
||||||
}: DataTableToolbarProps<TData>) {
|
}: DataTableToolbarProps<TData>) {
|
||||||
const { t } = useTranslation();
|
const { t } = useTranslation();
|
||||||
const meta = table.options.meta as DataTableMeta<TData> | undefined;
|
const meta = table.options.meta as DataTableMeta<TData> | undefined;
|
||||||
@ -32,10 +46,7 @@ export function DataTableToolbar<TData>({
|
|||||||
const hasSelection = selectedCount > 0;
|
const hasSelection = selectedCount > 0;
|
||||||
|
|
||||||
// Índices seleccionados (memoizado)
|
// Índices seleccionados (memoizado)
|
||||||
const selectedIndexes = React.useMemo(
|
const selectedIndexes = React.useMemo(() => selectedRows.map((r) => r.index), [selectedRows]);
|
||||||
() => selectedRows.map((r) => r.index),
|
|
||||||
[selectedRows]
|
|
||||||
);
|
|
||||||
|
|
||||||
const handleAdd = React.useCallback(() => {
|
const handleAdd = React.useCallback(() => {
|
||||||
if (!readOnly) meta?.tableOps?.onAdd?.(table);
|
if (!readOnly) meta?.tableOps?.onAdd?.(table);
|
||||||
@ -63,25 +74,20 @@ export function DataTableToolbar<TData>({
|
|||||||
|
|
||||||
// Render principal
|
// Render principal
|
||||||
return (
|
return (
|
||||||
<div
|
<div className={cn("flex items-center justify-between gap-2 py-2 bg-transparent", className)}>
|
||||||
className={cn(
|
|
||||||
"flex items-center justify-between gap-2 py-2 bg-transparent",
|
|
||||||
className
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
{/* IZQUIERDA: acciones + contador */}
|
{/* IZQUIERDA: acciones + contador */}
|
||||||
<div className="flex flex-1 items-center gap-3 flex-wrap">
|
<div className="flex flex-1 items-center gap-3 flex-wrap">
|
||||||
{/* Botón añadir */}
|
{/* Botón añadir */}
|
||||||
{!readOnly && meta?.tableOps?.onAdd && (
|
{!readOnly && meta?.tableOps?.onAdd && (
|
||||||
<Button
|
<Button
|
||||||
className='cursor-pointer'
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
variant={'outline'}
|
|
||||||
onClick={handleAdd}
|
|
||||||
aria-label={t("components.datatable.actions.add")}
|
aria-label={t("components.datatable.actions.add")}
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={handleAdd}
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
variant={"outline"}
|
||||||
>
|
>
|
||||||
<PlusIcon className="size-4 mr-1" aria-hidden="true" />
|
<PlusIcon aria-hidden="true" className="size-4 mr-1" />
|
||||||
<span>{t("components.datatable.actions.add")}</span>
|
<span>{t("components.datatable.actions.add")}</span>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
@ -89,18 +95,18 @@ export function DataTableToolbar<TData>({
|
|||||||
{/* Acciones sobre selección */}
|
{/* Acciones sobre selección */}
|
||||||
{hasSelection && (
|
{hasSelection && (
|
||||||
<>
|
<>
|
||||||
<Separator orientation="vertical" className="h-5 mx-1" />
|
<Separator className="h-5 mx-1" orientation="vertical" />
|
||||||
|
|
||||||
{!readOnly && meta?.bulkOps?.duplicateSelected && (
|
{!readOnly && meta?.bulkOps?.duplicateSelected && (
|
||||||
<Button
|
<Button
|
||||||
className='cursor-pointer'
|
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={handleDuplicateSelected}
|
|
||||||
aria-label={t("components.datatable.actions.duplicate")}
|
aria-label={t("components.datatable.actions.duplicate")}
|
||||||
|
className="cursor-pointer"
|
||||||
|
onClick={handleDuplicateSelected}
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
>
|
>
|
||||||
<CopyPlusIcon className="size-4 mr-1" aria-hidden="true" />
|
<CopyPlusIcon aria-hidden="true" className="size-4 mr-1" />
|
||||||
<span>{t("components.datatable.actions.duplicate")}</span>
|
<span>{t("components.datatable.actions.duplicate")}</span>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
@ -109,18 +115,16 @@ export function DataTableToolbar<TData>({
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={handleMoveSelectedUp}
|
|
||||||
aria-label={t("components.datatable.actions.move_up")}
|
aria-label={t("components.datatable.actions.move_up")}
|
||||||
|
onClick={handleMoveSelectedUp}
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
>
|
>
|
||||||
<ArrowUpIcon className="size-4" aria-hidden="true" />
|
<ArrowUpIcon aria-hidden="true" className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>{t("components.datatable.actions.move_up")}</TooltipContent>
|
||||||
{t("components.datatable.actions.move_up")}
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@ -128,71 +132,56 @@ export function DataTableToolbar<TData>({
|
|||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={handleMoveSelectedDown}
|
|
||||||
aria-label={t("components.datatable.actions.move_down")}
|
aria-label={t("components.datatable.actions.move_down")}
|
||||||
|
onClick={handleMoveSelectedDown}
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
variant="outline"
|
||||||
>
|
>
|
||||||
<ArrowDownIcon className="size-4" aria-hidden="true" />
|
<ArrowDownIcon aria-hidden="true" className="size-4" />
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>{t("components.datatable.actions.move_down")}</TooltipContent>
|
||||||
{t("components.datatable.actions.move_down")}
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{!readOnly && meta?.bulkOps?.removeSelected && (
|
{!readOnly && meta?.bulkOps?.removeSelected && (
|
||||||
<>
|
<>
|
||||||
<Separator
|
<Separator className="h-5 mx-1 w-[1px] bg-red-500/70" orientation="vertical" />
|
||||||
orientation="vertical"
|
|
||||||
className="h-5 mx-1 w-[1px] bg-red-500/70"
|
|
||||||
/>
|
|
||||||
<Button
|
<Button
|
||||||
type="button"
|
|
||||||
size="sm"
|
|
||||||
variant="destructive"
|
|
||||||
onClick={handleRemoveSelected}
|
|
||||||
aria-label={t("components.datatable.actions.remove")}
|
aria-label={t("components.datatable.actions.remove")}
|
||||||
|
onClick={handleRemoveSelected}
|
||||||
|
size="sm"
|
||||||
|
type="button"
|
||||||
|
variant="destructive"
|
||||||
>
|
>
|
||||||
<TrashIcon className="size-4 mr-1" aria-hidden="true" />
|
<TrashIcon aria-hidden="true" className="size-4 mr-1" />
|
||||||
<span>{t("components.datatable.actions.remove")}</span>
|
<span>{t("components.datatable.actions.remove")}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Separator orientation="vertical" className="h-6 mx-1 bg-muted/50" />
|
<Separator className="h-6 mx-1 bg-muted/50" orientation="vertical" />
|
||||||
|
|
||||||
<Tooltip>
|
<Tooltip>
|
||||||
<TooltipTrigger asChild>
|
<TooltipTrigger asChild>
|
||||||
<Button
|
<Button onClick={handleClearSelection} size="sm" type="button" variant="outline">
|
||||||
type="button"
|
<ScanIcon aria-hidden="true" className="size-4 mr-1" />
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={handleClearSelection}
|
|
||||||
>
|
|
||||||
<ScanIcon className="size-4 mr-1" aria-hidden="true" />
|
|
||||||
<span>{t("components.datatable.actions.clear_selection")}</span>
|
<span>{t("components.datatable.actions.clear_selection")}</span>
|
||||||
</Button>
|
</Button>
|
||||||
</TooltipTrigger>
|
</TooltipTrigger>
|
||||||
<TooltipContent>
|
<TooltipContent>{t("components.datatable.actions.clear_selection")}</TooltipContent>
|
||||||
{t("components.datatable.actions.clear_selection")}
|
|
||||||
</TooltipContent>
|
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{/* Contador de selección */}
|
{/* Contador de selección */}
|
||||||
<div
|
<div aria-live="polite" className="text-sm text-muted-foreground ml-2">
|
||||||
className="text-sm text-muted-foreground ml-2"
|
|
||||||
aria-live="polite"
|
|
||||||
>
|
|
||||||
{hasSelection
|
{hasSelection
|
||||||
? t("components.datatable.selection_summary", {
|
? t("components.datatable.selection_summary", {
|
||||||
count: selectedCount,
|
count: selectedCount,
|
||||||
total: totalCount,
|
total: totalCount,
|
||||||
})
|
})
|
||||||
: t("components.datatable.selection_none", { total: totalCount })}
|
: t("components.datatable.selection_none", { total: totalCount })}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -205,4 +194,4 @@ export function DataTableToolbar<TData>({
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export const MemoizedDataTableToolbar = React.memo(DataTableToolbar) as typeof DataTableToolbar;
|
export const MemoizedDataTableToolbar = React.memo(DataTableToolbar) as typeof DataTableToolbar;
|
||||||
|
|||||||
@ -189,7 +189,7 @@ export function DataTable<TData, TValue>({
|
|||||||
<div className="overflow-hidden rounded-md border">
|
<div className="overflow-hidden rounded-md border">
|
||||||
<TableComp className="w-full text-sm">
|
<TableComp className="w-full text-sm">
|
||||||
{/* CABECERA */}
|
{/* CABECERA */}
|
||||||
<TableHeader className="sticky top-0 z-10 bg-muted">
|
<TableHeader className="sticky top-0 z-10 bg-muted/50">
|
||||||
{table.getHeaderGroups().map((hg) => (
|
{table.getHeaderGroups().map((hg) => (
|
||||||
<TableRow key={hg.id}>
|
<TableRow key={hg.id}>
|
||||||
{hg.headers.map((h) => {
|
{hg.headers.map((h) => {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user