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 type { EditorState, ResizeHandle } from './types';
|
||||
import { clampRectToBounds } from './types';
|
||||
type UpdateWidgetPropsAction =
|
||||
| { type: 'updateWidgetProps'; widgetType: 'text'; id: string; props: Partial<WidgetPropsByType['text']> }
|
||||
| { type: 'updateWidgetProps'; widgetType: 'image'; id: string; props: Partial<WidgetPropsByType['image']> }
|
||||
| { type: 'updateWidgetProps'; widgetType: 'iframe'; id: string; props: Partial<WidgetPropsByType['iframe']> }
|
||||
| { type: 'updateWidgetProps'; widgetType: 'video'; id: string; props: Partial<WidgetPropsByType['video']> };
|
||||
type EditorWidgetKind = 'text' | 'image' | 'iframe' | 'video';
|
||||
|
||||
type UpdateWidgetPropsAction = {
|
||||
type: 'updateWidgetProps';
|
||||
id: string;
|
||||
} & {
|
||||
[K in EditorWidgetKind]: {
|
||||
widgetType: K;
|
||||
props: Partial<WidgetPropsByType[K]>;
|
||||
};
|
||||
}[EditorWidgetKind];
|
||||
|
||||
export type EditorAction =
|
||||
| { type: 'keyboard'; ctrl: boolean; space: boolean }
|
||||
@ -95,30 +101,44 @@ function isWidgetType<K extends WidgetKind>(
|
||||
return node.type === widgetType;
|
||||
}
|
||||
|
||||
function updateWidgetProps<K extends WidgetKind>(
|
||||
state: EditorRuntimeState,
|
||||
action: Extract<UpdateWidgetPropsAction, { widgetType: K }>,
|
||||
): 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 = <K extends EditorWidgetKind>(widgetType: K, props: Partial<WidgetPropsByType[K]>): 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': {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user