import { Context } from "koa"; import { FlatTemplatable, tempstream } from "tempstream"; import { getRequiredClass, inputWrapper } from "../../utils/input-wrapper.js"; import { renderAttributes } from "../../utils/render-attributes.js"; import { FormField } from "../fields/field.js"; import { FormDataValue } from "../form-types.js"; import { FormControlContext } from "./form-control.js"; import { FormFieldControl } from "./form-field-control.js"; import { SimpleFormField } from "../fields/simple-form-field.js"; export type SimpleInputOptions = { id?: string; label?: string; autocomplete?: boolean; hide_errors?: boolean; type?: string; value?: string; placeholder?: string; readonly?: boolean; step?: number; suffix?: string; pattern?: string; inputmode?: string; }; export class SimpleInput< Options extends SimpleInputOptions = SimpleInputOptions, > extends FormFieldControl { options: SimpleInputOptions; constructor( // eslint-disable-next-line @typescript-eslint/no-explicit-any public field: FormField, options?: Options ) { super([field]); this.options = options || {}; } async preInput( _ctx: FormControlContext, _data: Record ): Promise { return ""; } getType(): string { return this.options.type || "text"; } getLabel(): string { return this.options.label != undefined ? this.options.label : this.field.label || this.field.name; } getID(): string { return this.options.id || this.field.name; } getPlaceholder(): string { if (this.field instanceof SimpleFormField && this.field.placeholder) { return this.field.placeholder; } return this.options.placeholder === "" ? "" : this.options.placeholder || this.getType(); } async getInputAttributes( fctx: FormControlContext ): Promise> { const readonly = this.options.readonly || false; const required = this.field.required; const { raw, valid } = await this.field.getParsedValue( fctx.ctx, fctx.data.raw_values, true ); return Object.fromEntries([ ["id", this.getID()], ["type", this.getType()], ["name", `${fctx.field_name_prefix}${this.field.name}`], ["value", raw], ...(fctx.form_id ? [["form", fctx.form_id]] : []), ["placeholder", this.getPlaceholder()], ...(readonly ? [["readonly", true]] : []), ...(required ? [["required", true]] : []), ...(!this.options.autocomplete ? [["autocomplete", "off"]] : []), ...(this.options.step ? [["step", this.options.step]] : []), ["aria-invalid", String(!valid)], ["disabled", this.field.disabled], ...(this.options.inputmode ? [["inputmode", this.options.inputmode]] : []), ]) as Record; } async postInput(_: Context): Promise { return this.options.suffix ? /* HTML */ `${this.options.suffix}` : ""; } async renderInput( _ctx: Context, attributes_str: string, _data: Record ): Promise { return ``; } getWrapperModifiers(): string[] { return [ this.getID(), this.getType(), "type__" + this.getType(), getRequiredClass(this.field.required), ]; } async render(fctx: FormControlContext): Promise { const id = this.getID(); const label = this.getLabel(); const { valid, message } = await this.field.getParsedValue( fctx.ctx, fctx.data.raw_values, true ); return inputWrapper( "simple-input", this.getWrapperModifiers(), tempstream /* HTML */ ` ${label ? `` : ""} ${await this.preInput(fctx, fctx.data.raw_values)} ${this.renderInput( fctx.ctx, renderAttributes(await this.getInputAttributes(fctx)), fctx.data.raw_values )} ${this.postInput(fctx.ctx)} ${~valid && !this.options.hide_errors && fctx.validate ? `
${[ message, fctx.data.field_messages?.[this.field.name]?.message, ] .filter((e) => !!e) .join(" ยท ")}
` : ""} ` ); } }