LayoutProps, ComponentType and other helpers
Small helper types: a custom layout's props, the components the registry stores, loosely shaped JSON data, and nested translations.
import { LayoutProps, ComponentType, ComponentDefinition, JsonObject, TranslationMap } from '@salla.sa/twilight-theme-engine/types';In plain words
Helpers the other types build on. LayoutProps is { children }, the props of a layout component you pass to TwilightProvider. ComponentType and ComponentDefinition describe the components the engine's registry stores. JsonObject stands for loosely shaped API data, and TranslationMap for nested translation strings.
Signature
interface LayoutProps { children: ReactNode }
type ComponentType<P = Record<string, unknown>> = React.ComponentType<P>;
interface ComponentDefinition {
component: ComponentType;
displayName?: string;
original?: ComponentDefinition; // what an override replaced
}
type JsonObject = { [key: string]: {} }; // any non-null value
interface TranslationMap { [key: string]: string | TranslationMap }Example
import type { LayoutProps } from '@salla.sa/twilight-theme-engine/types';
import { MasterLayout } from '@salla.sa/twilight-theme-engine/components/layout';
/** Wraps every page: the engine header and footer, plus a shell of the theme's own. */
export function ThemeLayout({ children }: LayoutProps) {
return (
<MasterLayout>
<div className="theme-shell">{children}</div>
</MasterLayout>
);
}
// app/routes/__root.tsx: <TwilightProvider layout={ThemeLayout}>…</TwilightProvider>
How it behaves
TwilightProviderrenderslayout(typedComponentType<LayoutProps> | false, defaultMasterLayout) around every page.@salla.sa/twilight-theme-engine/components/layoutexports an identicalLayoutProps.ComponentTypeis React'sComponentTypewith a different default:Record<string, unknown>props instead of{}.No public function returns a
ComponentDefinition: the registry keeps them in a private map, andregistry.resolve(name)andregistry.getOriginal(name)hand back the components inside.JsonObjecttypesProduct.digital_files_settings,Product.preorder,CartItem.donation,NotifyAvailability.subscribed_optionsandHomeComponentData.component. Its values are{}on purpose, to fit TanStack Router's type inference.Nothing in the engine uses
TranslationMap: thetranslationsprop ofTwilightProvideris typedTranslationMessages(Record<string, Record<string, string>>, from@salla.sa/twilight-theme-engine/i18n).
Gotchas
registerComponentsandoverrideComponentstakeRecord<string, ComponentType>, and a component with a required prop does not fit:registerComponents({ "product:card": Card })withCard({ product }: { product: Product })fails with TS2322.registry.registeranddefineComponentare generic and accept it.A
JsonObjectvalue is typed{}:const count: number = data.countfails, and{ a: null }is rejected even though the API does sendnullin such fields (preorderarrives asnullin details and[]on list cards, demo store). Narrow withtypeofbefore use.
Related
The component a theme mounts once around its pages; it shares the store, theme, language and navigation with everything inside it.
MasterLayoutThe default page frame: header, main content and footer, plus the login, offer and branch pop-ups a storefront needs.
registryThe shared name-to-component table the engine consults for a few swappable parts: the product card, the product gallery and home blocks.
registerComponents, overrideComponentsRegister or override many named components in one call, from an object whose keys are names and whose values are components.
defineComponentRegisters a component under a name when its file loads, and returns the same component so it can also be imported and rendered directly.