;
customClassName?: string;
+ /** Injected by NodeRenderer — the node's id (equals widgetInstanceId in node mode). */
+ nodeId?: string;
+ /** Injected by NodeRenderer — layout hints for structural nodes. */
+ layout?: NodeLayout;
+ /** Populated by NodeRenderer for nodes with canHaveChildren: true. */
+ children?: ReactNode;
}
export type WidgetCategory =
@@ -75,6 +119,8 @@ export interface WidgetDefinition {
editComponent?: React.LazyExoticComponent>;
previewComponent?: ComponentType;
validate?: (props: P) => Record | null;
+ /** Node model: structural constraints evaluated at runtime (not persisted). */
+ constraints?: NodeConstraints;
}
export interface WidgetInstance {
@@ -86,7 +132,10 @@ export interface WidgetInstance {
// ─── Plugins & hooks (§13) ───────────────────────────────────────────────────
-export type LayoutStore = Record;
+/** Read-only snapshot exposed to plugins via PluginAPI.getStore(). */
+export type LayoutStore = {
+ pages: Record;
+};
export interface HookContext {
pluginId: string;
@@ -140,6 +189,15 @@ export type WidgetWrapper = (
Component: ComponentType
,
) => ComponentType
;
+/** Minimal accessor interface passed into PluginManager / createPluginAPI. */
+export interface LayoutStoreAccessor {
+ getState: () => Readonly;
+ subscribe: (
+ selector: (state: LayoutStore) => T,
+ callback: (value: T) => void,
+ ) => () => void;
+}
+
export interface PluginAPI {
registerWidget: (definition: WidgetDefinition
) => void;
unregisterWidget: (widgetId: string) => void;