/* Input.tsx - ESP3D WebUI component file Copyright (c) 2021 Alexandre Aussourd. All rights reserved. Modified by Luc LEBOSSE 2021 This code is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. This code is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with This code; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ import { FunctionalComponent, TargetedMouseEvent, TargetedKeyboardEvent, TargetedEvent, JSX } from "preact" import { useRef, useState, useEffect } from "preact/hooks" import { Eye, EyeOff, Search, ChevronDown, HelpCircle, XCircle, } from "preact-feather" import { ButtonImg } from "../../Controls" import { ScanApList } from "../ScanAp" import { T } from "./../../Translations" import { showModal } from "../../Modal" import { useUiContextFn, useSettingsContext, useModalsContext, } from "../../../contexts" import { generateDependIds, checkDependencies, } from "../../Helpers" import type { DependencyCondition } from "../../../types/dependencies.types" interface RevealProps { applyTo: { current: HTMLInputElement | null } } interface ClearTextProps { setValue?: (value: string) => void } interface DropListOption { value: string display: string } type ValueChangeCallback = (value: string | number | null, shouldValidate?: boolean) => void interface InputProps { label?: string type?: string id?: string value?: string | number width?: string setValue?: ValueChangeCallback options?: DropListOption[] extra?: string inline?: boolean append?: string depend?: DependencyCondition[] help?: string button?: JSX.Element disabled?: boolean prec?: string | number shortkey?: boolean step?: string | number [key: string]: any } const Reveal: FunctionalComponent = ({ applyTo }) => { const [reveal, setReveal] = useState(false) const clickReveal = () => { useUiContextFn.haptic() setReveal(!reveal) //note: reveal is not yet updated so need to upside down compare to use effect if (applyTo.current) { applyTo.current.type = reveal ? "password" : "text" } } useEffect(() => { //for consistency in case of redraw if (applyTo.current) { applyTo.current.type = reveal ? "text" : "password" } }, []) return (
{reveal ? ( ) : ( )}
) } const ClearText: FunctionalComponent = ({ setValue }) => { const clickClear = () => { useUiContextFn.haptic() if (setValue) setValue("") } useEffect(() => {}, []) return (
) } const Input: FunctionalComponent = ({ label = "", type = "text", id = "", value = "", width, setValue, options = [], extra, inline, append, depend, help, button, disabled, prec, shortkey, ...rest }) => { const { interfaceSettings, connectionSettings } = useSettingsContext() const dependIds = generateDependIds( depend, interfaceSettings.current.settings ) const { step } = rest const inputref = useRef(null) const appendtooltip = prec ? "tooltip tooltip-left" : "" const appendtooltipdata = prec ? T("S208").replace("$", prec.toString()) : "" const onKeyPress = (e: TargetedKeyboardEvent) => { if (!shortkey) return e.preventDefault() let v = "" let k = "" if ( !( e.key == "Control" || e.key == "Alt" || e.key == "Shift" || e.key == "Meta" ) ) k = e.key.toUpperCase() if (e.ctrlKey) v += "Control+" if (e.altKey) v += "Alt+" if (e.shiftKey) v += "Shift+" if (e.metaKey) v += "Meta+" e.currentTarget.value = v + k if (setValue) { setValue(e.currentTarget.value) } } const onInput = (e: TargetedEvent) => { if (shortkey) return if (setValue) { setValue(e.currentTarget.value) } } const { modals } = useModalsContext() const props = { type, id, name: id, value, step: step ? step : "any", } let ScanNetworks: (() => void) | null = null const refreshList = () => { if (ScanNetworks) ScanNetworks() } useEffect(() => { let visible = checkDependencies(depend, interfaceSettings.current.settings, connectionSettings.current) if (document.getElementById(id)) document.getElementById(id)!.style.display = visible ? "block" : "none" if (document.getElementById(`group-${ id}`)) document.getElementById(`group-${ id}`)!.style.display = visible ? "block" : "none" }, [...dependIds]) useEffect(() => { //to update state when import- but why ? if (setValue) setValue(null, true) }, [value]) if (shortkey) { return (
) } if (type === "password") return (
) if (extra == "dropList") { return (
{append && ( {T(append)} )} {options.length > 0 && ( } data-tooltip={T(help)} onClick={(e: TargetedMouseEvent) => { useUiContextFn.haptic() e.currentTarget.blur() const modalId = `list${ id}` showModal({ modals, title: T("S198"), button2: { text: T("S24") }, icon: , id: modalId, content: (
    {options.map((option) => { return (
  • ) => { useUiContextFn.haptic() setValue && setValue(option.value) modals.removeModal( modals.getModalIndex( modalId ) ) }} > {option.display}
  • ) })}
), }) }} /> )}
) } if (extra == "scan") { return (
} onClick={(e: TargetedMouseEvent) => { useUiContextFn.haptic() e.currentTarget.blur() const modalId = "scan" showModal({ modals, title: T("S45"), button2: { text: T("S24") }, button1: { cb: refreshList, text: T("S50"), noclose: true, }, icon: , id: modalId, content: ( setValue && setValue(value)} refreshfn={(scannetwork: () => void) => (ScanNetworks = scannetwork) } /> ), }) }} />
) } //we can do a better way to remove class by doing a split a fitter on several key name and then join //but this is a quick fix let classAddition = "" if (rest.class) classAddition = rest.class.replace("form-input", "") return (
{append && ( {T(append)} )} {button}
) } export default Input