mirror of
https://github.com/lifegpc/eh-downloader.git
synced 2026-06-06 13:48:51 +08:00
131 lines
4.1 KiB
TypeScript
131 lines
4.1 KiB
TypeScript
import { Component, ComponentChildren, ContextType } from "preact";
|
|
import { SettingsCtx } from "./SettingsContext.tsx";
|
|
import type { ConfigType } from "../config.ts";
|
|
import TextField from "preact-material-components/TextField";
|
|
import { Ref, StateUpdater, useRef } from "preact/hooks";
|
|
|
|
interface TextType {
|
|
text: string;
|
|
password: string;
|
|
number: number;
|
|
}
|
|
|
|
interface DataType {
|
|
text: never;
|
|
password: never;
|
|
number: number;
|
|
}
|
|
|
|
export type SettingsTextProps<T extends keyof TextType> = {
|
|
value: TextType[T];
|
|
name: keyof ConfigType;
|
|
description: string;
|
|
type: T;
|
|
label?: string;
|
|
helpertext?: string;
|
|
textarea?: boolean;
|
|
fullwidth?: boolean;
|
|
disabled?: boolean;
|
|
children?: ComponentChildren;
|
|
set_value?: StateUpdater<TextType[T]>;
|
|
min?: DataType[T];
|
|
max?: DataType[T];
|
|
outlined?: boolean;
|
|
};
|
|
|
|
export default class SettingsText<T extends keyof TextType>
|
|
extends Component<SettingsTextProps<T>, unknown> {
|
|
static contextType = SettingsCtx;
|
|
ref: Ref<TextField | undefined> | undefined;
|
|
declare context: ContextType<typeof SettingsCtx>;
|
|
update(value: TextType[T]) {
|
|
const e = this.ref?.current;
|
|
if (e) {
|
|
const b = e.base;
|
|
if (b) {
|
|
const t = b as HTMLElement;
|
|
const d = t.querySelector("input");
|
|
if (d) {
|
|
const type = this.props.type;
|
|
// @ts-ignore Checked
|
|
if (type === "text" || type === "password") d.value = value;
|
|
// @ts-ignore Checked
|
|
else d.valueAsNumber = value;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
set_changed() {
|
|
if (this.context) {
|
|
this.context.set_changed((v) => {
|
|
v.add(this.props.name);
|
|
return v;
|
|
});
|
|
}
|
|
}
|
|
set_value(value: TextType[T]) {
|
|
if (this.props.set_value) {
|
|
this.props.set_value(value);
|
|
this.set_changed();
|
|
} else if (this.context) {
|
|
this.context.set_settings((v) => {
|
|
if (v) {
|
|
const t: Record<string, unknown> = v;
|
|
t[this.props.name] = value;
|
|
this.set_changed();
|
|
return t as ConfigType;
|
|
}
|
|
});
|
|
}
|
|
}
|
|
componentDidMount() {
|
|
this.update(this.props.value);
|
|
}
|
|
componentWillUpdate(
|
|
nextProps: Readonly<SettingsTextProps<T>>,
|
|
_nextState: Readonly<unknown>,
|
|
_nextContext: unknown,
|
|
) {
|
|
this.update(nextProps.value);
|
|
}
|
|
get_value(e: HTMLInputElement): TextType[T] {
|
|
const type = this.props.type;
|
|
// @ts-ignore Checked
|
|
if (type === "text" || type === "password") return e.value;
|
|
// @ts-ignore Checked
|
|
return e.valueAsNumber;
|
|
}
|
|
render() {
|
|
this.ref = useRef<TextField>();
|
|
const id = `s-${this.props.name}`;
|
|
let cn = "text";
|
|
if (this.props.helpertext) cn += " helper";
|
|
if (this.props.outlined) cn += " outlined";
|
|
if (this.props.label) cn += " label";
|
|
return (
|
|
<div class={cn} id={id}>
|
|
<label>{this.props.description}</label>
|
|
<TextField
|
|
fullwidth={this.props.fullwidth}
|
|
textarea={this.props.textarea}
|
|
type={this.props.type}
|
|
disabled={this.props.disabled}
|
|
helperText={this.props.helpertext}
|
|
label={this.props.label}
|
|
ref={this.ref}
|
|
onInput={(ev: InputEvent) => {
|
|
if (ev.target) {
|
|
const e = ev.target as HTMLInputElement;
|
|
this.set_value(this.get_value(e));
|
|
}
|
|
}}
|
|
min={this.props.min}
|
|
max={this.props.max}
|
|
outlined={this.props.outlined}
|
|
/>
|
|
{this.props.children}
|
|
</div>
|
|
);
|
|
}
|
|
}
|