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.

152 lines
3.6 KiB
TypeScript

import { VNode, h } from "preact";
import {
FieldKind,
FieldOptions as FieldOptionsModels,
} from "../../../../common/schema.ts";
import { ValidationErrors } from "../../../../common/validation.ts";
import { Select } from "../../lib/input/Select.ts";
import { Labeled } from "../../lib/Labeled.ts";
import { NumberInput } from "../../lib/input/NumberInput.ts";
import { Callback } from "../../../utils.ts";
import { Checkbox } from "../../lib/input/Checkbox.ts";
import { ShowHide } from "../../lib/ShowHide.ts";
import { Validated } from "../../lib/input/Validated.ts";
const ToggleField = (p: {
label: string;
onToggle: Callback<[boolean]>;
errors?: string[];
show: boolean;
inner: () => VNode;
}) => {
return h(
"div",
{ class: "toggle-field" },
h(
Validated,
{ errors: p.errors },
h(
Labeled,
{ label: p.label },
h(Checkbox, { onToggle: p.onToggle, checked: p.show }),
),
h(ShowHide, { show: p.show, inner: p.inner }),
),
);
};
export type SetFieldOption<K extends FieldKind = FieldKind> = <
KK extends keyof FieldOptionsModels[K],
>(
optionProp: KK,
value: FieldOptionsModels[K][KK],
) => void;
type Props<K extends FieldKind> = {
options: FieldOptionsModels[K];
errors?: ValidationErrors<FieldOptionsModels[K]>;
setFieldOption: SetFieldOption<K>;
};
const StringFieldOptions = (p: Props<"string">) => {
type DisplayAs = FieldOptionsModels["string"]["displayAs"];
const displayAs = h(
Labeled,
{ label: "Display as" },
h(Select<DisplayAs>, {
value: p.options.displayAs,
options: {
input: "input",
textarea: "textarea",
},
onChange: (v) => p.setFieldOption("displayAs", v),
}),
);
const minLength = h(
Validated,
{ errors: p.errors?.minLength },
h(
Labeled,
{ label: "Min length" },
h(NumberInput, {
max: p.options.maxLength,
value: p.options.minLength,
onInput: (v) => p.setFieldOption("minLength", v),
}),
),
);
const maxLength = h(ToggleField, {
label: "Max length?",
errors: p.errors?.maxLength,
show: p.options.maxLength != undefined,
onToggle: (active) => p.setFieldOption("maxLength", active ? 0 : undefined),
inner: () => {
return h(NumberInput, {
value: p.options.maxLength ?? 0,
min: p.options.minLength,
onInput: (v) => p.setFieldOption("maxLength", v),
});
},
});
return h(
"div",
{ class: "field-options string" },
displayAs,
minLength,
maxLength,
);
};
const NumberFieldOptions = (p: Props<"number">) => {
const min = h(ToggleField, {
errors: p.errors?.min,
label: "Min?",
show: p.options.min != undefined,
onToggle: (b) => p.setFieldOption("min", b ? 0 : undefined),
inner: () =>
h(NumberInput, {
max: p.options.max,
value: p.options.min ?? 0,
onInput: (v) => p.setFieldOption("min", v),
}),
});
const max = h(ToggleField, {
errors: p.errors?.max,
label: "Max?",
show: p.options.max != undefined,
onToggle: (b) => p.setFieldOption("max", b ? 0 : undefined),
inner: () =>
h(NumberInput, {
min: p.options.min,
value: p.options.max ?? 0,
onInput: (v) => p.setFieldOption("max", v),
}),
});
return h("div", { class: "field-options number" }, min, max);
};
type FieldOptionComponentRegistry = {
[K in FieldKind]: (p: Props<K>) => VNode;
};
const FIELD_OPTION_COMPONENT_REGISTRY: FieldOptionComponentRegistry = {
number: NumberFieldOptions,
string: StringFieldOptions,
};
export const FieldOptions = (p: {
kind: FieldKind;
options: FieldOptionsModels[FieldKind];
errors?: ValidationErrors<FieldOptionsModels[FieldKind]>;
setFieldOption: SetFieldOption<FieldKind>;
}) => {
const Component = FIELD_OPTION_COMPONENT_REGISTRY[p.kind];
return h(Component as any, p);
};