diff --git a/packages/editor/src/editor/store.ts b/packages/editor/src/editor/store.ts index 414e48b..da6b732 100644 --- a/packages/editor/src/editor/store.ts +++ b/packages/editor/src/editor/store.ts @@ -16,11 +16,17 @@ import { didRectsChange } from './history'; import { snapRect, snapRectResize } from './snap'; import type { EditorState, ResizeHandle } from './types'; import { clampRectToBounds } from './types'; -type UpdateWidgetPropsAction = - | { type: 'updateWidgetProps'; widgetType: 'text'; id: string; props: Partial } - | { type: 'updateWidgetProps'; widgetType: 'image'; id: string; props: Partial } - | { type: 'updateWidgetProps'; widgetType: 'iframe'; id: string; props: Partial } - | { type: 'updateWidgetProps'; widgetType: 'video'; id: string; props: Partial }; +type EditorWidgetKind = 'text' | 'image' | 'iframe' | 'video'; + +type UpdateWidgetPropsAction = { + type: 'updateWidgetProps'; + id: string; +} & { + [K in EditorWidgetKind]: { + widgetType: K; + props: Partial; + }; +}[EditorWidgetKind]; export type EditorAction = | { type: 'keyboard'; ctrl: boolean; space: boolean } @@ -95,30 +101,44 @@ function isWidgetType( return node.type === widgetType; } -function updateWidgetProps( - state: EditorRuntimeState, - action: Extract, -): EditorRuntimeState { - const target = state.doc.screen.nodes.find( - (n): n is WidgetNodeByType[K] => n.id === action.id && n.type === action.widgetType, - ); - if (!target) return state; +function updateWidgetProps(state: EditorRuntimeState, action: UpdateWidgetPropsAction): EditorRuntimeState { + // Helper to keep the per-widget prop merge strongly typed. + const update = (widgetType: K, props: Partial): EditorRuntimeState => { + const target = state.doc.screen.nodes.find( + (n): n is WidgetNodeByType[K] => n.id === action.id && n.type === widgetType, + ); + if (!target) return state; - return { - ...historyPush(state), - doc: { - screen: { - ...state.doc.screen, - nodes: state.doc.screen.nodes.map((n) => { - if (n.id !== action.id || !isWidgetType(n, action.widgetType)) return n; - return { - ...n, - props: { ...n.props, ...action.props }, - }; - }), + return { + ...historyPush(state), + doc: { + screen: { + ...state.doc.screen, + nodes: state.doc.screen.nodes.map((n) => { + if (n.id !== action.id || !isWidgetType(n, widgetType)) return n; + return { + ...n, + props: { ...n.props, ...props }, + }; + }), + }, }, - }, + }; }; + + switch (action.widgetType) { + case 'text': + return update('text', action.props); + case 'image': + return update('image', action.props); + case 'iframe': + return update('iframe', action.props); + case 'video': + return update('video', action.props); + default: + // If the SDK adds a new widget kind, the editor can safely ignore it until supported. + return state; + } } function historyPush(state: EditorRuntimeState): EditorRuntimeState { @@ -253,18 +273,7 @@ export function editorReducer(state: EditorRuntimeState, action: EditorAction): } case 'updateWidgetProps': { - switch (action.widgetType) { - case 'text': - return updateWidgetProps(state, action); - case 'image': - return updateWidgetProps(state, action); - case 'iframe': - return updateWidgetProps(state, action); - case 'video': - return updateWidgetProps(state, action); - default: - return assertNever(action); - } + return updateWidgetProps(state, action); } case 'deleteSelected': {