File tree Expand file tree Collapse file tree 4 files changed +53
-5
lines changed Expand file tree Collapse file tree 4 files changed +53
-5
lines changed Original file line number Diff line number Diff line change @@ -23,7 +23,7 @@ function hasVariablePathSegment(path: string): boolean {
23
23
*
24
24
* @returns A list of menu items.
25
25
*/
26
- export function createMenuItems ( ) : readonly MenuItem [ ] {
26
+ export function createMenuItems < T = unknown > ( ) : ReadonlyArray < MenuItem < T > > {
27
27
// @ts -expect-error: esbuild injection
28
28
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
29
29
__REGISTER__ ( 'createMenuItems' , ( window as VaadinWindow ) . Vaadin ) ;
@@ -44,6 +44,7 @@ export function createMenuItems(): readonly MenuItem[] {
44
44
icon : config . menu ?. icon ,
45
45
title : config . menu ?. title ?? config . title ,
46
46
order : config . menu ?. order ,
47
+ detail : config . detail as T | undefined ,
47
48
} ) )
48
49
// Sort views according to the order specified in the view configuration.
49
50
. sort ( ( menuA , menuB ) => {
Original file line number Diff line number Diff line change @@ -5,11 +5,11 @@ import type { RouteParamType } from './routeParamType.js';
5
5
* Internal type used for server communication and menu building. It extends the
6
6
* view configuration with the route parameters.
7
7
*/
8
- export type ServerViewConfig = Readonly < {
8
+ export type ServerViewConfig < T = unknown > = Readonly < {
9
9
children ?: readonly ServerViewConfig [ ] ;
10
10
params ?: Readonly < Record < string , RouteParamType > > ;
11
11
} > &
12
- ViewConfig ;
12
+ ViewConfig < T > ;
13
13
14
14
export type VaadinObject = Readonly < {
15
15
views : Readonly < Record < string , ViewConfig > > ;
Original file line number Diff line number Diff line change 1
1
import type { createBrowserRouter , RouteObject } from 'react-router' ;
2
2
3
- export type ViewConfig = Readonly < {
3
+ /**
4
+ * A configuration object for a view. This is used to define the view's
5
+ * metadata, such as the title, roles allowed, and other properties.
6
+ *
7
+ * @typeParam T - The type of the detail object.
8
+ */
9
+ export type ViewConfig < T = unknown > = Readonly < {
4
10
/**
5
11
* View title used in the main layout header, as <title> and as the default
6
12
* for the menu entry. If not defined, the component name will be taken,
@@ -59,6 +65,14 @@ export type ViewConfig = Readonly<{
59
65
*/
60
66
icon ?: string ;
61
67
} > ;
68
+
69
+ /**
70
+ * Used to add additional properties to the view. This object will be
71
+ * available when building the menu.
72
+ *
73
+ * @see {@link ./runtime/createMenuItems.ts#createMenuItems }
74
+ */
75
+ detail ?: T ;
62
76
} > ;
63
77
64
78
/**
@@ -87,11 +101,14 @@ export type AgnosticRoute = Readonly<{
87
101
88
102
/**
89
103
* A menu item used in for building the navigation menu.
104
+ *
105
+ * @typeParam T - The type of the detail object, same as in the view configuration.
90
106
*/
91
- export type MenuItem = Readonly < {
107
+ export type MenuItem < T = unknown > = Readonly < {
92
108
to : string ;
93
109
icon ?: string ;
94
110
title ?: string ;
111
+ detail ?: T ;
95
112
} > ;
96
113
97
114
export type RouterConfiguration = Readonly < {
Original file line number Diff line number Diff line change 1
1
import './vaadinGlobals.js' ; // eslint-disable-line import/no-unassigned-import
2
2
import { expect , describe , it } from 'vitest' ;
3
3
import { createMenuItems , viewsSignal } from '../../src/runtime/createMenuItems.js' ;
4
+ import type { ViewConfig } from '../../src/types.js' ;
4
5
import { deepRemoveNullProps } from '../utils.js' ;
5
6
6
7
const collator = new Intl . Collator ( 'en-US' ) ;
@@ -165,5 +166,34 @@ describe('@vaadin/hilla-file-router', () => {
165
166
} ,
166
167
] ) ;
167
168
} ) ;
169
+
170
+ it ( 'should include detail objects in menu items' , ( ) => {
171
+ // used to check that the type of the detail object is correct
172
+ // this is a compile-time check, does nothing at runtime
173
+ type Detail = {
174
+ foo : string ;
175
+ bar ?: number ;
176
+ } ;
177
+
178
+ const views : Record < string , ViewConfig < Detail > > = {
179
+ '/bar' : { title : 'Bar' , detail : { foo : '1' , bar : 2 } } ,
180
+ '/foo' : { title : 'Foo' , detail : { foo : '3' } } ,
181
+ } ;
182
+ viewsSignal . value = views ;
183
+
184
+ const items = createMenuItems < Detail > ( ) ;
185
+ expect ( deepRemoveNullProps ( items ) ) . to . be . deep . equal ( [
186
+ {
187
+ title : 'Bar' ,
188
+ to : '/bar' ,
189
+ detail : { foo : '1' , bar : 2 } ,
190
+ } ,
191
+ {
192
+ title : 'Foo' ,
193
+ to : '/foo' ,
194
+ detail : { foo : '3' } ,
195
+ } ,
196
+ ] ) ;
197
+ } ) ;
168
198
} ) ;
169
199
} ) ;
You can’t perform that action at this time.
0 commit comments