@asteby/metacore-runtime-react 18.10.0 → 18.10.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +15 -0
- package/dist/dynamic-table.d.ts.map +1 -1
- package/dist/dynamic-table.js +8 -7
- package/package.json +1 -1
- package/src/dynamic-table.tsx +23 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,20 @@
|
|
|
1
1
|
# @asteby/metacore-runtime-react
|
|
2
2
|
|
|
3
|
+
## 18.10.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 530ad31: The totals footer is now pinned to the bottom of the table box even with few
|
|
8
|
+
rows (the table fills its container height and a spacer row absorbs the slack),
|
|
9
|
+
instead of floating right under the last row.
|
|
10
|
+
|
|
11
|
+
## 18.10.1
|
|
12
|
+
|
|
13
|
+
### Patch Changes
|
|
14
|
+
|
|
15
|
+
- ea5e587: The dynamic table totals footer is now sticky (pinned to the bottom of the
|
|
16
|
+
scroll area) so the column totals stay visible while scrolling the rows.
|
|
17
|
+
|
|
3
18
|
## 18.10.0
|
|
4
19
|
|
|
5
20
|
### Minor Changes
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAUnF,UAAU,iBAAiB;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,EAC5C,QAAQ,EACR,QAAQ,GACX,EAAE,iBAAiB,+
|
|
1
|
+
{"version":3,"file":"dynamic-table.d.ts","sourceRoot":"","sources":["../src/dynamic-table.tsx"],"names":[],"mappings":"AAiBA,OAAO,EAKH,KAAK,SAAS,EAajB,MAAM,uBAAuB,CAAA;AAgC9B,OAAO,KAAK,EAAsB,iBAAiB,EAAE,MAAM,wBAAwB,CAAA;AAUnF,UAAU,iBAAiB;IACvB,KAAK,EAAE,MAAM,CAAA;IACb,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,aAAa,CAAC,EAAE,OAAO,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,EAAE,CAAA;IACxB,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,KAAK,IAAI,CAAA;IAC7C,cAAc,CAAC,EAAE,GAAG,CAAA;IACpB,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;IACpC,YAAY,CAAC,EAAE,SAAS,CAAC,GAAG,CAAC,EAAE,CAAA;IAC/B;;;;;OAKG;IACH,iBAAiB,CAAC,EAAE,iBAAiB,CAAA;IACrC;;;;;OAKG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB;;;;OAIG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB;AAED,wBAAgB,YAAY,CAAC,EACzB,KAAK,EACL,QAAQ,EACR,aAAoB,EACpB,aAAkB,EAClB,QAAQ,EACR,cAAc,EACd,cAAc,EACd,YAAiB,EACjB,iBAA4C,EAC5C,QAAQ,EACR,QAAQ,GACX,EAAE,iBAAiB,+BAo3BnB"}
|
package/dist/dynamic-table.js
CHANGED
|
@@ -620,21 +620,22 @@ export function DynamicTable({ model, endpoint, enableUrlSync = true, hiddenColu
|
|
|
620
620
|
if (!metadata) {
|
|
621
621
|
return _jsx("div", { className: "text-center text-muted-foreground py-8", children: "Error al cargar la configuraci\u00F3n de la tabla." });
|
|
622
622
|
}
|
|
623
|
-
return (_jsxs(OptionsContext.Provider, { value: { optionsMap }, children: [_jsxs("div", { className: 'flex flex-col h-full min-h-0 w-full', children: [_jsx("div", { className: 'pb-4 shrink-0', children: _jsx(DataTableToolbar, { table: table, searchPlaceholder: metadata.searchPlaceholder || 'Buscar...', filters: filters, activeFilters: dynamicFilters, onDynamicFilterChange: handleDynamicFilterChange, dateFilter: { value: dateRange, onChange: setDateRange, placeholder: 'Filtrar por fecha' }, perPageOptions: metadata.perPageOptions, onRefresh: handleRefresh, isLoading: loadingData, selectedCount: Object.keys(rowSelection).length, onBulkDelete: () => setShowBulkDeleteConfirm(true), extraActions: _jsxs(_Fragment, { children: [metadata.canExport && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setExportOpen(true), children: [_jsx(Download, { className: "h-4 w-4 mr-1" }), " Exportar"] })), metadata.canImport && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setImportOpen(true), children: [_jsx(Upload, { className: "h-4 w-4 mr-1" }), " Importar"] }))] }) }) }), _jsx("div", { className: 'hidden sm:block flex-1 min-h-0 overflow-auto border rounded-md bg-card', children: _jsxs(Table, { noWrapper: true, className:
|
|
623
|
+
return (_jsxs(OptionsContext.Provider, { value: { optionsMap }, children: [_jsxs("div", { className: 'flex flex-col h-full min-h-0 w-full', children: [_jsx("div", { className: 'pb-4 shrink-0', children: _jsx(DataTableToolbar, { table: table, searchPlaceholder: metadata.searchPlaceholder || 'Buscar...', filters: filters, activeFilters: dynamicFilters, onDynamicFilterChange: handleDynamicFilterChange, dateFilter: { value: dateRange, onChange: setDateRange, placeholder: 'Filtrar por fecha' }, perPageOptions: metadata.perPageOptions, onRefresh: handleRefresh, isLoading: loadingData, selectedCount: Object.keys(rowSelection).length, onBulkDelete: () => setShowBulkDeleteConfirm(true), extraActions: _jsxs(_Fragment, { children: [metadata.canExport && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setExportOpen(true), children: [_jsx(Download, { className: "h-4 w-4 mr-1" }), " Exportar"] })), metadata.canImport && (_jsxs(Button, { variant: "outline", size: "sm", className: "h-8", onClick: () => setImportOpen(true), children: [_jsx(Upload, { className: "h-4 w-4 mr-1" }), " Importar"] }))] }) }) }), _jsx("div", { className: 'hidden sm:block flex-1 min-h-0 overflow-auto border rounded-md bg-card', children: _jsxs(Table, { noWrapper: true, className: cn('min-w-max w-full', aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && 'h-full'), children: [_jsx(TableHeader, { className: 'sticky top-0 z-10', children: table.getHeaderGroups().map((headerGroup) => (_jsx(TableRow, { className: 'border-b-0 hover:bg-transparent', children: headerGroup.headers.map((header) => {
|
|
624
624
|
const isActionsColumn = header.id === 'actions';
|
|
625
625
|
return (_jsx(TableHead, { colSpan: header.colSpan, style: header.column.columnDef.size ? { width: header.column.columnDef.size } : undefined, className: cn('bg-card border-b h-10', isActionsColumn && 'sticky right-0 z-20 bg-card shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.1)]'), children: header.isPlaceholder ? null : flexRender(header.column.columnDef.header, header.getContext()) }, header.id));
|
|
626
|
-
}) }, headerGroup.id))) }), _jsx(TableBody, { children: loadingData && data.length === 0 ? (_jsx(TableSkeleton, {})) : table.getRowModel().rows?.length ? (table.getRowModel().rows.map((row) => (_jsx(TableRow, { "data-state": row.getIsSelected() && 'selected', children: row.getVisibleCells().map((cell) => {
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
626
|
+
}) }, headerGroup.id))) }), _jsx(TableBody, { children: loadingData && data.length === 0 ? (_jsx(TableSkeleton, {})) : table.getRowModel().rows?.length ? (_jsxs(_Fragment, { children: [table.getRowModel().rows.map((row) => (_jsx(TableRow, { "data-state": row.getIsSelected() && 'selected', children: row.getVisibleCells().map((cell) => {
|
|
627
|
+
const isActionsColumn = cell.column.id === 'actions';
|
|
628
|
+
return (_jsx(TableCell, { style: cell.column.columnDef.size ? { width: cell.column.columnDef.size } : undefined, className: cn('py-2', isActionsColumn && 'sticky right-0 bg-card shadow-[-2px_0_5px_-2px_rgba(0,0,0,0.1)]'), children: flexRender(cell.column.columnDef.cell, cell.getContext()) }, cell.id));
|
|
629
|
+
}) }, row.id))), aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && (_jsx(TableRow, { className: 'border-0 hover:bg-transparent', children: _jsx(TableCell, { colSpan: columns.length, className: 'h-full p-0' }) }))] })) : (_jsx(TableRow, { className: 'border-b-0 hover:bg-transparent', children: _jsx(TableCell, { colSpan: columns.length, className: 'h-full p-0', children: _jsxs("div", { className: "flex h-full py-12 flex-col items-center justify-center gap-2 text-muted-foreground", children: [_jsx("div", { className: "flex h-20 w-20 items-center justify-center rounded-full bg-muted/50", children: _jsx(Inbox, { className: "h-10 w-10" }) }), _jsxs("div", { className: "flex flex-col items-center gap-1", children: [_jsx("h3", { className: "text-lg font-semibold text-foreground", children: "No se encontraron resultados" }), _jsx("p", { className: "text-sm text-muted-foreground", children: "No hay datos para mostrar en este momento." })] })] }) }) })) }), aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && (_jsx(TableFooter, { className: "bg-transparent", children: _jsx(TableRow, { className: "hover:bg-transparent", children: table.getVisibleLeafColumns().map((leaf, idx) => {
|
|
630
630
|
const col = (metadata?.columns ?? []).find((c) => c.key === leaf.id);
|
|
631
631
|
const isFirst = idx === 0;
|
|
632
|
+
const stickyBase = 'sticky bottom-0 z-10 border-t bg-background py-2 font-semibold';
|
|
632
633
|
// Aggregate cell: render the SUM formatted like the body cell.
|
|
633
634
|
if (col && aggregateOf(col)) {
|
|
634
|
-
return (_jsx(TableCell, { className:
|
|
635
|
+
return (_jsx(TableCell, { className: `${stickyBase} text-right tabular-nums`, children: formatAggregateTotal(col, footerTotals[leaf.id], currency, i18n.language) }, leaf.id));
|
|
635
636
|
}
|
|
636
637
|
// First non-aggregate column carries the "Total" label.
|
|
637
|
-
return (_jsx(TableCell, { className:
|
|
638
|
+
return (_jsx(TableCell, { className: stickyBase, children: isFirst ? t('common.total', 'Total') : '' }, leaf.id));
|
|
638
639
|
}) }) }))] }) }), _jsx("div", { className: 'flex flex-1 min-h-0 flex-col gap-2 overflow-y-auto sm:hidden', children: loadingData && data.length === 0 ? (Array.from({ length: 5 }).map((_, i) => (_jsxs("div", { className: 'rounded-lg border bg-card p-3', children: [_jsx(Skeleton, { className: 'h-4 w-24' }), _jsx(Skeleton, { className: 'mt-2 h-4 w-40' }), _jsx(Skeleton, { className: 'mt-2 h-4 w-32' })] }, i)))) : table.getRowModel().rows?.length ? (table.getRowModel().rows.map((row) => {
|
|
639
640
|
const cells = row.getVisibleCells();
|
|
640
641
|
const actionsCell = cells.find((c) => c.column.id === 'actions');
|
package/package.json
CHANGED
package/src/dynamic-table.tsx
CHANGED
|
@@ -755,7 +755,7 @@ export function DynamicTable({
|
|
|
755
755
|
a 7-column table forces a wide horizontal scroll there, so we
|
|
756
756
|
render a card-per-row list instead (see MobileCards below). */}
|
|
757
757
|
<div className='hidden sm:block flex-1 min-h-0 overflow-auto border rounded-md bg-card'>
|
|
758
|
-
<Table noWrapper className=
|
|
758
|
+
<Table noWrapper className={cn('min-w-max w-full', aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && 'h-full')}>
|
|
759
759
|
<TableHeader className='sticky top-0 z-10'>
|
|
760
760
|
{table.getHeaderGroups().map((headerGroup: HeaderGroup<any>) => (
|
|
761
761
|
<TableRow key={headerGroup.id} className='border-b-0 hover:bg-transparent'>
|
|
@@ -779,7 +779,8 @@ export function DynamicTable({
|
|
|
779
779
|
{loadingData && data.length === 0 ? (
|
|
780
780
|
<TableSkeleton />
|
|
781
781
|
) : table.getRowModel().rows?.length ? (
|
|
782
|
-
|
|
782
|
+
<>
|
|
783
|
+
{table.getRowModel().rows.map((row: Row<any>) => (
|
|
783
784
|
<TableRow key={row.id} data-state={row.getIsSelected() && 'selected'}>
|
|
784
785
|
{row.getVisibleCells().map((cell: Cell<any, unknown>) => {
|
|
785
786
|
const isActionsColumn = cell.column.id === 'actions'
|
|
@@ -794,7 +795,16 @@ export function DynamicTable({
|
|
|
794
795
|
)
|
|
795
796
|
})}
|
|
796
797
|
</TableRow>
|
|
797
|
-
|
|
798
|
+
))}
|
|
799
|
+
{/* Spacer row: absorbs the table's leftover height (table is
|
|
800
|
+
h-full when a footer shows) so the totals footer is pinned to
|
|
801
|
+
the bottom of the box even with only a few rows. */}
|
|
802
|
+
{aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && (
|
|
803
|
+
<TableRow className='border-0 hover:bg-transparent'>
|
|
804
|
+
<TableCell colSpan={columns.length} className='h-full p-0' />
|
|
805
|
+
</TableRow>
|
|
806
|
+
)}
|
|
807
|
+
</>
|
|
798
808
|
) : (
|
|
799
809
|
<TableRow className='border-b-0 hover:bg-transparent'>
|
|
800
810
|
<TableCell colSpan={columns.length} className='h-full p-0'>
|
|
@@ -812,19 +822,26 @@ export function DynamicTable({
|
|
|
812
822
|
)}
|
|
813
823
|
</TableBody>
|
|
814
824
|
{aggregateColumns.length > 0 && Object.keys(footerTotals).length > 0 && (
|
|
815
|
-
|
|
825
|
+
// Sticky footer: the totals row stays pinned to the bottom of
|
|
826
|
+
// the scroll area instead of scrolling away with the rows. The
|
|
827
|
+
// sticky lives on the cells (a <tr> can't be position:sticky
|
|
828
|
+
// reliably); each carries an opaque bg + top border so the body
|
|
829
|
+
// scrolls underneath cleanly.
|
|
830
|
+
<TableFooter className="bg-transparent">
|
|
816
831
|
<TableRow className="hover:bg-transparent">
|
|
817
832
|
{table.getVisibleLeafColumns().map((leaf: any, idx: number) => {
|
|
818
833
|
const col = (metadata?.columns ?? []).find(
|
|
819
834
|
(c) => c.key === leaf.id,
|
|
820
835
|
)
|
|
821
836
|
const isFirst = idx === 0
|
|
837
|
+
const stickyBase =
|
|
838
|
+
'sticky bottom-0 z-10 border-t bg-background py-2 font-semibold'
|
|
822
839
|
// Aggregate cell: render the SUM formatted like the body cell.
|
|
823
840
|
if (col && aggregateOf(col as any)) {
|
|
824
841
|
return (
|
|
825
842
|
<TableCell
|
|
826
843
|
key={leaf.id}
|
|
827
|
-
className=
|
|
844
|
+
className={`${stickyBase} text-right tabular-nums`}
|
|
828
845
|
>
|
|
829
846
|
{formatAggregateTotal(
|
|
830
847
|
col as any,
|
|
@@ -837,7 +854,7 @@ export function DynamicTable({
|
|
|
837
854
|
}
|
|
838
855
|
// First non-aggregate column carries the "Total" label.
|
|
839
856
|
return (
|
|
840
|
-
<TableCell key={leaf.id} className=
|
|
857
|
+
<TableCell key={leaf.id} className={stickyBase}>
|
|
841
858
|
{isFirst ? t('common.total', 'Total') : ''}
|
|
842
859
|
</TableCell>
|
|
843
860
|
)
|