@rakeyshgidwani/roger-ui-bank-theme-harvey 0.2.52 → 0.3.1
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/CHANGELOG.md +1 -1
- package/dist/components/ui/button.d.ts +3 -1
- package/dist/components/ui/button.d.ts.map +1 -1
- package/dist/components/ui/button.esm.js +3 -2
- package/dist/components/ui/button.js +3 -2
- package/dist/components/ui/layout/container.d.ts +57 -0
- package/dist/components/ui/layout/container.d.ts.map +1 -0
- package/dist/components/ui/layout/container.esm.js +173 -0
- package/dist/components/ui/layout/container.js +173 -0
- package/dist/components/ui/layout/index.d.ts +9 -0
- package/dist/components/ui/layout/index.d.ts.map +1 -0
- package/dist/components/ui/layout/index.esm.js +6 -0
- package/dist/components/ui/layout/index.js +6 -0
- package/dist/components/ui/layout/responsive-grid.d.ts +93 -0
- package/dist/components/ui/layout/responsive-grid.d.ts.map +1 -0
- package/dist/components/ui/layout/responsive-grid.esm.js +124 -0
- package/dist/components/ui/layout/responsive-grid.js +124 -0
- package/dist/components/ui/layouts/adaptive-layout.d.ts +1 -0
- package/dist/components/ui/layouts/adaptive-layout.d.ts.map +1 -1
- package/dist/components/ui/layouts/adaptive-layout.esm.js +2 -2
- package/dist/components/ui/layouts/adaptive-layout.js +2 -2
- package/dist/components/ui/navigation/index.d.ts +2 -1
- package/dist/components/ui/navigation/index.d.ts.map +1 -1
- package/dist/components/ui/navigation/index.esm.js +1 -0
- package/dist/components/ui/navigation/index.js +1 -0
- package/dist/components/ui/navigation/progressive-navigation.d.ts +37 -0
- package/dist/components/ui/navigation/progressive-navigation.d.ts.map +1 -0
- package/dist/components/ui/navigation/progressive-navigation.esm.js +145 -0
- package/dist/components/ui/navigation/progressive-navigation.js +145 -0
- package/dist/components/ui/navigation/types.d.ts +21 -0
- package/dist/components/ui/navigation/types.d.ts.map +1 -1
- package/dist/hooks/use-adaptive-layout.d.ts +2 -1
- package/dist/hooks/use-adaptive-layout.d.ts.map +1 -1
- package/dist/hooks/use-adaptive-layout.esm.js +13 -8
- package/dist/hooks/use-adaptive-layout.js +13 -8
- package/dist/hooks/use-device.d.ts +3 -1
- package/dist/hooks/use-device.d.ts.map +1 -1
- package/dist/hooks/use-device.esm.js +14 -7
- package/dist/hooks/use-device.js +14 -7
- package/dist/index.d.ts +19 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +9 -4
- package/dist/index.js +9 -4
- package/dist/plugins/css-purge-optimizer.d.ts +25 -0
- package/dist/plugins/css-purge-optimizer.d.ts.map +1 -0
- package/dist/plugins/css-purge-optimizer.esm.js +414 -0
- package/dist/plugins/css-purge-optimizer.js +414 -0
- package/dist/plugins/performance-monitor.d.ts +29 -0
- package/dist/plugins/performance-monitor.d.ts.map +1 -0
- package/dist/plugins/performance-monitor.esm.js +221 -0
- package/dist/plugins/performance-monitor.js +221 -0
- package/dist/plugins/progressive-css-loader.d.ts +21 -0
- package/dist/plugins/progressive-css-loader.d.ts.map +1 -0
- package/dist/plugins/progressive-css-loader.esm.js +227 -0
- package/dist/plugins/progressive-css-loader.js +227 -0
- package/dist/plugins/theme-css-generator.d.ts.map +1 -1
- package/dist/plugins/theme-css-generator.esm.js +19 -6
- package/dist/plugins/theme-css-generator.js +19 -6
- package/dist/styles.css +1027 -112
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.esm.js +4 -1
- package/dist/theme.js +4 -1
- package/dist/themes/phase1-constants.d.ts +23 -0
- package/dist/themes/phase1-constants.d.ts.map +1 -0
- package/dist/themes/phase1-constants.esm.js +180 -0
- package/dist/themes/phase1-constants.js +180 -0
- package/dist/themes/themes/default.d.ts.map +1 -1
- package/dist/themes/themes/default.esm.js +4 -1
- package/dist/themes/themes/default.js +4 -1
- package/dist/themes/themes/harvey.d.ts.map +1 -1
- package/dist/themes/themes/harvey.esm.js +4 -1
- package/dist/themes/themes/harvey.js +4 -1
- package/dist/themes/types.d.ts +62 -0
- package/dist/themes/types.d.ts.map +1 -1
- package/dist/themes/validation.d.ts +17 -0
- package/dist/themes/validation.d.ts.map +1 -1
- package/dist/themes/validation.esm.js +218 -0
- package/dist/themes/validation.js +218 -0
- package/dist/types.d.ts +62 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/progressive-css-injector.d.ts +80 -0
- package/dist/utils/progressive-css-injector.d.ts.map +1 -0
- package/dist/utils/progressive-css-injector.esm.js +217 -0
- package/dist/utils/progressive-css-injector.js +217 -0
- package/package.json +1 -1
- package/src/components/ui/button.tsx +9 -6
- package/src/components/ui/layout/container.tsx +312 -0
- package/src/components/ui/layout/index.ts +10 -0
- package/src/components/ui/layout/responsive-grid.tsx +286 -0
- package/src/components/ui/layouts/adaptive-layout.tsx +3 -1
- package/src/components/ui/navigation/index.ts +2 -0
- package/src/components/ui/navigation/progressive-navigation.tsx +453 -0
- package/src/components/ui/navigation/types.ts +41 -0
- package/src/hooks/use-adaptive-layout.ts +13 -9
- package/src/hooks/use-device.tsx +17 -10
- package/src/index.ts +19 -4
- package/src/plugins/css-purge-optimizer.ts +491 -0
- package/src/plugins/performance-monitor.ts +292 -0
- package/src/plugins/progressive-css-loader.ts +269 -0
- package/src/plugins/theme-css-generator.ts +22 -6
- package/src/styles/components/base/badge.css +2 -2
- package/src/styles/components/base/button.css +238 -35
- package/src/styles/components/base/card.css +2 -2
- package/src/styles/components/base/checkbox.css +3 -3
- package/src/styles/components/base/label.css +3 -3
- package/src/styles/components/feedback/skeleton.css +1 -1
- package/src/styles/components/feedback/toast.css +1 -1
- package/src/styles/components/index.css +3 -0
- package/src/styles/components/layout/container.css +466 -0
- package/src/styles/components/layout/index.css +5 -0
- package/src/styles/components/layout/responsive-grid.css +422 -0
- package/src/styles/components/navigation/breadcrumb.css +1 -1
- package/src/styles/components/navigation/index.css +1 -0
- package/src/styles/components/navigation/menu.css +2 -2
- package/src/styles/components/navigation/pagination.css +4 -4
- package/src/styles/components/navigation/progressive-navigation.css +633 -0
- package/src/styles/components/navigation/sidebar.css +4 -4
- package/src/styles/components/navigation/stepper.css +2 -2
- package/src/styles/components/navigation/tabs.css +1 -1
- package/src/styles/components/ui/theme-toggle.css +2 -2
- package/src/styles/progressive.css +17 -0
- package/src/styles/themes/harvey.css +103 -19
- package/src/styles/utilities/semantic-input-system.css +7 -13
- package/src/theme.ts +5 -1
- package/src/themes/phase1-constants.ts +189 -0
- package/src/themes/themes/default.ts +5 -1
- package/src/themes/themes/harvey.ts +5 -1
- package/src/themes/types.ts +77 -1
- package/src/themes/validation.ts +249 -0
- package/src/types.ts +77 -1
- package/src/utils/progressive-css-injector.ts +254 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responsive Grid Component
|
|
3
|
+
* Implements Phase 2 responsive grid system as defined in the implementation plan
|
|
4
|
+
*
|
|
5
|
+
* Grid Progression:
|
|
6
|
+
* - xs: 1 column (Single column mobile)
|
|
7
|
+
* - sm: 2 columns (2 columns small tablet)
|
|
8
|
+
* - md: 2 columns (2 columns tablet)
|
|
9
|
+
* - lg: 3 columns (3 columns desktop)
|
|
10
|
+
* - xl: 4 columns (4 columns large desktop)
|
|
11
|
+
* - 2xl: 4 columns (4 columns ultra-wide)
|
|
12
|
+
* - 3xl: 5 columns (5 columns large displays)
|
|
13
|
+
*
|
|
14
|
+
* Gap Progression:
|
|
15
|
+
* - xs: 16px, sm: 20px, md: 24px, lg: 28px, xl: 32px, 2xl: 36px, 3xl: 40px
|
|
16
|
+
*/
|
|
17
|
+
'use client';
|
|
18
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
19
|
+
import * as React from 'react';
|
|
20
|
+
// Pre-defined grid patterns
|
|
21
|
+
const GRID_PATTERNS = {
|
|
22
|
+
default: {
|
|
23
|
+
columns: { xs: 1, sm: 2, md: 2, lg: 3, xl: 4, '2xl': 4, '3xl': 5 },
|
|
24
|
+
gaps: { xs: '16px', sm: '20px', md: '24px', lg: '28px', xl: '32px', '2xl': '36px', '3xl': '40px' }
|
|
25
|
+
},
|
|
26
|
+
content: {
|
|
27
|
+
columns: { xs: 1, sm: 1, md: 2, lg: 2, xl: 3, '2xl': 3, '3xl': 4 },
|
|
28
|
+
gaps: { xs: '16px', sm: '20px', md: '24px', lg: '28px', xl: '32px', '2xl': '36px', '3xl': '40px' }
|
|
29
|
+
},
|
|
30
|
+
dashboard: {
|
|
31
|
+
columns: { xs: 1, sm: 2, md: 3, lg: 4, xl: 5, '2xl': 6, '3xl': 7 },
|
|
32
|
+
gaps: { xs: '12px', sm: '16px', md: '20px', lg: '24px', xl: '28px', '2xl': '32px', '3xl': '36px' }
|
|
33
|
+
},
|
|
34
|
+
gallery: {
|
|
35
|
+
columns: { xs: 2, sm: 3, md: 4, lg: 5, xl: 6, '2xl': 7, '3xl': 8 },
|
|
36
|
+
gaps: { xs: '8px', sm: '12px', md: '16px', lg: '20px', xl: '24px', '2xl': '28px', '3xl': '32px' }
|
|
37
|
+
},
|
|
38
|
+
cards: {
|
|
39
|
+
columns: { xs: 1, sm: 1, md: 2, lg: 3, xl: 3, '2xl': 4, '3xl': 4 },
|
|
40
|
+
gaps: { xs: '20px', sm: '24px', md: '28px', lg: '32px', xl: '36px', '2xl': '40px', '3xl': '44px' }
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
export const ResponsiveGrid = ({ children, columns: customColumns, gaps: customGaps, pattern = 'default', autoFit = false, minItemWidth = '250px', alignItems = 'stretch', justifyItems = 'stretch', 'aria-label': ariaLabel, 'data-testid': testId = 'responsive-grid', className = '', }) => {
|
|
44
|
+
// Get pattern configuration
|
|
45
|
+
const patternConfig = GRID_PATTERNS[pattern];
|
|
46
|
+
// Use custom configuration or fall back to pattern
|
|
47
|
+
const columns = customColumns || patternConfig.columns;
|
|
48
|
+
const gaps = customGaps || patternConfig.gaps;
|
|
49
|
+
// Build CSS custom properties for responsive grid
|
|
50
|
+
const gridStyle = React.useMemo(() => {
|
|
51
|
+
const style = {};
|
|
52
|
+
// Set column configurations
|
|
53
|
+
Object.entries(columns).forEach(([breakpoint, columnCount]) => {
|
|
54
|
+
style[`--responsive-grid-columns-${breakpoint}`] = columnCount;
|
|
55
|
+
});
|
|
56
|
+
// Set gap configurations
|
|
57
|
+
Object.entries(gaps).forEach(([breakpoint, gapValue]) => {
|
|
58
|
+
style[`--responsive-grid-gap-${breakpoint}`] = gapValue;
|
|
59
|
+
});
|
|
60
|
+
// Set alignment
|
|
61
|
+
style['--responsive-grid-align-items'] = alignItems;
|
|
62
|
+
style['--responsive-grid-justify-items'] = justifyItems;
|
|
63
|
+
// Set auto-fit configuration
|
|
64
|
+
if (autoFit) {
|
|
65
|
+
style['--responsive-grid-min-item-width'] = minItemWidth;
|
|
66
|
+
}
|
|
67
|
+
return style;
|
|
68
|
+
}, [columns, gaps, alignItems, justifyItems, autoFit, minItemWidth]);
|
|
69
|
+
// Build CSS classes
|
|
70
|
+
const gridClasses = React.useMemo(() => {
|
|
71
|
+
const baseClass = 'responsive-grid';
|
|
72
|
+
const patternClass = `responsive-grid--${pattern}`;
|
|
73
|
+
const autoFitClass = autoFit ? 'responsive-grid--auto-fit' : '';
|
|
74
|
+
return [baseClass, patternClass, autoFitClass, className]
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join(' ');
|
|
77
|
+
}, [pattern, autoFit, className]);
|
|
78
|
+
return (_jsx("div", { className: gridClasses, style: gridStyle, "aria-label": ariaLabel, "data-testid": testId, children: children }));
|
|
79
|
+
};
|
|
80
|
+
export const ResponsiveGridItem = ({ children, colSpan, rowSpan, colStart, rowStart, alignSelf = 'auto', justifySelf = 'auto', className = '', 'data-testid': testId = 'responsive-grid-item', }) => {
|
|
81
|
+
// Build CSS custom properties for grid item
|
|
82
|
+
const itemStyle = React.useMemo(() => {
|
|
83
|
+
const style = {};
|
|
84
|
+
// Set column span configurations
|
|
85
|
+
if (colSpan) {
|
|
86
|
+
Object.entries(colSpan).forEach(([breakpoint, span]) => {
|
|
87
|
+
style[`--responsive-grid-item-col-span-${breakpoint}`] = span;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
// Set row span configurations
|
|
91
|
+
if (rowSpan) {
|
|
92
|
+
Object.entries(rowSpan).forEach(([breakpoint, span]) => {
|
|
93
|
+
style[`--responsive-grid-item-row-span-${breakpoint}`] = span;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Set column start configurations
|
|
97
|
+
if (colStart) {
|
|
98
|
+
Object.entries(colStart).forEach(([breakpoint, start]) => {
|
|
99
|
+
style[`--responsive-grid-item-col-start-${breakpoint}`] = start;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// Set row start configurations
|
|
103
|
+
if (rowStart) {
|
|
104
|
+
Object.entries(rowStart).forEach(([breakpoint, start]) => {
|
|
105
|
+
style[`--responsive-grid-item-row-start-${breakpoint}`] = start;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Set alignment
|
|
109
|
+
style['--responsive-grid-item-align-self'] = alignSelf;
|
|
110
|
+
style['--responsive-grid-item-justify-self'] = justifySelf;
|
|
111
|
+
return style;
|
|
112
|
+
}, [colSpan, rowSpan, colStart, rowStart, alignSelf, justifySelf]);
|
|
113
|
+
// Build CSS classes
|
|
114
|
+
const itemClasses = React.useMemo(() => {
|
|
115
|
+
const baseClass = 'responsive-grid-item';
|
|
116
|
+
const spanClass = colSpan || rowSpan ? 'responsive-grid-item--has-span' : '';
|
|
117
|
+
const positionClass = colStart || rowStart ? 'responsive-grid-item--has-position' : '';
|
|
118
|
+
return [baseClass, spanClass, positionClass, className]
|
|
119
|
+
.filter(Boolean)
|
|
120
|
+
.join(' ');
|
|
121
|
+
}, [colSpan, rowSpan, colStart, rowStart, className]);
|
|
122
|
+
return (_jsx("div", { className: itemClasses, style: itemStyle, "data-testid": testId, children: children }));
|
|
123
|
+
};
|
|
124
|
+
export default ResponsiveGrid;
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Responsive Grid Component
|
|
3
|
+
* Implements Phase 2 responsive grid system as defined in the implementation plan
|
|
4
|
+
*
|
|
5
|
+
* Grid Progression:
|
|
6
|
+
* - xs: 1 column (Single column mobile)
|
|
7
|
+
* - sm: 2 columns (2 columns small tablet)
|
|
8
|
+
* - md: 2 columns (2 columns tablet)
|
|
9
|
+
* - lg: 3 columns (3 columns desktop)
|
|
10
|
+
* - xl: 4 columns (4 columns large desktop)
|
|
11
|
+
* - 2xl: 4 columns (4 columns ultra-wide)
|
|
12
|
+
* - 3xl: 5 columns (5 columns large displays)
|
|
13
|
+
*
|
|
14
|
+
* Gap Progression:
|
|
15
|
+
* - xs: 16px, sm: 20px, md: 24px, lg: 28px, xl: 32px, 2xl: 36px, 3xl: 40px
|
|
16
|
+
*/
|
|
17
|
+
'use client';
|
|
18
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
19
|
+
import * as React from 'react';
|
|
20
|
+
// Pre-defined grid patterns
|
|
21
|
+
const GRID_PATTERNS = {
|
|
22
|
+
default: {
|
|
23
|
+
columns: { xs: 1, sm: 2, md: 2, lg: 3, xl: 4, '2xl': 4, '3xl': 5 },
|
|
24
|
+
gaps: { xs: '16px', sm: '20px', md: '24px', lg: '28px', xl: '32px', '2xl': '36px', '3xl': '40px' }
|
|
25
|
+
},
|
|
26
|
+
content: {
|
|
27
|
+
columns: { xs: 1, sm: 1, md: 2, lg: 2, xl: 3, '2xl': 3, '3xl': 4 },
|
|
28
|
+
gaps: { xs: '16px', sm: '20px', md: '24px', lg: '28px', xl: '32px', '2xl': '36px', '3xl': '40px' }
|
|
29
|
+
},
|
|
30
|
+
dashboard: {
|
|
31
|
+
columns: { xs: 1, sm: 2, md: 3, lg: 4, xl: 5, '2xl': 6, '3xl': 7 },
|
|
32
|
+
gaps: { xs: '12px', sm: '16px', md: '20px', lg: '24px', xl: '28px', '2xl': '32px', '3xl': '36px' }
|
|
33
|
+
},
|
|
34
|
+
gallery: {
|
|
35
|
+
columns: { xs: 2, sm: 3, md: 4, lg: 5, xl: 6, '2xl': 7, '3xl': 8 },
|
|
36
|
+
gaps: { xs: '8px', sm: '12px', md: '16px', lg: '20px', xl: '24px', '2xl': '28px', '3xl': '32px' }
|
|
37
|
+
},
|
|
38
|
+
cards: {
|
|
39
|
+
columns: { xs: 1, sm: 1, md: 2, lg: 3, xl: 3, '2xl': 4, '3xl': 4 },
|
|
40
|
+
gaps: { xs: '20px', sm: '24px', md: '28px', lg: '32px', xl: '36px', '2xl': '40px', '3xl': '44px' }
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
export const ResponsiveGrid = ({ children, columns: customColumns, gaps: customGaps, pattern = 'default', autoFit = false, minItemWidth = '250px', alignItems = 'stretch', justifyItems = 'stretch', 'aria-label': ariaLabel, 'data-testid': testId = 'responsive-grid', className = '', }) => {
|
|
44
|
+
// Get pattern configuration
|
|
45
|
+
const patternConfig = GRID_PATTERNS[pattern];
|
|
46
|
+
// Use custom configuration or fall back to pattern
|
|
47
|
+
const columns = customColumns || patternConfig.columns;
|
|
48
|
+
const gaps = customGaps || patternConfig.gaps;
|
|
49
|
+
// Build CSS custom properties for responsive grid
|
|
50
|
+
const gridStyle = React.useMemo(() => {
|
|
51
|
+
const style = {};
|
|
52
|
+
// Set column configurations
|
|
53
|
+
Object.entries(columns).forEach(([breakpoint, columnCount]) => {
|
|
54
|
+
style[`--responsive-grid-columns-${breakpoint}`] = columnCount;
|
|
55
|
+
});
|
|
56
|
+
// Set gap configurations
|
|
57
|
+
Object.entries(gaps).forEach(([breakpoint, gapValue]) => {
|
|
58
|
+
style[`--responsive-grid-gap-${breakpoint}`] = gapValue;
|
|
59
|
+
});
|
|
60
|
+
// Set alignment
|
|
61
|
+
style['--responsive-grid-align-items'] = alignItems;
|
|
62
|
+
style['--responsive-grid-justify-items'] = justifyItems;
|
|
63
|
+
// Set auto-fit configuration
|
|
64
|
+
if (autoFit) {
|
|
65
|
+
style['--responsive-grid-min-item-width'] = minItemWidth;
|
|
66
|
+
}
|
|
67
|
+
return style;
|
|
68
|
+
}, [columns, gaps, alignItems, justifyItems, autoFit, minItemWidth]);
|
|
69
|
+
// Build CSS classes
|
|
70
|
+
const gridClasses = React.useMemo(() => {
|
|
71
|
+
const baseClass = 'responsive-grid';
|
|
72
|
+
const patternClass = `responsive-grid--${pattern}`;
|
|
73
|
+
const autoFitClass = autoFit ? 'responsive-grid--auto-fit' : '';
|
|
74
|
+
return [baseClass, patternClass, autoFitClass, className]
|
|
75
|
+
.filter(Boolean)
|
|
76
|
+
.join(' ');
|
|
77
|
+
}, [pattern, autoFit, className]);
|
|
78
|
+
return (_jsx("div", { className: gridClasses, style: gridStyle, "aria-label": ariaLabel, "data-testid": testId, children: children }));
|
|
79
|
+
};
|
|
80
|
+
export const ResponsiveGridItem = ({ children, colSpan, rowSpan, colStart, rowStart, alignSelf = 'auto', justifySelf = 'auto', className = '', 'data-testid': testId = 'responsive-grid-item', }) => {
|
|
81
|
+
// Build CSS custom properties for grid item
|
|
82
|
+
const itemStyle = React.useMemo(() => {
|
|
83
|
+
const style = {};
|
|
84
|
+
// Set column span configurations
|
|
85
|
+
if (colSpan) {
|
|
86
|
+
Object.entries(colSpan).forEach(([breakpoint, span]) => {
|
|
87
|
+
style[`--responsive-grid-item-col-span-${breakpoint}`] = span;
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
// Set row span configurations
|
|
91
|
+
if (rowSpan) {
|
|
92
|
+
Object.entries(rowSpan).forEach(([breakpoint, span]) => {
|
|
93
|
+
style[`--responsive-grid-item-row-span-${breakpoint}`] = span;
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
// Set column start configurations
|
|
97
|
+
if (colStart) {
|
|
98
|
+
Object.entries(colStart).forEach(([breakpoint, start]) => {
|
|
99
|
+
style[`--responsive-grid-item-col-start-${breakpoint}`] = start;
|
|
100
|
+
});
|
|
101
|
+
}
|
|
102
|
+
// Set row start configurations
|
|
103
|
+
if (rowStart) {
|
|
104
|
+
Object.entries(rowStart).forEach(([breakpoint, start]) => {
|
|
105
|
+
style[`--responsive-grid-item-row-start-${breakpoint}`] = start;
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
// Set alignment
|
|
109
|
+
style['--responsive-grid-item-align-self'] = alignSelf;
|
|
110
|
+
style['--responsive-grid-item-justify-self'] = justifySelf;
|
|
111
|
+
return style;
|
|
112
|
+
}, [colSpan, rowSpan, colStart, rowStart, alignSelf, justifySelf]);
|
|
113
|
+
// Build CSS classes
|
|
114
|
+
const itemClasses = React.useMemo(() => {
|
|
115
|
+
const baseClass = 'responsive-grid-item';
|
|
116
|
+
const spanClass = colSpan || rowSpan ? 'responsive-grid-item--has-span' : '';
|
|
117
|
+
const positionClass = colStart || rowStart ? 'responsive-grid-item--has-position' : '';
|
|
118
|
+
return [baseClass, spanClass, positionClass, className]
|
|
119
|
+
.filter(Boolean)
|
|
120
|
+
.join(' ');
|
|
121
|
+
}, [colSpan, rowSpan, colStart, rowStart, className]);
|
|
122
|
+
return (_jsx("div", { className: itemClasses, style: itemStyle, "data-testid": testId, children: children }));
|
|
123
|
+
};
|
|
124
|
+
export default ResponsiveGrid;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adaptive-layout.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/layouts/adaptive-layout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAC;AAKvD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;AAExD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,SAAS,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,
|
|
1
|
+
{"version":3,"file":"adaptive-layout.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/layouts/adaptive-layout.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAC/B,OAAO,EAAE,SAAS,EAAuB,MAAM,OAAO,CAAC;AAKvD,MAAM,MAAM,UAAU,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,CAAA;AAExD,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,SAAS,CAAA;IACnB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,WAAW,CAAC,EAAE,OAAO,CAAA;IACrB,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,uBAAuB,CAAC,EAAE,OAAO,CAAA;IACjC,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC,sBAAsB,CAAC,EAAE,OAAO,CAAA;IAChC,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,eAAO,MAAM,cAAc,EAAE,KAAK,CAAC,EAAE,CAAC,mBAAmB,CA8FxD,CAAA;AAED,eAAe,cAAc,CAAA"}
|
|
@@ -4,7 +4,7 @@ import { useState, useEffect } from 'react';
|
|
|
4
4
|
import { MobileLayout } from './mobile-layout.js';
|
|
5
5
|
import { TabletLayout } from './tablet-layout.js';
|
|
6
6
|
import { DesktopLayout } from './desktop-layout.js';
|
|
7
|
-
export const AdaptiveLayout = ({ children, title = 'Adaptive Layout', description = 'Automatically adapts to different device types with optimal layouts', showHeader = true, showSidebar = true, enableTouchOptimization = true, enablePerformanceMonitoring = true, enableAdvancedFeatures = true, className = '' }) => {
|
|
7
|
+
export const AdaptiveLayout = ({ children, title = 'Adaptive Layout', description = 'Automatically adapts to different device types with optimal layouts', showHeader = true, showSidebar = true, showFooter = false, enableTouchOptimization = true, enablePerformanceMonitoring = true, enableAdvancedFeatures = true, className = '' }) => {
|
|
8
8
|
const [deviceType, setDeviceType] = useState('desktop');
|
|
9
9
|
// Device detection and adaptation
|
|
10
10
|
useEffect(() => {
|
|
@@ -40,7 +40,7 @@ export const AdaptiveLayout = ({ children, title = 'Adaptive Layout', descriptio
|
|
|
40
40
|
};
|
|
41
41
|
switch (deviceType) {
|
|
42
42
|
case 'mobile':
|
|
43
|
-
return (_jsx(MobileLayout, { ...commonProps, showFooter:
|
|
43
|
+
return (_jsx(MobileLayout, { ...commonProps, showFooter: showFooter, enableTouchOptimization: enableTouchOptimization, children: children }));
|
|
44
44
|
case 'tablet':
|
|
45
45
|
return (_jsx(TabletLayout, { ...commonProps, showSidebar: showSidebar, enableTouchOptimization: enableTouchOptimization, children: children }));
|
|
46
46
|
case 'desktop':
|
|
@@ -4,7 +4,7 @@ import { useState, useEffect } from 'react';
|
|
|
4
4
|
import { MobileLayout } from './mobile-layout.js';
|
|
5
5
|
import { TabletLayout } from './tablet-layout.js';
|
|
6
6
|
import { DesktopLayout } from './desktop-layout.js';
|
|
7
|
-
export const AdaptiveLayout = ({ children, title = 'Adaptive Layout', description = 'Automatically adapts to different device types with optimal layouts', showHeader = true, showSidebar = true, enableTouchOptimization = true, enablePerformanceMonitoring = true, enableAdvancedFeatures = true, className = '' }) => {
|
|
7
|
+
export const AdaptiveLayout = ({ children, title = 'Adaptive Layout', description = 'Automatically adapts to different device types with optimal layouts', showHeader = true, showSidebar = true, showFooter = false, enableTouchOptimization = true, enablePerformanceMonitoring = true, enableAdvancedFeatures = true, className = '' }) => {
|
|
8
8
|
const [deviceType, setDeviceType] = useState('desktop');
|
|
9
9
|
// Device detection and adaptation
|
|
10
10
|
useEffect(() => {
|
|
@@ -40,7 +40,7 @@ export const AdaptiveLayout = ({ children, title = 'Adaptive Layout', descriptio
|
|
|
40
40
|
};
|
|
41
41
|
switch (deviceType) {
|
|
42
42
|
case 'mobile':
|
|
43
|
-
return (_jsx(MobileLayout, { ...commonProps, showFooter:
|
|
43
|
+
return (_jsx(MobileLayout, { ...commonProps, showFooter: showFooter, enableTouchOptimization: enableTouchOptimization, children: children }));
|
|
44
44
|
case 'tablet':
|
|
45
45
|
return (_jsx(TabletLayout, { ...commonProps, showSidebar: showSidebar, enableTouchOptimization: enableTouchOptimization, children: children }));
|
|
46
46
|
case 'desktop':
|
|
@@ -8,8 +8,9 @@ export { Tabs } from './tabs';
|
|
|
8
8
|
export { Stepper } from './stepper';
|
|
9
9
|
export { Menu } from './menu';
|
|
10
10
|
export { Sidebar } from './sidebar';
|
|
11
|
+
export { ProgressiveNavigation } from './progressive-navigation';
|
|
11
12
|
export { UserMenu } from './user-menu.js';
|
|
12
13
|
export { UserAvatar } from './user-avatar.js';
|
|
13
14
|
export { SubscriptionBadge } from './subscription-badge.js';
|
|
14
|
-
export type { NavigationBaseProps, NavigationItem, NavigationGroup, BreadcrumbProps, BreadcrumbItem, PaginationProps, PaginationItem, TabsProps, TabItem, StepperProps, StepItem, StepAction, MenuProps, SidebarProps, NavigationState, NavigationContextValue, NavigationAction, NavigationBreakpoint, NavigationSpacing, NavigationAnimation, NavigationAccessibility, UserMenuProps, UserMenuUser, UserMenuSubscription, UserMenuItem, UserMenuGroup, UserAvatarProps, SubscriptionBadgeProps } from './types';
|
|
15
|
+
export type { NavigationBaseProps, NavigationItem, NavigationGroup, BreadcrumbProps, BreadcrumbItem, PaginationProps, PaginationItem, TabsProps, TabItem, StepperProps, StepItem, StepAction, MenuProps, SidebarProps, ProgressiveNavigationProps, NavigationState, NavigationContextValue, NavigationAction, NavigationBreakpoint, NavigationSpacing, NavigationAnimation, NavigationAccessibility, UserMenuProps, UserMenuUser, UserMenuSubscription, UserMenuItem, UserMenuGroup, UserAvatarProps, SubscriptionBadgeProps } from './types';
|
|
15
16
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/navigation/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAC1C,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAGjE,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AAC1C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAC9C,OAAO,EAAE,iBAAiB,EAAE,MAAM,yBAAyB,CAAC;AAG5D,YAAY,EACV,mBAAmB,EACnB,cAAc,EACd,eAAe,EACf,eAAe,EACf,cAAc,EACd,eAAe,EACf,cAAc,EACd,SAAS,EACT,OAAO,EACP,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,SAAS,EACT,YAAY,EACZ,0BAA0B,EAC1B,eAAe,EACf,sBAAsB,EACtB,gBAAgB,EAChB,oBAAoB,EACpB,iBAAiB,EACjB,mBAAmB,EACnB,uBAAuB,EAEvB,aAAa,EACb,YAAY,EACZ,oBAAoB,EACpB,YAAY,EACZ,aAAa,EACb,eAAe,EACf,sBAAsB,EACvB,MAAM,SAAS,CAAC"}
|
|
@@ -8,6 +8,7 @@ export { Tabs } from './tabs';
|
|
|
8
8
|
export { Stepper } from './stepper';
|
|
9
9
|
export { Menu } from './menu';
|
|
10
10
|
export { Sidebar } from './sidebar';
|
|
11
|
+
export { ProgressiveNavigation } from './progressive-navigation';
|
|
11
12
|
// User Menu Components
|
|
12
13
|
export { UserMenu } from './user-menu.js';
|
|
13
14
|
export { UserAvatar } from './user-avatar.js';
|
|
@@ -8,6 +8,7 @@ export { Tabs } from './tabs';
|
|
|
8
8
|
export { Stepper } from './stepper';
|
|
9
9
|
export { Menu } from './menu';
|
|
10
10
|
export { Sidebar } from './sidebar';
|
|
11
|
+
export { ProgressiveNavigation } from './progressive-navigation';
|
|
11
12
|
// User Menu Components
|
|
12
13
|
export { UserMenu } from './user-menu.js';
|
|
13
14
|
export { UserAvatar } from './user-avatar.js';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progressive Navigation Component
|
|
3
|
+
* Implements Phase 2 progressive navigation patterns as defined in the implementation plan
|
|
4
|
+
*
|
|
5
|
+
* Navigation Patterns:
|
|
6
|
+
* - mobile (xs-sm): hamburger menu pattern with 56px height
|
|
7
|
+
* - tablet (md): horizontal-compact pattern with 64px height
|
|
8
|
+
* - desktop (lg+): horizontal-full pattern with 72px height
|
|
9
|
+
*/
|
|
10
|
+
import * as React from 'react';
|
|
11
|
+
import { NavigationItem, NavigationGroup } from './types.js';
|
|
12
|
+
export interface ProgressiveNavigationProps {
|
|
13
|
+
items?: NavigationItem[];
|
|
14
|
+
groups?: NavigationGroup[];
|
|
15
|
+
logo?: React.ReactNode;
|
|
16
|
+
logoHref?: string;
|
|
17
|
+
hamburgerHeight?: string;
|
|
18
|
+
mobileLogoSize?: 'sm' | 'md' | 'lg';
|
|
19
|
+
mobileTouchTarget?: string;
|
|
20
|
+
tabletHeight?: string;
|
|
21
|
+
tabletLogoSize?: 'sm' | 'md' | 'lg';
|
|
22
|
+
desktopHeight?: string;
|
|
23
|
+
desktopLogoSize?: 'sm' | 'md' | 'lg';
|
|
24
|
+
showSecondaryActions?: boolean;
|
|
25
|
+
secondaryActions?: React.ReactNode[];
|
|
26
|
+
mobileBreakpoint?: string;
|
|
27
|
+
tabletBreakpoint?: string;
|
|
28
|
+
desktopBreakpoint?: string;
|
|
29
|
+
onItemClick?: (item: NavigationItem) => void;
|
|
30
|
+
onLogoClick?: () => void;
|
|
31
|
+
'aria-label'?: string;
|
|
32
|
+
'data-testid'?: string;
|
|
33
|
+
className?: string;
|
|
34
|
+
}
|
|
35
|
+
export declare const ProgressiveNavigation: React.FC<ProgressiveNavigationProps>;
|
|
36
|
+
export default ProgressiveNavigation;
|
|
37
|
+
//# sourceMappingURL=progressive-navigation.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"progressive-navigation.d.ts","sourceRoot":"","sources":["../../../../src/components/ui/navigation/progressive-navigation.tsx"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAIH,OAAO,KAAK,KAAK,MAAM,OAAO,CAAC;AAE/B,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAqB7D,MAAM,WAAW,0BAA0B;IAEzC,KAAK,CAAC,EAAE,cAAc,EAAE,CAAC;IACzB,MAAM,CAAC,EAAE,eAAe,EAAE,CAAC;IAG3B,IAAI,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IACvB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAGlB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,cAAc,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACpC,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,cAAc,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IAGpC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,eAAe,CAAC,EAAE,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;IACrC,oBAAoB,CAAC,EAAE,OAAO,CAAC;IAC/B,gBAAgB,CAAC,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;IAGrC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,iBAAiB,CAAC,EAAE,MAAM,CAAC;IAG3B,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC7C,WAAW,CAAC,EAAE,MAAM,IAAI,CAAC;IAGzB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,CAAC;IAGvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,qBAAqB,EAAE,KAAK,CAAC,EAAE,CAAC,0BAA0B,CAsXtE,CAAC;AAEF,eAAe,qBAAqB,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Progressive Navigation Component
|
|
3
|
+
* Implements Phase 2 progressive navigation patterns as defined in the implementation plan
|
|
4
|
+
*
|
|
5
|
+
* Navigation Patterns:
|
|
6
|
+
* - mobile (xs-sm): hamburger menu pattern with 56px height
|
|
7
|
+
* - tablet (md): horizontal-compact pattern with 64px height
|
|
8
|
+
* - desktop (lg+): horizontal-full pattern with 72px height
|
|
9
|
+
*/
|
|
10
|
+
'use client';
|
|
11
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
12
|
+
import { useState, useCallback, useRef, useEffect } from 'react';
|
|
13
|
+
// Simple icon components for navigation
|
|
14
|
+
const HamburgerIcon = ({ className = '' }) => (_jsx("svg", { className: className, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M4 6h16M4 12h16M4 18h16" }) }));
|
|
15
|
+
const XMarkIcon = ({ className = '' }) => (_jsx("svg", { className: className, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M6 18L18 6M6 6l12 12" }) }));
|
|
16
|
+
const ChevronDownIcon = ({ className = '' }) => (_jsx("svg", { className: className, fill: "none", viewBox: "0 0 24 24", stroke: "currentColor", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: 2, d: "M19 9l-7 7-7-7" }) }));
|
|
17
|
+
export const ProgressiveNavigation = ({ items = [], groups = [], logo, logoHref, hamburgerHeight = '56px', mobileLogoSize = 'sm', mobileTouchTarget = '48px', tabletHeight = '64px', tabletLogoSize = 'md', desktopHeight = '72px', desktopLogoSize = 'lg', showSecondaryActions = true, secondaryActions = [], mobileBreakpoint = '640px', tabletBreakpoint = '768px', // Currently unused - reserved for future tablet sub-patterns
|
|
18
|
+
desktopBreakpoint = '1024px', onItemClick, onLogoClick, 'aria-label': ariaLabel = 'Main navigation', 'data-testid': testId = 'progressive-navigation', className = '', }) => {
|
|
19
|
+
// Suppress unused variable warning for tabletBreakpoint (reserved for future use)
|
|
20
|
+
void tabletBreakpoint;
|
|
21
|
+
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
|
|
22
|
+
const [activeDropdown, setActiveDropdown] = useState(null);
|
|
23
|
+
const [screenSize, setScreenSize] = useState('desktop');
|
|
24
|
+
const navRef = useRef(null);
|
|
25
|
+
// Determine current screen size based on configurable breakpoints
|
|
26
|
+
// Default: mobile < 640px, tablet 640-1023px, desktop >= 1024px
|
|
27
|
+
// This ensures sm range (640-767px) uses tablet-compact pattern, not hamburger
|
|
28
|
+
useEffect(() => {
|
|
29
|
+
const handleResize = () => {
|
|
30
|
+
const width = window.innerWidth;
|
|
31
|
+
if (width < parseInt(mobileBreakpoint)) {
|
|
32
|
+
setScreenSize('mobile'); // < 640px: hamburger menu
|
|
33
|
+
}
|
|
34
|
+
else if (width < parseInt(desktopBreakpoint)) {
|
|
35
|
+
setScreenSize('tablet'); // 640-1023px: horizontal-compact
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
setScreenSize('desktop'); // >= 1024px: horizontal-full
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
handleResize();
|
|
42
|
+
window.addEventListener('resize', handleResize);
|
|
43
|
+
return () => window.removeEventListener('resize', handleResize);
|
|
44
|
+
}, [mobileBreakpoint, desktopBreakpoint]);
|
|
45
|
+
// Close mobile menu on escape key
|
|
46
|
+
useEffect(() => {
|
|
47
|
+
const handleEscape = (event) => {
|
|
48
|
+
if (event.key === 'Escape' && isMobileMenuOpen) {
|
|
49
|
+
setIsMobileMenuOpen(false);
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
if (isMobileMenuOpen) {
|
|
53
|
+
document.addEventListener('keydown', handleEscape);
|
|
54
|
+
}
|
|
55
|
+
return () => {
|
|
56
|
+
document.removeEventListener('keydown', handleEscape);
|
|
57
|
+
};
|
|
58
|
+
}, [isMobileMenuOpen]);
|
|
59
|
+
const handleItemClick = useCallback((item) => {
|
|
60
|
+
if (item.disabled)
|
|
61
|
+
return;
|
|
62
|
+
if (onItemClick) {
|
|
63
|
+
onItemClick(item);
|
|
64
|
+
}
|
|
65
|
+
if (item.onClick) {
|
|
66
|
+
item.onClick();
|
|
67
|
+
}
|
|
68
|
+
// Close mobile menu after item click
|
|
69
|
+
if (screenSize === 'mobile') {
|
|
70
|
+
setIsMobileMenuOpen(false);
|
|
71
|
+
}
|
|
72
|
+
// Close dropdown if open
|
|
73
|
+
setActiveDropdown(null);
|
|
74
|
+
}, [onItemClick, screenSize]);
|
|
75
|
+
const handleDropdownToggle = useCallback((groupId) => {
|
|
76
|
+
setActiveDropdown(activeDropdown === groupId ? null : groupId);
|
|
77
|
+
}, [activeDropdown]);
|
|
78
|
+
const handleLogoClick = useCallback(() => {
|
|
79
|
+
if (onLogoClick) {
|
|
80
|
+
onLogoClick();
|
|
81
|
+
}
|
|
82
|
+
}, [onLogoClick]);
|
|
83
|
+
const getNavigationHeight = () => {
|
|
84
|
+
switch (screenSize) {
|
|
85
|
+
case 'mobile':
|
|
86
|
+
return hamburgerHeight;
|
|
87
|
+
case 'tablet':
|
|
88
|
+
return tabletHeight;
|
|
89
|
+
case 'desktop':
|
|
90
|
+
return desktopHeight;
|
|
91
|
+
default:
|
|
92
|
+
return desktopHeight;
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
const getLogoSize = () => {
|
|
96
|
+
switch (screenSize) {
|
|
97
|
+
case 'mobile':
|
|
98
|
+
return mobileLogoSize;
|
|
99
|
+
case 'tablet':
|
|
100
|
+
return tabletLogoSize;
|
|
101
|
+
case 'desktop':
|
|
102
|
+
return desktopLogoSize;
|
|
103
|
+
default:
|
|
104
|
+
return desktopLogoSize;
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
const renderLogo = () => {
|
|
108
|
+
const logoContent = (_jsx("div", { className: `progressive-nav__logo progressive-nav__logo--${getLogoSize()}`, children: logo }));
|
|
109
|
+
if (logoHref) {
|
|
110
|
+
return (_jsx("a", { href: logoHref, className: "progressive-nav__logo-link", onClick: handleLogoClick, children: logoContent }));
|
|
111
|
+
}
|
|
112
|
+
return logoContent;
|
|
113
|
+
};
|
|
114
|
+
const renderNavigationItems = () => {
|
|
115
|
+
const allItems = groups.length > 0
|
|
116
|
+
? groups.flatMap(group => group.items)
|
|
117
|
+
: items;
|
|
118
|
+
return allItems.map((item) => (_jsxs("button", { onClick: () => handleItemClick(item), disabled: item.disabled, className: `progressive-nav__item ${item.active ? 'progressive-nav__item--active' : ''} ${item.disabled ? 'progressive-nav__item--disabled' : ''}`, children: [item.icon && (_jsx("span", { className: "progressive-nav__item-icon", children: item.icon })), _jsx("span", { className: "progressive-nav__item-label", children: item.label }), item.badge && (_jsx("span", { className: "progressive-nav__item-badge", children: item.badge }))] }, item.id)));
|
|
119
|
+
};
|
|
120
|
+
const renderDropdownItems = (groupItems) => {
|
|
121
|
+
return groupItems.map((item) => (_jsxs("button", { onClick: () => handleItemClick(item), disabled: item.disabled, className: `progressive-nav__dropdown-item ${item.active ? 'progressive-nav__dropdown-item--active' : ''} ${item.disabled ? 'progressive-nav__dropdown-item--disabled' : ''}`, children: [item.icon && (_jsx("span", { className: "progressive-nav__dropdown-item-icon", children: item.icon })), _jsx("span", { className: "progressive-nav__dropdown-item-label", children: item.label }), item.badge && (_jsx("span", { className: "progressive-nav__dropdown-item-badge", children: item.badge }))] }, item.id)));
|
|
122
|
+
};
|
|
123
|
+
const renderNavigationGroups = () => {
|
|
124
|
+
return groups.map((group) => (_jsxs("div", { className: "progressive-nav__group", children: [_jsxs("button", { onClick: () => handleDropdownToggle(group.id), className: `progressive-nav__group-trigger ${activeDropdown === group.id ? 'progressive-nav__group-trigger--active' : ''}`, children: [_jsx("span", { className: "progressive-nav__group-title", children: group.title }), _jsx(ChevronDownIcon, { className: `progressive-nav__group-arrow ${activeDropdown === group.id ? 'progressive-nav__group-arrow--expanded' : ''}` })] }), activeDropdown === group.id && (_jsx("div", { className: "progressive-nav__dropdown", children: renderDropdownItems(group.items) }))] }, group.id)));
|
|
125
|
+
};
|
|
126
|
+
const renderSecondaryActions = () => {
|
|
127
|
+
if (!showSecondaryActions || !secondaryActions.length)
|
|
128
|
+
return null;
|
|
129
|
+
return (_jsx("div", { className: "progressive-nav__secondary-actions", children: secondaryActions.map((action, index) => (_jsx("div", { className: "progressive-nav__secondary-action", children: action }, index))) }));
|
|
130
|
+
};
|
|
131
|
+
// Mobile hamburger menu pattern
|
|
132
|
+
if (screenSize === 'mobile') {
|
|
133
|
+
return (_jsx("nav", { ref: navRef, className: `progressive-nav progressive-nav--mobile ${className}`, style: { height: getNavigationHeight() }, "aria-label": ariaLabel, "data-testid": testId, children: _jsxs("div", { className: "progressive-nav__mobile-container", children: [_jsxs("div", { className: "progressive-nav__mobile-header", children: [renderLogo(), _jsx("button", { onClick: () => setIsMobileMenuOpen(!isMobileMenuOpen), className: "progressive-nav__mobile-toggle", style: {
|
|
134
|
+
minHeight: mobileTouchTarget,
|
|
135
|
+
minWidth: mobileTouchTarget
|
|
136
|
+
}, "aria-label": isMobileMenuOpen ? 'Close menu' : 'Open menu', "aria-expanded": isMobileMenuOpen, children: isMobileMenuOpen ? (_jsx(XMarkIcon, { className: "progressive-nav__mobile-toggle-icon" })) : (_jsx(HamburgerIcon, { className: "progressive-nav__mobile-toggle-icon" })) })] }), isMobileMenuOpen && (_jsxs(_Fragment, { children: [_jsx("div", { className: "progressive-nav__mobile-overlay", onClick: () => setIsMobileMenuOpen(false) }), _jsx("div", { className: "progressive-nav__mobile-menu", children: _jsx("div", { className: "progressive-nav__mobile-content", children: groups.length > 0 ? (_jsx("div", { className: "progressive-nav__mobile-groups", children: groups.map((group) => (_jsxs("div", { className: "progressive-nav__mobile-group", children: [group.title && (_jsx("div", { className: "progressive-nav__mobile-group-title", children: group.title })), _jsx("div", { className: "progressive-nav__mobile-group-items", children: group.items.map((item) => (_jsxs("button", { onClick: () => handleItemClick(item), disabled: item.disabled, className: `progressive-nav__mobile-item ${item.active ? 'progressive-nav__mobile-item--active' : ''} ${item.disabled ? 'progressive-nav__mobile-item--disabled' : ''}`, children: [item.icon && (_jsx("span", { className: "progressive-nav__mobile-item-icon", children: item.icon })), _jsx("span", { className: "progressive-nav__mobile-item-label", children: item.label }), item.badge && (_jsx("span", { className: "progressive-nav__mobile-item-badge", children: item.badge }))] }, item.id))) })] }, group.id))) })) : (_jsx("div", { className: "progressive-nav__mobile-items", children: renderNavigationItems() })) }) })] }))] }) }));
|
|
137
|
+
}
|
|
138
|
+
// Tablet horizontal-compact pattern
|
|
139
|
+
if (screenSize === 'tablet') {
|
|
140
|
+
return (_jsx("nav", { ref: navRef, className: `progressive-nav progressive-nav--tablet ${className}`, style: { height: getNavigationHeight() }, "aria-label": ariaLabel, "data-testid": testId, children: _jsxs("div", { className: "progressive-nav__tablet-container", children: [renderLogo(), _jsx("div", { className: "progressive-nav__tablet-content", children: groups.length > 0 ? renderNavigationGroups() : (_jsx("div", { className: "progressive-nav__tablet-items", children: renderNavigationItems() })) })] }) }));
|
|
141
|
+
}
|
|
142
|
+
// Desktop horizontal-full pattern
|
|
143
|
+
return (_jsx("nav", { ref: navRef, className: `progressive-nav progressive-nav--desktop ${className}`, style: { height: getNavigationHeight() }, "aria-label": ariaLabel, "data-testid": testId, children: _jsxs("div", { className: "progressive-nav__desktop-container", children: [renderLogo(), _jsx("div", { className: "progressive-nav__desktop-content", children: groups.length > 0 ? renderNavigationGroups() : (_jsx("div", { className: "progressive-nav__desktop-items", children: renderNavigationItems() })) }), renderSecondaryActions()] }) }));
|
|
144
|
+
};
|
|
145
|
+
export default ProgressiveNavigation;
|