@pagamio/frontend-commons-lib 0.8.309 → 0.8.311

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.
@@ -1,37 +1,15 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Input, MultiSelect, Select } from '@mantine/core';
3
2
  import { IconSearch } from '@tabler/icons-react';
4
3
  import { endOfDay, startOfDay } from 'date-fns';
5
- import React from 'react';
4
+ import { cn } from '../../helpers';
6
5
  import { isDefaultFilterValue } from '../../shared/utils/filterUtils';
7
6
  import Button from './Button';
8
7
  import DatePicker from './DatePicker';
9
8
  import DateRangePickerWithPresets from './DateRangePickerWithPresets';
10
9
  import FilterWrapper from './FilterWrapper';
11
- const sharedStyles = {
12
- input: {
13
- borderRadius: '6px',
14
- },
15
- label: {
16
- fontSize: '13px',
17
- },
18
- };
19
- const selectInputStyles = {
20
- input: {
21
- borderRadius: '6px',
22
- fontSize: '0.8rem',
23
- height: '39px',
24
- },
25
- dropdown: {
26
- fontSize: '0.75rem',
27
- },
28
- };
29
- const commonProps = {
30
- size: 'md',
31
- style: { width: 240 },
32
- };
10
+ import MultiSelect from './MultiSelect';
11
+ import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from './Select';
33
12
  const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = true, showClearFilters, searctInputPlaceHolder = 'Search...', showApplyFilters = true, showSearch = false, searchQuery = '', children, isNarrow, handleFilterChange, handleApplyFilters, resetFilters, onSearch = () => { }, }) => {
34
- const [activeRangePicker, setActiveRangePicker] = React.useState(null);
35
13
  const hasSelectedActiveFilters = Object.entries(selectedFilters).some(([key, v]) => !isDefaultFilterValue(v, key));
36
14
  const shouldShowActionButtons = hasSelectedActiveFilters || (showSearch && searchQuery.length > 0);
37
15
  const parseDateValue = (value) => {
@@ -44,7 +22,6 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
44
22
  const parsed = new Date(value);
45
23
  return Number.isNaN(parsed.getTime()) ? null : parsed;
46
24
  };
47
- // Keyboard handler for search input
48
25
  const handleSearchKeyDown = (e) => {
49
26
  if (e.key === 'Enter') {
50
27
  handleApplyFilters();
@@ -54,28 +31,16 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
54
31
  resetFilters();
55
32
  }
56
33
  };
57
- // Keyboard handler for select/multiselect (dropdown) filters
58
- const handleFilterKeyDown = (e, name) => {
59
- if (e.key === 'Enter') {
60
- handleApplyFilters();
61
- }
62
- else if (e.key === 'Escape') {
63
- handleFilterChange(name, '');
64
- resetFilters();
65
- }
66
- };
67
- return (_jsxs(FilterWrapper, { isNarrow: isNarrow, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [showSearch && (_jsx("div", { className: "w-full sm:w-[300px]", children: _jsx(Input, { leftSection: _jsx(IconSearch, { size: 16 }), placeholder: searctInputPlaceHolder, value: searchQuery, onChange: (event) => onSearch(event), onKeyDown: handleSearchKeyDown, className: "w-full", styles: { input: { height: 39, backgroundColor: 'hsl(var(--muted))' } }, "aria-label": "Search" }) })), filters.map((filter) => {
34
+ return (_jsxs(FilterWrapper, { isNarrow: isNarrow, children: [_jsxs("div", { className: "flex flex-wrap items-center gap-2", children: [showSearch && (_jsxs("div", { className: "relative w-full sm:w-[300px]", children: [_jsx(IconSearch, { size: 16, className: "pointer-events-none absolute left-3 top-1/2 -translate-y-1/2 text-muted-foreground" }), _jsx("input", { type: "text", placeholder: searctInputPlaceHolder, value: searchQuery, onChange: onSearch, onKeyDown: handleSearchKeyDown, "aria-label": "Search", className: cn('h-9 w-full rounded-md border border-border bg-background pl-9 pr-3 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') })] })), filters.map((filter) => {
68
35
  const { name, type, options } = filter;
69
36
  const value = selectedFilters[name];
70
37
  const renderFilterInput = () => {
71
38
  if (type === 'date-range') {
72
39
  const rangeKeys = filter.rangeKeys;
73
- if (!rangeKeys) {
74
- console.warn('Date range filter requires rangeKeys', filter);
40
+ if (!rangeKeys)
75
41
  return null;
76
- }
77
- const startDateValue = rangeKeys ? selectedFilters[rangeKeys.start] : undefined;
78
- const endDateValue = rangeKeys ? selectedFilters[rangeKeys.end] : undefined;
42
+ const startDateValue = selectedFilters[rangeKeys.start];
43
+ const endDateValue = selectedFilters[rangeKeys.end];
79
44
  const startDate = parseDateValue(startDateValue);
80
45
  const endDate = parseDateValue(endDateValue);
81
46
  const dateRange = startDate && endDate
@@ -84,8 +49,6 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
84
49
  ? { from: startDate, to: startDate }
85
50
  : undefined;
86
51
  const handleRangeChange = (range) => {
87
- if (!rangeKeys)
88
- return;
89
52
  if (range?.from) {
90
53
  handleFilterChange(rangeKeys.start, startOfDay(range.from));
91
54
  handleFilterChange(rangeKeys.end, range.to ? endOfDay(range.to) : endOfDay(range.from));
@@ -101,16 +64,13 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
101
64
  return (_jsx(DatePicker, { value: value || null, onChange: (date) => handleFilterChange(name, date), placeholder: filter.placeholder ?? `Select ${name}` }));
102
65
  }
103
66
  if (type === 'multi-select') {
104
- return (_jsx(MultiSelect, { data: options || [], placeholder: filter.placeholder ?? `Select ${name}`, value: value || [], onChange: (val) => handleFilterChange(name, val), searchable: true, clearable: true, className: "w-full", styles: {
105
- ...sharedStyles,
106
- }, ...commonProps, onKeyDown: (e) => handleFilterKeyDown(e, name), "aria-label": filter.placeholder ?? name }));
67
+ return (_jsx(MultiSelect, { options: options ?? [], placeholder: filter.placeholder ?? `Select ${name}`, value: value || [], onChange: (val) => handleFilterChange(name, val), className: "w-full" }));
107
68
  }
108
- return (_jsx(Select, { data: options || [], placeholder: filter.placeholder ?? `Select ${name}`, value: value || null, onChange: (val) => handleFilterChange(name, val), searchable: true, clearable: true, className: "w-full", styles: {
109
- ...sharedStyles,
110
- ...selectInputStyles,
111
- }, onKeyDown: (e) => handleFilterKeyDown(e, name), "aria-label": filter.placeholder ?? name }));
69
+ // Default: select
70
+ const currentValue = value || '';
71
+ return (_jsxs(Select, { value: currentValue || undefined, onValueChange: (val) => handleFilterChange(name, val === '__clear__' ? '' : val), children: [_jsx(SelectTrigger, { className: "h-9 w-full border-border bg-background text-sm text-foreground", "aria-label": filter.placeholder ?? name, children: _jsx(SelectValue, { placeholder: filter.placeholder ?? `Select ${name}` }) }), _jsxs(SelectContent, { children: [currentValue && (_jsx(SelectItem, { value: "__clear__", className: "text-muted-foreground", children: filter.placeholder ?? 'All' })), (options ?? []).map((opt) => (_jsx(SelectItem, { value: opt.value, children: opt.label }, opt.value)))] })] }));
112
72
  };
113
73
  return (_jsx("div", { className: "w-full sm:w-[240px]", children: renderFilterInput() }, name));
114
- }), showApplyFilterButton && shouldShowActionButtons && (_jsx(Button, { onClick: handleApplyFilters, variant: "primary", className: "w-full sm:w-auto", style: { height: 39 }, 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: 39 }, tabIndex: 0, "aria-label": "Clear Filters", children: "Clear Filters" }))] }), children] }));
74
+ }), 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" }))] }), children] }));
115
75
  };
116
76
  export default FilterComponent;
@@ -27,9 +27,11 @@ const SearchableMultiSelectInput = forwardRef(({ field, error, options: rawOptio
27
27
  if (!triggerRef.current)
28
28
  return;
29
29
  const rect = triggerRef.current.getBoundingClientRect();
30
+ // Dropdown uses position: fixed, which is viewport-relative.
31
+ // getBoundingClientRect() is already viewport-relative, so do NOT add scroll offsets.
30
32
  setDropdownPos({
31
- top: rect.bottom + window.scrollY + 4,
32
- left: rect.left + window.scrollX,
33
+ top: rect.bottom + 4,
34
+ left: rect.left,
33
35
  width: rect.width,
34
36
  });
35
37
  }, []);
package/lib/styles.css CHANGED
@@ -2958,6 +2958,9 @@ video {
2958
2958
  .pl-8 {
2959
2959
  padding-left: 2rem;
2960
2960
  }
2961
+ .pl-9 {
2962
+ padding-left: 2.25rem;
2963
+ }
2961
2964
  .pr-10 {
2962
2965
  padding-right: 2.5rem;
2963
2966
  }
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.309",
4
+ "version": "0.8.311",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "provenance": false