@pagamio/frontend-commons-lib 0.8.366 → 0.8.368

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.
@@ -333,16 +333,16 @@ export function PagamioLoginPage({ logo, text = loginPageDefaultText, appLabel,
333
333
  setPhoneError(null);
334
334
  }, className: `flex-1 whitespace-nowrap px-3 py-2.5 text-center text-sm font-medium transition-colors ${activeTab === 'phone'
335
335
  ? 'bg-primary text-primary-foreground'
336
- : 'bg-background text-foreground/70 hover:bg-muted'}`, children: phoneTabLabel })), showUsernameTab && (_jsx("button", { type: "button", role: "tab", "aria-selected": activeTab === 'username', onClick: () => {
336
+ : 'bg-background text-foreground/70 hover:bg-muted'}`, children: phoneTabLabel })), _jsx("button", { type: "button", role: "tab", "aria-selected": activeTab === 'password', onClick: () => setActiveTab('password'), className: `flex-1 whitespace-nowrap px-3 py-2.5 text-center text-sm font-medium transition-colors ${activeTab === 'password'
337
+ ? 'bg-primary text-primary-foreground'
338
+ : 'bg-background text-foreground/70 hover:bg-muted'}`, children: passwordTabLabel }), showUsernameTab && (_jsx("button", { type: "button", role: "tab", "aria-selected": activeTab === 'username', onClick: () => {
337
339
  setActiveTab('username');
338
340
  setUsernameStep('enterLoginNumber');
339
341
  setLoginNumberPinValue('');
340
342
  setUsernameError(null);
341
343
  }, className: `flex-1 whitespace-nowrap px-3 py-2.5 text-center text-sm font-medium transition-colors ${activeTab === 'username'
342
344
  ? 'bg-primary text-primary-foreground'
343
- : 'bg-background text-foreground/70 hover:bg-muted'}`, children: usernameTabLabel })), _jsx("button", { type: "button", role: "tab", "aria-selected": activeTab === 'password', onClick: () => setActiveTab('password'), className: `flex-1 whitespace-nowrap px-3 py-2.5 text-center text-sm font-medium transition-colors ${activeTab === 'password'
344
- ? 'bg-primary text-primary-foreground'
345
- : 'bg-background text-foreground/70 hover:bg-muted'}`, children: passwordTabLabel })] })), activeTab === 'password' && (_jsxs(_Fragment, { children: [_jsx(FormEngine, { fields: loginFields, onSubmit: handleSubmit, layout: "vertical", className: "mb-0 px-0", submitButtonClass: "w-full", submitButtonText: isLoading ? text.loadingButtonLabel : text.loginButtonLabel, onCancel: () => { }, showCancelButton: false, showSubmittingText: false, formRef: formRef, initialValues: {
345
+ : 'bg-background text-foreground/70 hover:bg-muted'}`, children: usernameTabLabel }))] })), activeTab === 'password' && (_jsxs(_Fragment, { children: [_jsx(FormEngine, { fields: loginFields, onSubmit: handleSubmit, layout: "vertical", className: "mb-0 px-0", submitButtonClass: "w-full", submitButtonText: isLoading ? text.loadingButtonLabel : text.loginButtonLabel, onCancel: () => { }, showCancelButton: false, showSubmittingText: false, formRef: formRef, initialValues: {
346
346
  ...(loginFieldType === 'email' ? { email: '' } : { username: '' }),
347
347
  password: '',
348
348
  rememberMe: false,
@@ -4,7 +4,7 @@ type FilterValue = string | string[] | Date | null | undefined;
4
4
  interface FilterDefinition {
5
5
  name: string;
6
6
  placeholder?: string;
7
- type?: 'select' | 'multi-select' | 'date' | 'date-range';
7
+ type?: 'select' | 'multi-select' | 'date' | 'date-range' | 'amount';
8
8
  options?: Array<{
9
9
  label: string;
10
10
  value: string;
@@ -12,6 +12,13 @@ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '.
12
12
  const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = true, showClearFilters, searctInputPlaceHolder = 'Search...', showApplyFilters = true, showSearch = false, searchQuery = '', children, isNarrow, handleFilterChange, handleApplyFilters, resetFilters, onSearch = () => { }, }) => {
13
13
  const hasSelectedActiveFilters = Object.entries(selectedFilters).some(([key, v]) => !isDefaultFilterValue(v, key));
14
14
  const shouldShowActionButtons = hasSelectedActiveFilters || (showSearch && searchQuery.length > 0);
15
+ const normalizeAmountValue = (input) => {
16
+ const cleaned = input.replace(/[^0-9.,]/g, '').replace(/,/g, '.');
17
+ const [whole, ...fractionParts] = cleaned.split('.');
18
+ if (fractionParts.length === 0)
19
+ return whole;
20
+ return `${whole}.${fractionParts.join('')}`;
21
+ };
15
22
  const parseDateValue = (value) => {
16
23
  if (!value)
17
24
  return null;
@@ -66,6 +73,17 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
66
73
  if (type === 'multi-select') {
67
74
  return (_jsx(MultiSelect, { options: Array.isArray(options) ? options : [], placeholder: filter.placeholder ?? `Select ${name}`, value: value || [], onChange: (val) => handleFilterChange(name, val), className: "w-full" }));
68
75
  }
76
+ if (type === 'amount') {
77
+ const currentValue = typeof value === 'string' ? value : '';
78
+ return (_jsxs("div", { className: "relative w-full", children: [_jsx("span", { className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-sm text-muted-foreground", "aria-hidden": "true", children: "R" }), _jsx("input", { type: "text", inputMode: "decimal", value: currentValue, onChange: (event) => handleFilterChange(name, normalizeAmountValue(event.target.value)), onKeyDown: (event) => {
79
+ if (event.key === 'Enter') {
80
+ handleApplyFilters();
81
+ }
82
+ else if (event.key === 'Escape') {
83
+ handleFilterChange(name, '');
84
+ }
85
+ }, placeholder: filter.placeholder ?? 'Amount', "aria-label": filter.placeholder ?? name, className: cn('h-9 w-full rounded-md border border-border bg-background pl-8 pr-9 text-sm text-foreground', 'placeholder:text-muted-foreground', 'focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring', 'disabled:cursor-not-allowed disabled:opacity-50') }), !isDefaultFilterValue(currentValue) && (_jsx("button", { type: "button", className: cn('absolute right-2 top-1/2 -translate-y-1/2 rounded-sm px-1 text-base leading-none text-muted-foreground', 'hover:text-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring'), onClick: () => handleFilterChange(name, ''), "aria-label": "Clear amount filter", children: "\u00D7" }))] }));
86
+ }
69
87
  // Default: select — always keep controlled via sentinel to avoid
70
88
  // Radix switching to uncontrolled mode when value is cleared.
71
89
  const SENTINEL = '__all__';
@@ -76,7 +94,7 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
76
94
  return (
77
95
  // Fluid width: full width on mobile, fluid 180–260px on wider
78
96
  // viewports so filters share the row evenly and shrink under pressure.
79
- _jsx("div", { className: "w-full sm:flex-1 sm:min-w-[180px] sm:max-w-[260px] min-w-0", children: renderFilterInput() }, name));
97
+ _jsx("div", { className: cn('w-full sm:flex-1 min-w-0', type === 'amount' ? 'sm:min-w-[150px] sm:max-w-[220px]' : 'sm:min-w-[180px] sm:max-w-[260px]'), children: renderFilterInput() }, name));
80
98
  }), showApplyFilterButton && shouldShowActionButtons && (_jsx(Button, { onClick: handleApplyFilters, variant: "primary", className: "w-full sm:w-auto", style: { height: 36 }, tabIndex: 0, "aria-label": "Apply Filters", children: "Apply Filters" })), showClearFilters && shouldShowActionButtons && (_jsx(Button, { onClick: resetFilters, variant: "outline-primary", className: "w-full sm:w-auto", style: { height: 36 }, tabIndex: 0, "aria-label": "Clear Filters", children: "Clear Filters" }))] }), _jsx("div", { className: "ml-auto flex flex-wrap items-center justify-end gap-2", children: children })] }));
81
99
  };
82
100
  export default FilterComponent;
@@ -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, 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;
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, disableInternalTableScroll, defaultColumn, mantineTableOptions, }: PagamioTableProps<T>) => import("react/jsx-runtime").JSX.Element;
3
3
  export default PagamioTable;
@@ -101,8 +101,11 @@ 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', 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, }) => {
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, disableInternalTableScroll, defaultColumn, mantineTableOptions, }) => {
105
105
  const [expanded, setExpanded] = useState({});
106
+ const externalState = mantineTableOptions?.state;
107
+ const { state: ignoredState, ...mantineOptionsWithoutState } = mantineTableOptions ?? {};
108
+ void ignoredState;
106
109
  const tableRef = useRef(null);
107
110
  // ── Internal max-height ─────────────────────────────────────────────
108
111
  // The mantine table container is height-capped to `viewportHeight - tableTop`
@@ -138,6 +141,10 @@ const PagamioTable = ({ columns, data, isLoading = false, isFetching = false, ro
138
141
  const mrtContainer = el.querySelector('.mrt-table-container');
139
142
  if (!mrtContainer)
140
143
  return;
144
+ if (disableInternalTableScroll) {
145
+ mrtContainer.style.removeProperty('max-height');
146
+ return;
147
+ }
141
148
  // If a parent is already handling the scroll, let the table render at
142
149
  // its natural height — the user gets one continuous page scroll.
143
150
  if (!tableShouldOwnScroll(el)) {
@@ -244,6 +251,7 @@ const PagamioTable = ({ columns, data, isLoading = false, isFetching = false, ro
244
251
  pagination: paginationState,
245
252
  sorting: sortingState,
246
253
  expanded,
254
+ ...(externalState ?? {}),
247
255
  },
248
256
  // Manual modes (server-side)
249
257
  manualPagination: hasServerPagination,
@@ -328,7 +336,7 @@ const PagamioTable = ({ columns, data, isLoading = false, isFetching = false, ro
328
336
  className: rowClassName,
329
337
  }),
330
338
  // Escape hatch — OCP: consumer can override anything (spread last)
331
- ...mantineTableOptions,
339
+ ...mantineOptionsWithoutState,
332
340
  });
333
341
  // ── Toolbar rendering ──────────────────────────────────────────────
334
342
  const showCustomToolbar = toolbarMode === 'custom' && (!!toolbar || !!search || !!filtering);
@@ -28,7 +28,7 @@ export interface SortConfig {
28
28
  export interface BaseFilter {
29
29
  columnKey: string;
30
30
  label?: string;
31
- type?: 'select' | 'multi-select' | 'date' | 'date-range' | 'range' | 'boolean';
31
+ type?: 'select' | 'multi-select' | 'date' | 'date-range' | 'amount' | 'range' | 'boolean';
32
32
  options?: Array<{
33
33
  label: string;
34
34
  value: string;
@@ -209,6 +209,11 @@ export interface PagamioTableProps<T extends Record<string, any>> {
209
209
  renderTopToolbarCustomActions?: MRT_TableOptions<T>['renderTopToolbarCustomActions'];
210
210
  renderBottomToolbarCustomActions?: MRT_TableOptions<T>['renderBottomToolbarCustomActions'];
211
211
  layoutMode?: 'semantic' | 'grid';
212
+ /**
213
+ * When true, PagamioTable will not cap `.mrt-table-container` height.
214
+ * Use this when the page itself should own vertical scrolling.
215
+ */
216
+ disableInternalTableScroll?: boolean;
212
217
  defaultColumn?: Partial<MRT_ColumnDef<T>>;
213
218
  mantineTableOptions?: Partial<MRT_TableOptions<T>>;
214
219
  }
@@ -259,6 +264,7 @@ export interface UsePagamioTableConfig<T extends BaseEntity> {
259
264
  rowClassName?: string;
260
265
  expandable?: boolean;
261
266
  renderDetailPanel?: PagamioTableProps<T>['renderDetailPanel'];
267
+ disableInternalTableScroll?: boolean;
262
268
  }
263
269
  export interface UsePagamioTableReturn<T extends BaseEntity> {
264
270
  tableProps: PagamioTableProps<T>;
package/lib/styles.css CHANGED
@@ -2872,6 +2872,10 @@ video {
2872
2872
  padding-left: 0px;
2873
2873
  padding-right: 0px;
2874
2874
  }
2875
+ .px-1 {
2876
+ padding-left: 0.25rem;
2877
+ padding-right: 0.25rem;
2878
+ }
2875
2879
  .px-1\.5 {
2876
2880
  padding-left: 0.375rem;
2877
2881
  padding-right: 0.375rem;
@@ -3011,6 +3015,9 @@ video {
3011
3015
  .pr-8 {
3012
3016
  padding-right: 2rem;
3013
3017
  }
3018
+ .pr-9 {
3019
+ padding-right: 2.25rem;
3020
+ }
3014
3021
  .ps-5 {
3015
3022
  padding-inline-start: 1.25rem;
3016
3023
  }
@@ -6545,6 +6552,10 @@ video {
6545
6552
  width: auto;
6546
6553
  }
6547
6554
 
6555
+ .sm\:min-w-\[150px\] {
6556
+ min-width: 150px;
6557
+ }
6558
+
6548
6559
  .sm\:min-w-\[180px\] {
6549
6560
  min-width: 180px;
6550
6561
  }
@@ -6553,6 +6564,10 @@ video {
6553
6564
  min-width: 200px;
6554
6565
  }
6555
6566
 
6567
+ .sm\:max-w-\[220px\] {
6568
+ max-width: 220px;
6569
+ }
6570
+
6556
6571
  .sm\:max-w-\[260px\] {
6557
6572
  max-width: 260px;
6558
6573
  }
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.366",
4
+ "version": "0.8.368",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "provenance": false