@pagamio/frontend-commons-lib 0.8.359 → 0.8.361
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/lib/components/ui/MonthCalendar.d.ts +37 -0
- package/lib/components/ui/MonthCalendar.js +63 -0
- package/lib/components/ui/index.d.ts +1 -0
- package/lib/components/ui/index.js +1 -0
- package/lib/pagamio-table/data-table/index.d.ts +1 -1
- package/lib/pagamio-table/data-table/index.js +10 -2
- package/lib/pagamio-table/data-table/types.d.ts +11 -0
- package/lib/shared/hooks/usePagamioTable.js +4 -0
- package/lib/styles.css +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import * as React from 'react';
|
|
2
|
+
/** A single day rendered in the grid. `inMonth` is false for leading/trailing days. */
|
|
3
|
+
export interface MonthCalendarDay {
|
|
4
|
+
date: Date;
|
|
5
|
+
/** YYYY-MM-DD, handy as a map key for consumer data. */
|
|
6
|
+
key: string;
|
|
7
|
+
inMonth: boolean;
|
|
8
|
+
isToday: boolean;
|
|
9
|
+
}
|
|
10
|
+
export interface MonthCalendarProps {
|
|
11
|
+
/** Any date within the month to display. Controlled. */
|
|
12
|
+
month: Date;
|
|
13
|
+
/** Fired when the user pages to a previous/next month. */
|
|
14
|
+
onMonthChange?: (next: Date) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Render the contents of a single day cell — typically a number plus any
|
|
17
|
+
* badges/metrics the consumer wants. The cell chrome (border, today ring,
|
|
18
|
+
* out-of-month dimming) is handled here.
|
|
19
|
+
*/
|
|
20
|
+
renderDay?: (day: MonthCalendarDay) => React.ReactNode;
|
|
21
|
+
/** Optional click handler per day. */
|
|
22
|
+
onDayClick?: (day: MonthCalendarDay) => void;
|
|
23
|
+
className?: string;
|
|
24
|
+
/** Hide the built-in month header + nav (e.g. when the parent supplies its own). */
|
|
25
|
+
hideHeader?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* A generic month-grid calendar (Sunday-first) with a render-prop for day
|
|
29
|
+
* cell contents — for dashboards, attendance, schedules, etc. Distinct from
|
|
30
|
+
* the date-picker `Calendar`: this one is for *displaying* data across a
|
|
31
|
+
* month, not selecting a date.
|
|
32
|
+
*
|
|
33
|
+
* The grid always renders 6 weeks (42 cells) so its height is stable as the
|
|
34
|
+
* user pages between months. Out-of-month days are dimmed.
|
|
35
|
+
*/
|
|
36
|
+
export declare function MonthCalendar({ month, onMonthChange, renderDay, onDayClick, className, hideHeader, }: MonthCalendarProps): import("react/jsx-runtime").JSX.Element;
|
|
37
|
+
export default MonthCalendar;
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { HiChevronLeft, HiChevronRight } from 'react-icons/hi';
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { cn } from '../../helpers/utils';
|
|
5
|
+
import IconButton from './IconButton';
|
|
6
|
+
const WEEKDAY_LABELS = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
7
|
+
const MONTH_LABELS = [
|
|
8
|
+
'January',
|
|
9
|
+
'February',
|
|
10
|
+
'March',
|
|
11
|
+
'April',
|
|
12
|
+
'May',
|
|
13
|
+
'June',
|
|
14
|
+
'July',
|
|
15
|
+
'August',
|
|
16
|
+
'September',
|
|
17
|
+
'October',
|
|
18
|
+
'November',
|
|
19
|
+
'December',
|
|
20
|
+
];
|
|
21
|
+
const toKey = (d) => {
|
|
22
|
+
const y = d.getFullYear();
|
|
23
|
+
const m = `${d.getMonth() + 1}`.padStart(2, '0');
|
|
24
|
+
const day = `${d.getDate()}`.padStart(2, '0');
|
|
25
|
+
return `${y}-${m}-${day}`;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* A generic month-grid calendar (Sunday-first) with a render-prop for day
|
|
29
|
+
* cell contents — for dashboards, attendance, schedules, etc. Distinct from
|
|
30
|
+
* the date-picker `Calendar`: this one is for *displaying* data across a
|
|
31
|
+
* month, not selecting a date.
|
|
32
|
+
*
|
|
33
|
+
* The grid always renders 6 weeks (42 cells) so its height is stable as the
|
|
34
|
+
* user pages between months. Out-of-month days are dimmed.
|
|
35
|
+
*/
|
|
36
|
+
export function MonthCalendar({ month, onMonthChange, renderDay, onDayClick, className, hideHeader = false, }) {
|
|
37
|
+
// Stable "today" key so the day grid memo doesn't recompute every render.
|
|
38
|
+
const todayKey = toKey(new Date());
|
|
39
|
+
const days = React.useMemo(() => {
|
|
40
|
+
const firstOfMonth = new Date(month.getFullYear(), month.getMonth(), 1);
|
|
41
|
+
// Back up to the Sunday on or before the 1st.
|
|
42
|
+
const gridStart = new Date(firstOfMonth);
|
|
43
|
+
gridStart.setDate(firstOfMonth.getDate() - firstOfMonth.getDay());
|
|
44
|
+
return Array.from({ length: 42 }, (_, i) => {
|
|
45
|
+
const date = new Date(gridStart);
|
|
46
|
+
date.setDate(gridStart.getDate() + i);
|
|
47
|
+
const key = toKey(date);
|
|
48
|
+
return {
|
|
49
|
+
date,
|
|
50
|
+
key,
|
|
51
|
+
inMonth: date.getMonth() === month.getMonth(),
|
|
52
|
+
isToday: key === todayKey,
|
|
53
|
+
};
|
|
54
|
+
});
|
|
55
|
+
}, [month, todayKey]);
|
|
56
|
+
const goToMonth = (offset) => {
|
|
57
|
+
if (!onMonthChange)
|
|
58
|
+
return;
|
|
59
|
+
onMonthChange(new Date(month.getFullYear(), month.getMonth() + offset, 1));
|
|
60
|
+
};
|
|
61
|
+
return (_jsxs("div", { className: cn('rounded-lg border border-border bg-background', className), children: [!hideHeader && (_jsxs("div", { className: "flex items-center justify-between border-b border-border px-4 py-3", children: [_jsxs("h3", { className: "text-sm font-semibold text-foreground", children: [MONTH_LABELS[month.getMonth()], " ", month.getFullYear()] }), _jsxs("div", { className: "flex items-center gap-1", children: [_jsx(IconButton, { icon: HiChevronLeft, label: "Previous month", variant: "outline", size: "sm", onClick: () => goToMonth(-1) }), _jsx(IconButton, { icon: HiChevronRight, label: "Next month", variant: "outline", size: "sm", onClick: () => goToMonth(1) })] })] })), _jsx("div", { className: "grid grid-cols-7 border-b border-border", children: WEEKDAY_LABELS.map((label) => (_jsx("div", { className: "px-2 py-2 text-center text-xs font-medium uppercase tracking-wide text-muted-foreground", children: label }, label))) }), _jsx("div", { className: "grid grid-cols-7", children: days.map((day) => (_jsxs("div", { onClick: onDayClick ? () => onDayClick(day) : undefined, className: cn('min-h-[88px] border-b border-r border-border p-1.5 last:border-r-0', !day.inMonth && 'bg-muted/30 text-muted-foreground', onDayClick && 'cursor-pointer hover:bg-muted/40'), children: [_jsx("div", { className: "flex items-center justify-between", children: _jsx("span", { className: cn('inline-flex h-6 w-6 items-center justify-center rounded-full text-xs', day.isToday && 'bg-primary font-semibold text-primary-foreground', !day.isToday && !day.inMonth && 'text-muted-foreground', !day.isToday && day.inMonth && 'text-foreground'), children: day.date.getDate() }) }), renderDay && day.inMonth ? _jsx("div", { className: "mt-1", children: renderDay(day) }) : null] }, day.key))) })] }));
|
|
62
|
+
}
|
|
63
|
+
export default MonthCalendar;
|
|
@@ -15,6 +15,7 @@ export * from './Sheet';
|
|
|
15
15
|
export { default as AvatorIcon } from './AvatarIcon';
|
|
16
16
|
export { default as Button, ButtonGroup, type ButtonVariant, type ButtonSize, variantStyles } from './Button';
|
|
17
17
|
export { default as Calendar } from './Calendar';
|
|
18
|
+
export { MonthCalendar, default as MonthCalendarDefault, type MonthCalendarProps, type MonthCalendarDay, } from './MonthCalendar';
|
|
18
19
|
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from './Card';
|
|
19
20
|
export { default as LegacyCard } from './LegacyCard';
|
|
20
21
|
export { Skeleton, SkeletonText, SkeletonCircle, SkeletonCard, SkeletonAvatar, SkeletonChart, SkeletonStatCard, } from './Skeleton';
|
|
@@ -14,6 +14,7 @@ export * from './Sheet';
|
|
|
14
14
|
export { default as AvatorIcon } from './AvatarIcon';
|
|
15
15
|
export { default as Button, ButtonGroup, variantStyles } from './Button';
|
|
16
16
|
export { default as Calendar } from './Calendar';
|
|
17
|
+
export { MonthCalendar, default as MonthCalendarDefault, } from './MonthCalendar';
|
|
17
18
|
// Card - v2 shadcn-style primitives (composable)
|
|
18
19
|
export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } from './Card';
|
|
19
20
|
// LegacyCard - v1 Card for backward compatibility
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { PagamioTableProps } from './types';
|
|
2
|
-
declare const PagamioTable: <T extends Record<string, any>>({ columns, data, isLoading, isFetching, rowCount, sorting, pagination, filtering, search, onRowClick, rowClassName, expandable, renderDetailPanel, toolbar, toolbarMode, enableColumnResizing, enableColumnPinning, enableColumnOrdering, enableColumnFilters, enableHiding, enableRowSelection, enableRowActions, enableRowVirtualization, enableGrouping, enableEditing, enableDensityToggle, enableFullScreenToggle, enableClickToCopy, enableRowNumbers, enableMultiSort, enableStickyHeader, enableStickyFooter, editDisplayMode, onEditingRowSave, onEditingRowCancel, renderRowActions, renderRowActionMenuItems, positionActionsColumn, renderTopToolbarCustomActions, renderBottomToolbarCustomActions, layoutMode, defaultColumn, mantineTableOptions, }: PagamioTableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
declare const PagamioTable: <T extends Record<string, any>>({ columns, data, isLoading, isFetching, rowCount, sorting, pagination, filtering, search, onRowClick, rowClassName, expandable, renderDetailPanel, toolbar, toolbarMode, fetchAllData, enableColumnResizing, enableColumnPinning, enableColumnOrdering, enableColumnFilters, enableHiding, enableRowSelection, enableRowActions, enableRowVirtualization, enableGrouping, enableEditing, enableDensityToggle, enableFullScreenToggle, enableClickToCopy, enableRowNumbers, enableMultiSort, enableStickyHeader, enableStickyFooter, editDisplayMode, onEditingRowSave, onEditingRowCancel, renderRowActions, renderRowActionMenuItems, positionActionsColumn, renderTopToolbarCustomActions, renderBottomToolbarCustomActions, layoutMode, defaultColumn, mantineTableOptions, }: PagamioTableProps<T>) => import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
export default PagamioTable;
|
|
@@ -101,7 +101,7 @@ function CustomToolbar({ filters, appliedFilters, onFilterChange, onApply, onCle
|
|
|
101
101
|
(typeof addButton === 'boolean' ? (_jsx(IconButton, { onClick: onAdd ?? (() => { }), icon: HiPlusSm, label: "add-new-entry", className: cn('items-center text-nowrap', isNarrow ? 'w-full' : undefined), children: addText ?? 'Add New Entry' })) : (addButton))] }) }));
|
|
102
102
|
}
|
|
103
103
|
// ─── PagamioTable Component ──────────────────────────────────────────
|
|
104
|
-
const PagamioTable = ({ columns, data, isLoading = false, isFetching = false, rowCount, sorting, pagination, filtering, search, onRowClick, rowClassName, expandable = false, renderDetailPanel, toolbar, toolbarMode = 'custom', enableColumnResizing, enableColumnPinning, enableColumnOrdering, enableColumnFilters, enableHiding, enableRowSelection, enableRowActions, enableRowVirtualization, enableGrouping, enableEditing, enableDensityToggle, enableFullScreenToggle, enableClickToCopy, enableRowNumbers, enableMultiSort, enableStickyHeader, enableStickyFooter, editDisplayMode, onEditingRowSave, onEditingRowCancel, renderRowActions, renderRowActionMenuItems, positionActionsColumn, renderTopToolbarCustomActions, renderBottomToolbarCustomActions, layoutMode, defaultColumn, mantineTableOptions, }) => {
|
|
104
|
+
const PagamioTable = ({ columns, data, isLoading = false, isFetching = false, rowCount, sorting, pagination, filtering, search, onRowClick, rowClassName, expandable = false, renderDetailPanel, toolbar, toolbarMode = 'custom', fetchAllData, enableColumnResizing, enableColumnPinning, enableColumnOrdering, enableColumnFilters, enableHiding, enableRowSelection, enableRowActions, enableRowVirtualization, enableGrouping, enableEditing, enableDensityToggle, enableFullScreenToggle, enableClickToCopy, enableRowNumbers, enableMultiSort, enableStickyHeader, enableStickyFooter, editDisplayMode, onEditingRowSave, onEditingRowCancel, renderRowActions, renderRowActionMenuItems, positionActionsColumn, renderTopToolbarCustomActions, renderBottomToolbarCustomActions, layoutMode, defaultColumn, mantineTableOptions, }) => {
|
|
105
105
|
const [expanded, setExpanded] = useState({});
|
|
106
106
|
const tableRef = useRef(null);
|
|
107
107
|
// ── Internal max-height ─────────────────────────────────────────────
|
|
@@ -332,6 +332,14 @@ const PagamioTable = ({ columns, data, isLoading = false, isFetching = false, ro
|
|
|
332
332
|
});
|
|
333
333
|
// ── Toolbar rendering ──────────────────────────────────────────────
|
|
334
334
|
const showCustomToolbar = toolbarMode === 'custom' && (!!toolbar || !!search || !!filtering);
|
|
335
|
-
return (_jsxs("div", { children: [showCustomToolbar && (_jsx(CustomToolbar, { filters: toolbar?.filters ?? [], appliedFilters: filtering?.appliedFilters ?? {}, onFilterChange: filtering?.onFilterChange ?? (() => { }), onApply: filtering?.onApply ?? (() => { }), onClearFilters: toolbar?.onClearFilters, showClearFilters: toolbar?.showClearFilters ?? false, showApplyFilterButton: toolbar?.showApplyFilterButton ?? true, searchEnabled: !!search, searchQuery: search?.query ?? '', onSearch: search?.onChange ?? (() => { }), searchPlaceholder: search?.placeholder, exportConfig: toolbar?.export
|
|
335
|
+
return (_jsxs("div", { children: [showCustomToolbar && (_jsx(CustomToolbar, { filters: toolbar?.filters ?? [], appliedFilters: filtering?.appliedFilters ?? {}, onFilterChange: filtering?.onFilterChange ?? (() => { }), onApply: filtering?.onApply ?? (() => { }), onClearFilters: toolbar?.onClearFilters, showClearFilters: toolbar?.showClearFilters ?? false, showApplyFilterButton: toolbar?.showApplyFilterButton ?? true, searchEnabled: !!search, searchQuery: search?.query ?? '', onSearch: search?.onChange ?? (() => { }), searchPlaceholder: search?.placeholder, exportConfig: toolbar?.export
|
|
336
|
+
? {
|
|
337
|
+
...toolbar.export,
|
|
338
|
+
// Fall back to the hook's top-level fetcher when a consumer's
|
|
339
|
+
// toolbar override didn't carry one — keeps "Export all data"
|
|
340
|
+
// working even when `toolbar` is replaced wholesale.
|
|
341
|
+
fetchAllData: toolbar.export.fetchAllData ?? fetchAllData,
|
|
342
|
+
}
|
|
343
|
+
: undefined, columns: columns, data: data, addButton: toolbar?.addButton, addText: toolbar?.addText, onAdd: toolbar?.onAdd })), _jsx("div", { ref: tableRef, className: "border border-border rounded-md overflow-y-hidden", children: _jsx(MantineReactTable, { table: table }) })] }));
|
|
336
344
|
};
|
|
337
345
|
export default PagamioTable;
|
|
@@ -172,6 +172,17 @@ export interface PagamioTableProps<T extends Record<string, any>> {
|
|
|
172
172
|
}) => ReactNode;
|
|
173
173
|
toolbar?: ToolbarConfig<T>;
|
|
174
174
|
toolbarMode?: 'custom' | 'mrt' | 'none';
|
|
175
|
+
/**
|
|
176
|
+
* Server-side "export all" fetcher, auto-wired by `usePagamioTable` as a
|
|
177
|
+
* TOP-LEVEL prop (not just inside `toolbar.export`). Consumers spread
|
|
178
|
+
* `{...tableProps}` but frequently pass their own `toolbar={{...}}` for
|
|
179
|
+
* add-buttons/filters, which would otherwise drop the hook's
|
|
180
|
+
* `toolbar.export.fetchAllData` and silently break "Export all data".
|
|
181
|
+
* PagamioTable falls back to this when `toolbar.export.fetchAllData` is unset,
|
|
182
|
+
* so export-all keeps working regardless of a toolbar override. A consumer
|
|
183
|
+
* can still override by setting `toolbar.export.fetchAllData` explicitly.
|
|
184
|
+
*/
|
|
185
|
+
fetchAllData?: (params?: Record<string, string>, onProgress?: (fetched: number, total: number) => void) => Promise<T[]>;
|
|
175
186
|
enableColumnResizing?: boolean;
|
|
176
187
|
enableColumnPinning?: boolean;
|
|
177
188
|
enableColumnOrdering?: boolean;
|
|
@@ -327,6 +327,10 @@ export const usePagamioTable = ({ queryKey, queryFn, enabled: queryEnabled = tru
|
|
|
327
327
|
isLoading,
|
|
328
328
|
isFetching,
|
|
329
329
|
rowCount: totalItems,
|
|
330
|
+
// Top-level so it survives a consumer's `toolbar={{...}}` override.
|
|
331
|
+
// PagamioTable falls back to this for export-all. Only for server mode
|
|
332
|
+
// (client tables already hold the whole set).
|
|
333
|
+
...(isServerMode && { fetchAllData: fetchAllPages }),
|
|
330
334
|
...(paginationConfig.enabled && {
|
|
331
335
|
pagination: {
|
|
332
336
|
pageIndex: currentPage,
|
package/lib/styles.css
CHANGED
|
@@ -1336,6 +1336,9 @@ video {
|
|
|
1336
1336
|
.min-h-\[60px\] {
|
|
1337
1337
|
min-height: 60px;
|
|
1338
1338
|
}
|
|
1339
|
+
.min-h-\[88px\] {
|
|
1340
|
+
min-height: 88px;
|
|
1341
|
+
}
|
|
1339
1342
|
.min-h-\[calc\(100vh-5rem\)\] {
|
|
1340
1343
|
min-height: calc(100vh - 5rem);
|
|
1341
1344
|
}
|
|
@@ -4237,6 +4240,9 @@ video {
|
|
|
4237
4240
|
.last\:border-0:last-child {
|
|
4238
4241
|
border-width: 0px;
|
|
4239
4242
|
}
|
|
4243
|
+
.last\:border-r-0:last-child {
|
|
4244
|
+
border-right-width: 0px;
|
|
4245
|
+
}
|
|
4240
4246
|
.odd\:bg-white:nth-child(odd) {
|
|
4241
4247
|
--tw-bg-opacity: 1;
|
|
4242
4248
|
background-color: rgb(255 255 255 / var(--tw-bg-opacity, 1));
|
|
@@ -4425,6 +4431,9 @@ video {
|
|
|
4425
4431
|
.hover\:bg-muted:hover {
|
|
4426
4432
|
background-color: hsl(var(--muted));
|
|
4427
4433
|
}
|
|
4434
|
+
.hover\:bg-muted\/40:hover {
|
|
4435
|
+
background-color: hsl(var(--muted) / 0.4);
|
|
4436
|
+
}
|
|
4428
4437
|
.hover\:bg-pink-200:hover {
|
|
4429
4438
|
--tw-bg-opacity: 1;
|
|
4430
4439
|
background-color: rgb(250 209 232 / var(--tw-bg-opacity, 1));
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@pagamio/frontend-commons-lib",
|
|
3
3
|
"description": "Pagamio library for Frontend reusable components like the form engine and table container",
|
|
4
|
-
"version": "0.8.
|
|
4
|
+
"version": "0.8.361",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|