refactor(editor): stabilize updateWidgetProps typing
This commit is contained in:
parent
3c3c2b74aa
commit
4e7bf37fdd
@ -16,11 +16,17 @@ import { didRectsChange } from './history';
|
|||||||
import { snapRect, snapRectResize } from './snap';
|
import { snapRect, snapRectResize } from './snap';
|
||||||
import type { EditorState, ResizeHandle } from './types';
|
import type { EditorState, ResizeHandle } from './types';
|
||||||
import { clampRectToBounds } from './types';
|
import { clampRectToBounds } from './types';
|
||||||
type UpdateWidgetPropsAction =
|
type EditorWidgetKind = 'text' | 'image' | 'iframe' | 'video';
|
||||||
| { type: 'updateWidgetProps'; widgetType: 'text'; id: string; props: Partial<WidgetPropsByType['text']> }
|
|
||||||
| { type: 'updateWidgetProps'; widgetType: 'image'; id: string; props: Partial<WidgetPropsByType['image']> }
|
type UpdateWidgetPropsAction = {
|
||||||
| { type: 'updateWidgetProps'; widgetType: 'iframe'; id: string; props: Partial<WidgetPropsByType['iframe']> }
|
type: 'updateWidgetProps';
|
||||||
| { type: 'updateWidgetProps'; widgetType: 'video'; id: string; props: Partial<WidgetPropsByType['video']> };
|
id: string;
|
||||||
|
} & {
|
||||||
|
[K in EditorWidgetKind]: {
|
||||||
|
widgetType: K;
|
||||||
|
props: Partial<WidgetPropsByType[K]>;
|
||||||
|
};
|
||||||
|
}[EditorWidgetKind];
|
||||||
|
|
||||||
export type EditorAction =
|
export type EditorAction =
|
||||||
| { type: 'keyboard'; ctrl: boolean; space: boolean }
|
| { type: 'keyboard'; ctrl: boolean; space: boolean }
|
||||||
@ -95,30 +101,44 @@ function isWidgetType<K extends WidgetKind>(
|
|||||||
return node.type === widgetType;
|
return node.type === widgetType;
|
||||||
}
|
}
|
||||||
|
|
||||||
function updateWidgetProps<K extends WidgetKind>(
|
function updateWidgetProps(state: EditorRuntimeState, action: UpdateWidgetPropsAction): EditorRuntimeState {
|
||||||
state: EditorRuntimeState,
|
// Helper to keep the per-widget prop merge strongly typed.
|
||||||
action: Extract<UpdateWidgetPropsAction, { widgetType: K }>,
|
const update = <K extends EditorWidgetKind>(widgetType: K, props: Partial<WidgetPropsByType[K]>): EditorRuntimeState => {
|
||||||
): EditorRuntimeState {
|
const target = state.doc.screen.nodes.find(
|
||||||
const target = state.doc.screen.nodes.find(
|
(n): n is WidgetNodeByType[K] => n.id === action.id && n.type === widgetType,
|
||||||
(n): n is WidgetNodeByType[K] => n.id === action.id && n.type === action.widgetType,
|
);
|
||||||
);
|
if (!target) return state;
|
||||||
if (!target) return state;
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...historyPush(state),
|
...historyPush(state),
|
||||||
doc: {
|
doc: {
|
||||||
screen: {
|
screen: {
|
||||||
...state.doc.screen,
|
...state.doc.screen,
|
||||||
nodes: state.doc.screen.nodes.map((n) => {
|
nodes: state.doc.screen.nodes.map((n) => {
|
||||||
if (n.id !== action.id || !isWidgetType(n, action.widgetType)) return n;
|
if (n.id !== action.id || !isWidgetType(n, widgetType)) return n;
|
||||||
return {
|
return {
|
||||||
...n,
|
...n,
|
||||||
props: { ...n.props, ...action.props },
|
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 {
|
function historyPush(state: EditorRuntimeState): EditorRuntimeState {
|
||||||
@ -253,18 +273,7 @@ export function editorReducer(state: EditorRuntimeState, action: EditorAction):
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 'updateWidgetProps': {
|
case 'updateWidgetProps': {
|
||||||
switch (action.widgetType) {
|
return updateWidgetProps(state, action);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'deleteSelected': {
|
case 'deleteSelected': {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user