You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
131 lines
2.8 KiB
TypeScript
131 lines
2.8 KiB
TypeScript
import { Reducer } from "preact/hooks";
|
|
import {
|
|
Field,
|
|
FieldKind,
|
|
FieldOptions,
|
|
MaybePersistedSchema,
|
|
defaultOptionsForFieldKind,
|
|
} from "../../../common/schema.ts";
|
|
import { ViewState } from "../App/state.ts";
|
|
import { ReturnTypes, UnionToIntersection } from "../../../common/utils.ts";
|
|
import { deleteIdx, setIdx, setProp } from "../../../common/lib/imm.ts";
|
|
|
|
export const setName = (name: string) => ({ kind: "setName" as const, name });
|
|
export const addField = () => ({ kind: "addField" as const });
|
|
export const setFieldProp = <K extends keyof Field>(
|
|
index: number,
|
|
prop: K,
|
|
value: Field[K],
|
|
) => ({
|
|
kind: "setFieldProp" as const,
|
|
index,
|
|
prop,
|
|
value,
|
|
});
|
|
|
|
export type AllOptions = UnionToIntersection<FieldOptions[FieldKind]>;
|
|
export const setFieldOption = <K extends keyof AllOptions>(
|
|
index: number,
|
|
option: K,
|
|
value: AllOptions[K],
|
|
) => ({
|
|
kind: "setFieldOption" as const,
|
|
index,
|
|
option,
|
|
value,
|
|
});
|
|
export const deleteField = (index: number) => ({
|
|
kind: "deleteField" as const,
|
|
index,
|
|
});
|
|
export type Action = ReturnTypes<
|
|
[
|
|
typeof setName,
|
|
typeof addField,
|
|
typeof setFieldProp,
|
|
typeof deleteField,
|
|
typeof setFieldOption,
|
|
]
|
|
>;
|
|
|
|
export type State = MaybePersistedSchema;
|
|
|
|
const reduce_ = (state: State, action: Action): ViewState => {
|
|
if (action.kind == "setName") {
|
|
return {
|
|
kind: "SchemaEditor",
|
|
state: {
|
|
...state,
|
|
name: action.name,
|
|
},
|
|
};
|
|
} else if (action.kind == "addField") {
|
|
return {
|
|
kind: "SchemaEditor",
|
|
state: {
|
|
...state,
|
|
fields: [
|
|
...state.fields,
|
|
{
|
|
kind: "string",
|
|
name: "New field",
|
|
options: defaultOptionsForFieldKind("string"),
|
|
required: false,
|
|
},
|
|
],
|
|
},
|
|
};
|
|
} else if (action.kind == "setFieldProp") {
|
|
let field = setProp(state.fields[action.index], action.prop, action.value);
|
|
if (action.prop == "kind") {
|
|
field = setProp(field, "options", {
|
|
...defaultOptionsForFieldKind(field.kind),
|
|
...field.options,
|
|
});
|
|
}
|
|
|
|
return {
|
|
kind: "SchemaEditor",
|
|
state: {
|
|
...state,
|
|
fields: setIdx(state.fields, action.index, field),
|
|
},
|
|
};
|
|
} else if (action.kind == "setFieldOption") {
|
|
return {
|
|
kind: "SchemaEditor",
|
|
state: setProp(
|
|
state,
|
|
"fields",
|
|
setIdx(
|
|
state.fields,
|
|
action.index,
|
|
setProp(
|
|
state.fields[action.index],
|
|
"options",
|
|
setProp(
|
|
state.fields[action.index].options,
|
|
action.option as never,
|
|
action.value as never,
|
|
),
|
|
),
|
|
),
|
|
),
|
|
};
|
|
} else if (action.kind == "deleteField") {
|
|
return {
|
|
kind: "SchemaEditor",
|
|
state: setProp(state, "fields", deleteIdx(state.fields, action.index)),
|
|
};
|
|
}
|
|
|
|
return {
|
|
kind: "SchemaEditor",
|
|
state,
|
|
};
|
|
};
|
|
|
|
export const reduce: Reducer<ViewState, Action> = (state, action) => {
|
|
return reduce_(state.state as State, action);
|
|
};
|