@pagamio/frontend-commons-lib 0.8.253 → 0.8.255
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,13 +1,12 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
|
-
interface FeatureItem {
|
|
2
|
+
export interface FeatureItem {
|
|
3
3
|
icon?: React.ReactNode;
|
|
4
4
|
title: string;
|
|
5
5
|
description: string;
|
|
6
6
|
}
|
|
7
|
-
interface FeatureCarouselProps {
|
|
7
|
+
export interface FeatureCarouselProps {
|
|
8
8
|
features: FeatureItem[];
|
|
9
9
|
className?: string;
|
|
10
10
|
interval?: number;
|
|
11
11
|
}
|
|
12
12
|
export declare function FeatureCarousel({ features, className, interval }: FeatureCarouselProps): import("react/jsx-runtime").JSX.Element | null;
|
|
13
|
-
export {};
|
|
@@ -6,5 +6,6 @@ export { default as PagamioCustomerRegistrationPage, customerRegistrationPageDef
|
|
|
6
6
|
export { default as PagamioForgotPasswordPage, forgotPasswordDefaultText, type PagamioForgotPasswordPageProps, } from './ForgotPasswordPage';
|
|
7
7
|
export { default as PagamioResetPasswordPage, resetPasswordDefaultText, type PagamioResetPasswordPageProps, } from './ResetPasswordPage';
|
|
8
8
|
export { AuthPageLayout as PagamioAuthPageLayout } from './AuthPageLayout';
|
|
9
|
+
export { FeatureCarousel, type FeatureCarouselProps, type FeatureItem } from './FeatureCarousel';
|
|
9
10
|
export { default as OtpVerificationPage, OtpInput, otpVerificationDefaultText, type OtpInputProps, type OtpVerificationConfig, type OtpVerificationHandlers, type OtpVerificationPageProps, type OtpVerificationText, } from './OtpVerification';
|
|
10
11
|
export { passwordValidation } from './AuthFormUtils';
|
|
@@ -5,5 +5,6 @@ export { default as PagamioCustomerRegistrationPage, customerRegistrationPageDef
|
|
|
5
5
|
export { default as PagamioForgotPasswordPage, forgotPasswordDefaultText, } from './ForgotPasswordPage';
|
|
6
6
|
export { default as PagamioResetPasswordPage, resetPasswordDefaultText, } from './ResetPasswordPage';
|
|
7
7
|
export { AuthPageLayout as PagamioAuthPageLayout } from './AuthPageLayout';
|
|
8
|
+
export { FeatureCarousel } from './FeatureCarousel';
|
|
8
9
|
export { default as OtpVerificationPage, OtpInput, otpVerificationDefaultText, } from './OtpVerification';
|
|
9
10
|
export { passwordValidation } from './AuthFormUtils';
|
|
@@ -1,60 +1,103 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import
|
|
3
|
-
import {
|
|
4
|
-
import * as Popover from '@radix-ui/react-popover';
|
|
5
|
-
import { forwardRef, useEffect, useState } from 'react';
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { ChevronDownIcon, Cross2Icon } from '@radix-ui/react-icons';
|
|
3
|
+
import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
|
|
6
4
|
import { cn } from '../../helpers';
|
|
7
5
|
import Button from './Button';
|
|
8
|
-
const
|
|
9
|
-
if (selectedOptions.length === 0) {
|
|
10
|
-
return _jsx("span", { className: "truncate", children: placeholder ?? 'Select options' });
|
|
11
|
-
}
|
|
12
|
-
return (_jsx("div", { className: "flex flex-wrap gap-2", children: selectedOptions.map((option) => (_jsxs("div", { className: "flex items-center gap-1 px-2 py-1 text-sm bg-muted rounded-md", children: [option.label, _jsx(Button, { type: "button", size: "icon", variant: "ghost", onClick: (e) => removeTag(option.value, e), className: "p-0.5 hover:bg-gray-200 rounded-full", children: _jsx(Cross2Icon, { className: "w-3 h-3" }) })] }, option.value))) }));
|
|
13
|
-
};
|
|
14
|
-
const MultiSelect = forwardRef(({ options, value, defaultValue = [], disabled, onChange, placeholder, className, onSearch, field, tagPosition = 'inside', }, ref) => {
|
|
6
|
+
const MultiSelect = forwardRef(({ options, value, defaultValue = [], disabled, onChange, placeholder, className, field, tagPosition = 'inside' }, ref) => {
|
|
15
7
|
const [selectedValues, setSelectedValues] = useState(defaultValue);
|
|
16
|
-
const [searchTerm, setSearchTerm] = useState('');
|
|
17
|
-
const [filteredOptions, setFilteredOptions] = useState(options);
|
|
18
8
|
const [isOpen, setIsOpen] = useState(false);
|
|
9
|
+
const [dropdownPos, setDropdownPos] = useState(null);
|
|
10
|
+
const containerRef = useRef(null);
|
|
11
|
+
const triggerRef = useRef(null);
|
|
12
|
+
// Sync external value changes (e.g. form reset / initial values)
|
|
19
13
|
useEffect(() => {
|
|
20
|
-
if (
|
|
21
|
-
|
|
14
|
+
if (value !== undefined) {
|
|
15
|
+
setSelectedValues(value);
|
|
22
16
|
}
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
:
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
17
|
+
}, [value]);
|
|
18
|
+
// Measure trigger position so the fixed dropdown aligns correctly
|
|
19
|
+
const updateDropdownPosition = useCallback(() => {
|
|
20
|
+
if (!triggerRef.current)
|
|
21
|
+
return;
|
|
22
|
+
const rect = triggerRef.current.getBoundingClientRect();
|
|
23
|
+
setDropdownPos({
|
|
24
|
+
top: rect.bottom + window.scrollY + 4,
|
|
25
|
+
left: rect.left + window.scrollX,
|
|
26
|
+
width: rect.width,
|
|
27
|
+
});
|
|
28
|
+
}, []);
|
|
29
|
+
// Reposition on scroll / resize while open
|
|
30
|
+
useEffect(() => {
|
|
31
|
+
if (!isOpen)
|
|
32
|
+
return;
|
|
33
|
+
updateDropdownPosition();
|
|
34
|
+
window.addEventListener('scroll', updateDropdownPosition, true);
|
|
35
|
+
window.addEventListener('resize', updateDropdownPosition);
|
|
36
|
+
return () => {
|
|
37
|
+
window.removeEventListener('scroll', updateDropdownPosition, true);
|
|
38
|
+
window.removeEventListener('resize', updateDropdownPosition);
|
|
39
|
+
};
|
|
40
|
+
}, [isOpen, updateDropdownPosition]);
|
|
41
|
+
// Close on outside click
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
if (!isOpen)
|
|
44
|
+
return;
|
|
45
|
+
const handleOutside = (e) => {
|
|
46
|
+
const target = e.target;
|
|
47
|
+
const clickedInsideTrigger = containerRef.current?.contains(target);
|
|
48
|
+
const dropdown = document.getElementById('ms-dropdown-portal');
|
|
49
|
+
const clickedInsideDropdown = dropdown?.contains(target);
|
|
50
|
+
if (!clickedInsideTrigger && !clickedInsideDropdown) {
|
|
51
|
+
setIsOpen(false);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
document.addEventListener('mousedown', handleOutside);
|
|
55
|
+
return () => document.removeEventListener('mousedown', handleOutside);
|
|
56
|
+
}, [isOpen]);
|
|
57
|
+
const internalValues = value ?? selectedValues;
|
|
58
|
+
const handleToggle = (optionValue) => {
|
|
59
|
+
const updated = internalValues.includes(optionValue)
|
|
60
|
+
? internalValues.filter((v) => v !== optionValue)
|
|
61
|
+
: [...internalValues, optionValue];
|
|
62
|
+
if (value === undefined)
|
|
63
|
+
setSelectedValues(updated);
|
|
64
|
+
onChange?.(updated);
|
|
36
65
|
};
|
|
37
66
|
const removeTag = (optionValue, e) => {
|
|
38
67
|
e.stopPropagation();
|
|
39
68
|
handleToggle(optionValue);
|
|
40
69
|
};
|
|
41
|
-
const
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
70
|
+
const handleTriggerClick = () => {
|
|
71
|
+
if (disabled)
|
|
72
|
+
return;
|
|
73
|
+
if (!isOpen)
|
|
74
|
+
updateDropdownPosition();
|
|
75
|
+
setIsOpen((o) => !o);
|
|
76
|
+
};
|
|
77
|
+
const selectedOptions = options.filter((o) => internalValues.includes(o.value));
|
|
78
|
+
const displayPlaceholder = field?.placeholder ?? placeholder ?? 'Select options';
|
|
79
|
+
const tags = (_jsx(_Fragment, { children: selectedOptions.map((opt) => (_jsxs("span", { className: "inline-flex items-center gap-1 px-2 py-0.5 rounded-md text-xs font-medium bg-primary/10 text-primary", children: [opt.label, _jsx(Button, { type: "button", variant: "ghost", size: "icon", "aria-label": `Remove ${opt.label}`, onClick: (e) => removeTag(opt.value, e), className: "h-4 w-4 p-0 hover:bg-primary/20 rounded-full", children: _jsx(Cross2Icon, { className: "w-2.5 h-2.5" }) })] }, opt.value))) }));
|
|
80
|
+
return (_jsxs("div", { ref: containerRef, className: cn('relative w-full', className), children: [_jsxs("button", { ref: triggerRef, type: "button", disabled: disabled, onClick: handleTriggerClick, onKeyDown: (e) => {
|
|
81
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
82
|
+
e.preventDefault();
|
|
83
|
+
handleTriggerClick();
|
|
84
|
+
}
|
|
85
|
+
if (e.key === 'Escape')
|
|
86
|
+
setIsOpen(false);
|
|
87
|
+
}, className: cn('flex items-center w-full px-3 py-2 text-sm border border-input rounded-md bg-background text-left', 'focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-0', 'transition-colors duration-150 min-h-[38px]', disabled
|
|
88
|
+
? 'opacity-50 cursor-not-allowed bg-muted text-muted-foreground'
|
|
89
|
+
: 'cursor-pointer hover:border-primary/60', isOpen && 'border-primary ring-2 ring-ring'), "aria-haspopup": "listbox", "aria-expanded": isOpen, children: [_jsx("span", { className: "flex-1 min-w-0", children: tagPosition === 'inside' && selectedOptions.length > 0 ? (_jsx("span", { className: "flex flex-wrap gap-1", children: tags })) : (_jsx("span", { className: cn('truncate block', selectedOptions.length === 0 && 'text-muted-foreground'), children: selectedOptions.length === 0 || tagPosition === 'inside'
|
|
90
|
+
? displayPlaceholder
|
|
91
|
+
: `${selectedOptions.length} selected` })) }), _jsx(ChevronDownIcon, { className: cn('ml-2 flex-shrink-0 text-muted-foreground transition-transform duration-150', isOpen && 'rotate-180') })] }), tagPosition === 'bottom' && selectedOptions.length > 0 && (_jsx("div", { className: "flex flex-wrap gap-1 mt-2", children: tags })), isOpen && dropdownPos && (_jsx("div", { ref: ref, id: "ms-dropdown-portal", style: {
|
|
92
|
+
position: 'fixed',
|
|
93
|
+
top: dropdownPos.top,
|
|
94
|
+
left: dropdownPos.left,
|
|
95
|
+
width: dropdownPos.width,
|
|
96
|
+
}, className: cn('z-[9999]', 'bg-popover border border-border rounded-md shadow-lg', 'animate-in fade-in-0 zoom-in-95 duration-100'), children: _jsx("ul", { className: "max-h-56 overflow-y-auto p-1.5 space-y-0.5", children: options.length > 0 ? (options.map((option) => {
|
|
97
|
+
const checked = internalValues.includes(option.value);
|
|
98
|
+
const id = `ms-opt-${field?.name ?? 'ms'}-${option.value}`;
|
|
99
|
+
return (_jsx("li", { children: _jsxs("label", { htmlFor: id, className: cn('flex items-center gap-2.5 px-2 py-2 rounded-md cursor-pointer text-sm', 'hover:bg-accent hover:text-accent-foreground transition-colors', checked && 'bg-primary/5'), children: [_jsx("input", { id: id, type: "checkbox", checked: checked, onChange: () => handleToggle(option.value), className: cn('w-4 h-4 rounded border border-input bg-background flex-shrink-0', 'accent-[hsl(var(--primary))] cursor-pointer', 'focus:ring-2 focus:ring-ring focus:ring-offset-0') }), _jsx("span", { className: "flex-1 font-medium text-foreground", children: option.label })] }) }, option.value));
|
|
100
|
+
})) : (_jsx("li", { className: "px-3 py-2 text-sm text-muted-foreground text-center", children: "No options found" })) }) }))] }));
|
|
58
101
|
});
|
|
59
102
|
MultiSelect.displayName = 'MultiSelect';
|
|
60
103
|
export default MultiSelect;
|
package/lib/styles.css
CHANGED
|
@@ -842,6 +842,9 @@ video {
|
|
|
842
842
|
.z-\[70\] {
|
|
843
843
|
z-index: 70;
|
|
844
844
|
}
|
|
845
|
+
.z-\[9999\] {
|
|
846
|
+
z-index: 9999;
|
|
847
|
+
}
|
|
845
848
|
.z-auto {
|
|
846
849
|
z-index: auto;
|
|
847
850
|
}
|
|
@@ -1243,8 +1246,8 @@ video {
|
|
|
1243
1246
|
.max-h-16 {
|
|
1244
1247
|
max-height: 4rem;
|
|
1245
1248
|
}
|
|
1246
|
-
.max-h-
|
|
1247
|
-
max-height:
|
|
1249
|
+
.max-h-56 {
|
|
1250
|
+
max-height: 14rem;
|
|
1248
1251
|
}
|
|
1249
1252
|
.max-h-64 {
|
|
1250
1253
|
max-height: 16rem;
|
|
@@ -1279,6 +1282,9 @@ video {
|
|
|
1279
1282
|
.min-h-\[200px\] {
|
|
1280
1283
|
min-height: 200px;
|
|
1281
1284
|
}
|
|
1285
|
+
.min-h-\[38px\] {
|
|
1286
|
+
min-height: 38px;
|
|
1287
|
+
}
|
|
1282
1288
|
.min-h-\[60px\] {
|
|
1283
1289
|
min-height: 60px;
|
|
1284
1290
|
}
|
|
@@ -1727,6 +1733,9 @@ video {
|
|
|
1727
1733
|
.gap-2 {
|
|
1728
1734
|
gap: 0.5rem;
|
|
1729
1735
|
}
|
|
1736
|
+
.gap-2\.5 {
|
|
1737
|
+
gap: 0.625rem;
|
|
1738
|
+
}
|
|
1730
1739
|
.gap-3 {
|
|
1731
1740
|
gap: 0.75rem;
|
|
1732
1741
|
}
|
|
@@ -2638,9 +2647,6 @@ video {
|
|
|
2638
2647
|
.p-0 {
|
|
2639
2648
|
padding: 0px;
|
|
2640
2649
|
}
|
|
2641
|
-
.p-0\.5 {
|
|
2642
|
-
padding: 0.125rem;
|
|
2643
|
-
}
|
|
2644
2650
|
.p-1 {
|
|
2645
2651
|
padding: 0.25rem;
|
|
2646
2652
|
}
|
|
@@ -3311,6 +3317,9 @@ video {
|
|
|
3311
3317
|
--tw-placeholder-opacity: 1;
|
|
3312
3318
|
color: rgb(142 75 16 / var(--tw-placeholder-opacity, 1));
|
|
3313
3319
|
}
|
|
3320
|
+
.accent-\[hsl\(var\(--primary\)\)\] {
|
|
3321
|
+
accent-color: hsl(var(--primary));
|
|
3322
|
+
}
|
|
3314
3323
|
.opacity-0 {
|
|
3315
3324
|
opacity: 0;
|
|
3316
3325
|
}
|
|
@@ -3422,6 +3431,9 @@ video {
|
|
|
3422
3431
|
--tw-ring-opacity: 1;
|
|
3423
3432
|
--tw-ring-color: rgb(240 82 82 / var(--tw-ring-opacity, 1));
|
|
3424
3433
|
}
|
|
3434
|
+
.ring-ring {
|
|
3435
|
+
--tw-ring-color: hsl(var(--ring));
|
|
3436
|
+
}
|
|
3425
3437
|
.ring-white {
|
|
3426
3438
|
--tw-ring-opacity: 1;
|
|
3427
3439
|
--tw-ring-color: rgb(255 255 255 / var(--tw-ring-opacity, 1));
|
|
@@ -3919,6 +3931,9 @@ video {
|
|
|
3919
3931
|
--tw-border-opacity: 1;
|
|
3920
3932
|
border-color: rgb(23 14 49 / var(--tw-border-opacity, 1));
|
|
3921
3933
|
}
|
|
3934
|
+
.hover\:border-primary\/60:hover {
|
|
3935
|
+
border-color: hsl(var(--primary) / 0.6);
|
|
3936
|
+
}
|
|
3922
3937
|
.hover\:border-purple-800:hover {
|
|
3923
3938
|
--tw-border-opacity: 1;
|
|
3924
3939
|
border-color: rgb(85 33 181 / var(--tw-border-opacity, 1));
|
|
@@ -4042,6 +4057,9 @@ video {
|
|
|
4042
4057
|
.hover\:bg-primary\/15:hover {
|
|
4043
4058
|
background-color: hsl(var(--primary) / 0.15);
|
|
4044
4059
|
}
|
|
4060
|
+
.hover\:bg-primary\/20:hover {
|
|
4061
|
+
background-color: hsl(var(--primary) / 0.2);
|
|
4062
|
+
}
|
|
4045
4063
|
.hover\:bg-primary\/90:hover {
|
|
4046
4064
|
background-color: hsl(var(--primary) / 0.9);
|
|
4047
4065
|
}
|
|
@@ -4446,6 +4464,9 @@ video {
|
|
|
4446
4464
|
--tw-ring-opacity: 1;
|
|
4447
4465
|
--tw-ring-color: rgb(194 120 3 / var(--tw-ring-opacity, 1));
|
|
4448
4466
|
}
|
|
4467
|
+
.focus\:ring-offset-0:focus {
|
|
4468
|
+
--tw-ring-offset-width: 0px;
|
|
4469
|
+
}
|
|
4449
4470
|
.focus\:ring-offset-2:focus {
|
|
4450
4471
|
--tw-ring-offset-width: 2px;
|
|
4451
4472
|
}
|
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.255",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|