views
├── customers
│ ├── {customersId}
│ │ ├───────────────other folder
│ │ ├── @index.tsx
│ │ ├── edit.tsx
│ │ └── @layout.tsx (1)
│ └── @index.tsx
├── @index.tsx
└── @layout.tsx (2)
so Im trying add @layout.tsx under folder which name is route parameter
createMenuItems only give views with static path
but how can i get dynamic path views like customers/{customersId}/edit.tsx
so if customersId value is cake
then i expect get menu something like ‘cake/index.tsx’ 、 ‘cake/other folder’ 、 ‘cake/edit.tsx’ … auto without manually set views in layout.tsx
my tmp solution modify one from createMenuItems source code
import { type Signal, signal } from '@vaadin/hilla-react-signals';
import type { MenuItem, ViewConfig } from '@vaadin/hilla-file-router/types.js';
export enum RouteParamType {
Required = 'req',
Optional = 'opt',
Wildcard = '*',
}
export type ServerViewConfig<T = unknown> = Readonly<{
children?: readonly ServerViewConfig[];
params?: Readonly<Record<string, RouteParamType>>;
}> &
ViewConfig<T>;
export type VaadinObject = Readonly<{
views: Readonly<Record<string, ViewConfig>>;
}>;
export type VaadinWindow = Readonly<{
Vaadin?: VaadinObject;
}> &
Window;
export const viewsSignal: Signal<Readonly<Record<string, Readonly<ViewConfig>>> | undefined> = signal(
(window as unknown as VaadinWindow).Vaadin?.views,
);
function isExcluded(value: ViewConfig): boolean {
return !!value.menu?.exclude;
}
function hasVariablePathSegment(path: string): boolean {
return path.split('/').some((segment) => segment.startsWith(':customersId'));
}
export function createCustomersMenuItems<T = unknown>(): ReadonlyArray<MenuItem<T>> {
const collator = new Intl.Collator('en-US');
if (!viewsSignal.value) {
return [];
}
const views = Object.entries(viewsSignal.value);
return (
views
.filter(([path, value]) => !isExcluded(value) && hasVariablePathSegment(path))
.map(([path, config]) => ({
to: path,
icon: config.menu?.icon,
title: config.menu?.title ?? config.title,
order: config.menu?.order,
detail: config.detail as T | undefined,
}))
.sort((menuA, menuB) => {
const ordersDiff = (menuA.order ?? Number.MAX_VALUE) - (menuB.order ?? Number.MAX_VALUE);
return ordersDiff !== 0 ? ordersDiff : collator.compare(menuA.to, menuB.to);
})
);
}
and import to @layout.tsx
const { customersId } = useParams<{ customersId: string }>();
const items = createCustomersMenuItems().map((item) => ({
...item,
to: (item.to ?? "").replace(":customersId", customersId?? ""),
}));
any better solution?
Thank you!