@djangocfg/ui-nextjs 2.1.268 → 2.1.271
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/ui-nextjs",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.271",
|
|
4
4
|
"description": "Next.js UI component library with Radix UI primitives, Tailwind CSS styling, charts, and form components",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ui-components",
|
|
@@ -85,11 +85,11 @@
|
|
|
85
85
|
"check": "tsc --noEmit"
|
|
86
86
|
},
|
|
87
87
|
"peerDependencies": {
|
|
88
|
-
"@djangocfg/api": "^2.1.
|
|
89
|
-
"@djangocfg/i18n": "^2.1.
|
|
90
|
-
"@djangocfg/nextjs": "^2.1.
|
|
91
|
-
"@djangocfg/ui-core": "^2.1.
|
|
92
|
-
"@djangocfg/ui-tools": "^2.1.
|
|
88
|
+
"@djangocfg/api": "^2.1.271",
|
|
89
|
+
"@djangocfg/i18n": "^2.1.271",
|
|
90
|
+
"@djangocfg/nextjs": "^2.1.271",
|
|
91
|
+
"@djangocfg/ui-core": "^2.1.271",
|
|
92
|
+
"@djangocfg/ui-tools": "^2.1.271",
|
|
93
93
|
"@types/react": "^19.1.0",
|
|
94
94
|
"@types/react-dom": "^19.1.0",
|
|
95
95
|
"consola": "^3.4.2",
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
"react-chartjs-2": "^5.3.0"
|
|
113
113
|
},
|
|
114
114
|
"devDependencies": {
|
|
115
|
-
"@djangocfg/typescript-config": "^2.1.
|
|
115
|
+
"@djangocfg/typescript-config": "^2.1.271",
|
|
116
116
|
"@radix-ui/react-dropdown-menu": "^2.1.16",
|
|
117
117
|
"@radix-ui/react-slot": "^1.2.4",
|
|
118
118
|
"@types/node": "^24.7.2",
|
|
@@ -1,65 +1,74 @@
|
|
|
1
1
|
import { Link } from '../lib/navigation';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
-
// cn is available for future use
|
|
5
|
-
// import { cn } from '@djangocfg/ui-core/lib';
|
|
6
|
-
|
|
7
4
|
import {
|
|
8
5
|
Breadcrumb, BreadcrumbEllipsis, BreadcrumbItem, BreadcrumbLink, BreadcrumbList, BreadcrumbPage,
|
|
9
6
|
BreadcrumbSeparator
|
|
10
7
|
} from './breadcrumb';
|
|
11
8
|
|
|
12
9
|
export interface BreadcrumbItem {
|
|
13
|
-
/** Display text for the breadcrumb */
|
|
14
10
|
label: string;
|
|
15
|
-
/** URL to navigate to. If not provided, item will be rendered as current page */
|
|
16
11
|
href?: string;
|
|
17
|
-
/**
|
|
12
|
+
/**
|
|
13
|
+
* Force render as current page (non-interactive, aria-current="page").
|
|
14
|
+
* By default only the last item without href is treated as current page.
|
|
15
|
+
*/
|
|
18
16
|
isCurrentPage?: boolean;
|
|
19
|
-
/** Optional icon to display before the label */
|
|
20
17
|
icon?: React.ReactNode;
|
|
21
18
|
}
|
|
22
19
|
|
|
23
20
|
export interface BreadcrumbNavigationProps {
|
|
24
|
-
/** Array of breadcrumb items */
|
|
25
21
|
items: BreadcrumbItem[];
|
|
26
|
-
/** Custom separator between items */
|
|
27
22
|
separator?: React.ReactNode;
|
|
28
|
-
/**
|
|
23
|
+
/**
|
|
24
|
+
* Max visible items (excluding the ellipsis slot) before collapsing.
|
|
25
|
+
* Must be >= 2. Defaults to 5.
|
|
26
|
+
*/
|
|
29
27
|
maxItems?: number;
|
|
30
|
-
/** Custom className for the breadcrumb container */
|
|
31
28
|
className?: string;
|
|
32
|
-
/** Whether to use Next.js Link component for navigation */
|
|
33
|
-
useNextLink?: boolean;
|
|
34
29
|
}
|
|
35
30
|
|
|
31
|
+
type DisplayEntry =
|
|
32
|
+
| { type: 'item'; item: BreadcrumbItem; originalIndex: number }
|
|
33
|
+
| { type: 'ellipsis' };
|
|
34
|
+
|
|
36
35
|
export const BreadcrumbNavigation: React.FC<BreadcrumbNavigationProps> = ({
|
|
37
36
|
items,
|
|
38
37
|
separator,
|
|
39
38
|
maxItems = 5,
|
|
40
39
|
className,
|
|
41
|
-
useNextLink = true,
|
|
42
40
|
}) => {
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
if (shouldCollapse && items.length > 0) {
|
|
53
|
-
// Show first item, ellipsis, and last few items
|
|
54
|
-
if(items.length > 0) {
|
|
55
|
-
const firstItem = items[0]!;
|
|
56
|
-
const lastItems = items.slice(-(maxItems - 2)).filter(Boolean);
|
|
57
|
-
displayItems = [firstItem, ...lastItems];
|
|
41
|
+
if (!items || items.length === 0) return null;
|
|
42
|
+
|
|
43
|
+
const clampedMax = Math.max(2, maxItems);
|
|
44
|
+
|
|
45
|
+
// Build the list of entries to render
|
|
46
|
+
const entries: DisplayEntry[] = (() => {
|
|
47
|
+
if (items.length <= clampedMax) {
|
|
48
|
+
return items.map((item, i) => ({ type: 'item' as const, item, originalIndex: i }));
|
|
58
49
|
}
|
|
59
|
-
|
|
50
|
+
// Always show first item, ellipsis, then last (clampedMax - 2) items
|
|
51
|
+
// e.g. maxItems=4 → show 1 + ellipsis + 2 last = 4 visible items + ellipsis
|
|
52
|
+
const tailCount = Math.max(1, clampedMax - 2);
|
|
53
|
+
const tail = items.slice(-tailCount).map((item, i) => ({
|
|
54
|
+
type: 'item' as const,
|
|
55
|
+
item,
|
|
56
|
+
originalIndex: items.length - tailCount + i,
|
|
57
|
+
}));
|
|
58
|
+
return [
|
|
59
|
+
{ type: 'item' as const, item: items[0]!, originalIndex: 0 },
|
|
60
|
+
{ type: 'ellipsis' as const },
|
|
61
|
+
...tail,
|
|
62
|
+
];
|
|
63
|
+
})();
|
|
60
64
|
|
|
61
|
-
const
|
|
62
|
-
|
|
65
|
+
const resolveIsCurrentPage = (item: BreadcrumbItem, originalIndex: number): boolean => {
|
|
66
|
+
if (item.isCurrentPage !== undefined) return item.isCurrentPage;
|
|
67
|
+
return originalIndex === items.length - 1;
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
const renderItem = (item: BreadcrumbItem, originalIndex: number) => {
|
|
71
|
+
const current = resolveIsCurrentPage(item, originalIndex);
|
|
63
72
|
|
|
64
73
|
const content = (
|
|
65
74
|
<>
|
|
@@ -68,23 +77,23 @@ export const BreadcrumbNavigation: React.FC<BreadcrumbNavigationProps> = ({
|
|
|
68
77
|
</>
|
|
69
78
|
);
|
|
70
79
|
|
|
71
|
-
if (
|
|
80
|
+
if (current) {
|
|
72
81
|
return (
|
|
73
|
-
<BreadcrumbItem key={
|
|
82
|
+
<BreadcrumbItem key={`item-${originalIndex}`}>
|
|
74
83
|
<BreadcrumbPage>{content}</BreadcrumbPage>
|
|
75
84
|
</BreadcrumbItem>
|
|
76
85
|
);
|
|
77
86
|
}
|
|
78
87
|
|
|
79
88
|
return (
|
|
80
|
-
<BreadcrumbItem key={
|
|
81
|
-
|
|
82
|
-
{
|
|
83
|
-
<Link href={item.href
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
89
|
+
<BreadcrumbItem key={`item-${originalIndex}`}>
|
|
90
|
+
{item.href ? (
|
|
91
|
+
<BreadcrumbLink href={item.href}>
|
|
92
|
+
<Link href={item.href}>{content}</Link>
|
|
93
|
+
</BreadcrumbLink>
|
|
94
|
+
) : (
|
|
95
|
+
<BreadcrumbLink>{content}</BreadcrumbLink>
|
|
96
|
+
)}
|
|
88
97
|
</BreadcrumbItem>
|
|
89
98
|
);
|
|
90
99
|
};
|
|
@@ -92,28 +101,24 @@ export const BreadcrumbNavigation: React.FC<BreadcrumbNavigationProps> = ({
|
|
|
92
101
|
return (
|
|
93
102
|
<Breadcrumb className={className}>
|
|
94
103
|
<BreadcrumbList>
|
|
95
|
-
{
|
|
96
|
-
const
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
// Show ellipsis after first item if we collapsed items
|
|
100
|
-
if (shouldCollapse && isFirst && displayItems.length > 2) {
|
|
104
|
+
{entries.map((entry, displayIndex) => {
|
|
105
|
+
const isFirst = displayIndex === 0;
|
|
106
|
+
|
|
107
|
+
if (entry.type === 'ellipsis') {
|
|
101
108
|
return (
|
|
102
|
-
<React.Fragment key=
|
|
103
|
-
{renderBreadcrumbItem(item, index, isLast)}
|
|
109
|
+
<React.Fragment key="ellipsis">
|
|
104
110
|
<BreadcrumbSeparator>{separator}</BreadcrumbSeparator>
|
|
105
111
|
<BreadcrumbItem>
|
|
106
112
|
<BreadcrumbEllipsis />
|
|
107
113
|
</BreadcrumbItem>
|
|
108
|
-
{!isLast && <BreadcrumbSeparator>{separator}</BreadcrumbSeparator>}
|
|
109
114
|
</React.Fragment>
|
|
110
115
|
);
|
|
111
116
|
}
|
|
112
117
|
|
|
113
118
|
return (
|
|
114
|
-
<React.Fragment key={`fragment-${
|
|
115
|
-
{
|
|
116
|
-
{
|
|
119
|
+
<React.Fragment key={`fragment-${entry.originalIndex}`}>
|
|
120
|
+
{!isFirst && <BreadcrumbSeparator>{separator}</BreadcrumbSeparator>}
|
|
121
|
+
{renderItem(entry.item, entry.originalIndex)}
|
|
117
122
|
</React.Fragment>
|
|
118
123
|
);
|
|
119
124
|
})}
|