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
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);
|
|
};
|