@pagamio/frontend-commons-lib 0.8.249 → 0.8.251
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/sidebar-v2/SidebarV2.js +6 -3
- package/lib/components/sidebar-v2/SidebarV2Primitives.js +3 -3
- package/lib/components/ui/FilterComponent.js +1 -1
- package/lib/components/ui/FilterWrapper.js +1 -1
- package/lib/components/ui/PagamioTabs.d.ts +3 -3
- package/lib/components/ui/PagamioTabs.js +69 -36
- package/lib/styles.css +7 -7
- package/package.json +1 -1
|
@@ -31,13 +31,16 @@ const MenuItemRenderer = ({ item, depth = 0, iconResolver = defaultIconResolver,
|
|
|
31
31
|
const [isExpanded, setIsExpanded] = useState(false);
|
|
32
32
|
// Resolve icon
|
|
33
33
|
const IconComponent = resolveIcon(item.icon, iconResolver);
|
|
34
|
-
// Check active state
|
|
35
|
-
const
|
|
34
|
+
// Check active state — exact match only for leaf items, prefix match for parents with children
|
|
35
|
+
const hasChildren = item.items && item.items.length > 0;
|
|
36
|
+
const isActive = item.href
|
|
37
|
+
? pathname === item.href || (hasChildren && pathname.startsWith(`${item.href}/`))
|
|
38
|
+
: false;
|
|
36
39
|
// Check if any child is active
|
|
37
40
|
const hasActiveChild = useMemo(() => {
|
|
38
41
|
const checkActive = (items = []) => {
|
|
39
42
|
return items.some((child) => {
|
|
40
|
-
if (child.href && pathname.startsWith(child.href))
|
|
43
|
+
if (child.href && (pathname === child.href || pathname.startsWith(`${child.href}/`)))
|
|
41
44
|
return true;
|
|
42
45
|
if (child.items)
|
|
43
46
|
return checkActive(child.items);
|
|
@@ -20,12 +20,12 @@ const SidebarContainer = forwardRef(({ className, side = 'left', variant = 'defa
|
|
|
20
20
|
// Mobile sidebar (offcanvas)
|
|
21
21
|
if (isMobile) {
|
|
22
22
|
const { setOpenMobile } = useSidebarV2();
|
|
23
|
-
return (_jsxs(_Fragment, { children: [openMobile && (_jsx("div", { className: "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm transition-opacity cursor-pointer", onClick: () => setOpenMobile(false), "aria-hidden": "true" })), _jsx("aside", { ref: ref, "data-state": openMobile ? 'open' : 'closed', "data-side": side, className: cn('fixed top-16 bottom-0 z-[60] flex flex-col', 'bg-
|
|
23
|
+
return (_jsxs(_Fragment, { children: [openMobile && (_jsx("div", { className: "fixed inset-0 z-40 bg-black/50 backdrop-blur-sm transition-opacity cursor-pointer", onClick: () => setOpenMobile(false), "aria-hidden": "true" })), _jsx("aside", { ref: ref, "data-state": openMobile ? 'open' : 'closed', "data-side": side, className: cn('fixed top-16 bottom-0 z-[60] flex flex-col', 'bg-card', 'text-foreground', 'transition-transform duration-300 ease-in-out', side === 'left' ? 'left-0' : 'right-0', openMobile ? 'translate-x-0' : side === 'left' ? '-translate-x-full' : 'translate-x-full', className), style: {
|
|
24
24
|
width: config.mobileWidth,
|
|
25
25
|
}, ...props, children: children })] }));
|
|
26
26
|
}
|
|
27
27
|
// Desktop sidebar - Fixed position, starts below navbar
|
|
28
|
-
return (_jsx("aside", { ref: ref, "data-state": state, "data-side": side, "data-variant": variant, className: cn('group/sidebar fixed top-16 left-0 z-50', 'hidden md:flex flex-col', 'bg-
|
|
28
|
+
return (_jsx("aside", { ref: ref, "data-state": state, "data-side": side, "data-variant": variant, className: cn('group/sidebar fixed top-16 left-0 z-50', 'hidden md:flex flex-col', 'bg-card', 'text-foreground', 'border-border', 'transition-all duration-200 ease-in-out', side === 'left' ? 'border-r' : 'border-l', variant === 'floating' && 'rounded-lg border m-2 shadow-lg', variant === 'inset' && 'rounded-lg', className), style: {
|
|
29
29
|
width: open ? config.width : config.collapsedWidth,
|
|
30
30
|
height: 'calc(100vh - 4rem)', // Full height minus navbar (64px)
|
|
31
31
|
}, ...props, children: children }));
|
|
@@ -35,7 +35,7 @@ SidebarContainer.displayName = 'SidebarContainer';
|
|
|
35
35
|
* Sticky header at the top of sidebar
|
|
36
36
|
*/
|
|
37
37
|
const SidebarHeader = forwardRef(({ className, children, ...props }, ref) => {
|
|
38
|
-
return (_jsx("div", { ref: ref, className: cn('flex flex-col gap-2 p-4 border-b border-sidebar-border z-[60] relative bg-
|
|
38
|
+
return (_jsx("div", { ref: ref, className: cn('flex flex-col gap-2 p-4 border-b border-sidebar-border z-[60] relative bg-card', className), ...props, children: children }));
|
|
39
39
|
});
|
|
40
40
|
SidebarHeader.displayName = 'SidebarHeader';
|
|
41
41
|
/**
|
|
@@ -64,7 +64,7 @@ const FilterComponent = ({ filters, selectedFilters, showApplyFilterButton = tru
|
|
|
64
64
|
resetFilters();
|
|
65
65
|
}
|
|
66
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 } }, "aria-label": "Search" }) })), filters.map((filter) => {
|
|
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) => {
|
|
68
68
|
const { name, type, options } = filter;
|
|
69
69
|
const value = selectedFilters[name];
|
|
70
70
|
const renderFilterInput = () => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
const FilterWrapper = ({ isNarrow, children }) => {
|
|
3
|
-
return (_jsx("div", { className: "bg-
|
|
3
|
+
return (_jsx("div", { className: "bg-card shadow-xl rounded-lg p-4 mb-2", children: _jsx("div", { className: isNarrow
|
|
4
4
|
? 'flex flex-col w-full space-y-4'
|
|
5
5
|
: 'flex flex-row justify-between items-start w-full space-y-0 space-x-0 sm:space-x-4', children: children }) }));
|
|
6
6
|
};
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* ISP: Only the props you use matter — everything is optional.
|
|
7
7
|
*
|
|
8
8
|
* Supports ALL Flowbite tab variants (default, underline, pills, fullWidth)
|
|
9
|
-
* plus vertical orientation with
|
|
9
|
+
* plus vertical orientation using the same Flowbite Tabs with a vertical theme.
|
|
10
10
|
*/
|
|
11
11
|
import { type TabsTheme } from 'flowbite-react';
|
|
12
12
|
import type { ComponentProps, FC, ReactNode } from 'react';
|
|
@@ -21,7 +21,7 @@ export interface PagamioTabsProps {
|
|
|
21
21
|
tabs: PagamioTabItem[];
|
|
22
22
|
/** Flowbite tab variant */
|
|
23
23
|
variant?: 'default' | 'underline' | 'pills' | 'fullWidth';
|
|
24
|
-
/** Tab orientation — horizontal
|
|
24
|
+
/** Tab orientation — horizontal or vertical, both use Flowbite Tabs */
|
|
25
25
|
orientation?: 'horizontal' | 'vertical';
|
|
26
26
|
/** Controlled active tab index (0-based) */
|
|
27
27
|
activeTab?: number;
|
|
@@ -39,7 +39,7 @@ export interface PagamioTabsProps {
|
|
|
39
39
|
description?: string;
|
|
40
40
|
/** Container className */
|
|
41
41
|
className?: string;
|
|
42
|
-
/** Tab list className
|
|
42
|
+
/** Tab list className */
|
|
43
43
|
tabListClassName?: string;
|
|
44
44
|
/** Tab panel className */
|
|
45
45
|
tabPanelClassName?: string;
|
|
@@ -7,12 +7,11 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
7
7
|
* ISP: Only the props you use matter — everything is optional.
|
|
8
8
|
*
|
|
9
9
|
* Supports ALL Flowbite tab variants (default, underline, pills, fullWidth)
|
|
10
|
-
* plus vertical orientation with
|
|
10
|
+
* plus vertical orientation using the same Flowbite Tabs with a vertical theme.
|
|
11
11
|
*/
|
|
12
12
|
import { TabItem as FlowbiteTabItem, Tabs } from 'flowbite-react';
|
|
13
13
|
import { useRef, useState } from 'react';
|
|
14
|
-
|
|
15
|
-
// ─── Contained Tab Theme (matches old ContainedTab look) ─────────────
|
|
14
|
+
// ─── Horizontal Tab Theme (matches old ContainedTab look) ────────────
|
|
16
15
|
const containedTheme = {
|
|
17
16
|
base: 'flex flex-col gap-2',
|
|
18
17
|
tablist: {
|
|
@@ -69,26 +68,63 @@ const containedTheme = {
|
|
|
69
68
|
},
|
|
70
69
|
tabpanel: 'p-0',
|
|
71
70
|
};
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
71
|
+
// ─── Vertical Tab Theme ──────────────────────────────────────────────
|
|
72
|
+
const verticalTheme = {
|
|
73
|
+
base: 'flex flex-col md:flex-row gap-2',
|
|
74
|
+
tablist: {
|
|
75
|
+
base: 'flex flex-row md:flex-col md:w-44 flex-shrink-0 space-x-2 md:space-x-0 md:space-y-1 text-sm font-medium overflow-x-auto md:overflow-x-visible p-[5px] rounded-lg bg-card',
|
|
76
|
+
variant: {
|
|
77
|
+
default: '',
|
|
78
|
+
fullWidth: '',
|
|
79
|
+
pills: '',
|
|
80
|
+
underline: '',
|
|
81
|
+
},
|
|
82
|
+
tabitem: {
|
|
83
|
+
base: 'flex items-center justify-center px-4 py-2 rounded-lg w-full text-center text-sm font-medium whitespace-nowrap first:ml-0 disabled:cursor-not-allowed disabled:text-muted-foreground focus:outline-none transition-colors duration-200',
|
|
84
|
+
variant: {
|
|
85
|
+
default: {
|
|
86
|
+
base: '',
|
|
87
|
+
active: {
|
|
88
|
+
on: 'text-foreground bg-card shadow-sm border border-border',
|
|
89
|
+
off: 'text-foreground/70 bg-muted hover:text-foreground hover:bg-accent',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
fullWidth: {
|
|
93
|
+
base: '',
|
|
94
|
+
active: {
|
|
95
|
+
on: 'text-foreground bg-card shadow-sm border border-border',
|
|
96
|
+
off: 'text-foreground/70 bg-muted hover:text-foreground hover:bg-accent',
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
pills: {
|
|
100
|
+
base: '',
|
|
101
|
+
active: {
|
|
102
|
+
on: 'text-white bg-primary',
|
|
103
|
+
off: 'text-foreground/70 hover:text-foreground hover:bg-accent',
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
underline: {
|
|
107
|
+
base: '',
|
|
108
|
+
active: {
|
|
109
|
+
on: 'text-primary border-l-2 border-primary bg-primary/10',
|
|
110
|
+
off: 'text-foreground/70 border-l-2 border-transparent hover:text-foreground hover:bg-accent',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
},
|
|
114
|
+
icon: 'mr-2 h-5 w-5',
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
tabitemcontainer: {
|
|
118
|
+
base: 'flex-1 min-w-0',
|
|
119
|
+
variant: {
|
|
120
|
+
default: '',
|
|
121
|
+
fullWidth: '',
|
|
122
|
+
pills: '',
|
|
123
|
+
underline: '',
|
|
124
|
+
},
|
|
125
|
+
},
|
|
126
|
+
tabpanel: 'p-0',
|
|
127
|
+
};
|
|
92
128
|
// ─── PagamioTabs Component ───────────────────────────────────────────
|
|
93
129
|
const PagamioTabs = ({ tabs, variant = 'default', orientation = 'horizontal', activeTab: controlledTab, defaultTab = 0, onTabChange, isSticky = false, isFullWidth = true, title, description, className = '', tabListClassName = '', tabPanelClassName = '', theme: customTheme, }) => {
|
|
94
130
|
const [internalTab, setInternalTab] = useState(defaultTab);
|
|
@@ -103,24 +139,21 @@ const PagamioTabs = ({ tabs, variant = 'default', orientation = 'horizontal', ac
|
|
|
103
139
|
};
|
|
104
140
|
// ── Header ───────────────────────────────────────────────────────
|
|
105
141
|
const header = title || description ? (_jsxs("div", { className: "mb-2", children: [title && _jsx("h2", { className: "text-lg font-semibold", children: title }), description && _jsx("p", { className: "text-sm text-muted-foreground", children: description })] })) : null;
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
const stickyClass = isSticky ? 'sticky top-0 z-10 bg-background' : '';
|
|
112
|
-
const widthClass = isFullWidth ? 'w-full' : 'w-fit';
|
|
113
|
-
// Merge themes: containedTheme base + customTheme overrides
|
|
142
|
+
const isVertical = orientation === 'vertical';
|
|
143
|
+
const baseTheme = isVertical ? verticalTheme : containedTheme;
|
|
144
|
+
// ── Build merged theme ─────────────────────────────────────────
|
|
145
|
+
const stickyClass = !isVertical && isSticky ? 'sticky top-0 z-10 bg-background' : '';
|
|
146
|
+
const widthClass = !isVertical && isFullWidth ? 'w-full' : '';
|
|
114
147
|
const mergedTheme = {
|
|
115
|
-
...
|
|
148
|
+
...baseTheme,
|
|
116
149
|
...customTheme,
|
|
117
150
|
tablist: {
|
|
118
|
-
...
|
|
151
|
+
...baseTheme.tablist,
|
|
119
152
|
...customTheme?.tablist,
|
|
120
|
-
base: `${stickyClass} ${
|
|
153
|
+
base: `${stickyClass} ${baseTheme.tablist?.base ?? ''} ${widthClass} ${tabListClassName}`.trim(),
|
|
121
154
|
},
|
|
122
|
-
tabpanel: tabPanelClassName ||
|
|
155
|
+
tabpanel: tabPanelClassName || baseTheme.tabpanel || 'p-0',
|
|
123
156
|
};
|
|
124
|
-
return (_jsxs("div", { className: `w-full ${className}`, children: [header, _jsx(Tabs, { ref: tabsRef, "aria-label": "Tabs", variant: variant, onActiveTabChange: handleTabChange, theme: mergedTheme,
|
|
157
|
+
return (_jsxs("div", { className: `w-full ${className}`, children: [header, _jsx(Tabs, { ref: tabsRef, "aria-label": "Tabs", variant: variant, onActiveTabChange: handleTabChange, theme: mergedTheme, children: tabs.map((tab) => (_jsx(FlowbiteTabItem, { title: tab.title, icon: tab.icon, disabled: tab.disabled, active: currentTab === tabs.indexOf(tab), children: tab.content }, tab.id))) })] }));
|
|
125
158
|
};
|
|
126
159
|
export default PagamioTabs;
|
package/lib/styles.css
CHANGED
|
@@ -6143,12 +6143,12 @@ video {
|
|
|
6143
6143
|
max-height: 100%;
|
|
6144
6144
|
}
|
|
6145
6145
|
|
|
6146
|
-
.md\:w-
|
|
6147
|
-
width:
|
|
6146
|
+
.md\:w-44 {
|
|
6147
|
+
width: 11rem;
|
|
6148
6148
|
}
|
|
6149
6149
|
|
|
6150
|
-
.md\:w-
|
|
6151
|
-
width:
|
|
6150
|
+
.md\:w-48 {
|
|
6151
|
+
width: 12rem;
|
|
6152
6152
|
}
|
|
6153
6153
|
|
|
6154
6154
|
.md\:w-96 {
|
|
@@ -6211,10 +6211,10 @@ video {
|
|
|
6211
6211
|
margin-left: calc(2rem * calc(1 - var(--tw-space-x-reverse)));
|
|
6212
6212
|
}
|
|
6213
6213
|
|
|
6214
|
-
.md\:space-y-
|
|
6214
|
+
.md\:space-y-1 > :not([hidden]) ~ :not([hidden]) {
|
|
6215
6215
|
--tw-space-y-reverse: 0;
|
|
6216
|
-
margin-top: calc(0.
|
|
6217
|
-
margin-bottom: calc(0.
|
|
6216
|
+
margin-top: calc(0.25rem * calc(1 - var(--tw-space-y-reverse)));
|
|
6217
|
+
margin-bottom: calc(0.25rem * var(--tw-space-y-reverse));
|
|
6218
6218
|
}
|
|
6219
6219
|
|
|
6220
6220
|
.md\:overflow-x-visible {
|
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.251",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public",
|
|
7
7
|
"provenance": false
|