@jfdevelops/react-layout 0.21.0 → 0.22.2
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/dist/create-config/create-resource-links.cjs +50 -20
- package/dist/create-config/create-resource-links.cjs.map +1 -1
- package/dist/create-config/create-resource-links.d.cts +18 -2
- package/dist/create-config/create-resource-links.d.cts.map +1 -1
- package/dist/create-config/create-resource-links.d.mts +18 -2
- package/dist/create-config/create-resource-links.d.mts.map +1 -1
- package/dist/create-config/create-resource-links.mjs +51 -20
- package/dist/create-config/create-resource-links.mjs.map +1 -1
- package/dist/create-config/define-layout.cjs +3 -2
- package/dist/create-config/define-layout.cjs.map +1 -1
- package/dist/create-config/define-layout.d.cts.map +1 -1
- package/dist/create-config/define-layout.d.mts.map +1 -1
- package/dist/create-config/define-layout.mjs +3 -2
- package/dist/create-config/define-layout.mjs.map +1 -1
- package/dist/create-config/for-paths/builder.cjs +6 -6
- package/dist/create-config/for-paths/builder.cjs.map +1 -1
- package/dist/create-config/for-paths/builder.mjs +6 -6
- package/dist/create-config/for-paths/builder.mjs.map +1 -1
- package/dist/create-config/for-resource.cjs +2 -1
- package/dist/create-config/for-resource.cjs.map +1 -1
- package/dist/create-config/for-resource.d.cts.map +1 -1
- package/dist/create-config/for-resource.d.mts.map +1 -1
- package/dist/create-config/for-resource.mjs +2 -1
- package/dist/create-config/for-resource.mjs.map +1 -1
- package/dist/create-config/for-resources/create-for-resources.cjs +15 -14
- package/dist/create-config/for-resources/create-for-resources.cjs.map +1 -1
- package/dist/create-config/for-resources/create-for-resources.mjs +15 -14
- package/dist/create-config/for-resources/create-for-resources.mjs.map +1 -1
- package/dist/create-config/index.d.cts +1 -1
- package/dist/create-config/index.d.mts +1 -1
- package/dist/errors/invalid-component.cjs +15 -7
- package/dist/errors/invalid-component.cjs.map +1 -1
- package/dist/errors/invalid-component.d.cts +106 -10
- package/dist/errors/invalid-component.d.cts.map +1 -1
- package/dist/errors/invalid-component.d.mts +106 -10
- package/dist/errors/invalid-component.d.mts.map +1 -1
- package/dist/errors/invalid-component.mjs +15 -7
- package/dist/errors/invalid-component.mjs.map +1 -1
- package/dist/errors/invalid-config.cjs +8 -3
- package/dist/errors/invalid-config.cjs.map +1 -1
- package/dist/errors/invalid-config.d.cts +96 -6
- package/dist/errors/invalid-config.d.cts.map +1 -1
- package/dist/errors/invalid-config.d.mts +96 -6
- package/dist/errors/invalid-config.d.mts.map +1 -1
- package/dist/errors/invalid-config.mjs +8 -3
- package/dist/errors/invalid-config.mjs.map +1 -1
- package/dist/errors/invalid-path.cjs +11 -5
- package/dist/errors/invalid-path.cjs.map +1 -1
- package/dist/errors/invalid-path.d.cts +100 -8
- package/dist/errors/invalid-path.d.cts.map +1 -1
- package/dist/errors/invalid-path.d.mts +100 -8
- package/dist/errors/invalid-path.d.mts.map +1 -1
- package/dist/errors/invalid-path.mjs +11 -5
- package/dist/errors/invalid-path.mjs.map +1 -1
- package/dist/errors/invalid-resource.cjs +11 -5
- package/dist/errors/invalid-resource.cjs.map +1 -1
- package/dist/errors/invalid-resource.d.cts +100 -8
- package/dist/errors/invalid-resource.d.cts.map +1 -1
- package/dist/errors/invalid-resource.d.mts +100 -8
- package/dist/errors/invalid-resource.d.mts.map +1 -1
- package/dist/errors/invalid-resource.mjs +11 -5
- package/dist/errors/invalid-resource.mjs.map +1 -1
- package/dist/errors/invalid-sub-resource.cjs +12 -5
- package/dist/errors/invalid-sub-resource.cjs.map +1 -1
- package/dist/errors/invalid-sub-resource.d.cts +103 -9
- package/dist/errors/invalid-sub-resource.d.cts.map +1 -1
- package/dist/errors/invalid-sub-resource.d.mts +103 -9
- package/dist/errors/invalid-sub-resource.d.mts.map +1 -1
- package/dist/errors/invalid-sub-resource.mjs +12 -5
- package/dist/errors/invalid-sub-resource.mjs.map +1 -1
- package/dist/errors/layout-configuration-error.cjs +17 -0
- package/dist/errors/layout-configuration-error.cjs.map +1 -0
- package/dist/errors/layout-configuration-error.d.cts +99 -0
- package/dist/errors/layout-configuration-error.d.cts.map +1 -0
- package/dist/errors/layout-configuration-error.d.mts +99 -0
- package/dist/errors/layout-configuration-error.d.mts.map +1 -0
- package/dist/errors/layout-configuration-error.mjs +17 -0
- package/dist/errors/layout-configuration-error.mjs.map +1 -0
- package/dist/errors/missing-path-variable.cjs +12 -5
- package/dist/errors/missing-path-variable.cjs.map +1 -1
- package/dist/errors/missing-path-variable.d.cts +99 -7
- package/dist/errors/missing-path-variable.d.cts.map +1 -1
- package/dist/errors/missing-path-variable.d.mts +99 -7
- package/dist/errors/missing-path-variable.d.mts.map +1 -1
- package/dist/errors/missing-path-variable.mjs +12 -5
- package/dist/errors/missing-path-variable.mjs.map +1 -1
- package/dist/errors/react-layout-error.cjs +38 -43
- package/dist/errors/react-layout-error.cjs.map +1 -1
- package/dist/errors/react-layout-error.d.cts +81 -38
- package/dist/errors/react-layout-error.d.cts.map +1 -1
- package/dist/errors/react-layout-error.d.mts +81 -38
- package/dist/errors/react-layout-error.d.mts.map +1 -1
- package/dist/errors/react-layout-error.mjs +39 -43
- package/dist/errors/react-layout-error.mjs.map +1 -1
- package/dist/index.cjs +4 -3
- package/dist/index.d.cts +4 -2
- package/dist/index.d.mts +4 -2
- package/dist/index.mjs +5 -4
- package/dist/node_modules/.pnpm/@jfdevelops_create-error@0.2.0_patch_hash_afc71b16c3f866f54416d30f467784ddc31736feb04f281a5fc4772ea422f4a9/node_modules/@jfdevelops/create-error/dist/types.d.cts +107 -0
- package/dist/node_modules/.pnpm/@jfdevelops_create-error@0.2.0_patch_hash_afc71b16c3f866f54416d30f467784ddc31736feb04f281a5fc4772ea422f4a9/node_modules/@jfdevelops/create-error/dist/types.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/@jfdevelops_create-error@0.2.0_patch_hash_afc71b16c3f866f54416d30f467784ddc31736feb04f281a5fc4772ea422f4a9/node_modules/@jfdevelops/create-error/dist/types.d.mts +107 -0
- package/dist/node_modules/.pnpm/@jfdevelops_create-error@0.2.0_patch_hash_afc71b16c3f866f54416d30f467784ddc31736feb04f281a5fc4772ea422f4a9/node_modules/@jfdevelops/create-error/dist/types.d.mts.map +1 -0
- package/dist/resource.cjs +2 -1
- package/dist/resource.cjs.map +1 -1
- package/dist/resource.d.cts.map +1 -1
- package/dist/resource.d.mts.map +1 -1
- package/dist/resource.mjs +3 -1
- package/dist/resource.mjs.map +1 -1
- package/package.json +8 -6
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"define-layout.mjs","names":[],"sources":["../../src/create-config/define-layout.tsx"],"sourcesContent":["import {\n type JSX,\n type ReactNode,\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n type ComposableComponents,\n type ComposableNameContext,\n type ComposableResourceLayout,\n type CreateLayoutComposable,\n collectComposablePresetEntries,\n LayoutComposablePresetProvider,\n MakeComposable,\n makeComposable,\n MakeComposableOptions,\n RequiredPresetLayoutProps,\n resolveLayoutComposables,\n} from '@jfdevelops/react-layout-composables';\nimport {\n type AnyBuiltPropDefinition,\n createPrimitivePropBuilder,\n createProp,\n type ResolveLayoutProps,\n type ResolveProps,\n resolvePropDefinitionValues,\n validateProps,\n} from '@jfdevelops/react-layout-validator';\nimport {\n IncludedProps,\n type IncludedPropBehavior,\n InferredInProps,\n InPropsDefinition,\n InPropsObject,\n LayoutRenderProps,\n MergedLayoutInProps,\n ResolvedIncludedComponentProps,\n ResolvedIncludedConfigProps,\n ResolvedIncludedProps,\n} from '../props';\nimport {\n createIsValidResourceFn,\n normalizeResources,\n toResourceEnum,\n type LayoutResourceKey,\n type ResourceDefinition,\n type ResourceDefinitionValue,\n} from '../resource';\nimport { BaseComponent, functionalUpdate, pick, Show, Updater } from '../utils';\nimport { capitalize } from '../utils/capitalize';\nimport { InvalidConfigError } from '../errors';\nimport { isResourceConfigComponentKey } from './component-keys';\nimport {\n type CreateResourceConfigFn,\n createResourceConfig,\n} from './get-component';\nimport type { AssertUnreservedResources } from './types';\nimport {\n createResourceLinksFn,\n type CreateResourceLinksFn,\n} from './create-resource-links';\nimport {\n createForResource,\n type CreateLayoutForResource,\n type CreateResourceLayoutOptions,\n type CreateResourceLayoutOptionsBase,\n} from './for-resource';\nimport {\n createForResources,\n type CreateResourceLayoutForResourcesFn,\n} from './for-resources';\nimport {\n type ResourceLayoutShellPublisher,\n ResourceLayoutShellPublisherContext,\n useResourceLayoutShellPublisher,\n} from './shell-context';\n\nexport type LayoutIncludeProps<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n> = IncludedProps<MergedLayoutInProps<Resources, Options, Composables>>;\n\nexport type LayoutProps<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = {\n /**\n * Props to include in the layout.\n */\n include?: LayoutIncludeProps<Resources, Options, Composables> & IncludeProps;\n /**\n * Custom props that the layout will receive.\n */\n custom?: CustomProps;\n};\n\ntype LayoutRenderContext<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Composables extends ComposableComponents,\n> = {\n composables: LayoutRenderComposables<Composables>;\n inProps: Record<string, unknown>;\n /**\n * @deprecated Use `resources.current` instead. `resource` will be removed in\n * the next major version.\n */\n resource: LayoutResourceKey<Resources>;\n /**\n * Accessor for the resources bound to this definition. Read `resources.current`\n * for the resource this instance renders, call `resources()` for the raw\n * value, use `resources.pick(...)` / `resources.omit(...)` to filter, or\n * `resources.isResource(...)` to narrow an unknown value.\n */\n resources: LayoutRenderResourcesAccessor<Resources>;\n name: string;\n};\n\n/**\n * A single {@link ResourceDefinition} kept by a `pick`, or `never` when it does\n * not match. Widened definitions (`string`, `{ value: string }`) are always\n * kept — the concrete keys are not known statically, so the runtime filter is\n * the source of truth.\n */\ntype PickResourceDefinition<\n Definition,\n Keys extends string,\n> = Definition extends ResourceDefinition\n ? string extends ResourceDefinitionValue<Definition>\n ? Definition\n : ResourceDefinitionValue<Definition> extends Keys\n ? Definition\n : never\n : never;\n\ntype PickResourceDefinitions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Keys extends LayoutResourceKey<Resources>,\n> = Array<PickResourceDefinition<Resources[number], Keys>>;\n\n/**\n * A single {@link ResourceDefinition} kept by an `omit`, or `never` when it is\n * one of the omitted keys. Widened definitions are always kept.\n */\ntype OmitResourceDefinition<\n Definition,\n Keys extends string,\n> = Definition extends ResourceDefinition\n ? string extends ResourceDefinitionValue<Definition>\n ? Definition\n : ResourceDefinitionValue<Definition> extends Keys\n ? never\n : Definition\n : never;\n\ntype OmitResourceDefinitions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Keys extends LayoutResourceKey<Resources>,\n> = Array<OmitResourceDefinition<Resources[number], Keys>>;\n\n/**\n * The result of `resources.pick(...)` / `resources.omit(...)`.\n *\n * - calling it returns the selected resource definitions.\n * - `.isResource(value)` narrows an unknown value to one of the selected keys.\n */\nexport type ResourceSelection<\n Definitions extends ReadonlyArray<ResourceDefinition>,\n> = {\n /** Returns the selected resource definitions. */\n (): Show<Definitions>;\n /**\n * Narrows an unknown value to one of the selected resource keys.\n *\n * @param value - The value to test.\n */\n isResource(value: unknown): value is LayoutResourceKey<Definitions>;\n};\n\n/**\n * Accessor for the resources bound to a `defineResourceLayout` definition.\n *\n * - `resources()` returns the raw resources.\n * - `resources.omit(key, ...rest)` selects every resource except the named ones.\n * - `resources.pick(key, ...rest)` selects only the named resources.\n * - `resources.isResource(value)` narrows an unknown value to a resource key.\n *\n * `pick` / `omit` return a {@link ResourceSelection} thunk: call it for the\n * definitions, or use its `isResource` guard.\n */\nexport type LayoutResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = {\n /**\n * Returns the raw `resources` value passed to `defineResourceLayout`,\n * exactly as declared.\n */\n (): Resources;\n /**\n * Narrows an unknown value to one of this definition's top-level resource\n * keys.\n *\n * @param value - The value to test.\n */\n isResource(value: unknown): value is LayoutResourceKey<Resources>;\n /**\n * Selects every declared resource except the named ones. Requires at least\n * one key.\n *\n * @param keys - Top-level resource names to exclude.\n */\n omit<\n Keys extends [\n LayoutResourceKey<Resources>,\n ...LayoutResourceKey<Resources>[],\n ],\n >(\n ...keys: Keys\n ): ResourceSelection<OmitResourceDefinitions<Resources, Keys[number]>>;\n /**\n * Selects only the named resources. Requires at least one key.\n *\n * @param keys - Top-level resource names to keep.\n */\n pick<\n Keys extends [\n LayoutResourceKey<Resources>,\n ...LayoutResourceKey<Resources>[],\n ],\n >(\n ...keys: Keys\n ): ResourceSelection<PickResourceDefinitions<Resources, Keys[number]>>;\n};\n\n/**\n * Render-scoped {@link LayoutResourcesAccessor}, extended with `current` — the\n * resource key the layout instance is rendering for.\n */\nexport type LayoutRenderResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = LayoutResourcesAccessor<Resources> & {\n /** The resource this layout instance is rendering for. */\n readonly current: LayoutResourceKey<Resources>;\n};\n\nfunction createResourceSelection(\n definitions: ReadonlyArray<ResourceDefinition>,\n): ResourceSelection<ReadonlyArray<ResourceDefinition>> {\n const selection = (() => definitions) as ResourceSelection<\n ReadonlyArray<ResourceDefinition>\n >;\n\n selection.isResource = createIsValidResourceFn(definitions);\n\n return selection;\n}\n\nfunction createLayoutResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(resources: Resources): LayoutResourcesAccessor<Resources> {\n const accessor = (() => resources) as LayoutResourcesAccessor<Resources>;\n\n accessor.isResource = createIsValidResourceFn(resources);\n accessor.omit = ((...keys: string[]) =>\n createResourceSelection(\n resources.filter(\n (resource) => !keys.includes(readResourceSlug(resource)),\n ),\n )) as LayoutResourcesAccessor<Resources>['omit'];\n accessor.pick = ((...keys: string[]) =>\n createResourceSelection(\n resources.filter((resource) =>\n keys.includes(readResourceSlug(resource)),\n ),\n )) as LayoutResourcesAccessor<Resources>['pick'];\n\n return accessor;\n}\n\nfunction createLayoutRenderResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n resources: Resources,\n current: LayoutResourceKey<Resources>,\n): LayoutRenderResourcesAccessor<Resources> {\n return Object.assign(createLayoutResourcesAccessor(resources), { current });\n}\ntype LayoutRenderComposables<Composables extends ComposableComponents> = [\n keyof Composables,\n] extends [never]\n ? undefined\n : Composables;\n\ntype SplitLayoutInPropDefinition<\n Props extends InPropsObject = {},\n Content = unknown,\n> = {\n props?: Props;\n render: ((props: ResolveProps<Props>) => Content) | Content;\n};\n\nfunction isBuiltPropDefinition(\n value: unknown,\n): value is AnyBuiltPropDefinition {\n return typeof value === 'function' && value !== null && 'visibility' in value;\n}\n\nfunction isSplitLayoutInPropDefinition(\n value: unknown,\n): value is SplitLayoutInPropDefinition {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'render' in value &&\n (value as { render?: unknown }).render !== undefined\n );\n}\n\nfunction isJSXElementDefinition(\n definition: unknown,\n): definition is AnyBuiltPropDefinition & { type: 'JSX.Element' } {\n return (\n isBuiltPropDefinition(definition) &&\n 'type' in definition &&\n definition.type === 'JSX.Element'\n );\n}\n\nfunction toLayoutRenderPropKey(includeKey: string, definition: unknown) {\n return isJSXElementDefinition(definition)\n ? capitalize(includeKey)\n : includeKey;\n}\n\nfunction readLayoutOptionValue(\n includeKey: string,\n definition: unknown,\n sources: Record<string, unknown>,\n) {\n const layoutOptionKeys = isJSXElementDefinition(definition)\n ? [capitalize(includeKey), includeKey]\n : [includeKey, capitalize(includeKey)];\n\n for (const key of layoutOptionKeys) {\n if (key in sources) {\n return sources[key];\n }\n }\n\n return undefined;\n}\n\nfunction getIncludedPropBehavior(value: unknown): IncludedPropBehavior | null {\n if (\n value !== null &&\n typeof value === 'object' &&\n 'visibility' in value &&\n 'passthrough' in value\n ) {\n return value as IncludedPropBehavior;\n }\n\n return null;\n}\n\nfunction isIncludedPropRequired(value: unknown) {\n return (\n value === true ||\n value === 'required' ||\n getIncludedPropBehavior(value)?.visibility === 'required'\n );\n}\n\nfunction allowsConfigPassthrough(value: unknown) {\n const behavior = getIncludedPropBehavior(value);\n\n if (!behavior) {\n return true;\n }\n\n if (behavior.passthrough === 'config') {\n return true;\n }\n\n // optional + component passthrough still accepts create-time defaults\n return (\n behavior.passthrough === 'component' && behavior.visibility === 'optional'\n );\n}\n\nfunction allowsComponentPassthrough(value: unknown) {\n const behavior = getIncludedPropBehavior(value);\n\n return behavior ? behavior.passthrough === 'component' : value === 'optional';\n}\n\nfunction splitLayoutInProps(inProps: Record<string, unknown>) {\n const resolvedInProps: Record<string, AnyBuiltPropDefinition> = {};\n const splitInProps: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(inProps)) {\n if (isBuiltPropDefinition(value)) {\n resolvedInProps[key] = value;\n continue;\n }\n\n if (isSplitLayoutInPropDefinition(value)) {\n splitInProps[key] = value.render;\n\n if (value.props && typeof value.props === 'object') {\n Object.assign(resolvedInProps, value.props);\n }\n }\n }\n\n return {\n resolvedInProps,\n splitInProps,\n };\n}\n\nfunction resolveLayoutOptionDefaults(\n defaults: Record<string, unknown>,\n options: Record<string, unknown>,\n) {\n const resolved = { ...options };\n\n for (const [key, defaultValue] of Object.entries(defaults)) {\n if (key in options) {\n if (typeof defaultValue === 'function') {\n resolved[key] = options[key];\n } else {\n resolved[key] = functionalUpdate(\n defaultValue,\n options[key] as Updater<unknown>,\n );\n }\n }\n }\n\n return resolved;\n}\n\n/**\n * The `layout` block of a {@link defineResourceLayout} call: the props, the\n * composable map, and the render for a per-resource page component.\n *\n * Extracted so {@link defineResourceLayout.withLayout} can reuse the exact same\n * shape while making `render` optional (see {@link ShellLayoutDefinition}).\n */\ntype LayoutDefinition<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables>,\n CustomProps extends InPropsObject,\n> = {\n /**\n * The props to pass to the layout.\n */\n props?: LayoutProps<Resources, Options, Composables, IncludeProps, CustomProps>;\n /**\n * Components used to compose the layout. Invoked per layout instance with\n * a scoped `create` that resolves composable `name` callbacks using the\n * layout's `resource` and `name`.\n */\n composables?: (\n create: CreateLayoutComposable<LayoutResourceKey<Resources>>,\n ) => Composables;\n /**\n * The render function for the layout.\n */\n render: (\n props: LayoutRenderProps<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n >,\n context: LayoutRenderContext<Resources, Composables>,\n ) => JSX.Element;\n};\n\ntype CreateViewMapOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = {\n /**\n * An array of valid resource names to support. Nested sub-resource slugs that\n * collide with config keys (`component`, `detail`, `new`, …) are reserved.\n */\n resources: AssertUnreservedResources<Resources>;\n /**\n * The options that are passed into the created resource layout.\n */\n options?: Options;\n layout: LayoutDefinition<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n >;\n};\n\ntype ResourceLayoutComposition<\n Name extends string,\n Composables extends ComposableComponents,\n> = [keyof Composables] extends [never]\n ? {}\n : {\n makeComposable: MakeComposable<Composables, Name>;\n };\nexport type ResourceLayoutComponent<\n Name extends string,\n Props extends InPropsObject = {},\n Composables extends ComposableComponents = {},\n Resource extends string = string,\n IncludedCallProps extends object = {},\n> = ResourceLayoutComposition<Name, Composables> &\n BaseComponent<Name, Show<ResolveProps<Props> & IncludedCallProps>> & {\n (props: Show<ResolveProps<Props> & IncludedCallProps>): JSX.Element;\n /**\n * A type-only property containing the resource associated with this\n * component. This property is `undefined` at runtime.\n */\n readonly resource: Resource;\n };\n\nexport type LayoutPropsForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n> = [keyof IncludeProps] extends [never]\n ? ResolveLayoutProps<InferredInProps<Resources, InProps>> &\n RequiredPresetLayoutProps<Composables>\n : ResolvedIncludedConfigProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >;\n\ntype CreateResourceLayoutFnImpl<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = <\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n>(\n options: CreateResourceLayoutOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n Name,\n Resource,\n Props\n >,\n) => ResourceLayoutComponent<\n Name,\n CustomProps,\n Composables,\n Resource,\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >\n>;\n\nexport type CreateResourceLayoutMakeComposableOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n> = CreateResourceLayoutOptionsBase<Resources, Name, Resource, Props> &\n Partial<\n LayoutPropsForResource<Resources, InProps, Composables, IncludeProps>\n >;\n\ntype CreateResourceLayoutMakeComposableFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables>,\n CustomProps extends InPropsObject,\n> = <\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n>(\n options: CreateResourceLayoutMakeComposableOptions<\n Resources,\n InProps,\n Composables,\n Name,\n Resource,\n Props,\n IncludeProps\n >,\n) => ComposableResourceLayout<Composables, Name, any, any, any>;\n\ntype CreateResourceLayoutFnBase<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = CreateResourceLayoutFnImpl<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n> & {\n /**\n * A function to create a resource layout for a specific resource.\n */\n forResource: CreateLayoutForResource<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n /**\n * Creates resource layout factories for multiple defined resources.\n */\n forResources: CreateResourceLayoutForResourcesFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n};\n\ntype CreateResourceLayoutMakeComposableMember<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables>,\n CustomProps extends InPropsObject,\n> = [keyof Composables] extends [never]\n ? {}\n : {\n makeComposable: CreateResourceLayoutMakeComposableFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n };\n\nexport type CreateResourceLayoutFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = CreateResourceLayoutFnBase<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n> &\n CreateResourceLayoutMakeComposableMember<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n\ntype DefinedResourceLayout<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = {\n createResourceConfig: CreateResourceConfigFn<Resources>;\n createResourceLayout: CreateResourceLayoutFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n createResourceLinks: CreateResourceLinksFn<Resources>;\n /**\n * Accessor for the resources bound to this definition. Call `resources()` for\n * the raw value, or `resources.pick(...)` / `resources.omit(...)` to filter.\n */\n resources: LayoutResourcesAccessor<Resources>;\n};\n\nfunction readResourceSlug(resource: ResourceDefinition) {\n return typeof resource === 'string' ? resource : resource.value;\n}\n\nfunction assertUnreservedResourceSlugs(\n resources: ReadonlyArray<ResourceDefinition>,\n owner?: string,\n) {\n for (const resource of resources) {\n const slug = readResourceSlug(resource);\n\n if (owner !== undefined && isResourceConfigComponentKey(slug)) {\n throw new InvalidConfigError({\n reason: `Sub-resource \"${slug}\" under \"${owner}\" collides with a reserved config key`,\n });\n }\n\n if (typeof resource !== 'string') {\n assertUnreservedResourceSlugs(resource.subResources, slug);\n }\n }\n}\n\nfunction defineResourceLayoutImpl<\n const Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n Resources,\n InProps,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n>(\n options: CreateViewMapOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >,\n): DefinedResourceLayout<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n> {\n const { options: inProps = {} as InProps, resources, layout } = options;\n // Internal, set only by `defineResourceLayout.withLayout`: the identity of the\n // owning definition, forwarded when a page reports its resource so the shell\n // can tell its own pages apart from ones belonging to another definition.\n const shellId = (options as { shellId?: symbol }).shellId;\n\n assertUnreservedResourceSlugs(resources);\n\n const resourcesAccessor = createLayoutResourcesAccessor(resources);\n const normalizedResources = normalizeResources(resources);\n const resourcesEnum = createPrimitivePropBuilder('string').enum(\n toResourceEnum(normalizedResources),\n );\n const definedResourceLayout = (<\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n >(\n layoutOptions: CreateResourceLayoutOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n Name,\n Resource,\n Props\n >,\n ) => {\n const {\n name,\n props: instancePropDefinitions,\n ...layoutOptionProps\n } = layoutOptions;\n const createComposableLayout =\n makeComposable<\n LayoutRenderProps<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >\n >();\n const nameProp = createProp.string().literal(name);\n const rawResolvedOptions =\n typeof inProps === 'function'\n ? inProps({\n resource: resourcesEnum,\n name: nameProp,\n })\n : inProps;\n const { resolvedInProps, splitInProps } = splitLayoutInProps({\n ...(rawResolvedOptions as Record<string, unknown>),\n ...(instancePropDefinitions as Record<string, unknown> | undefined),\n ...layoutOptionProps,\n });\n const { composables, render, props: layoutProps } = layout;\n const customLayoutProps = layoutProps?.custom;\n const includeLayoutProps = layoutProps?.include;\n const layoutOptionValues = layoutOptionProps as Record<string, unknown>;\n const resolvedLayoutProps = {\n ...customLayoutProps,\n };\n const layoutContext: ComposableNameContext<\n LayoutResourceKey<Resources>,\n typeof name\n > = {\n resource: layoutOptions.resource,\n name,\n capitalize,\n };\n const validationContext = {\n layoutName: name,\n resource: layoutContext.resource,\n };\n const resolvedComposables = composables\n ? resolveLayoutComposables(composables, layoutContext)\n : undefined;\n const mergedResolvedInProps = { ...resolvedInProps };\n\n for (const {\n props: presetPropDefinitions,\n } of collectComposablePresetEntries(resolvedComposables)) {\n Object.assign(mergedResolvedInProps, presetPropDefinitions);\n }\n\n const composablePresetProps = Object.fromEntries(\n collectComposablePresetEntries(resolvedComposables).map(\n ({ key, props: presetPropDefinitions }) => {\n const presetPropEntries = Object.entries(presetPropDefinitions);\n const validatedDefinitions = Object.fromEntries(\n presetPropEntries.filter(([propKey]) => {\n const includeBehavior = includeLayoutProps?.[propKey];\n\n return (\n includeBehavior === undefined ||\n (allowsConfigPassthrough(includeBehavior) &&\n (isIncludedPropRequired(includeBehavior) ||\n layoutOptionValues[propKey] !== undefined))\n );\n }),\n );\n const presetPropValues = Object.fromEntries(\n presetPropEntries.flatMap(([propKey]) =>\n propKey in layoutOptionValues\n ? [[propKey, layoutOptionValues[propKey]]]\n : [],\n ),\n );\n\n return [\n key,\n validateProps(\n validatedDefinitions as Record<string, AnyBuiltPropDefinition>,\n presetPropValues,\n validationContext,\n ),\n ];\n },\n ),\n );\n const mergedRenderContext = {\n composables: resolvedComposables as LayoutRenderComposables<Composables>,\n resource: layoutContext.resource,\n resources: createLayoutRenderResourcesAccessor(\n resources as Resources,\n layoutContext.resource,\n ),\n name: layoutContext.name,\n inProps: splitInProps,\n } as LayoutRenderContext<Resources, Composables>;\n\n function Component(\n props: Show<\n ResolveProps<CustomProps> &\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >\n >,\n ) {\n const publishResource = useResourceLayoutShellPublisher();\n\n // Report the resource this page renders for so an ancestor `Shell` (from\n // `defineResourceLayout.withLayout`) can resolve `resources.current` for\n // its own render without the consumer threading a route param down to it.\n // A layout effect, not a passive one, so the shell reflects the new\n // resource in the same commit the page mounts — a passive effect would\n // leave one painted frame of stale shell chrome mid-navigation. Degrades\n // to a no-op when rendered without a `Shell` (context defaults to null).\n useLayoutEffect(() => {\n publishResource?.(layoutContext.resource, shellId);\n\n return () => publishResource?.(undefined, shellId);\n }, [publishResource, layoutContext.resource]);\n\n const validatedProps = validateProps(resolvedLayoutProps, props, {\n ...validationContext,\n });\n const includedPropKeys = Object.keys(includeLayoutProps ?? {});\n const includedPropDefinitions = pick(\n mergedResolvedInProps,\n includedPropKeys,\n ) as Record<string, unknown>;\n const includedPropValues = {\n ...resolvePropDefinitionValues(includedPropDefinitions),\n } as Record<string, unknown>;\n\n for (const key of includedPropKeys) {\n const definition = mergedResolvedInProps[key];\n const includeBehavior = includeLayoutProps?.[key];\n const callSiteValue = allowsComponentPassthrough(includeBehavior)\n ? readLayoutOptionValue(\n key,\n definition,\n props as Record<string, unknown>,\n )\n : undefined;\n const layoutOptionValue = allowsConfigPassthrough(includeBehavior)\n ? readLayoutOptionValue(key, definition, layoutOptionValues)\n : undefined;\n const splitValue = key in splitInProps ? splitInProps[key] : undefined;\n const value = callSiteValue ?? layoutOptionValue ?? splitValue;\n\n if (value !== undefined) {\n includedPropValues[key] = value;\n }\n }\n\n const requiredIncludedPropDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(([key]) =>\n isIncludedPropRequired(includeLayoutProps?.[key]),\n ),\n );\n const optionalIncludedPropDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(\n ([key]) =>\n !isIncludedPropRequired(includeLayoutProps?.[key]) &&\n includedPropValues[key] !== undefined,\n ),\n );\n const validatedIncludedProps = validateProps(\n {\n ...requiredIncludedPropDefinitions,\n ...optionalIncludedPropDefinitions,\n } as Record<string, AnyBuiltPropDefinition>,\n includedPropValues,\n validationContext,\n );\n const layoutRenderIncludedProps = Object.fromEntries(\n includedPropKeys.flatMap((key) => {\n if (!(key in validatedIncludedProps)) {\n return [];\n }\n\n return [\n [\n toLayoutRenderPropKey(key, mergedResolvedInProps[key]),\n validatedIncludedProps[\n key as keyof typeof validatedIncludedProps\n ],\n ],\n ];\n }),\n );\n const layoutRenderProps = {\n ...validatedProps,\n ...layoutRenderIncludedProps,\n } as unknown as LayoutRenderProps<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n\n return (\n <LayoutComposablePresetProvider value={composablePresetProps}>\n {render(layoutRenderProps, mergedRenderContext)}\n </LayoutComposablePresetProvider>\n );\n }\n\n function createComposition<\n LayoutName extends string,\n const Defined extends MakeComposableOptions<Composables, LayoutName>,\n >(compositionOptions: Defined) {\n if (!compositionOptions.components) {\n return {} as ResourceLayoutComposition<LayoutName, Composables>;\n }\n\n return {\n makeComposable: createComposableLayout(\n compositionOptions,\n ) as MakeComposable<Composables, LayoutName>,\n };\n }\n\n return Object.assign(Component, {\n displayName: name,\n props: undefined as unknown as Show<\n ResolveProps<CustomProps> &\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >\n >,\n resource: undefined as unknown as Resource,\n ...createComposition({\n components: resolvedComposables as Composables | undefined,\n name,\n }),\n });\n }) as CreateResourceLayoutFnImpl<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n const createTopLevelMakeComposable = () => {\n return (options: Record<string, unknown>) => {\n const layout = definedResourceLayout(options as never);\n\n if (\n !('makeComposable' in layout) ||\n typeof layout.makeComposable !== 'function'\n ) {\n throw new Error(\n 'makeComposable requires composables to be defined in the layout',\n );\n }\n\n return layout.makeComposable();\n };\n };\n\n function getComponentPropDefinitions(resource: LayoutResourceKey<Resources>) {\n const componentName = 'ScopedResourceComponent';\n const rawResolvedOptions =\n typeof inProps === 'function'\n ? inProps({\n resource: resourcesEnum,\n name: createProp.string().literal(componentName),\n })\n : inProps;\n const { resolvedInProps } = splitLayoutInProps(\n rawResolvedOptions as Record<string, unknown>,\n );\n const resolvedComposables = layout.composables\n ? resolveLayoutComposables(layout.composables, {\n resource,\n name: componentName,\n capitalize,\n })\n : undefined;\n\n for (const {\n props: presetPropDefinitions,\n } of collectComposablePresetEntries(resolvedComposables)) {\n Object.assign(resolvedInProps, presetPropDefinitions);\n }\n\n return {\n ...resolvedInProps,\n ...layout.props?.custom,\n };\n }\n\n const { createLayoutForResourceBuilder, forResource } = createForResource<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >({\n createResourceLayout: definedResourceLayout as never,\n resolveLayoutOptionDefaults,\n });\n const forResources = createForResources<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >({\n createLayoutForResource: createLayoutForResourceBuilder,\n ...(layout.composables\n ? { createMakeComposableLayout: createTopLevelMakeComposable }\n : {}),\n createResourceLayout: definedResourceLayout as never,\n getComponentPropDefinitions,\n });\n\n const createResourceLayoutExtras: {\n forResource: CreateLayoutForResource<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n forResources: CreateResourceLayoutForResourcesFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n makeComposable?: ReturnType<typeof createTopLevelMakeComposable>;\n } = {\n forResource,\n forResources,\n };\n\n if (layout.composables) {\n createResourceLayoutExtras.makeComposable = createTopLevelMakeComposable();\n }\n\n const createResourceLayout = Object.assign(\n definedResourceLayout,\n createResourceLayoutExtras,\n ) as CreateResourceLayoutFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n\n const createResourceLinks = createResourceLinksFn(resources);\n\n return {\n createResourceConfig,\n createResourceLayout,\n createResourceLinks,\n resources: resourcesAccessor,\n } as DefinedResourceLayout<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n}\n\ntype DefineResourceLayoutForResourcesOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n ExtraResources extends ReadonlyArray<ResourceDefinition> = [],\n> = Omit<\n CreateViewMapOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >,\n 'resources'\n> & {\n /**\n * Additional resources to merge with those bound by\n * {@link defineResourceLayout.forResources}.\n */\n resources?: AssertUnreservedResources<ExtraResources>;\n};\n\ntype NonEmptyResourceDefinitions = readonly [\n ResourceDefinition,\n ...ResourceDefinition[],\n];\n\n/**\n * Factory returned by {@link DefineResourceLayout.forResources}.\n */\nexport type DefineResourceLayoutForResourcesFactory<\n BaseResources extends NonEmptyResourceDefinitions,\n> = <\n const ExtraResources extends ReadonlyArray<ResourceDefinition> = [],\n InProps extends InPropsDefinition<[...BaseResources, ...ExtraResources]> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n [...BaseResources, ...ExtraResources],\n InProps,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n>(\n options: DefineResourceLayoutForResourcesOptions<\n [...BaseResources, ...ExtraResources],\n InProps,\n Composables,\n IncludeProps,\n CustomProps,\n ExtraResources\n >,\n) => DefinedResourceLayout<\n [...BaseResources, ...ExtraResources],\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n>;\n\n/**\n * Binds one or more resources, then accepts the remaining\n * {@link defineResourceLayout} options (with optional extra `resources`).\n */\nexport type DefineResourceLayoutForResources = <\n const Resources extends NonEmptyResourceDefinitions,\n>(\n ...resources: Resources\n) => DefineResourceLayoutForResourcesFactory<Resources>;\n\n/**\n * Creates a resource layout definition for a set of resources.\n */\nexport type DefineResourceLayoutFn = {\n <\n const Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n Resources,\n InProps,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n >(\n options: CreateViewMapOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >,\n ): DefinedResourceLayout<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n};\n\n/**\n * Captures a `resources` array with its literal tuple type intact, so it can be\n * declared separately from the `defineResourceLayout` call without needing an\n * `as const` assertion.\n */\nexport type DefineResourcesFn = <\n const Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n ...resources: Resources\n) => Resources;\n\nfunction defineResources<\n const Resources extends ReadonlyArray<ResourceDefinition>,\n>(...resources: Resources): Resources {\n return resources;\n}\n\nexport type DefineResourceLayout = DefineResourceLayoutFn & {\n forResources: DefineResourceLayoutForResources;\n /**\n * Builds a strongly-typed `resources` array to pass to `defineResourceLayout`\n * (or `defineResourceLayout.forResources`) without an `as const` assertion.\n */\n defineResources: DefineResourcesFn;\n /**\n * Like {@link defineResourceLayout}, but also returns a `Shell` component.\n *\n * With plain `defineResourceLayout`, every page is wrapped in its own\n * `createResourceLayout` component, so navigating between resources unmounts\n * one page component and mounts another — the shared chrome the `render`\n * produces (a sidebar, a header, subscriptions, observers) is rebuilt every\n * time. `withLayout` splits that chrome into a `shell` that mounts once,\n * above the router outlet, and stays mounted across navigation; pages mount\n * and unmount inside it and report their resource up automatically.\n */\n withLayout: DefineResourceLayoutWithLayoutFn;\n};\n\nfunction defineResourceLayoutForResources<\n const Resources extends NonEmptyResourceDefinitions,\n>(\n ...baseResources: Resources\n): DefineResourceLayoutForResourcesFactory<Resources> {\n return ((options) => {\n const { resources: extraResources, ...rest } = options;\n const resources = extraResources\n ? [...baseResources, ...extraResources]\n : [...baseResources];\n\n return defineResourceLayoutImpl({\n ...rest,\n resources,\n } as never);\n }) as DefineResourceLayoutForResourcesFactory<Resources>;\n}\n\n/* -------------------------------------------------------------------------- */\n/* defineResourceLayout.withLayout — a once-mounted application shell */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Render context passed as the second argument to\n * {@link ShellLayoutDefinition.render}.\n *\n * The same shape as a per-resource `render` context (`composables`,\n * `resources`, `name`, `inProps`), with two differences that follow from the\n * shell being mounted once above the router outlet rather than per page:\n *\n * - `resource` / `resources.current` are `LayoutResourceKey | undefined`. The\n * shell outlives any single page, so the current resource is whatever the\n * mounted page last reported (or the `resource` prop, or nothing yet).\n * - `children` is the shell's content region. Render it where page content\n * belongs; it is already wrapped so mounted pages report their resource back.\n */\nexport type ShellRenderContext<\n Resources extends ReadonlyArray<ResourceDefinition>,\n ShellComposables extends ComposableComponents,\n> = {\n composables: LayoutRenderComposables<ShellComposables>;\n inProps: Record<string, unknown>;\n /**\n * The resource currently rendered in the outlet, or `undefined` when no\n * per-resource page is mounted and no `resource` prop was passed.\n */\n resource: LayoutResourceKey<Resources> | undefined;\n /**\n * Resources accessor for this definition. `current` follows `resource` above\n * and may be `undefined`.\n */\n resources: LayoutResourcesAccessor<Resources> & {\n readonly current: LayoutResourceKey<Resources> | undefined;\n };\n name: string;\n /**\n * The shell's content region — typically a router `<Outlet />`. Render it\n * where page content belongs.\n */\n children: ReactNode;\n};\n\n/**\n * The `shell` block of a {@link defineResourceLayout.withLayout} call: the\n * chrome that mounts once and stays mounted while pages navigate inside it.\n *\n * Mirrors {@link LayoutDefinition} (`props`, `composables`, `render`) so the\n * two blocks read the same, plus an optional `name`.\n */\nexport type ShellLayoutDefinition<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n ShellComposables extends ComposableComponents,\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n >,\n ShellCustomProps extends InPropsObject,\n> = {\n /**\n * Stable name for the shell component (React DevTools) and the base for any\n * resource-scoped composable names. Defaults to `'ResourceLayoutShell'`.\n */\n name?: string;\n props?: LayoutProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >;\n composables?: (\n create: CreateLayoutComposable<LayoutResourceKey<Resources>>,\n ) => ShellComposables;\n render: (\n props: LayoutRenderProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >,\n context: ShellRenderContext<Resources, ShellComposables>,\n ) => JSX.Element;\n};\n\n/**\n * Props accepted by the `Shell` component from\n * {@link defineResourceLayout.withLayout}.\n */\nexport type ResourceLayoutShellProps<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n ShellComposables extends ComposableComponents,\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n >,\n ShellCustomProps extends InPropsObject,\n> = Show<\n ResolveProps<ShellCustomProps> &\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, Options, ShellComposables>,\n ShellIncludeProps\n > & {\n /**\n * The resource the shell renders for. Overrides the value reported by the\n * page mounted in `children`. Always available — pass it from tests,\n * stories, or a route that renders non-library content but still wants\n * the shell.\n */\n resource?: LayoutResourceKey<Resources>;\n /** The shell's content region — typically a router `<Outlet />`. */\n children: ReactNode;\n }\n>;\n\n/**\n * The once-mounted application shell returned from\n * {@link defineResourceLayout.withLayout}. Wrap the router outlet with it.\n */\nexport type ResourceLayoutShellComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n ShellComposables extends ComposableComponents = {},\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n> = BaseComponent<\n string,\n ResourceLayoutShellProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >\n> & {\n (\n props: ResourceLayoutShellProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >,\n ): JSX.Element;\n};\n\n/**\n * Options for {@link defineResourceLayout.withLayout}: everything\n * {@link defineResourceLayout} accepts, plus a required `shell`, and with the\n * per-resource `layout.render` made optional.\n */\nexport type CreateResourceLayoutWithLayoutOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n ShellComposables extends ComposableComponents = {},\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n> = {\n /**\n * An array of valid resource names to support. Nested sub-resource slugs that\n * collide with config keys (`component`, `detail`, `new`, …) are reserved.\n */\n resources: AssertUnreservedResources<Resources>;\n /**\n * The options that are passed into the created resource layout. Shared by the\n * shell and the per-resource layout, so an `include` on either side can draw\n * from the same definitions.\n */\n options?: Options;\n /**\n * The once-mounted shell. The returned `Shell` wraps the router outlet and\n * stays mounted across resource navigation, so its composables (a persistent\n * sidebar, header, breadcrumb container, …) keep their state and DOM while\n * pages mount and unmount inside it.\n */\n shell: ShellLayoutDefinition<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >;\n /**\n * Per-resource content. Optional here: when the shell renders the whole\n * chrome, a page is just a slot — omit `render` and the generated component\n * renders its own `children` into the shell's outlet. Provide it to give a\n * resource its own header, actions, or per-page structure.\n */\n layout?: Omit<\n LayoutDefinition<Resources, Options, Composables, IncludeProps, CustomProps>,\n 'render'\n > & {\n render?: LayoutDefinition<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n >['render'];\n };\n};\n\n/**\n * {@link DefinedResourceLayout} plus the once-mounted `Shell`.\n */\nexport type DefinedResourceLayoutWithShell<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n ShellComposables extends ComposableComponents = {},\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n> = DefinedResourceLayout<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n> & {\n /**\n * The application shell. Mount it once, wrapping the router outlet:\n *\n * ```tsx\n * function AdminRoute() {\n * const resource = Route.useParams({ select: (p) => p.resource });\n * return (\n * <Shell resource={resource}>\n * <Outlet />\n * </Shell>\n * );\n * }\n * ```\n *\n * Passing `resource` is optional: a page created by `createResourceLayout`\n * reports its own resource to the shell automatically. Pass it for routes\n * that render non-library content, or in tests and stories.\n */\n Shell: ResourceLayoutShellComponent<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >;\n};\n\n/**\n * Signature of {@link defineResourceLayout.withLayout}.\n */\nexport type DefineResourceLayoutWithLayoutFn = <\n const Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n ShellComposables extends ComposableComponents = {},\n const ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n>(\n options: CreateResourceLayoutWithLayoutOptions<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >,\n) => DefinedResourceLayoutWithShell<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n>;\n\n/**\n * Loose runtime shape of a `shell` block, used by the impl below.\n */\ntype ShellLayoutRuntime = {\n name?: string;\n composables?: (create: unknown) => ComposableComponents;\n props?: {\n include?: Record<string, unknown>;\n custom?: Record<string, unknown>;\n };\n render: (\n props: Record<string, unknown>,\n context: Record<string, unknown>,\n ) => JSX.Element;\n};\n\n/**\n * Builds the `Shell` component. Kept beside {@link defineResourceLayoutImpl} so\n * it can reuse the same private prop-resolution helpers.\n *\n * Unlike a per-resource component, the shell re-reads the current resource on\n * every render (reported by the mounted page) so resource-scoped composable\n * *names* can update. Composable *component identities* are resolved once and\n * kept stable: React reconciles by element type, so recreating\n * `composables.Layout` each render would remount wrapWith targets, sidebar\n * state, and the outlet. Display names are synced onto those stable functions\n * when the resource changes.\n *\n * @param shellId - Identity of the owning `withLayout` definition. The shell\n * only accepts resource reports tagged with this id, so a page or pane from a\n * different definition rendered in the outlet cannot corrupt its state.\n */\nfunction createResourceLayoutShellComponent(\n resources: ReadonlyArray<ResourceDefinition>,\n inProps:\n | InPropsObject\n | ((opts: Record<string, unknown>) => InPropsObject),\n shell: ShellLayoutRuntime,\n shellId: symbol,\n) {\n const shellName = shell.name ?? 'ResourceLayoutShell';\n // `resources` is the wide `ResourceDefinition[]` here (not the const generic\n // that `defineResourceLayoutImpl` captures), so the normalize/enum types are\n // erased to keep TS from trying to instantiate them structurally. Only the\n // runtime key list matters — the shell validates against it, it does not\n // surface it in a public type.\n const resourceKeys = Object.keys(\n normalizeResources(resources as never) as Record<string, unknown>,\n );\n const resourcesEnum = createPrimitivePropBuilder('string').enum(\n resourceKeys as never,\n );\n\n // `options` may be a function of `{ resource, name }`. The shell has no single\n // resource, so — like the component path in `defineResourceLayoutImpl` — the\n // enum stands in for `resource` while resolving the definitions.\n const rawResolvedOptions =\n typeof inProps === 'function'\n ? inProps({\n resource: resourcesEnum,\n name: createProp.string().literal(shellName),\n })\n : inProps;\n const { resolvedInProps, splitInProps } = splitLayoutInProps(\n rawResolvedOptions as Record<string, unknown>,\n );\n\n const includeShellProps = shell.props?.include;\n const includeShellPropKeys = Object.keys(includeShellProps ?? {});\n const shellCustomDefinitions = {\n ...(shell.props?.custom ?? {}),\n } as Record<string, AnyBuiltPropDefinition>;\n\n function syncShellComposableDisplayNames(\n stable: ComposableComponents,\n resource: string,\n ) {\n if (!shell.composables) {\n return;\n }\n\n const named = resolveLayoutComposables(shell.composables as never, {\n resource,\n name: shellName,\n capitalize,\n } as never) as ComposableComponents;\n\n for (const [key, component] of Object.entries(named)) {\n const stableComponent = stable[key];\n\n if (\n typeof stableComponent === 'function' &&\n typeof component === 'function' &&\n 'displayName' in component\n ) {\n (stableComponent as { displayName?: string }).displayName = (\n component as { displayName?: string }\n ).displayName;\n }\n }\n }\n\n function Shell(props: Record<string, unknown>) {\n const { children: outlet, resource: resourceProp } = props as {\n children: ReactNode;\n resource?: string;\n };\n\n // Which resource is currently in the outlet. A per-resource page reports its\n // own resource here on mount (see the layout effect in `Component`);\n // `undefined` between pages or on a route with no per-resource layout. An\n // explicit `resource` prop always wins.\n const [reportedResource, setReportedResource] = useState<\n string | undefined\n >(undefined);\n const publishResource = useCallback<ResourceLayoutShellPublisher>(\n (resource, ownerId) => {\n // Ignore reports from components that belong to a different\n // `defineResourceLayout` definition — they share this context but their\n // resource is unrelated to this shell.\n if (ownerId !== shellId) {\n return;\n }\n\n setReportedResource(resource);\n },\n [],\n );\n const resource = resourceProp ?? reportedResource;\n\n // The outlet subtree must not re-render when `reportedResource` changes —\n // only the shell chrome should. Memoising the wrapped element lets React\n // bail out of reconciling the page while, say, the breadcrumb label updates.\n const shellChildren = useMemo(\n () => (\n <ResourceLayoutShellPublisherContext.Provider value={publishResource}>\n {outlet}\n </ResourceLayoutShellPublisherContext.Provider>\n ),\n [outlet, publishResource],\n );\n\n // Resolve composables once so `<composables.Layout>` keeps a stable element\n // type across Shell re-renders (including the layout-effect resource report).\n // Re-resolving every render would allocate new component functions and React\n // would remount the whole chrome tree. Names still track the live resource\n // via {@link syncShellComposableDisplayNames}.\n const composablesRef = useRef<ComposableComponents | undefined>(undefined);\n if (shell.composables) {\n const nameContextResource = resource ?? '';\n\n if (!composablesRef.current) {\n composablesRef.current = resolveLayoutComposables(\n shell.composables as never,\n {\n resource: nameContextResource,\n name: shellName,\n capitalize,\n } as never,\n ) as ComposableComponents;\n } else {\n syncShellComposableDisplayNames(\n composablesRef.current,\n nameContextResource,\n );\n }\n }\n const resolvedComposables = composablesRef.current;\n const validationContext = {\n layoutName: shellName,\n resource: resource ?? '',\n };\n\n const mergedResolvedInProps = { ...resolvedInProps } as Record<\n string,\n unknown\n >;\n for (const {\n props: presetPropDefinitions,\n } of collectComposablePresetEntries(resolvedComposables)) {\n Object.assign(mergedResolvedInProps, presetPropDefinitions);\n }\n\n // Included props: definition-time defaults from `options`, overridden by\n // anything passed to `<Shell>` (component passthrough). Computed before\n // preset validation so config-passthrough includes can reuse the defaults.\n const includedPropDefinitions = pick(\n mergedResolvedInProps,\n includeShellPropKeys,\n ) as Record<string, unknown>;\n const includedPropValues = {\n ...resolvePropDefinitionValues(includedPropDefinitions),\n } as Record<string, unknown>;\n\n for (const key of includeShellPropKeys) {\n const definition = mergedResolvedInProps[key];\n const behavior = includeShellProps?.[key];\n const callSiteValue = allowsComponentPassthrough(behavior)\n ? readLayoutOptionValue(key, definition, props)\n : undefined;\n // Config passthrough has no create-time call on Shell; still honour\n // literal / split defaults from `options` when present.\n const configValue = allowsConfigPassthrough(behavior)\n ? readLayoutOptionValue(key, definition, {\n ...includedPropValues,\n ...splitInProps,\n })\n : undefined;\n const splitValue = key in splitInProps ? splitInProps[key] : undefined;\n const value = callSiteValue ?? configValue ?? splitValue;\n\n if (value !== undefined) {\n includedPropValues[key] = value;\n }\n }\n\n // Preset props: Shell has no create-time call. Component-passthrough values\n // come from `<Shell>` props; config-passthrough values only from definition\n // defaults. Required config includes without a default are omitted from\n // validation — they are not typed on Shell and cannot be supplied.\n const composablePresetProps = Object.fromEntries(\n collectComposablePresetEntries(resolvedComposables).map(\n ({ key, props: presetPropDefinitions }) => {\n const entries = Object.entries(presetPropDefinitions);\n const validatedDefinitions = Object.fromEntries(\n entries.filter(([propKey]) => {\n const behavior = includeShellProps?.[propKey];\n\n if (behavior === undefined) {\n return true;\n }\n\n if (allowsComponentPassthrough(behavior)) {\n return true;\n }\n\n if (allowsConfigPassthrough(behavior)) {\n return includedPropValues[propKey] !== undefined;\n }\n\n return false;\n }),\n );\n const values = Object.fromEntries(\n entries.flatMap(([propKey]) => {\n if (propKey in props) {\n return [[propKey, props[propKey]]];\n }\n\n if (includedPropValues[propKey] !== undefined) {\n return [[propKey, includedPropValues[propKey]]];\n }\n\n return [];\n }),\n );\n\n return [\n key,\n validateProps(\n validatedDefinitions as Record<string, AnyBuiltPropDefinition>,\n values,\n validationContext,\n ),\n ];\n },\n ),\n );\n\n const validatedCustomProps = validateProps(\n shellCustomDefinitions,\n props,\n validationContext,\n );\n\n const requiredIncludedDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(([key]) => {\n const behavior = includeShellProps?.[key];\n\n if (!isIncludedPropRequired(behavior)) {\n return false;\n }\n\n // Component passthrough stays required on `<Shell>` (and is typed there).\n if (allowsComponentPassthrough(behavior)) {\n return true;\n }\n\n // Config passthrough: only require when a definition-time value exists.\n return includedPropValues[key] !== undefined;\n }),\n );\n const optionalIncludedDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(\n ([key]) =>\n !isIncludedPropRequired(includeShellProps?.[key]) &&\n includedPropValues[key] !== undefined,\n ),\n );\n const validatedIncludedProps = validateProps(\n {\n ...requiredIncludedDefinitions,\n ...optionalIncludedDefinitions,\n } as Record<string, AnyBuiltPropDefinition>,\n includedPropValues,\n validationContext,\n );\n const renderIncludedProps = Object.fromEntries(\n includeShellPropKeys.flatMap((key) =>\n key in validatedIncludedProps\n ? [\n [\n toLayoutRenderPropKey(key, mergedResolvedInProps[key]),\n validatedIncludedProps[\n key as keyof typeof validatedIncludedProps\n ],\n ],\n ]\n : [],\n ),\n );\n\n const renderProps = { ...validatedCustomProps, ...renderIncludedProps };\n const renderContext = {\n composables: resolvedComposables,\n resource,\n resources: createLayoutRenderResourcesAccessor(\n resources as ReadonlyArray<ResourceDefinition>,\n resource as never,\n ),\n name: shellName,\n inProps: splitInProps,\n children: shellChildren,\n };\n\n const rendered = shell.render(renderProps, renderContext);\n\n return resolvedComposables ? (\n <LayoutComposablePresetProvider value={composablePresetProps}>\n {rendered}\n </LayoutComposablePresetProvider>\n ) : (\n rendered\n );\n }\n\n return Object.assign(Shell, {\n displayName: shellName,\n props: undefined as never,\n });\n}\n\n/**\n * Implementation of {@link defineResourceLayout.withLayout}. Delegates the\n * config / links / `createResourceLayout` pieces to {@link defineResourceLayoutImpl}\n * and adds the {@link createResourceLayoutShellComponent | Shell}.\n */\nfunction defineResourceLayoutWithLayoutImpl(\n options: Record<string, unknown>,\n): Record<string, unknown> {\n const {\n shell,\n layout,\n resources,\n options: inProps,\n } = options as {\n shell: ShellLayoutRuntime;\n layout?: {\n composables?: unknown;\n props?: { include?: unknown; custom?: Record<string, unknown> };\n render?: (\n props: Record<string, unknown>,\n context: unknown,\n ) => JSX.Element;\n };\n resources: ReadonlyArray<ResourceDefinition>;\n options?:\n | InPropsObject\n | ((opts: Record<string, unknown>) => InPropsObject);\n };\n\n // The per-resource `render` is optional under `withLayout`. When omitted, the\n // page is a pure content slot: give it a `children` prop (so\n // `<UsersPage>{content}</UsersPage>` type-checks and works) and a render that\n // drops that content into the shell's outlet. An explicit `render` is passed\n // through untouched.\n const resolvedLayout = layout?.render\n ? layout\n : {\n ...layout,\n props: {\n ...layout?.props,\n custom: {\n children: createProp.component({ type: 'ReactNode' }).optional(),\n ...(layout?.props?.custom ?? {}),\n },\n },\n render: (pageProps: Record<string, unknown>) => (\n <>{(pageProps.children as ReactNode) ?? null}</>\n ),\n };\n\n // Ties the shell to the pages created by *its* `createResourceLayout`. Pages\n // from other definitions rendered in the outlet carry a different id (or\n // none) and are ignored by the shell's resource tracking.\n const shellId = Symbol('resourceLayoutShell');\n\n const base = defineResourceLayoutImpl({\n resources,\n options: inProps,\n layout: resolvedLayout,\n shellId,\n } as never) as Record<string, unknown>;\n\n const Shell = createResourceLayoutShellComponent(\n resources,\n (inProps ?? {}) as never,\n shell,\n shellId,\n );\n\n return { ...base, Shell };\n}\n\nexport const defineResourceLayout: DefineResourceLayout = Object.assign(\n defineResourceLayoutImpl as DefineResourceLayoutFn,\n {\n forResources: defineResourceLayoutForResources,\n defineResources,\n withLayout:\n defineResourceLayoutWithLayoutImpl as unknown as DefineResourceLayoutWithLayoutFn,\n },\n);\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"define-layout.mjs","names":[],"sources":["../../src/create-config/define-layout.tsx"],"sourcesContent":["import {\n type JSX,\n type ReactNode,\n useCallback,\n useLayoutEffect,\n useMemo,\n useRef,\n useState,\n} from 'react';\nimport {\n type ComposableComponents,\n type ComposableNameContext,\n type ComposableResourceLayout,\n type CreateLayoutComposable,\n collectComposablePresetEntries,\n LayoutComposablePresetProvider,\n MakeComposable,\n makeComposable,\n MakeComposableOptions,\n RequiredPresetLayoutProps,\n resolveLayoutComposables,\n} from '@jfdevelops/react-layout-composables';\nimport { LayoutConfigurationError } from '../errors';\nimport {\n type AnyBuiltPropDefinition,\n createPrimitivePropBuilder,\n createProp,\n type ResolveLayoutProps,\n type ResolveProps,\n resolvePropDefinitionValues,\n validateProps,\n} from '@jfdevelops/react-layout-validator';\nimport {\n IncludedProps,\n type IncludedPropBehavior,\n InferredInProps,\n InPropsDefinition,\n InPropsObject,\n LayoutRenderProps,\n MergedLayoutInProps,\n ResolvedIncludedComponentProps,\n ResolvedIncludedConfigProps,\n ResolvedIncludedProps,\n} from '../props';\nimport {\n createIsValidResourceFn,\n normalizeResources,\n toResourceEnum,\n type LayoutResourceKey,\n type ResourceDefinition,\n type ResourceDefinitionValue,\n} from '../resource';\nimport { BaseComponent, functionalUpdate, pick, Show, Updater } from '../utils';\nimport { capitalize } from '../utils/capitalize';\nimport { InvalidConfigError } from '../errors';\nimport { isResourceConfigComponentKey } from './component-keys';\nimport {\n type CreateResourceConfigFn,\n createResourceConfig,\n} from './get-component';\nimport type { AssertUnreservedResources } from './types';\nimport {\n createResourceLinksFn,\n type CreateResourceLinksFn,\n} from './create-resource-links';\nimport {\n createForResource,\n type CreateLayoutForResource,\n type CreateResourceLayoutOptions,\n type CreateResourceLayoutOptionsBase,\n} from './for-resource';\nimport {\n createForResources,\n type CreateResourceLayoutForResourcesFn,\n} from './for-resources';\nimport {\n type ResourceLayoutShellPublisher,\n ResourceLayoutShellPublisherContext,\n useResourceLayoutShellPublisher,\n} from './shell-context';\n\nexport type LayoutIncludeProps<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n> = IncludedProps<MergedLayoutInProps<Resources, Options, Composables>>;\n\nexport type LayoutProps<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = {\n /**\n * Props to include in the layout.\n */\n include?: LayoutIncludeProps<Resources, Options, Composables> & IncludeProps;\n /**\n * Custom props that the layout will receive.\n */\n custom?: CustomProps;\n};\n\ntype LayoutRenderContext<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Composables extends ComposableComponents,\n> = {\n composables: LayoutRenderComposables<Composables>;\n inProps: Record<string, unknown>;\n /**\n * @deprecated Use `resources.current` instead. `resource` will be removed in\n * the next major version.\n */\n resource: LayoutResourceKey<Resources>;\n /**\n * Accessor for the resources bound to this definition. Read `resources.current`\n * for the resource this instance renders, call `resources()` for the raw\n * value, use `resources.pick(...)` / `resources.omit(...)` to filter, or\n * `resources.isResource(...)` to narrow an unknown value.\n */\n resources: LayoutRenderResourcesAccessor<Resources>;\n name: string;\n};\n\n/**\n * A single {@link ResourceDefinition} kept by a `pick`, or `never` when it does\n * not match. Widened definitions (`string`, `{ value: string }`) are always\n * kept — the concrete keys are not known statically, so the runtime filter is\n * the source of truth.\n */\ntype PickResourceDefinition<\n Definition,\n Keys extends string,\n> = Definition extends ResourceDefinition\n ? string extends ResourceDefinitionValue<Definition>\n ? Definition\n : ResourceDefinitionValue<Definition> extends Keys\n ? Definition\n : never\n : never;\n\ntype PickResourceDefinitions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Keys extends LayoutResourceKey<Resources>,\n> = Array<PickResourceDefinition<Resources[number], Keys>>;\n\n/**\n * A single {@link ResourceDefinition} kept by an `omit`, or `never` when it is\n * one of the omitted keys. Widened definitions are always kept.\n */\ntype OmitResourceDefinition<\n Definition,\n Keys extends string,\n> = Definition extends ResourceDefinition\n ? string extends ResourceDefinitionValue<Definition>\n ? Definition\n : ResourceDefinitionValue<Definition> extends Keys\n ? never\n : Definition\n : never;\n\ntype OmitResourceDefinitions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Keys extends LayoutResourceKey<Resources>,\n> = Array<OmitResourceDefinition<Resources[number], Keys>>;\n\n/**\n * The result of `resources.pick(...)` / `resources.omit(...)`.\n *\n * - calling it returns the selected resource definitions.\n * - `.isResource(value)` narrows an unknown value to one of the selected keys.\n */\nexport type ResourceSelection<\n Definitions extends ReadonlyArray<ResourceDefinition>,\n> = {\n /** Returns the selected resource definitions. */\n (): Show<Definitions>;\n /**\n * Narrows an unknown value to one of the selected resource keys.\n *\n * @param value - The value to test.\n */\n isResource(value: unknown): value is LayoutResourceKey<Definitions>;\n};\n\n/**\n * Accessor for the resources bound to a `defineResourceLayout` definition.\n *\n * - `resources()` returns the raw resources.\n * - `resources.omit(key, ...rest)` selects every resource except the named ones.\n * - `resources.pick(key, ...rest)` selects only the named resources.\n * - `resources.isResource(value)` narrows an unknown value to a resource key.\n *\n * `pick` / `omit` return a {@link ResourceSelection} thunk: call it for the\n * definitions, or use its `isResource` guard.\n */\nexport type LayoutResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = {\n /**\n * Returns the raw `resources` value passed to `defineResourceLayout`,\n * exactly as declared.\n */\n (): Resources;\n /**\n * Narrows an unknown value to one of this definition's top-level resource\n * keys.\n *\n * @param value - The value to test.\n */\n isResource(value: unknown): value is LayoutResourceKey<Resources>;\n /**\n * Selects every declared resource except the named ones. Requires at least\n * one key.\n *\n * @param keys - Top-level resource names to exclude.\n */\n omit<\n Keys extends [\n LayoutResourceKey<Resources>,\n ...LayoutResourceKey<Resources>[],\n ],\n >(\n ...keys: Keys\n ): ResourceSelection<OmitResourceDefinitions<Resources, Keys[number]>>;\n /**\n * Selects only the named resources. Requires at least one key.\n *\n * @param keys - Top-level resource names to keep.\n */\n pick<\n Keys extends [\n LayoutResourceKey<Resources>,\n ...LayoutResourceKey<Resources>[],\n ],\n >(\n ...keys: Keys\n ): ResourceSelection<PickResourceDefinitions<Resources, Keys[number]>>;\n};\n\n/**\n * Render-scoped {@link LayoutResourcesAccessor}, extended with `current` — the\n * resource key the layout instance is rendering for.\n */\nexport type LayoutRenderResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n> = LayoutResourcesAccessor<Resources> & {\n /** The resource this layout instance is rendering for. */\n readonly current: LayoutResourceKey<Resources>;\n};\n\nfunction createResourceSelection(\n definitions: ReadonlyArray<ResourceDefinition>,\n): ResourceSelection<ReadonlyArray<ResourceDefinition>> {\n const selection = (() => definitions) as ResourceSelection<\n ReadonlyArray<ResourceDefinition>\n >;\n\n selection.isResource = createIsValidResourceFn(definitions);\n\n return selection;\n}\n\nfunction createLayoutResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(resources: Resources): LayoutResourcesAccessor<Resources> {\n const accessor = (() => resources) as LayoutResourcesAccessor<Resources>;\n\n accessor.isResource = createIsValidResourceFn(resources);\n accessor.omit = ((...keys: string[]) =>\n createResourceSelection(\n resources.filter(\n (resource) => !keys.includes(readResourceSlug(resource)),\n ),\n )) as LayoutResourcesAccessor<Resources>['omit'];\n accessor.pick = ((...keys: string[]) =>\n createResourceSelection(\n resources.filter((resource) =>\n keys.includes(readResourceSlug(resource)),\n ),\n )) as LayoutResourcesAccessor<Resources>['pick'];\n\n return accessor;\n}\n\nfunction createLayoutRenderResourcesAccessor<\n Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n resources: Resources,\n current: LayoutResourceKey<Resources>,\n): LayoutRenderResourcesAccessor<Resources> {\n return Object.assign(createLayoutResourcesAccessor(resources), { current });\n}\ntype LayoutRenderComposables<Composables extends ComposableComponents> = [\n keyof Composables,\n] extends [never]\n ? undefined\n : Composables;\n\ntype SplitLayoutInPropDefinition<\n Props extends InPropsObject = {},\n Content = unknown,\n> = {\n props?: Props;\n render: ((props: ResolveProps<Props>) => Content) | Content;\n};\n\nfunction isBuiltPropDefinition(\n value: unknown,\n): value is AnyBuiltPropDefinition {\n return typeof value === 'function' && value !== null && 'visibility' in value;\n}\n\nfunction isSplitLayoutInPropDefinition(\n value: unknown,\n): value is SplitLayoutInPropDefinition {\n return (\n value !== null &&\n typeof value === 'object' &&\n 'render' in value &&\n (value as { render?: unknown }).render !== undefined\n );\n}\n\nfunction isJSXElementDefinition(\n definition: unknown,\n): definition is AnyBuiltPropDefinition & { type: 'JSX.Element' } {\n return (\n isBuiltPropDefinition(definition) &&\n 'type' in definition &&\n definition.type === 'JSX.Element'\n );\n}\n\nfunction toLayoutRenderPropKey(includeKey: string, definition: unknown) {\n return isJSXElementDefinition(definition)\n ? capitalize(includeKey)\n : includeKey;\n}\n\nfunction readLayoutOptionValue(\n includeKey: string,\n definition: unknown,\n sources: Record<string, unknown>,\n) {\n const layoutOptionKeys = isJSXElementDefinition(definition)\n ? [capitalize(includeKey), includeKey]\n : [includeKey, capitalize(includeKey)];\n\n for (const key of layoutOptionKeys) {\n if (key in sources) {\n return sources[key];\n }\n }\n\n return undefined;\n}\n\nfunction getIncludedPropBehavior(value: unknown): IncludedPropBehavior | null {\n if (\n value !== null &&\n typeof value === 'object' &&\n 'visibility' in value &&\n 'passthrough' in value\n ) {\n return value as IncludedPropBehavior;\n }\n\n return null;\n}\n\nfunction isIncludedPropRequired(value: unknown) {\n return (\n value === true ||\n value === 'required' ||\n getIncludedPropBehavior(value)?.visibility === 'required'\n );\n}\n\nfunction allowsConfigPassthrough(value: unknown) {\n const behavior = getIncludedPropBehavior(value);\n\n if (!behavior) {\n return true;\n }\n\n if (behavior.passthrough === 'config') {\n return true;\n }\n\n // optional + component passthrough still accepts create-time defaults\n return (\n behavior.passthrough === 'component' && behavior.visibility === 'optional'\n );\n}\n\nfunction allowsComponentPassthrough(value: unknown) {\n const behavior = getIncludedPropBehavior(value);\n\n return behavior ? behavior.passthrough === 'component' : value === 'optional';\n}\n\nfunction splitLayoutInProps(inProps: Record<string, unknown>) {\n const resolvedInProps: Record<string, AnyBuiltPropDefinition> = {};\n const splitInProps: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(inProps)) {\n if (isBuiltPropDefinition(value)) {\n resolvedInProps[key] = value;\n continue;\n }\n\n if (isSplitLayoutInPropDefinition(value)) {\n splitInProps[key] = value.render;\n\n if (value.props && typeof value.props === 'object') {\n Object.assign(resolvedInProps, value.props);\n }\n }\n }\n\n return {\n resolvedInProps,\n splitInProps,\n };\n}\n\nfunction resolveLayoutOptionDefaults(\n defaults: Record<string, unknown>,\n options: Record<string, unknown>,\n) {\n const resolved = { ...options };\n\n for (const [key, defaultValue] of Object.entries(defaults)) {\n if (key in options) {\n if (typeof defaultValue === 'function') {\n resolved[key] = options[key];\n } else {\n resolved[key] = functionalUpdate(\n defaultValue,\n options[key] as Updater<unknown>,\n );\n }\n }\n }\n\n return resolved;\n}\n\n/**\n * The `layout` block of a {@link defineResourceLayout} call: the props, the\n * composable map, and the render for a per-resource page component.\n *\n * Extracted so {@link defineResourceLayout.withLayout} can reuse the exact same\n * shape while making `render` optional (see {@link ShellLayoutDefinition}).\n */\ntype LayoutDefinition<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables>,\n CustomProps extends InPropsObject,\n> = {\n /**\n * The props to pass to the layout.\n */\n props?: LayoutProps<Resources, Options, Composables, IncludeProps, CustomProps>;\n /**\n * Components used to compose the layout. Invoked per layout instance with\n * a scoped `create` that resolves composable `name` callbacks using the\n * layout's `resource` and `name`.\n */\n composables?: (\n create: CreateLayoutComposable<LayoutResourceKey<Resources>>,\n ) => Composables;\n /**\n * The render function for the layout.\n */\n render: (\n props: LayoutRenderProps<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n >,\n context: LayoutRenderContext<Resources, Composables>,\n ) => JSX.Element;\n};\n\ntype CreateViewMapOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = {\n /**\n * An array of valid resource names to support. Nested sub-resource slugs that\n * collide with config keys (`component`, `detail`, `new`, …) are reserved.\n */\n resources: AssertUnreservedResources<Resources>;\n /**\n * The options that are passed into the created resource layout.\n */\n options?: Options;\n layout: LayoutDefinition<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n >;\n};\n\ntype ResourceLayoutComposition<\n Name extends string,\n Composables extends ComposableComponents,\n> = [keyof Composables] extends [never]\n ? {}\n : {\n makeComposable: MakeComposable<Composables, Name>;\n };\nexport type ResourceLayoutComponent<\n Name extends string,\n Props extends InPropsObject = {},\n Composables extends ComposableComponents = {},\n Resource extends string = string,\n IncludedCallProps extends object = {},\n> = ResourceLayoutComposition<Name, Composables> &\n BaseComponent<Name, Show<ResolveProps<Props> & IncludedCallProps>> & {\n (props: Show<ResolveProps<Props> & IncludedCallProps>): JSX.Element;\n /**\n * A type-only property containing the resource associated with this\n * component. This property is `undefined` at runtime.\n */\n readonly resource: Resource;\n };\n\nexport type LayoutPropsForResource<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n> = [keyof IncludeProps] extends [never]\n ? ResolveLayoutProps<InferredInProps<Resources, InProps>> &\n RequiredPresetLayoutProps<Composables>\n : ResolvedIncludedConfigProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >;\n\ntype CreateResourceLayoutFnImpl<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = <\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n>(\n options: CreateResourceLayoutOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n Name,\n Resource,\n Props\n >,\n) => ResourceLayoutComponent<\n Name,\n CustomProps,\n Composables,\n Resource,\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >\n>;\n\nexport type CreateResourceLayoutMakeComposableOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n> = CreateResourceLayoutOptionsBase<Resources, Name, Resource, Props> &\n Partial<\n LayoutPropsForResource<Resources, InProps, Composables, IncludeProps>\n >;\n\ntype CreateResourceLayoutMakeComposableFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables>,\n CustomProps extends InPropsObject,\n> = <\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n>(\n options: CreateResourceLayoutMakeComposableOptions<\n Resources,\n InProps,\n Composables,\n Name,\n Resource,\n Props,\n IncludeProps\n >,\n) => ComposableResourceLayout<Composables, Name, any, any, any>;\n\ntype CreateResourceLayoutFnBase<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = CreateResourceLayoutFnImpl<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n> & {\n /**\n * A function to create a resource layout for a specific resource.\n */\n forResource: CreateLayoutForResource<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n /**\n * Creates resource layout factories for multiple defined resources.\n */\n forResources: CreateResourceLayoutForResourcesFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n};\n\ntype CreateResourceLayoutMakeComposableMember<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents,\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables>,\n CustomProps extends InPropsObject,\n> = [keyof Composables] extends [never]\n ? {}\n : {\n makeComposable: CreateResourceLayoutMakeComposableFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n };\n\nexport type CreateResourceLayoutFn<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = CreateResourceLayoutFnBase<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n> &\n CreateResourceLayoutMakeComposableMember<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n\ntype DefinedResourceLayout<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n> = {\n createResourceConfig: CreateResourceConfigFn<Resources>;\n createResourceLayout: CreateResourceLayoutFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n createResourceLinks: CreateResourceLinksFn<Resources>;\n /**\n * Accessor for the resources bound to this definition. Call `resources()` for\n * the raw value, or `resources.pick(...)` / `resources.omit(...)` to filter.\n */\n resources: LayoutResourcesAccessor<Resources>;\n};\n\nfunction readResourceSlug(resource: ResourceDefinition) {\n return typeof resource === 'string' ? resource : resource.value;\n}\n\nfunction assertUnreservedResourceSlugs(\n resources: ReadonlyArray<ResourceDefinition>,\n owner?: string,\n) {\n for (const resource of resources) {\n const slug = readResourceSlug(resource);\n\n if (owner !== undefined && isResourceConfigComponentKey(slug)) {\n throw new InvalidConfigError({\n reason: `Sub-resource \"${slug}\" under \"${owner}\" collides with a reserved config key`,\n });\n }\n\n if (typeof resource !== 'string') {\n assertUnreservedResourceSlugs(resource.subResources, slug);\n }\n }\n}\n\nfunction defineResourceLayoutImpl<\n const Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n Resources,\n InProps,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n>(\n options: CreateViewMapOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >,\n): DefinedResourceLayout<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n> {\n const { options: inProps = {} as InProps, resources, layout } = options;\n // Internal, set only by `defineResourceLayout.withLayout`: the identity of the\n // owning definition, forwarded when a page reports its resource so the shell\n // can tell its own pages apart from ones belonging to another definition.\n const shellId = (options as { shellId?: symbol }).shellId;\n\n assertUnreservedResourceSlugs(resources);\n\n const resourcesAccessor = createLayoutResourcesAccessor(resources);\n const normalizedResources = normalizeResources(resources);\n const resourcesEnum = createPrimitivePropBuilder('string').enum(\n toResourceEnum(normalizedResources),\n );\n const definedResourceLayout = (<\n Name extends string,\n Resource extends LayoutResourceKey<Resources>,\n Props extends InPropsObject = {},\n >(\n layoutOptions: CreateResourceLayoutOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n Name,\n Resource,\n Props\n >,\n ) => {\n const {\n name,\n props: instancePropDefinitions,\n ...layoutOptionProps\n } = layoutOptions;\n const createComposableLayout =\n makeComposable<\n LayoutRenderProps<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >\n >();\n const nameProp = createProp.string().literal(name);\n const rawResolvedOptions =\n typeof inProps === 'function'\n ? inProps({\n resource: resourcesEnum,\n name: nameProp,\n })\n : inProps;\n const { resolvedInProps, splitInProps } = splitLayoutInProps({\n ...(rawResolvedOptions as Record<string, unknown>),\n ...(instancePropDefinitions as Record<string, unknown> | undefined),\n ...layoutOptionProps,\n });\n const { composables, render, props: layoutProps } = layout;\n const customLayoutProps = layoutProps?.custom;\n const includeLayoutProps = layoutProps?.include;\n const layoutOptionValues = layoutOptionProps as Record<string, unknown>;\n const resolvedLayoutProps = {\n ...customLayoutProps,\n };\n const layoutContext: ComposableNameContext<\n LayoutResourceKey<Resources>,\n typeof name\n > = {\n resource: layoutOptions.resource,\n name,\n capitalize,\n };\n const validationContext = {\n layoutName: name,\n resource: layoutContext.resource,\n };\n const resolvedComposables = composables\n ? resolveLayoutComposables(composables, layoutContext)\n : undefined;\n const mergedResolvedInProps = { ...resolvedInProps };\n\n for (const {\n props: presetPropDefinitions,\n } of collectComposablePresetEntries(resolvedComposables)) {\n Object.assign(mergedResolvedInProps, presetPropDefinitions);\n }\n\n const composablePresetProps = Object.fromEntries(\n collectComposablePresetEntries(resolvedComposables).map(\n ({ key, props: presetPropDefinitions }) => {\n const presetPropEntries = Object.entries(presetPropDefinitions);\n const validatedDefinitions = Object.fromEntries(\n presetPropEntries.filter(([propKey]) => {\n const includeBehavior = includeLayoutProps?.[propKey];\n\n return (\n includeBehavior === undefined ||\n (allowsConfigPassthrough(includeBehavior) &&\n (isIncludedPropRequired(includeBehavior) ||\n layoutOptionValues[propKey] !== undefined))\n );\n }),\n );\n const presetPropValues = Object.fromEntries(\n presetPropEntries.flatMap(([propKey]) =>\n propKey in layoutOptionValues\n ? [[propKey, layoutOptionValues[propKey]]]\n : [],\n ),\n );\n\n return [\n key,\n validateProps(\n validatedDefinitions as Record<string, AnyBuiltPropDefinition>,\n presetPropValues,\n validationContext,\n ),\n ];\n },\n ),\n );\n const mergedRenderContext = {\n composables: resolvedComposables as LayoutRenderComposables<Composables>,\n resource: layoutContext.resource,\n resources: createLayoutRenderResourcesAccessor(\n resources as Resources,\n layoutContext.resource,\n ),\n name: layoutContext.name,\n inProps: splitInProps,\n } as LayoutRenderContext<Resources, Composables>;\n\n function Component(\n props: Show<\n ResolveProps<CustomProps> &\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >\n >,\n ) {\n const publishResource = useResourceLayoutShellPublisher();\n\n // Report the resource this page renders for so an ancestor `Shell` (from\n // `defineResourceLayout.withLayout`) can resolve `resources.current` for\n // its own render without the consumer threading a route param down to it.\n // A layout effect, not a passive one, so the shell reflects the new\n // resource in the same commit the page mounts — a passive effect would\n // leave one painted frame of stale shell chrome mid-navigation. Degrades\n // to a no-op when rendered without a `Shell` (context defaults to null).\n useLayoutEffect(() => {\n publishResource?.(layoutContext.resource, shellId);\n\n return () => publishResource?.(undefined, shellId);\n }, [publishResource, layoutContext.resource]);\n\n const validatedProps = validateProps(resolvedLayoutProps, props, {\n ...validationContext,\n });\n const includedPropKeys = Object.keys(includeLayoutProps ?? {});\n const includedPropDefinitions = pick(\n mergedResolvedInProps,\n includedPropKeys,\n ) as Record<string, unknown>;\n const includedPropValues = {\n ...resolvePropDefinitionValues(includedPropDefinitions),\n } as Record<string, unknown>;\n\n for (const key of includedPropKeys) {\n const definition = mergedResolvedInProps[key];\n const includeBehavior = includeLayoutProps?.[key];\n const callSiteValue = allowsComponentPassthrough(includeBehavior)\n ? readLayoutOptionValue(\n key,\n definition,\n props as Record<string, unknown>,\n )\n : undefined;\n const layoutOptionValue = allowsConfigPassthrough(includeBehavior)\n ? readLayoutOptionValue(key, definition, layoutOptionValues)\n : undefined;\n const splitValue = key in splitInProps ? splitInProps[key] : undefined;\n const value = callSiteValue ?? layoutOptionValue ?? splitValue;\n\n if (value !== undefined) {\n includedPropValues[key] = value;\n }\n }\n\n const requiredIncludedPropDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(([key]) =>\n isIncludedPropRequired(includeLayoutProps?.[key]),\n ),\n );\n const optionalIncludedPropDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(\n ([key]) =>\n !isIncludedPropRequired(includeLayoutProps?.[key]) &&\n includedPropValues[key] !== undefined,\n ),\n );\n const validatedIncludedProps = validateProps(\n {\n ...requiredIncludedPropDefinitions,\n ...optionalIncludedPropDefinitions,\n } as Record<string, AnyBuiltPropDefinition>,\n includedPropValues,\n validationContext,\n );\n const layoutRenderIncludedProps = Object.fromEntries(\n includedPropKeys.flatMap((key) => {\n if (!(key in validatedIncludedProps)) {\n return [];\n }\n\n return [\n [\n toLayoutRenderPropKey(key, mergedResolvedInProps[key]),\n validatedIncludedProps[\n key as keyof typeof validatedIncludedProps\n ],\n ],\n ];\n }),\n );\n const layoutRenderProps = {\n ...validatedProps,\n ...layoutRenderIncludedProps,\n } as unknown as LayoutRenderProps<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n\n return (\n <LayoutComposablePresetProvider value={composablePresetProps}>\n {render(layoutRenderProps, mergedRenderContext)}\n </LayoutComposablePresetProvider>\n );\n }\n\n function createComposition<\n LayoutName extends string,\n const Defined extends MakeComposableOptions<Composables, LayoutName>,\n >(compositionOptions: Defined) {\n if (!compositionOptions.components) {\n return {} as ResourceLayoutComposition<LayoutName, Composables>;\n }\n\n return {\n makeComposable: createComposableLayout(\n compositionOptions,\n ) as MakeComposable<Composables, LayoutName>,\n };\n }\n\n return Object.assign(Component, {\n displayName: name,\n props: undefined as unknown as Show<\n ResolveProps<CustomProps> &\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, InProps, Composables>,\n IncludeProps\n >\n >,\n resource: undefined as unknown as Resource,\n ...createComposition({\n components: resolvedComposables as Composables | undefined,\n name,\n }),\n });\n }) as CreateResourceLayoutFnImpl<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n const createTopLevelMakeComposable = () => {\n return (options: Record<string, unknown>) => {\n const layout = definedResourceLayout(options as never);\n\n if (\n !('makeComposable' in layout) ||\n typeof layout.makeComposable !== 'function'\n ) {\n throw new LayoutConfigurationError(\n 'makeComposable requires composables to be defined in the layout',\n );\n }\n\n return layout.makeComposable();\n };\n };\n\n function getComponentPropDefinitions(resource: LayoutResourceKey<Resources>) {\n const componentName = 'ScopedResourceComponent';\n const rawResolvedOptions =\n typeof inProps === 'function'\n ? inProps({\n resource: resourcesEnum,\n name: createProp.string().literal(componentName),\n })\n : inProps;\n const { resolvedInProps } = splitLayoutInProps(\n rawResolvedOptions as Record<string, unknown>,\n );\n const resolvedComposables = layout.composables\n ? resolveLayoutComposables(layout.composables, {\n resource,\n name: componentName,\n capitalize,\n })\n : undefined;\n\n for (const {\n props: presetPropDefinitions,\n } of collectComposablePresetEntries(resolvedComposables)) {\n Object.assign(resolvedInProps, presetPropDefinitions);\n }\n\n return {\n ...resolvedInProps,\n ...layout.props?.custom,\n };\n }\n\n const { createLayoutForResourceBuilder, forResource } = createForResource<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >({\n createResourceLayout: definedResourceLayout as never,\n resolveLayoutOptionDefaults,\n });\n const forResources = createForResources<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >({\n createLayoutForResource: createLayoutForResourceBuilder,\n ...(layout.composables\n ? { createMakeComposableLayout: createTopLevelMakeComposable }\n : {}),\n createResourceLayout: definedResourceLayout as never,\n getComponentPropDefinitions,\n });\n\n const createResourceLayoutExtras: {\n forResource: CreateLayoutForResource<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n forResources: CreateResourceLayoutForResourcesFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n makeComposable?: ReturnType<typeof createTopLevelMakeComposable>;\n } = {\n forResource,\n forResources,\n };\n\n if (layout.composables) {\n createResourceLayoutExtras.makeComposable = createTopLevelMakeComposable();\n }\n\n const createResourceLayout = Object.assign(\n definedResourceLayout,\n createResourceLayoutExtras,\n ) as CreateResourceLayoutFn<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n\n const createResourceLinks = createResourceLinksFn(resources);\n\n return {\n createResourceConfig,\n createResourceLayout,\n createResourceLinks,\n resources: resourcesAccessor,\n } as DefinedResourceLayout<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n}\n\ntype DefineResourceLayoutForResourcesOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, InProps, Composables> = {},\n CustomProps extends InPropsObject = {},\n ExtraResources extends ReadonlyArray<ResourceDefinition> = [],\n> = Omit<\n CreateViewMapOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >,\n 'resources'\n> & {\n /**\n * Additional resources to merge with those bound by\n * {@link defineResourceLayout.forResources}.\n */\n resources?: AssertUnreservedResources<ExtraResources>;\n};\n\ntype NonEmptyResourceDefinitions = readonly [\n ResourceDefinition,\n ...ResourceDefinition[],\n];\n\n/**\n * Factory returned by {@link DefineResourceLayout.forResources}.\n */\nexport type DefineResourceLayoutForResourcesFactory<\n BaseResources extends NonEmptyResourceDefinitions,\n> = <\n const ExtraResources extends ReadonlyArray<ResourceDefinition> = [],\n InProps extends InPropsDefinition<[...BaseResources, ...ExtraResources]> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n [...BaseResources, ...ExtraResources],\n InProps,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n>(\n options: DefineResourceLayoutForResourcesOptions<\n [...BaseResources, ...ExtraResources],\n InProps,\n Composables,\n IncludeProps,\n CustomProps,\n ExtraResources\n >,\n) => DefinedResourceLayout<\n [...BaseResources, ...ExtraResources],\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n>;\n\n/**\n * Binds one or more resources, then accepts the remaining\n * {@link defineResourceLayout} options (with optional extra `resources`).\n */\nexport type DefineResourceLayoutForResources = <\n const Resources extends NonEmptyResourceDefinitions,\n>(\n ...resources: Resources\n) => DefineResourceLayoutForResourcesFactory<Resources>;\n\n/**\n * Creates a resource layout definition for a set of resources.\n */\nexport type DefineResourceLayoutFn = {\n <\n const Resources extends ReadonlyArray<ResourceDefinition>,\n InProps extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n Resources,\n InProps,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n >(\n options: CreateViewMapOptions<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >,\n ): DefinedResourceLayout<\n Resources,\n InProps,\n Composables,\n IncludeProps,\n CustomProps\n >;\n};\n\n/**\n * Captures a `resources` array with its literal tuple type intact, so it can be\n * declared separately from the `defineResourceLayout` call without needing an\n * `as const` assertion.\n */\nexport type DefineResourcesFn = <\n const Resources extends ReadonlyArray<ResourceDefinition>,\n>(\n ...resources: Resources\n) => Resources;\n\nfunction defineResources<\n const Resources extends ReadonlyArray<ResourceDefinition>,\n>(...resources: Resources): Resources {\n return resources;\n}\n\nexport type DefineResourceLayout = DefineResourceLayoutFn & {\n forResources: DefineResourceLayoutForResources;\n /**\n * Builds a strongly-typed `resources` array to pass to `defineResourceLayout`\n * (or `defineResourceLayout.forResources`) without an `as const` assertion.\n */\n defineResources: DefineResourcesFn;\n /**\n * Like {@link defineResourceLayout}, but also returns a `Shell` component.\n *\n * With plain `defineResourceLayout`, every page is wrapped in its own\n * `createResourceLayout` component, so navigating between resources unmounts\n * one page component and mounts another — the shared chrome the `render`\n * produces (a sidebar, a header, subscriptions, observers) is rebuilt every\n * time. `withLayout` splits that chrome into a `shell` that mounts once,\n * above the router outlet, and stays mounted across navigation; pages mount\n * and unmount inside it and report their resource up automatically.\n */\n withLayout: DefineResourceLayoutWithLayoutFn;\n};\n\nfunction defineResourceLayoutForResources<\n const Resources extends NonEmptyResourceDefinitions,\n>(\n ...baseResources: Resources\n): DefineResourceLayoutForResourcesFactory<Resources> {\n return ((options) => {\n const { resources: extraResources, ...rest } = options;\n const resources = extraResources\n ? [...baseResources, ...extraResources]\n : [...baseResources];\n\n return defineResourceLayoutImpl({\n ...rest,\n resources,\n } as never);\n }) as DefineResourceLayoutForResourcesFactory<Resources>;\n}\n\n/* -------------------------------------------------------------------------- */\n/* defineResourceLayout.withLayout — a once-mounted application shell */\n/* -------------------------------------------------------------------------- */\n\n/**\n * Render context passed as the second argument to\n * {@link ShellLayoutDefinition.render}.\n *\n * The same shape as a per-resource `render` context (`composables`,\n * `resources`, `name`, `inProps`), with two differences that follow from the\n * shell being mounted once above the router outlet rather than per page:\n *\n * - `resource` / `resources.current` are `LayoutResourceKey | undefined`. The\n * shell outlives any single page, so the current resource is whatever the\n * mounted page last reported (or the `resource` prop, or nothing yet).\n * - `children` is the shell's content region. Render it where page content\n * belongs; it is already wrapped so mounted pages report their resource back.\n */\nexport type ShellRenderContext<\n Resources extends ReadonlyArray<ResourceDefinition>,\n ShellComposables extends ComposableComponents,\n> = {\n composables: LayoutRenderComposables<ShellComposables>;\n inProps: Record<string, unknown>;\n /**\n * The resource currently rendered in the outlet, or `undefined` when no\n * per-resource page is mounted and no `resource` prop was passed.\n */\n resource: LayoutResourceKey<Resources> | undefined;\n /**\n * Resources accessor for this definition. `current` follows `resource` above\n * and may be `undefined`.\n */\n resources: LayoutResourcesAccessor<Resources> & {\n readonly current: LayoutResourceKey<Resources> | undefined;\n };\n name: string;\n /**\n * The shell's content region — typically a router `<Outlet />`. Render it\n * where page content belongs.\n */\n children: ReactNode;\n};\n\n/**\n * The `shell` block of a {@link defineResourceLayout.withLayout} call: the\n * chrome that mounts once and stays mounted while pages navigate inside it.\n *\n * Mirrors {@link LayoutDefinition} (`props`, `composables`, `render`) so the\n * two blocks read the same, plus an optional `name`.\n */\nexport type ShellLayoutDefinition<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n ShellComposables extends ComposableComponents,\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n >,\n ShellCustomProps extends InPropsObject,\n> = {\n /**\n * Stable name for the shell component (React DevTools) and the base for any\n * resource-scoped composable names. Defaults to `'ResourceLayoutShell'`.\n */\n name?: string;\n props?: LayoutProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >;\n composables?: (\n create: CreateLayoutComposable<LayoutResourceKey<Resources>>,\n ) => ShellComposables;\n render: (\n props: LayoutRenderProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >,\n context: ShellRenderContext<Resources, ShellComposables>,\n ) => JSX.Element;\n};\n\n/**\n * Props accepted by the `Shell` component from\n * {@link defineResourceLayout.withLayout}.\n */\nexport type ResourceLayoutShellProps<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n ShellComposables extends ComposableComponents,\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n >,\n ShellCustomProps extends InPropsObject,\n> = Show<\n ResolveProps<ShellCustomProps> &\n ResolvedIncludedComponentProps<\n MergedLayoutInProps<Resources, Options, ShellComposables>,\n ShellIncludeProps\n > & {\n /**\n * The resource the shell renders for. Overrides the value reported by the\n * page mounted in `children`. Always available — pass it from tests,\n * stories, or a route that renders non-library content but still wants\n * the shell.\n */\n resource?: LayoutResourceKey<Resources>;\n /** The shell's content region — typically a router `<Outlet />`. */\n children: ReactNode;\n }\n>;\n\n/**\n * The once-mounted application shell returned from\n * {@link defineResourceLayout.withLayout}. Wrap the router outlet with it.\n */\nexport type ResourceLayoutShellComponent<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n ShellComposables extends ComposableComponents = {},\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n> = BaseComponent<\n string,\n ResourceLayoutShellProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >\n> & {\n (\n props: ResourceLayoutShellProps<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >,\n ): JSX.Element;\n};\n\n/**\n * Options for {@link defineResourceLayout.withLayout}: everything\n * {@link defineResourceLayout} accepts, plus a required `shell`, and with the\n * per-resource `layout.render` made optional.\n */\nexport type CreateResourceLayoutWithLayoutOptions<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n ShellComposables extends ComposableComponents = {},\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n> = {\n /**\n * An array of valid resource names to support. Nested sub-resource slugs that\n * collide with config keys (`component`, `detail`, `new`, …) are reserved.\n */\n resources: AssertUnreservedResources<Resources>;\n /**\n * The options that are passed into the created resource layout. Shared by the\n * shell and the per-resource layout, so an `include` on either side can draw\n * from the same definitions.\n */\n options?: Options;\n /**\n * The once-mounted shell. The returned `Shell` wraps the router outlet and\n * stays mounted across resource navigation, so its composables (a persistent\n * sidebar, header, breadcrumb container, …) keep their state and DOM while\n * pages mount and unmount inside it.\n */\n shell: ShellLayoutDefinition<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >;\n /**\n * Per-resource content. Optional here: when the shell renders the whole\n * chrome, a page is just a slot — omit `render` and the generated component\n * renders its own `children` into the shell's outlet. Provide it to give a\n * resource its own header, actions, or per-page structure.\n */\n layout?: Omit<\n LayoutDefinition<Resources, Options, Composables, IncludeProps, CustomProps>,\n 'render'\n > & {\n render?: LayoutDefinition<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n >['render'];\n };\n};\n\n/**\n * {@link DefinedResourceLayout} plus the once-mounted `Shell`.\n */\nexport type DefinedResourceLayoutWithShell<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources>,\n Composables extends ComposableComponents = {},\n IncludeProps extends LayoutIncludeProps<Resources, Options, Composables> = {},\n CustomProps extends InPropsObject = {},\n ShellComposables extends ComposableComponents = {},\n ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n> = DefinedResourceLayout<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps\n> & {\n /**\n * The application shell. Mount it once, wrapping the router outlet:\n *\n * ```tsx\n * function AdminRoute() {\n * const resource = Route.useParams({ select: (p) => p.resource });\n * return (\n * <Shell resource={resource}>\n * <Outlet />\n * </Shell>\n * );\n * }\n * ```\n *\n * Passing `resource` is optional: a page created by `createResourceLayout`\n * reports its own resource to the shell automatically. Pass it for routes\n * that render non-library content, or in tests and stories.\n */\n Shell: ResourceLayoutShellComponent<\n Resources,\n Options,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >;\n};\n\n/**\n * Signature of {@link defineResourceLayout.withLayout}.\n */\nexport type DefineResourceLayoutWithLayoutFn = <\n const Resources extends ReadonlyArray<ResourceDefinition>,\n Options extends InPropsDefinition<Resources> = {},\n Composables extends ComposableComponents = {},\n const IncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n Composables\n > = {},\n CustomProps extends InPropsObject = {},\n ShellComposables extends ComposableComponents = {},\n const ShellIncludeProps extends LayoutIncludeProps<\n Resources,\n Options,\n ShellComposables\n > = {},\n ShellCustomProps extends InPropsObject = {},\n>(\n options: CreateResourceLayoutWithLayoutOptions<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n >,\n) => DefinedResourceLayoutWithShell<\n Resources,\n Options,\n Composables,\n IncludeProps,\n CustomProps,\n ShellComposables,\n ShellIncludeProps,\n ShellCustomProps\n>;\n\n/**\n * Loose runtime shape of a `shell` block, used by the impl below.\n */\ntype ShellLayoutRuntime = {\n name?: string;\n composables?: (create: unknown) => ComposableComponents;\n props?: {\n include?: Record<string, unknown>;\n custom?: Record<string, unknown>;\n };\n render: (\n props: Record<string, unknown>,\n context: Record<string, unknown>,\n ) => JSX.Element;\n};\n\n/**\n * Builds the `Shell` component. Kept beside {@link defineResourceLayoutImpl} so\n * it can reuse the same private prop-resolution helpers.\n *\n * Unlike a per-resource component, the shell re-reads the current resource on\n * every render (reported by the mounted page) so resource-scoped composable\n * *names* can update. Composable *component identities* are resolved once and\n * kept stable: React reconciles by element type, so recreating\n * `composables.Layout` each render would remount wrapWith targets, sidebar\n * state, and the outlet. Display names are synced onto those stable functions\n * when the resource changes.\n *\n * @param shellId - Identity of the owning `withLayout` definition. The shell\n * only accepts resource reports tagged with this id, so a page or pane from a\n * different definition rendered in the outlet cannot corrupt its state.\n */\nfunction createResourceLayoutShellComponent(\n resources: ReadonlyArray<ResourceDefinition>,\n inProps:\n | InPropsObject\n | ((opts: Record<string, unknown>) => InPropsObject),\n shell: ShellLayoutRuntime,\n shellId: symbol,\n) {\n const shellName = shell.name ?? 'ResourceLayoutShell';\n // `resources` is the wide `ResourceDefinition[]` here (not the const generic\n // that `defineResourceLayoutImpl` captures), so the normalize/enum types are\n // erased to keep TS from trying to instantiate them structurally. Only the\n // runtime key list matters — the shell validates against it, it does not\n // surface it in a public type.\n const resourceKeys = Object.keys(\n normalizeResources(resources as never) as Record<string, unknown>,\n );\n const resourcesEnum = createPrimitivePropBuilder('string').enum(\n resourceKeys as never,\n );\n\n // `options` may be a function of `{ resource, name }`. The shell has no single\n // resource, so — like the component path in `defineResourceLayoutImpl` — the\n // enum stands in for `resource` while resolving the definitions.\n const rawResolvedOptions =\n typeof inProps === 'function'\n ? inProps({\n resource: resourcesEnum,\n name: createProp.string().literal(shellName),\n })\n : inProps;\n const { resolvedInProps, splitInProps } = splitLayoutInProps(\n rawResolvedOptions as Record<string, unknown>,\n );\n\n const includeShellProps = shell.props?.include;\n const includeShellPropKeys = Object.keys(includeShellProps ?? {});\n const shellCustomDefinitions = {\n ...(shell.props?.custom ?? {}),\n } as Record<string, AnyBuiltPropDefinition>;\n\n function syncShellComposableDisplayNames(\n stable: ComposableComponents,\n resource: string,\n ) {\n if (!shell.composables) {\n return;\n }\n\n const named = resolveLayoutComposables(shell.composables as never, {\n resource,\n name: shellName,\n capitalize,\n } as never) as ComposableComponents;\n\n for (const [key, component] of Object.entries(named)) {\n const stableComponent = stable[key];\n\n if (\n typeof stableComponent === 'function' &&\n typeof component === 'function' &&\n 'displayName' in component\n ) {\n (stableComponent as { displayName?: string }).displayName = (\n component as { displayName?: string }\n ).displayName;\n }\n }\n }\n\n function Shell(props: Record<string, unknown>) {\n const { children: outlet, resource: resourceProp } = props as {\n children: ReactNode;\n resource?: string;\n };\n\n // Which resource is currently in the outlet. A per-resource page reports its\n // own resource here on mount (see the layout effect in `Component`);\n // `undefined` between pages or on a route with no per-resource layout. An\n // explicit `resource` prop always wins.\n const [reportedResource, setReportedResource] = useState<\n string | undefined\n >(undefined);\n const publishResource = useCallback<ResourceLayoutShellPublisher>(\n (resource, ownerId) => {\n // Ignore reports from components that belong to a different\n // `defineResourceLayout` definition — they share this context but their\n // resource is unrelated to this shell.\n if (ownerId !== shellId) {\n return;\n }\n\n setReportedResource(resource);\n },\n [],\n );\n const resource = resourceProp ?? reportedResource;\n\n // The outlet subtree must not re-render when `reportedResource` changes —\n // only the shell chrome should. Memoising the wrapped element lets React\n // bail out of reconciling the page while, say, the breadcrumb label updates.\n const shellChildren = useMemo(\n () => (\n <ResourceLayoutShellPublisherContext.Provider value={publishResource}>\n {outlet}\n </ResourceLayoutShellPublisherContext.Provider>\n ),\n [outlet, publishResource],\n );\n\n // Resolve composables once so `<composables.Layout>` keeps a stable element\n // type across Shell re-renders (including the layout-effect resource report).\n // Re-resolving every render would allocate new component functions and React\n // would remount the whole chrome tree. Names still track the live resource\n // via {@link syncShellComposableDisplayNames}.\n const composablesRef = useRef<ComposableComponents | undefined>(undefined);\n if (shell.composables) {\n const nameContextResource = resource ?? '';\n\n if (!composablesRef.current) {\n composablesRef.current = resolveLayoutComposables(\n shell.composables as never,\n {\n resource: nameContextResource,\n name: shellName,\n capitalize,\n } as never,\n ) as ComposableComponents;\n } else {\n syncShellComposableDisplayNames(\n composablesRef.current,\n nameContextResource,\n );\n }\n }\n const resolvedComposables = composablesRef.current;\n const validationContext = {\n layoutName: shellName,\n resource: resource ?? '',\n };\n\n const mergedResolvedInProps = { ...resolvedInProps } as Record<\n string,\n unknown\n >;\n for (const {\n props: presetPropDefinitions,\n } of collectComposablePresetEntries(resolvedComposables)) {\n Object.assign(mergedResolvedInProps, presetPropDefinitions);\n }\n\n // Included props: definition-time defaults from `options`, overridden by\n // anything passed to `<Shell>` (component passthrough). Computed before\n // preset validation so config-passthrough includes can reuse the defaults.\n const includedPropDefinitions = pick(\n mergedResolvedInProps,\n includeShellPropKeys,\n ) as Record<string, unknown>;\n const includedPropValues = {\n ...resolvePropDefinitionValues(includedPropDefinitions),\n } as Record<string, unknown>;\n\n for (const key of includeShellPropKeys) {\n const definition = mergedResolvedInProps[key];\n const behavior = includeShellProps?.[key];\n const callSiteValue = allowsComponentPassthrough(behavior)\n ? readLayoutOptionValue(key, definition, props)\n : undefined;\n // Config passthrough has no create-time call on Shell; still honour\n // literal / split defaults from `options` when present.\n const configValue = allowsConfigPassthrough(behavior)\n ? readLayoutOptionValue(key, definition, {\n ...includedPropValues,\n ...splitInProps,\n })\n : undefined;\n const splitValue = key in splitInProps ? splitInProps[key] : undefined;\n const value = callSiteValue ?? configValue ?? splitValue;\n\n if (value !== undefined) {\n includedPropValues[key] = value;\n }\n }\n\n // Preset props: Shell has no create-time call. Component-passthrough values\n // come from `<Shell>` props; config-passthrough values only from definition\n // defaults. Required config includes without a default are omitted from\n // validation — they are not typed on Shell and cannot be supplied.\n const composablePresetProps = Object.fromEntries(\n collectComposablePresetEntries(resolvedComposables).map(\n ({ key, props: presetPropDefinitions }) => {\n const entries = Object.entries(presetPropDefinitions);\n const validatedDefinitions = Object.fromEntries(\n entries.filter(([propKey]) => {\n const behavior = includeShellProps?.[propKey];\n\n if (behavior === undefined) {\n return true;\n }\n\n if (allowsComponentPassthrough(behavior)) {\n return true;\n }\n\n if (allowsConfigPassthrough(behavior)) {\n return includedPropValues[propKey] !== undefined;\n }\n\n return false;\n }),\n );\n const values = Object.fromEntries(\n entries.flatMap(([propKey]) => {\n if (propKey in props) {\n return [[propKey, props[propKey]]];\n }\n\n if (includedPropValues[propKey] !== undefined) {\n return [[propKey, includedPropValues[propKey]]];\n }\n\n return [];\n }),\n );\n\n return [\n key,\n validateProps(\n validatedDefinitions as Record<string, AnyBuiltPropDefinition>,\n values,\n validationContext,\n ),\n ];\n },\n ),\n );\n\n const validatedCustomProps = validateProps(\n shellCustomDefinitions,\n props,\n validationContext,\n );\n\n const requiredIncludedDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(([key]) => {\n const behavior = includeShellProps?.[key];\n\n if (!isIncludedPropRequired(behavior)) {\n return false;\n }\n\n // Component passthrough stays required on `<Shell>` (and is typed there).\n if (allowsComponentPassthrough(behavior)) {\n return true;\n }\n\n // Config passthrough: only require when a definition-time value exists.\n return includedPropValues[key] !== undefined;\n }),\n );\n const optionalIncludedDefinitions = Object.fromEntries(\n Object.entries(includedPropDefinitions).filter(\n ([key]) =>\n !isIncludedPropRequired(includeShellProps?.[key]) &&\n includedPropValues[key] !== undefined,\n ),\n );\n const validatedIncludedProps = validateProps(\n {\n ...requiredIncludedDefinitions,\n ...optionalIncludedDefinitions,\n } as Record<string, AnyBuiltPropDefinition>,\n includedPropValues,\n validationContext,\n );\n const renderIncludedProps = Object.fromEntries(\n includeShellPropKeys.flatMap((key) =>\n key in validatedIncludedProps\n ? [\n [\n toLayoutRenderPropKey(key, mergedResolvedInProps[key]),\n validatedIncludedProps[\n key as keyof typeof validatedIncludedProps\n ],\n ],\n ]\n : [],\n ),\n );\n\n const renderProps = { ...validatedCustomProps, ...renderIncludedProps };\n const renderContext = {\n composables: resolvedComposables,\n resource,\n resources: createLayoutRenderResourcesAccessor(\n resources as ReadonlyArray<ResourceDefinition>,\n resource as never,\n ),\n name: shellName,\n inProps: splitInProps,\n children: shellChildren,\n };\n\n const rendered = shell.render(renderProps, renderContext);\n\n return resolvedComposables ? (\n <LayoutComposablePresetProvider value={composablePresetProps}>\n {rendered}\n </LayoutComposablePresetProvider>\n ) : (\n rendered\n );\n }\n\n return Object.assign(Shell, {\n displayName: shellName,\n props: undefined as never,\n });\n}\n\n/**\n * Implementation of {@link defineResourceLayout.withLayout}. Delegates the\n * config / links / `createResourceLayout` pieces to {@link defineResourceLayoutImpl}\n * and adds the {@link createResourceLayoutShellComponent | Shell}.\n */\nfunction defineResourceLayoutWithLayoutImpl(\n options: Record<string, unknown>,\n): Record<string, unknown> {\n const {\n shell,\n layout,\n resources,\n options: inProps,\n } = options as {\n shell: ShellLayoutRuntime;\n layout?: {\n composables?: unknown;\n props?: { include?: unknown; custom?: Record<string, unknown> };\n render?: (\n props: Record<string, unknown>,\n context: unknown,\n ) => JSX.Element;\n };\n resources: ReadonlyArray<ResourceDefinition>;\n options?:\n | InPropsObject\n | ((opts: Record<string, unknown>) => InPropsObject);\n };\n\n // The per-resource `render` is optional under `withLayout`. When omitted, the\n // page is a pure content slot: give it a `children` prop (so\n // `<UsersPage>{content}</UsersPage>` type-checks and works) and a render that\n // drops that content into the shell's outlet. An explicit `render` is passed\n // through untouched.\n const resolvedLayout = layout?.render\n ? layout\n : {\n ...layout,\n props: {\n ...layout?.props,\n custom: {\n children: createProp.component({ type: 'ReactNode' }).optional(),\n ...(layout?.props?.custom ?? {}),\n },\n },\n render: (pageProps: Record<string, unknown>) => (\n <>{(pageProps.children as ReactNode) ?? null}</>\n ),\n };\n\n // Ties the shell to the pages created by *its* `createResourceLayout`. Pages\n // from other definitions rendered in the outlet carry a different id (or\n // none) and are ignored by the shell's resource tracking.\n const shellId = Symbol('resourceLayoutShell');\n\n const base = defineResourceLayoutImpl({\n resources,\n options: inProps,\n layout: resolvedLayout,\n shellId,\n } as never) as Record<string, unknown>;\n\n const Shell = createResourceLayoutShellComponent(\n resources,\n (inProps ?? {}) as never,\n shell,\n shellId,\n );\n\n return { ...base, Shell };\n}\n\nexport const defineResourceLayout: DefineResourceLayout = Object.assign(\n defineResourceLayoutImpl as DefineResourceLayoutFn,\n {\n forResources: defineResourceLayoutForResources,\n defineResources,\n withLayout:\n defineResourceLayoutWithLayoutImpl as unknown as DefineResourceLayoutWithLayoutFn,\n },\n);\n"],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@ function validateParams(params, state, sets) {
|
|
|
34
34
|
if (state.declaredPathParams.includes("resource") && resource !== void 0) {
|
|
35
35
|
if (typeof resource !== "string" || !sets.resources.includes(resource)) throw new require_invalid_resource.InvalidResourceError({
|
|
36
36
|
resource,
|
|
37
|
-
validResources: sets.resources
|
|
37
|
+
validResources: [...sets.resources]
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
if (state.declaredPathParams.includes("subResource") && subResource !== void 0) {
|
|
@@ -42,27 +42,27 @@ function validateParams(params, state, sets) {
|
|
|
42
42
|
for (const slug of slugs) if (!sets.subResources.includes(slug)) throw new require_invalid_sub_resource.InvalidSubResourceError({
|
|
43
43
|
subResource: slug,
|
|
44
44
|
resource: typeof resource === "string" ? resource : void 0,
|
|
45
|
-
validSubResources: sets.subResources
|
|
45
|
+
validSubResources: [...sets.subResources]
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
if (state.declaredPathParams.includes("component") && component !== void 0) {
|
|
49
49
|
if (typeof component !== "string" || !sets.components.includes(component)) throw new require_invalid_component.InvalidComponentError({
|
|
50
50
|
component,
|
|
51
|
-
validComponents: sets.components
|
|
51
|
+
validComponents: [...sets.components]
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
if (!state.componentKeyDeclared) return;
|
|
55
55
|
if (componentKey === void 0) {
|
|
56
56
|
if (!state.componentKeyOptional) throw new require_invalid_component.InvalidComponentError({
|
|
57
57
|
component: componentKey,
|
|
58
|
-
validComponents: sets.components,
|
|
58
|
+
validComponents: [...sets.components],
|
|
59
59
|
reason: "A \"componentKey\" prop is required for this component"
|
|
60
60
|
});
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
if (typeof componentKey !== "string" || !sets.components.includes(componentKey)) throw new require_invalid_component.InvalidComponentError({
|
|
64
64
|
component: componentKey,
|
|
65
|
-
validComponents: sets.components
|
|
65
|
+
validComponents: [...sets.components]
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
function readClosureProps(selected, closure) {
|
|
@@ -140,7 +140,7 @@ function createTargetPathBuilder(config, paths) {
|
|
|
140
140
|
getComponentForPath: (path) => {
|
|
141
141
|
if (!state.paths.includes(path)) throw new require_invalid_path.InvalidPathError({
|
|
142
142
|
path,
|
|
143
|
-
validPaths: state.paths,
|
|
143
|
+
validPaths: [...state.paths],
|
|
144
144
|
reason: "This component was not built for that path"
|
|
145
145
|
});
|
|
146
146
|
return require_get_component_for_path.createGetComponentForPath(config, path);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"builder.cjs","names":["collectPathResources","collectPathSubResourceKeys","collectPathComponentKeys","InvalidResourceError","flattenSubResourceParam","InvalidSubResourceError","InvalidComponentError","extractPathVariables","InvalidPathError","createGetComponentForPath","generateResourceConfigPaths"],"sources":["../../../src/create-config/for-paths/builder.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport {\n InvalidComponentError,\n InvalidPathError,\n InvalidResourceError,\n InvalidSubResourceError,\n} from '../../errors';\nimport type { ResourceDefinition } from '../../resource';\nimport type { IsUnion, Show } from '../../utils';\nimport {\n collectPathComponentKeys,\n collectPathResources,\n collectPathSubResourceKeys,\n extractPathVariables,\n flattenSubResourceParam,\n generateResourceConfigPaths,\n} from '../paths';\nimport type {\n PathComponentKeys,\n PathVariables,\n SubResourceParamValue,\n} from '../paths';\nimport {\n createGetComponentForPath,\n type CreateGetComponentForPath,\n} from './get-component-for-path';\n\ntype UnwrapTargetPaths<Paths> = Paths extends readonly [\n infer First,\n ...infer Rest,\n]\n ? (First & string) | UnwrapTargetPaths<Rest>\n : Paths extends readonly (infer Path)[]\n ? Path & string\n : never;\n\ntype PathVariablesForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n> =\n UnwrapTargetPaths<Paths> extends infer Path\n ? Path extends string\n ? PathVariables<Resources, Config, Path>\n : never\n : never;\n\ntype ComponentKeysForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n> =\n UnwrapTargetPaths<Paths> extends infer Path\n ? Path extends string\n ? PathComponentKeys<Resources, Config, Path>\n : never\n : never;\n\ntype ValueOrFunction<Value, Input> = Value | ((input: Input) => Value);\n\n/** Context handed to `render` and to `setDisplayName`. */\nexport type ForPathsRenderContext<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n Params,\n> = {\n /** Declared params merged with the props the component was called with. */\n params: Params;\n /** Creates a getter for any of the paths this component was built for. */\n getComponentForPath: CreateGetComponentForPath<\n Resources,\n Config,\n UnwrapTargetPaths<Paths>\n >;\n};\n\ntype HOFArgSelection<Params> = {\n [Key in keyof Params]?: true;\n};\n\n/**\n * Value closed over by `asHOF`. Selecting a single arg closes over that value directly;\n * selecting several closes over an object.\n */\ntype HOFClosureValue<Params, Args> = [keyof Args] extends [never]\n ? {}\n : IsUnion<keyof Args> extends false\n ? Params[keyof Args & keyof Params]\n : Show<Pick<Params, keyof Args & keyof Params>>;\n\nexport interface RenderedPathComponentHOF<Params, Args> {\n (closure: HOFClosureValue<Params, Args>): RenderedPathComponent<\n Show<Omit<Params, keyof Args>>\n >;\n /** Type-only view of the value this HOF closes over. At runtime this is `undefined`. */\n _args: HOFClosureValue<Params, Args>;\n}\n\nexport interface RenderedPathComponent<\n Params,\n DisplayName extends string = string,\n> {\n (props: Params): JSX.Element;\n displayName: DisplayName;\n /** Type-only view of the props this component accepts. */\n _args: Params;\n /**\n * Splits the props into a closure and the remaining props, so shared params can be\n * bound once and the component reused. Chained `asHOF` calls keep prior closures.\n */\n asHOF<Args extends HOFArgSelection<Params> = {}>(options?: {\n /** Params to close over. Anything omitted stays a prop. */\n args: Args;\n }): RenderedPathComponentHOF<Params, Args>;\n}\n\ntype WithComponentKeyParam<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n Optional extends boolean,\n> = Optional extends true\n ? { componentKey?: ComponentKeysForPaths<Resources, Config, Paths> }\n : { componentKey: ComponentKeysForPaths<Resources, Config, Paths> };\n\ntype PickedPathParams<\n Variables,\n Picked,\n> = [keyof Picked] extends [never]\n ? Variables\n : Pick<Variables, keyof Picked & keyof Variables>;\n\nexport type TargetPathBuilder<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n Params extends Record<string, unknown> = {},\n Used extends\n | 'addComponentKeyParams'\n | 'addPathParams'\n | 'addParams' = never,\n> = {\n render: (\n renderer: (\n context: ForPathsRenderContext<Resources, Config, Paths, Params>,\n ) => JSX.Element,\n ) => RenderedPathComponent<Params> & {\n /** Names the component, either statically or from the render context. */\n setDisplayName<Name extends string>(\n name: ValueOrFunction<\n Name,\n ForPathsRenderContext<Resources, Config, Paths, Params>\n >,\n ): RenderedPathComponent<Params, Name>;\n };\n} & ('addComponentKeyParams' extends Used\n ? {}\n : {\n /**\n * Adds a `componentKey` prop narrowed to the component slots configured for these\n * paths. Call it before `render` when building a reusable component.\n */\n addComponentKeyParams<Optional extends boolean = false>(options?: {\n /** Whether the caller may omit `componentKey`. */\n optional?: Optional;\n }): TargetPathBuilder<\n Resources,\n Config,\n Paths,\n Show<\n Params & WithComponentKeyParam<Resources, Config, Paths, Optional>\n >,\n Used | 'addComponentKeyParams'\n >;\n }) &\n ('addPathParams' extends Used\n ? {}\n : {\n /**\n * Turns the variables these paths leave open into props. Without `pick`, every\n * variable becomes a prop.\n */\n addPathParams<\n Variables extends PathVariablesForPaths<Resources, Config, Paths>,\n Picked extends { [Key in keyof Variables]?: true } = {},\n >(options?: {\n /** Variables to expose as props. Defaults to all of them. */\n pick?: Picked;\n }): TargetPathBuilder<\n Resources,\n Config,\n Paths,\n Show<Params & PickedPathParams<Variables, Picked>>,\n Used | 'addPathParams'\n >;\n }) &\n ('addParams' extends Used\n ? {}\n : {\n /**\n * Adds custom params with the given values as defaults. Defaults are\n * optional at the call site and filled in before `render` runs.\n */\n addParams<NewParams extends Record<string, unknown>>(\n params: NewParams,\n ): TargetPathBuilder<\n Resources,\n Config,\n Paths,\n Show<Params & Partial<NewParams>>,\n Used | 'addParams'\n >;\n });\n\nexport type ForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n AllowedPath extends string,\n> = <const Paths extends readonly [AllowedPath, ...AllowedPath[]]>(\n ...paths: Paths\n) => TargetPathBuilder<Resources, Config, Paths>;\n\nconst DEFAULT_DISPLAY_NAME = 'ResourcePathComponent';\n\ntype BuilderState = {\n paths: readonly string[];\n paramDefaults: Record<string, unknown>;\n declaredPathParams: readonly string[];\n componentKeyDeclared: boolean;\n componentKeyOptional: boolean;\n usedComponentKeyParams: boolean;\n usedPathParams: boolean;\n usedParams: boolean;\n};\n\ntype ValidationSets = {\n resources: readonly string[];\n subResources: readonly string[];\n components: readonly string[];\n};\n\nfunction collectValidationSets(\n config: Record<string, unknown>,\n paths: readonly string[],\n): ValidationSets {\n const resources = new Set<string>();\n const subResources = new Set<string>();\n const components = new Set<string>();\n\n for (const path of paths) {\n for (const resource of collectPathResources(config, path)) {\n resources.add(resource);\n }\n\n for (const subResource of collectPathSubResourceKeys(config, path)) {\n subResources.add(subResource);\n }\n\n for (const component of collectPathComponentKeys(config, path)) {\n components.add(component);\n }\n }\n\n return {\n resources: [...resources],\n subResources: [...subResources],\n components: [...components],\n };\n}\n\n/**\n * Validates the params a caller passed before the renderer runs, so a bad resource or\n * slot fails with a typed error naming what is available.\n */\nfunction validateParams(\n params: Record<string, unknown>,\n state: BuilderState,\n sets: ValidationSets,\n): void {\n const { resource, subResource, component, componentKey } = params as {\n resource?: unknown;\n subResource?: unknown;\n component?: unknown;\n componentKey?: unknown;\n };\n\n if (state.declaredPathParams.includes('resource') && resource !== undefined) {\n if (typeof resource !== 'string' || !sets.resources.includes(resource)) {\n throw new InvalidResourceError({\n resource,\n validResources: sets.resources,\n });\n }\n }\n\n if (\n state.declaredPathParams.includes('subResource') &&\n subResource !== undefined\n ) {\n const slugs = flattenSubResourceParam(subResource as SubResourceParamValue);\n\n for (const slug of slugs) {\n if (!sets.subResources.includes(slug)) {\n throw new InvalidSubResourceError({\n subResource: slug,\n resource: typeof resource === 'string' ? resource : undefined,\n validSubResources: sets.subResources,\n });\n }\n }\n }\n\n if (\n state.declaredPathParams.includes('component') &&\n component !== undefined\n ) {\n if (typeof component !== 'string' || !sets.components.includes(component)) {\n throw new InvalidComponentError({\n component,\n validComponents: sets.components,\n });\n }\n }\n\n if (!state.componentKeyDeclared) {\n return;\n }\n\n if (componentKey === undefined) {\n if (!state.componentKeyOptional) {\n throw new InvalidComponentError({\n component: componentKey,\n validComponents: sets.components,\n reason: 'A \"componentKey\" prop is required for this component',\n });\n }\n\n return;\n }\n\n if (\n typeof componentKey !== 'string' ||\n !sets.components.includes(componentKey)\n ) {\n throw new InvalidComponentError({\n component: componentKey,\n validComponents: sets.components,\n });\n }\n}\n\nfunction readClosureProps(\n selected: string[],\n closure: unknown,\n): Record<string, unknown> {\n if (selected.length === 0) {\n return {};\n }\n\n const [only] = selected;\n\n if (selected.length === 1 && only !== undefined) {\n return { [only]: closure };\n }\n\n if (\n typeof closure === 'object' &&\n closure !== null &&\n !Array.isArray(closure)\n ) {\n return { ...(closure as Record<string, unknown>) };\n }\n\n return {};\n}\n\nfunction createRenderedComponent(\n runRenderer: (props: Record<string, unknown>) => JSX.Element,\n paramTemplate: Record<string, unknown> | undefined,\n resolveDisplayName?: (props: Record<string, unknown>) => string,\n boundProps: Record<string, unknown> = {},\n) {\n function RenderedPathView(props: Record<string, unknown>): JSX.Element {\n const merged = { ...boundProps, ...props };\n\n if (resolveDisplayName) {\n RenderedPathView.displayName = resolveDisplayName(merged);\n }\n\n return runRenderer(merged);\n }\n\n RenderedPathView.displayName = DEFAULT_DISPLAY_NAME;\n\n function asHOF(options?: { args?: Record<string, true> }) {\n const selected = Object.entries(options?.args ?? {})\n .filter(([, enabled]) => enabled === true)\n .map(([key]) => key);\n\n function hof(closure: unknown) {\n const bound = createRenderedComponent(\n runRenderer,\n undefined,\n resolveDisplayName,\n { ...boundProps, ...readClosureProps(selected, closure) },\n );\n\n bound.displayName = RenderedPathView.displayName;\n\n return bound;\n }\n\n return Object.assign(hof, { _args: undefined as never });\n }\n\n return Object.assign(RenderedPathView, {\n _args: paramTemplate as never,\n asHOF,\n });\n}\n\nexport function createTargetPathBuilder<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config extends Record<string, unknown>,\n Paths extends ReadonlyArray<string>,\n>(config: Config, paths: Paths): TargetPathBuilder<Resources, Config, Paths> {\n const validationSets = collectValidationSets(config, paths);\n\n const makeBuilder = (state: BuilderState): Record<string, unknown> => {\n const builder: Record<string, unknown> = {};\n\n if (!state.usedComponentKeyParams) {\n builder.addComponentKeyParams = (options?: { optional?: boolean }) =>\n makeBuilder({\n ...state,\n usedComponentKeyParams: true,\n componentKeyDeclared: true,\n componentKeyOptional: options?.optional === true,\n });\n }\n\n if (!state.usedPathParams) {\n builder.addPathParams = (options?: { pick?: Record<string, true> }) => {\n const available = new Set<string>();\n\n for (const path of state.paths) {\n for (const name of extractPathVariables(path)) {\n available.add(name);\n }\n }\n\n const picked = Object.entries(options?.pick ?? {})\n .filter(([, enabled]) => enabled === true)\n .map(([key]) => key);\n const declared =\n picked.length === 0\n ? [...available]\n : picked.filter((name) => available.has(name));\n\n return makeBuilder({\n ...state,\n usedPathParams: true,\n declaredPathParams: [...state.declaredPathParams, ...declared],\n });\n };\n }\n\n if (!state.usedParams) {\n builder.addParams = (params: Record<string, unknown>) =>\n makeBuilder({\n ...state,\n usedParams: true,\n paramDefaults: { ...state.paramDefaults, ...params },\n });\n }\n\n builder.render = (\n renderer: (context: {\n params: Record<string, unknown>;\n getComponentForPath: unknown;\n }) => JSX.Element,\n ) => {\n const buildContext = (props: Record<string, unknown>) => {\n const params = { ...state.paramDefaults, ...props };\n\n validateParams(params, state, validationSets);\n\n return {\n params,\n getComponentForPath: (path: string) => {\n if (!state.paths.includes(path)) {\n throw new InvalidPathError({\n path,\n validPaths: state.paths,\n reason: 'This component was not built for that path',\n });\n }\n\n return createGetComponentForPath(config, path);\n },\n };\n };\n\n const runRenderer = (props: Record<string, unknown>) =>\n renderer(buildContext(props));\n\n const component = createRenderedComponent(runRenderer, {\n ...state.paramDefaults,\n });\n\n return Object.assign(component, {\n setDisplayName: (\n name:\n | string\n | ((context: {\n params: Record<string, unknown>;\n getComponentForPath: unknown;\n }) => string),\n ) => {\n if (typeof name === 'string') {\n const named = createRenderedComponent(runRenderer, {\n ...state.paramDefaults,\n });\n\n named.displayName = name;\n\n return named;\n }\n\n return createRenderedComponent(\n runRenderer,\n { ...state.paramDefaults },\n (props) => name(buildContext(props)),\n );\n },\n });\n };\n\n return builder;\n };\n\n return makeBuilder({\n paths,\n paramDefaults: {},\n declaredPathParams: [],\n componentKeyDeclared: false,\n componentKeyOptional: false,\n usedComponentKeyParams: false,\n usedPathParams: false,\n usedParams: false,\n }) as unknown as TargetPathBuilder<Resources, Config, Paths>;\n}\n\nexport function createForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config extends Record<string, unknown>,\n>(config: Config): ForPaths<Resources, Config, string> {\n const validPaths = generateResourceConfigPaths(config);\n\n return ((...paths: string[]) => {\n if (paths.length === 0) {\n throw new InvalidPathError({\n path: paths,\n validPaths,\n reason: 'At least one path is required',\n });\n }\n\n for (const path of paths) {\n if (!validPaths.includes(path)) {\n throw new InvalidPathError({ path, validPaths });\n }\n }\n\n return createTargetPathBuilder(config, paths);\n }) as unknown as ForPaths<Resources, Config, string>;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"builder.cjs","names":["collectPathResources","collectPathSubResourceKeys","collectPathComponentKeys","InvalidResourceError","flattenSubResourceParam","InvalidSubResourceError","InvalidComponentError","extractPathVariables","InvalidPathError","createGetComponentForPath","generateResourceConfigPaths"],"sources":["../../../src/create-config/for-paths/builder.ts"],"sourcesContent":["import type { JSX } from 'react';\nimport {\n InvalidComponentError,\n InvalidPathError,\n InvalidResourceError,\n InvalidSubResourceError,\n} from '../../errors';\nimport type { ResourceDefinition } from '../../resource';\nimport type { IsUnion, Show } from '../../utils';\nimport {\n collectPathComponentKeys,\n collectPathResources,\n collectPathSubResourceKeys,\n extractPathVariables,\n flattenSubResourceParam,\n generateResourceConfigPaths,\n} from '../paths';\nimport type {\n PathComponentKeys,\n PathVariables,\n SubResourceParamValue,\n} from '../paths';\nimport {\n createGetComponentForPath,\n type CreateGetComponentForPath,\n} from './get-component-for-path';\n\ntype UnwrapTargetPaths<Paths> = Paths extends readonly [\n infer First,\n ...infer Rest,\n]\n ? (First & string) | UnwrapTargetPaths<Rest>\n : Paths extends readonly (infer Path)[]\n ? Path & string\n : never;\n\ntype PathVariablesForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n> =\n UnwrapTargetPaths<Paths> extends infer Path\n ? Path extends string\n ? PathVariables<Resources, Config, Path>\n : never\n : never;\n\ntype ComponentKeysForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n> =\n UnwrapTargetPaths<Paths> extends infer Path\n ? Path extends string\n ? PathComponentKeys<Resources, Config, Path>\n : never\n : never;\n\ntype ValueOrFunction<Value, Input> = Value | ((input: Input) => Value);\n\n/** Context handed to `render` and to `setDisplayName`. */\nexport type ForPathsRenderContext<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n Params,\n> = {\n /** Declared params merged with the props the component was called with. */\n params: Params;\n /** Creates a getter for any of the paths this component was built for. */\n getComponentForPath: CreateGetComponentForPath<\n Resources,\n Config,\n UnwrapTargetPaths<Paths>\n >;\n};\n\ntype HOFArgSelection<Params> = {\n [Key in keyof Params]?: true;\n};\n\n/**\n * Value closed over by `asHOF`. Selecting a single arg closes over that value directly;\n * selecting several closes over an object.\n */\ntype HOFClosureValue<Params, Args> = [keyof Args] extends [never]\n ? {}\n : IsUnion<keyof Args> extends false\n ? Params[keyof Args & keyof Params]\n : Show<Pick<Params, keyof Args & keyof Params>>;\n\nexport interface RenderedPathComponentHOF<Params, Args> {\n (closure: HOFClosureValue<Params, Args>): RenderedPathComponent<\n Show<Omit<Params, keyof Args>>\n >;\n /** Type-only view of the value this HOF closes over. At runtime this is `undefined`. */\n _args: HOFClosureValue<Params, Args>;\n}\n\nexport interface RenderedPathComponent<\n Params,\n DisplayName extends string = string,\n> {\n (props: Params): JSX.Element;\n displayName: DisplayName;\n /** Type-only view of the props this component accepts. */\n _args: Params;\n /**\n * Splits the props into a closure and the remaining props, so shared params can be\n * bound once and the component reused. Chained `asHOF` calls keep prior closures.\n */\n asHOF<Args extends HOFArgSelection<Params> = {}>(options?: {\n /** Params to close over. Anything omitted stays a prop. */\n args: Args;\n }): RenderedPathComponentHOF<Params, Args>;\n}\n\ntype WithComponentKeyParam<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n Optional extends boolean,\n> = Optional extends true\n ? { componentKey?: ComponentKeysForPaths<Resources, Config, Paths> }\n : { componentKey: ComponentKeysForPaths<Resources, Config, Paths> };\n\ntype PickedPathParams<\n Variables,\n Picked,\n> = [keyof Picked] extends [never]\n ? Variables\n : Pick<Variables, keyof Picked & keyof Variables>;\n\nexport type TargetPathBuilder<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n Paths extends ReadonlyArray<string>,\n Params extends Record<string, unknown> = {},\n Used extends\n | 'addComponentKeyParams'\n | 'addPathParams'\n | 'addParams' = never,\n> = {\n render: (\n renderer: (\n context: ForPathsRenderContext<Resources, Config, Paths, Params>,\n ) => JSX.Element,\n ) => RenderedPathComponent<Params> & {\n /** Names the component, either statically or from the render context. */\n setDisplayName<Name extends string>(\n name: ValueOrFunction<\n Name,\n ForPathsRenderContext<Resources, Config, Paths, Params>\n >,\n ): RenderedPathComponent<Params, Name>;\n };\n} & ('addComponentKeyParams' extends Used\n ? {}\n : {\n /**\n * Adds a `componentKey` prop narrowed to the component slots configured for these\n * paths. Call it before `render` when building a reusable component.\n */\n addComponentKeyParams<Optional extends boolean = false>(options?: {\n /** Whether the caller may omit `componentKey`. */\n optional?: Optional;\n }): TargetPathBuilder<\n Resources,\n Config,\n Paths,\n Show<\n Params & WithComponentKeyParam<Resources, Config, Paths, Optional>\n >,\n Used | 'addComponentKeyParams'\n >;\n }) &\n ('addPathParams' extends Used\n ? {}\n : {\n /**\n * Turns the variables these paths leave open into props. Without `pick`, every\n * variable becomes a prop.\n */\n addPathParams<\n Variables extends PathVariablesForPaths<Resources, Config, Paths>,\n Picked extends { [Key in keyof Variables]?: true } = {},\n >(options?: {\n /** Variables to expose as props. Defaults to all of them. */\n pick?: Picked;\n }): TargetPathBuilder<\n Resources,\n Config,\n Paths,\n Show<Params & PickedPathParams<Variables, Picked>>,\n Used | 'addPathParams'\n >;\n }) &\n ('addParams' extends Used\n ? {}\n : {\n /**\n * Adds custom params with the given values as defaults. Defaults are\n * optional at the call site and filled in before `render` runs.\n */\n addParams<NewParams extends Record<string, unknown>>(\n params: NewParams,\n ): TargetPathBuilder<\n Resources,\n Config,\n Paths,\n Show<Params & Partial<NewParams>>,\n Used | 'addParams'\n >;\n });\n\nexport type ForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config,\n AllowedPath extends string,\n> = <const Paths extends readonly [AllowedPath, ...AllowedPath[]]>(\n ...paths: Paths\n) => TargetPathBuilder<Resources, Config, Paths>;\n\nconst DEFAULT_DISPLAY_NAME = 'ResourcePathComponent';\n\ntype BuilderState = {\n paths: readonly string[];\n paramDefaults: Record<string, unknown>;\n declaredPathParams: readonly string[];\n componentKeyDeclared: boolean;\n componentKeyOptional: boolean;\n usedComponentKeyParams: boolean;\n usedPathParams: boolean;\n usedParams: boolean;\n};\n\ntype ValidationSets = {\n resources: readonly string[];\n subResources: readonly string[];\n components: readonly string[];\n};\n\nfunction collectValidationSets(\n config: Record<string, unknown>,\n paths: readonly string[],\n): ValidationSets {\n const resources = new Set<string>();\n const subResources = new Set<string>();\n const components = new Set<string>();\n\n for (const path of paths) {\n for (const resource of collectPathResources(config, path)) {\n resources.add(resource);\n }\n\n for (const subResource of collectPathSubResourceKeys(config, path)) {\n subResources.add(subResource);\n }\n\n for (const component of collectPathComponentKeys(config, path)) {\n components.add(component);\n }\n }\n\n return {\n resources: [...resources],\n subResources: [...subResources],\n components: [...components],\n };\n}\n\n/**\n * Validates the params a caller passed before the renderer runs, so a bad resource or\n * slot fails with a typed error naming what is available.\n */\nfunction validateParams(\n params: Record<string, unknown>,\n state: BuilderState,\n sets: ValidationSets,\n): void {\n const { resource, subResource, component, componentKey } = params as {\n resource?: unknown;\n subResource?: unknown;\n component?: unknown;\n componentKey?: unknown;\n };\n\n if (state.declaredPathParams.includes('resource') && resource !== undefined) {\n if (typeof resource !== 'string' || !sets.resources.includes(resource)) {\n throw new InvalidResourceError({\n resource,\n validResources: [...sets.resources],\n });\n }\n }\n\n if (\n state.declaredPathParams.includes('subResource') &&\n subResource !== undefined\n ) {\n const slugs = flattenSubResourceParam(subResource as SubResourceParamValue);\n\n for (const slug of slugs) {\n if (!sets.subResources.includes(slug)) {\n throw new InvalidSubResourceError({\n subResource: slug,\n resource: typeof resource === 'string' ? resource : undefined,\n validSubResources: [...sets.subResources],\n });\n }\n }\n }\n\n if (\n state.declaredPathParams.includes('component') &&\n component !== undefined\n ) {\n if (typeof component !== 'string' || !sets.components.includes(component)) {\n throw new InvalidComponentError({\n component,\n validComponents: [...sets.components],\n });\n }\n }\n\n if (!state.componentKeyDeclared) {\n return;\n }\n\n if (componentKey === undefined) {\n if (!state.componentKeyOptional) {\n throw new InvalidComponentError({\n component: componentKey,\n validComponents: [...sets.components],\n reason: 'A \"componentKey\" prop is required for this component',\n });\n }\n\n return;\n }\n\n if (\n typeof componentKey !== 'string' ||\n !sets.components.includes(componentKey)\n ) {\n throw new InvalidComponentError({\n component: componentKey,\n validComponents: [...sets.components],\n });\n }\n}\n\nfunction readClosureProps(\n selected: string[],\n closure: unknown,\n): Record<string, unknown> {\n if (selected.length === 0) {\n return {};\n }\n\n const [only] = selected;\n\n if (selected.length === 1 && only !== undefined) {\n return { [only]: closure };\n }\n\n if (\n typeof closure === 'object' &&\n closure !== null &&\n !Array.isArray(closure)\n ) {\n return { ...(closure as Record<string, unknown>) };\n }\n\n return {};\n}\n\nfunction createRenderedComponent(\n runRenderer: (props: Record<string, unknown>) => JSX.Element,\n paramTemplate: Record<string, unknown> | undefined,\n resolveDisplayName?: (props: Record<string, unknown>) => string,\n boundProps: Record<string, unknown> = {},\n) {\n function RenderedPathView(props: Record<string, unknown>): JSX.Element {\n const merged = { ...boundProps, ...props };\n\n if (resolveDisplayName) {\n RenderedPathView.displayName = resolveDisplayName(merged);\n }\n\n return runRenderer(merged);\n }\n\n RenderedPathView.displayName = DEFAULT_DISPLAY_NAME;\n\n function asHOF(options?: { args?: Record<string, true> }) {\n const selected = Object.entries(options?.args ?? {})\n .filter(([, enabled]) => enabled === true)\n .map(([key]) => key);\n\n function hof(closure: unknown) {\n const bound = createRenderedComponent(\n runRenderer,\n undefined,\n resolveDisplayName,\n { ...boundProps, ...readClosureProps(selected, closure) },\n );\n\n bound.displayName = RenderedPathView.displayName;\n\n return bound;\n }\n\n return Object.assign(hof, { _args: undefined as never });\n }\n\n return Object.assign(RenderedPathView, {\n _args: paramTemplate as never,\n asHOF,\n });\n}\n\nexport function createTargetPathBuilder<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config extends Record<string, unknown>,\n Paths extends ReadonlyArray<string>,\n>(config: Config, paths: Paths): TargetPathBuilder<Resources, Config, Paths> {\n const validationSets = collectValidationSets(config, paths);\n\n const makeBuilder = (state: BuilderState): Record<string, unknown> => {\n const builder: Record<string, unknown> = {};\n\n if (!state.usedComponentKeyParams) {\n builder.addComponentKeyParams = (options?: { optional?: boolean }) =>\n makeBuilder({\n ...state,\n usedComponentKeyParams: true,\n componentKeyDeclared: true,\n componentKeyOptional: options?.optional === true,\n });\n }\n\n if (!state.usedPathParams) {\n builder.addPathParams = (options?: { pick?: Record<string, true> }) => {\n const available = new Set<string>();\n\n for (const path of state.paths) {\n for (const name of extractPathVariables(path)) {\n available.add(name);\n }\n }\n\n const picked = Object.entries(options?.pick ?? {})\n .filter(([, enabled]) => enabled === true)\n .map(([key]) => key);\n const declared =\n picked.length === 0\n ? [...available]\n : picked.filter((name) => available.has(name));\n\n return makeBuilder({\n ...state,\n usedPathParams: true,\n declaredPathParams: [...state.declaredPathParams, ...declared],\n });\n };\n }\n\n if (!state.usedParams) {\n builder.addParams = (params: Record<string, unknown>) =>\n makeBuilder({\n ...state,\n usedParams: true,\n paramDefaults: { ...state.paramDefaults, ...params },\n });\n }\n\n builder.render = (\n renderer: (context: {\n params: Record<string, unknown>;\n getComponentForPath: unknown;\n }) => JSX.Element,\n ) => {\n const buildContext = (props: Record<string, unknown>) => {\n const params = { ...state.paramDefaults, ...props };\n\n validateParams(params, state, validationSets);\n\n return {\n params,\n getComponentForPath: (path: string) => {\n if (!state.paths.includes(path)) {\n throw new InvalidPathError({\n path,\n validPaths: [...state.paths],\n reason: 'This component was not built for that path',\n });\n }\n\n return createGetComponentForPath(config, path);\n },\n };\n };\n\n const runRenderer = (props: Record<string, unknown>) =>\n renderer(buildContext(props));\n\n const component = createRenderedComponent(runRenderer, {\n ...state.paramDefaults,\n });\n\n return Object.assign(component, {\n setDisplayName: (\n name:\n | string\n | ((context: {\n params: Record<string, unknown>;\n getComponentForPath: unknown;\n }) => string),\n ) => {\n if (typeof name === 'string') {\n const named = createRenderedComponent(runRenderer, {\n ...state.paramDefaults,\n });\n\n named.displayName = name;\n\n return named;\n }\n\n return createRenderedComponent(\n runRenderer,\n { ...state.paramDefaults },\n (props) => name(buildContext(props)),\n );\n },\n });\n };\n\n return builder;\n };\n\n return makeBuilder({\n paths,\n paramDefaults: {},\n declaredPathParams: [],\n componentKeyDeclared: false,\n componentKeyOptional: false,\n usedComponentKeyParams: false,\n usedPathParams: false,\n usedParams: false,\n }) as unknown as TargetPathBuilder<Resources, Config, Paths>;\n}\n\nexport function createForPaths<\n Resources extends ReadonlyArray<ResourceDefinition>,\n Config extends Record<string, unknown>,\n>(config: Config): ForPaths<Resources, Config, string> {\n const validPaths = generateResourceConfigPaths(config);\n\n return ((...paths: string[]) => {\n if (paths.length === 0) {\n throw new InvalidPathError({\n path: paths,\n validPaths,\n reason: 'At least one path is required',\n });\n }\n\n for (const path of paths) {\n if (!validPaths.includes(path)) {\n throw new InvalidPathError({ path, validPaths });\n }\n }\n\n return createTargetPathBuilder(config, paths);\n }) as unknown as ForPaths<Resources, Config, string>;\n}\n"],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@ function validateParams(params, state, sets) {
|
|
|
34
34
|
if (state.declaredPathParams.includes("resource") && resource !== void 0) {
|
|
35
35
|
if (typeof resource !== "string" || !sets.resources.includes(resource)) throw new InvalidResourceError({
|
|
36
36
|
resource,
|
|
37
|
-
validResources: sets.resources
|
|
37
|
+
validResources: [...sets.resources]
|
|
38
38
|
});
|
|
39
39
|
}
|
|
40
40
|
if (state.declaredPathParams.includes("subResource") && subResource !== void 0) {
|
|
@@ -42,27 +42,27 @@ function validateParams(params, state, sets) {
|
|
|
42
42
|
for (const slug of slugs) if (!sets.subResources.includes(slug)) throw new InvalidSubResourceError({
|
|
43
43
|
subResource: slug,
|
|
44
44
|
resource: typeof resource === "string" ? resource : void 0,
|
|
45
|
-
validSubResources: sets.subResources
|
|
45
|
+
validSubResources: [...sets.subResources]
|
|
46
46
|
});
|
|
47
47
|
}
|
|
48
48
|
if (state.declaredPathParams.includes("component") && component !== void 0) {
|
|
49
49
|
if (typeof component !== "string" || !sets.components.includes(component)) throw new InvalidComponentError({
|
|
50
50
|
component,
|
|
51
|
-
validComponents: sets.components
|
|
51
|
+
validComponents: [...sets.components]
|
|
52
52
|
});
|
|
53
53
|
}
|
|
54
54
|
if (!state.componentKeyDeclared) return;
|
|
55
55
|
if (componentKey === void 0) {
|
|
56
56
|
if (!state.componentKeyOptional) throw new InvalidComponentError({
|
|
57
57
|
component: componentKey,
|
|
58
|
-
validComponents: sets.components,
|
|
58
|
+
validComponents: [...sets.components],
|
|
59
59
|
reason: "A \"componentKey\" prop is required for this component"
|
|
60
60
|
});
|
|
61
61
|
return;
|
|
62
62
|
}
|
|
63
63
|
if (typeof componentKey !== "string" || !sets.components.includes(componentKey)) throw new InvalidComponentError({
|
|
64
64
|
component: componentKey,
|
|
65
|
-
validComponents: sets.components
|
|
65
|
+
validComponents: [...sets.components]
|
|
66
66
|
});
|
|
67
67
|
}
|
|
68
68
|
function readClosureProps(selected, closure) {
|
|
@@ -140,7 +140,7 @@ function createTargetPathBuilder(config, paths) {
|
|
|
140
140
|
getComponentForPath: (path) => {
|
|
141
141
|
if (!state.paths.includes(path)) throw new InvalidPathError({
|
|
142
142
|
path,
|
|
143
|
-
validPaths: state.paths,
|
|
143
|
+
validPaths: [...state.paths],
|
|
144
144
|
reason: "This component was not built for that path"
|
|
145
145
|
});
|
|
146
146
|
return createGetComponentForPath(config, path);
|