// One visible breadcrumb trail per page (UI-SPEC L1): an app may place // in its layout while a layer's page renders one too; the // first instance that renders in a request claims the page and later ones // render nothing. The claim is kept per path, so a client navigation hands // it out again (the layout instance, set up first, claims first). Pure, so // `node --test` drives it; names start with `seo` (app/utils is // auto-imported). export interface SeoBreadcrumbClaim { path: string id: string } /** * Whether instance `id` owns the trail of `path`, and the claim to keep: * no claim or one for another path is taken over; the claim of this path * belongs to the instance that made it. */ export function seoClaimBreadcrumbs(state: SeoBreadcrumbClaim | null | undefined, path: string, id: string): { state: SeoBreadcrumbClaim; owns: boolean } { if (!state || state.path !== path) return { state: { path, id }, owns: true } return { state, owns: state.id === id } } /** Releases the claim of `id` (an instance that stops rendering its trail). */ export function seoReleaseBreadcrumbs(state: SeoBreadcrumbClaim | null | undefined, id: string): SeoBreadcrumbClaim | null { return state && state.id === id ? null : (state ?? null) }