@pagamio/frontend-commons-lib 0.8.365 → 0.8.367

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,
@@ -31,7 +31,7 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
31
31
  resetFilters();
32
32
  }
33
33
  };
34
- return (_jsxs(FilterWrapper, { isNarrow: isNarrow, children: [_jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-2 min-w-0", children: [showSearch && (_jsxs("div", { className: "relative w-full sm:flex-1 sm:min-w-[200px] sm:max-w-[340px] min-w-0", 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) => {
34
+ return (_jsxs(FilterWrapper, { isNarrow: isNarrow, allowOverflowVisible: Boolean(children), children: [_jsxs("div", { className: "flex flex-1 flex-wrap items-center gap-2 min-w-0", children: [showSearch && (_jsxs("div", { className: "relative w-full sm:flex-1 sm:min-w-[200px] sm:max-w-[340px] min-w-0", 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) => {
35
35
  const { name, type, options } = filter;
36
36
  const value = selectedFilters[name];
37
37
  const renderFilterInput = () => {
@@ -2,6 +2,7 @@ import React from 'react';
2
2
  interface FilterWrapperProps {
3
3
  isNarrow: boolean;
4
4
  children: React.ReactNode;
5
+ allowOverflowVisible?: boolean;
5
6
  }
6
- declare const FilterWrapper: ({ isNarrow, children }: FilterWrapperProps) => React.JSX.Element;
7
+ declare const FilterWrapper: ({ isNarrow, children, allowOverflowVisible }: FilterWrapperProps) => React.JSX.Element;
7
8
  export default FilterWrapper;
@@ -1,9 +1,10 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- const FilterWrapper = ({ isNarrow, children }) => {
2
+ const FilterWrapper = ({ isNarrow, children, allowOverflowVisible = false }) => {
3
3
  return (
4
- // `min-w-0` so this card can shrink inside a flex/grid parent;
5
- // `overflow-hidden` so wide filter rows never punch out of the toolbar.
6
- _jsx("div", { className: "bg-card shadow-xl rounded-lg p-4 mb-2 min-w-0 overflow-hidden", children: _jsx("div", { className: isNarrow
4
+ // `min-w-0` so this card can shrink inside a flex/grid parent.
5
+ // Most toolbars keep `overflow-hidden` so oversized rows do not punch out,
6
+ // but some controls (like export popovers) need to render beyond the card.
7
+ _jsx("div", { className: `bg-card shadow-xl rounded-lg p-4 mb-2 min-w-0 ${allowOverflowVisible ? 'overflow-visible' : 'overflow-hidden'}`, children: _jsx("div", { className: isNarrow
7
8
  ? 'flex flex-col w-full gap-3'
8
9
  : // `flex-wrap` lets the filter pills drop onto a second row instead of
9
10
  // overflowing the toolbar; each child group is set to `min-w-0` via its own
@@ -1,11 +1,9 @@
1
- import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import { Stack } from '@mantine/core';
3
3
  import { Checkbox, Label, TextInput } from 'flowbite-react';
4
4
  import { HiMail } from 'react-icons/hi';
5
5
  import { useEffect, useRef, useState } from 'react';
6
- // (useEffect / useRef / popoverRef / handelClickOutside can all be removed
7
- // Modal handles its own open/close + backdrop click)
8
- import { Modal, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components';
6
+ import { Button, Modal, Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '../../components';
9
7
  import { exportToCsv, exportToPdf, exportToXlsx, generateExportAsFile, sendExportEmail } from './exportUtils';
10
8
  const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, extraOptions = [], pdfOptions, xlsxOptions, csvOptions, exportAll = false, fetchData, asyncExport, enableEmailExport = false, emailExportApiUrl, onEmailExportSuccess, onEmailExportError, }) => {
11
9
  const [exportType, setExportType] = useState(null);
@@ -19,10 +17,10 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
19
17
  const [showEmailModal, setShowEmailModal] = useState(false);
20
18
  const [pendingExportData, setPendingExportData] = useState(null);
21
19
  const [pendingEmailFormat, setPendingEmailFormat] = useState(null);
22
- const popoverRef = useRef(null);
20
+ const containerRef = useRef(null);
23
21
  useEffect(() => {
24
22
  const handleClickOutside = (event) => {
25
- if (popoverRef.current && !popoverRef.current.contains(event.target)) {
23
+ if (containerRef.current && !containerRef.current.contains(event.target)) {
26
24
  setExportType(null);
27
25
  }
28
26
  };
@@ -181,30 +179,23 @@ const ExportDropdown = ({ data, columns, containerClassName, buttonClassName, ex
181
179
  };
182
180
  // Show popover when exportType is set and Select is closed
183
181
  const popoverOpened = exportType !== null && !selectOpen;
184
- const continueLable = isExporting
182
+ const continueLabel = isExporting
185
183
  ? exportProgress && exportProgress.total > exportProgress.fetched
186
184
  ? `Fetching ${exportProgress.fetched}/${exportProgress.total}...`
187
185
  : isEmailExport
188
186
  ? 'Preparing...'
189
187
  : 'Exporting...'
190
188
  : 'Continue';
191
- return (_jsxs("div", { className: `w-40 ${containerClassName ?? ''}`, children: [_jsxs(Select, { value: exportType ?? 'none', open: selectOpen, onOpenChange: setSelectOpen, onValueChange: (value) => handleExportChange(value === 'none' ? null : value), children: [_jsx(SelectTrigger, { className: `w-full ${buttonClassName ?? ''}`, children: _jsx(SelectValue, { placeholder: "Export Data" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "none", children: _jsx("span", { className: "text-muted-foreground", children: "Export Data As" }) }, "reset"), exportOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))), extraOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value)))] })] }, "export-dropdown"), _jsxs(Modal, { isOpen: popoverOpened, onClose: () => setExportType(null), title: "Export Data", size: "md", primaryButton: {
192
- label: continueLable,
193
- onClick: handleContinue,
194
- disabled: getIncludedColumns().length === 0 || isExporting,
195
- loading: isExporting,
196
- }, secondaryButton: {
197
- label: 'Cancel',
198
- onClick: () => setExportType(null),
199
- disabled: isExporting,
200
- variant: 'outline',
201
- }, children: [_jsx("div", { className: "text-sm text-muted-foreground pb-3", children: "Uncheck to exclude column from export" }), _jsxs("div", { className: "mb-4 p-3 bg-muted rounded-md", children: [_jsxs("div", { className: "flex items-center gap-x-2", children: [_jsx(Checkbox, { id: "export-all-data", checked: exportAllData, onChange: (event) => setExportAllData(event.currentTarget.checked), className: "checked:!bg-primary checked:!border-primary-50" }), _jsx("label", { htmlFor: "export-all-data", className: "text-sm font-medium", children: "Export all data" })] }), _jsx("p", { className: "text-xs text-muted-foreground mt-1 ml-6", children: shouldQueueAsync
202
- ? 'This dataset is large - it will be prepared in the background and and appear in export history.'
189
+ return (_jsxs("div", { ref: containerRef, className: `relative w-40 ${containerClassName ?? ''}`, children: [_jsxs(Select, { value: exportType ?? 'none', open: selectOpen, onOpenChange: setSelectOpen, onValueChange: (value) => handleExportChange(value === 'none' ? null : value), children: [_jsx(SelectTrigger, { className: `w-full ${buttonClassName ?? ''}`, children: _jsx(SelectValue, { placeholder: "Export Data" }) }), _jsxs(SelectContent, { children: [_jsx(SelectItem, { value: "none", children: _jsx("span", { className: "text-muted-foreground", children: "Export Data As" }) }, "reset"), exportOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value))), extraOptions.map((option) => (_jsx(SelectItem, { value: option.value, children: option.label }, option.value)))] })] }, "export-dropdown"), popoverOpened && (_jsxs("div", { className: "absolute left-0 top-full z-50 mt-2 w-64 rounded-md bg-background p-4 shadow-lg", children: [_jsx("div", { className: "pb-3 text-sm text-muted-foreground", children: "Uncheck to exclude column from export" }), _jsxs("div", { className: "mb-4 rounded-md bg-muted p-3", children: [_jsxs("div", { className: "flex items-center gap-x-2", children: [_jsx(Checkbox, { id: "export-all-data", checked: exportAllData, onChange: (event) => setExportAllData(event.currentTarget.checked), className: "checked:!bg-primary checked:!border-primary" }), _jsx(Label, { htmlFor: "export-all-data", className: "text-sm font-medium", children: "Export all data" })] }), _jsx("p", { className: "ml-6 mt-1 text-xs text-muted-foreground", children: shouldQueueAsync
190
+ ? 'This dataset is large — it will be prepared in the background and appear in export history.'
203
191
  : 'This will fetch all records for the table' })] }), _jsx(Stack, { children: columns.map((col) => {
204
192
  if (col.accessorKey !== 'action') {
205
193
  return (_jsxs("div", { className: "flex items-center gap-x-2", children: [_jsx(Checkbox, { id: col.accessorKey, checked: !excludedColumns.includes(col.accessorKey), onChange: (event) => handleCheckboxChange(col.accessorKey, !event.currentTarget.checked), className: "checked:!bg-primary checked:!border-primary" }), _jsx(Label, { htmlFor: col.accessorKey, children: col.header })] }, col.accessorKey));
206
194
  }
207
- }) })] }), _jsx(Modal, { isOpen: showEmailModal, onClose: handleEmailModalClose, title: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(HiMail, { className: "w-5 h-5 text-primary" }), _jsx("span", { children: "Send Export via Email" })] }), size: "md", primaryButton: {
195
+ return null;
196
+ }) }), _jsx(Button, { variant: "primary", className: `mt-4 flex w-full items-center justify-center rounded-md px-4 py-2 text-white ${getIncludedColumns().length === 0 || isExporting
197
+ ? 'cursor-not-allowed bg-gray-300'
198
+ : 'bg-primary hover:bg-primary/90'}`, onClick: handleContinue, disabled: getIncludedColumns().length === 0 || isExporting, children: isExporting ? (_jsxs(_Fragment, { children: [_jsxs("svg", { className: "-ml-1 mr-2 h-4 w-4 animate-spin text-white", xmlns: "http://www.w3.org/2000/svg", fill: "none", viewBox: "0 0 24 24", children: [_jsx("circle", { className: "opacity-25", cx: "12", cy: "12", r: "10", stroke: "currentColor", strokeWidth: "4" }), _jsx("path", { className: "opacity-75", fill: "currentColor", d: "M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z" })] }), continueLabel] })) : ('Continue') })] })), _jsx(Modal, { isOpen: showEmailModal, onClose: handleEmailModalClose, title: _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(HiMail, { className: "w-5 h-5 text-primary" }), _jsx("span", { children: "Send Export via Email" })] }), size: "md", primaryButton: {
208
199
  label: 'Send Email',
209
200
  onClick: () => {
210
201
  handleEmailModalSubmit().catch((error) => {
package/lib/styles.css CHANGED
@@ -815,6 +815,9 @@ video {
815
815
  .top-\[57\%\] {
816
816
  top: 57%;
817
817
  }
818
+ .top-full {
819
+ top: 100%;
820
+ }
818
821
  .\!z-\[1000\] {
819
822
  z-index: 1000 !important;
820
823
  }
@@ -971,6 +974,9 @@ video {
971
974
  .-mb-px {
972
975
  margin-bottom: -1px;
973
976
  }
977
+ .-ml-1 {
978
+ margin-left: -0.25rem;
979
+ }
974
980
  .-mt-2 {
975
981
  margin-top: -0.5rem;
976
982
  }
@@ -1973,6 +1979,9 @@ video {
1973
1979
  .overflow-hidden {
1974
1980
  overflow: hidden;
1975
1981
  }
1982
+ .overflow-visible {
1983
+ overflow: visible;
1984
+ }
1976
1985
  .overflow-x-auto {
1977
1986
  overflow-x: auto;
1978
1987
  }
@@ -4254,10 +4263,6 @@ video {
4254
4263
  .checked\:\!border-primary:checked {
4255
4264
  border-color: hsl(var(--primary)) !important;
4256
4265
  }
4257
- .checked\:\!border-primary-50:checked {
4258
- --tw-border-opacity: 1 !important;
4259
- border-color: rgb(237 234 244 / var(--tw-border-opacity, 1)) !important;
4260
- }
4261
4266
  .checked\:border-transparent:checked {
4262
4267
  border-color: transparent;
4263
4268
  }
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.365",
4
+ "version": "0.8.367",
5
5
  "publishConfig": {
6
6
  "access": "public",
7
7
  "provenance": false