chore: wip

Signed-off-by: blam <ben@blam.sh>
This commit is contained in:
blam
2024-07-30 15:47:45 +02:00
parent 3cd012c2dc
commit 66523e8d01
3 changed files with 223 additions and 14 deletions
@@ -22,6 +22,9 @@ import {
createExtension,
ResolvedExtensionInputs,
AnyExtensionInputMap,
createExtensionBlueprint,
ExtensionInput,
AnyExtensionDataRef,
} from '../wiring';
import { RouteRef } from '../routing';
import { Expand } from '../types';
@@ -95,3 +98,131 @@ export function createPageExtension<
},
});
}
export function createNewPageExtension<
TConfig extends { path: string },
TInputs extends {
[inputName in string]: ExtensionInput<
AnyExtensionDataRef,
{ optional: boolean; singleton: boolean }
>;
},
>(
options: (
| {
defaultPath: string;
}
| {
configSchema: PortableSchema<TConfig>;
}
) & {
namespace?: string;
name?: string;
attachTo?: { id: string; input: string };
disabled?: boolean;
inputs?: TInputs;
routeRef?: RouteRef;
loader: (options: {
config: TConfig;
inputs: Expand<ResolvedExtensionInputs<TInputs>>;
}) => Promise<JSX.Element>;
},
): ExtensionDefinition<TConfig> {
const configSchema =
'configSchema' in options
? options.configSchema
: (createSchemaFromZod(z =>
z.object({ path: z.string().default(options.defaultPath) }),
) as PortableSchema<TConfig>);
return createExtension({
kind: 'page',
namespace: options.namespace,
name: options.name,
attachTo: options.attachTo ?? { id: 'app/routes', input: 'routes' },
configSchema,
inputs: options.inputs,
disabled: options.disabled,
output: [
coreExtensionData.routePath,
coreExtensionData.reactElement,
coreExtensionData.routeRef.optional(),
],
factory({ config, inputs, node }) {
const ExtensionComponent = lazy(() =>
options
.loader({ config, inputs })
.then(element => ({ default: () => element })),
);
const outputs = [
coreExtensionData.routePath(config.path),
coreExtensionData.reactElement(
<ExtensionBoundary node={node}>
<ExtensionComponent />
</ExtensionBoundary>,
),
];
if (options.routeRef) {
return [...outputs, coreExtensionData.routeRef(options.routeRef)];
}
return outputs;
},
});
}
/**
* A blueprint for creating extensions for routable React page components.
* @public
*/
export const PageExtensionBlueprint = createExtensionBlueprint({
kind: 'page',
attachTo: { id: 'app/routes', input: 'routes' },
output: [
coreExtensionData.routePath,
coreExtensionData.reactElement,
coreExtensionData.routeRef.optional(),
],
config: {
schema: {
path: z => z.string().optional(),
},
},
factory(
{
defaultPath,
loader,
routeRef,
}: {
defaultPath?: string;
// TODO(blam) This type is impossible to type properly here as we don't have access
// to the input type generic. Maybe not a deal breaker though.
// It means we have to override the factory function in the `.make` method instead.
loader: (opts: unknown) => Promise<JSX.Element>;
routeRef?: RouteRef;
},
{ config, inputs, node },
) {
const ExtensionComponent = lazy(() =>
loader({ config, inputs }).then(element => ({ default: () => element })),
);
// TODO(blam): this is a little awkward for optional returns. I wonder if we should be using generators or yield instead
// for a better API here.
const outputs = [
coreExtensionData.routePath(config.path ?? defaultPath!),
coreExtensionData.reactElement(
<ExtensionBoundary node={node}>
<ExtensionComponent />
</ExtensionBoundary>,
),
];
if (routeRef) {
return [...outputs, coreExtensionData.routeRef(routeRef)];
}
return outputs;
},
});