commit 759b941d2431c23ca53792c8af791fe0b0717141
parent 112b0dc323371d11360c7ee3cf6655b0bd66c8d3
Author: Sebastian <sebasjm@taler-systems.com>
Date: Fri, 27 Feb 2026 10:02:56 -0300
fix #11165
Diffstat:
7 files changed, 74 insertions(+), 22 deletions(-)
diff --git a/packages/merchant-backoffice-ui/src/components/SolveMFA.tsx b/packages/merchant-backoffice-ui/src/components/SolveMFA.tsx
@@ -161,6 +161,7 @@ function SolveChallenge({
focus={focus}
readonly={showExpired}
dontRemember
+ inputType="numeric"
/>
{expiration.t_ms === "never" ? undefined : (
<p>
diff --git a/packages/merchant-backoffice-ui/src/components/form/Input.tsx b/packages/merchant-backoffice-ui/src/components/form/Input.tsx
@@ -22,8 +22,18 @@ import { ComponentChildren, h, VNode } from "preact";
import { InputProps, useField } from "./useField.js";
import { Tooltip } from "../Tooltip.js";
+export type SupportedTextInputType =
+ | "text"
+ | "numeric"
+ | "decimal"
+ | "tel"
+ | "email"
+ | "url"
+ | "search"
+ | "multiline"
+ | "password";
interface Props<T> extends InputProps<T> {
- inputType?: "text" | "number" | "multiline" | "password";
+ inputType?: SupportedTextInputType;
expand?: boolean;
toStr?: (v?: any) => string;
fromStr?: (s: string) => any;
@@ -47,22 +57,56 @@ export function doAutoFocus<T extends HTMLElement>(
const defaultToString = (f?: any): string => f || "";
const defaultFromString = (v: string): any => v as any;
-const TextInput = ({ inputType, focus, error, ...rest }: any) =>
- inputType === "multiline" ? (
- <textarea
- {...rest}
+export function InternalTextInputSwitch({
+ inputType,
+ focus,
+ hasError,
+ ...rest
+}: Props<any> & { hasError?: boolean }): VNode {
+ if (inputType === "multiline") {
+ return (
+ <textarea
+ {...(rest as any)}
+ ref={focus ? doAutoFocus : undefined}
+ class={hasError ? "textarea is-danger" : "textarea"}
+ rows={3}
+ />
+ );
+ }
+ if (inputType === "numeric" || inputType === "decimal") {
+ return (
+ <input
+ {...(rest as any)}
+ ref={focus ? doAutoFocus : undefined}
+ class={hasError ? "input is-danger" : "input"}
+ type={"number"}
+ inputMode={inputType}
+ />
+ );
+ }
+ if (
+ inputType === "email" ||
+ inputType === "tel" ||
+ inputType === "search" ||
+ inputType === "url"
+ ) {
+ <input
+ {...(rest as any)}
ref={focus ? doAutoFocus : undefined}
- class={error ? "textarea is-danger" : "textarea"}
- rows="3"
- />
- ) : (
+ class={hasError ? "input is-danger" : "input"}
+ type={inputType}
+ inputMode={inputType}
+ />;
+ }
+ return (
<input
- {...rest}
+ {...(rest as any)}
ref={focus ? doAutoFocus : undefined}
- class={error ? "input is-danger" : "input"}
+ class={hasError ? "input is-danger" : "input"}
type={inputType}
/>
);
+}
export function Input<T>({
name,
@@ -108,8 +152,8 @@ export function Input<T>({
: "control has-icons-right"
}
>
- <TextInput
- error={error}
+ <InternalTextInputSwitch
+ hasError={error}
{...inputExtra}
inputType={inputType}
placeholder={placeholder}
diff --git a/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx b/packages/merchant-backoffice-ui/src/components/form/InputCurrency.tsx
@@ -56,7 +56,7 @@ export function InputCurrency<T>({
help={help}
tooltip={tooltip}
addonAfter={addonAfter}
- inputType="number"
+ inputType="decimal"
expand={expand}
toStr={(v?: AmountString) => v?.split(":")[1] || ""}
fromStr={(v: string) => (!v ? undefined : `${config.currency}:${v}`)}
diff --git a/packages/merchant-backoffice-ui/src/components/form/InputNumber.tsx b/packages/merchant-backoffice-ui/src/components/form/InputNumber.tsx
@@ -46,7 +46,7 @@ export function InputNumber<T>({
readonly={readonly}
fromStr={(v) => (!v ? undefined : parseInt(v, 10))}
toStr={(v) => `${v}`}
- inputType="number"
+ inputType="numeric"
expand={expand}
label={label}
placeholder={placeholder}
diff --git a/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx b/packages/merchant-backoffice-ui/src/components/form/InputWithAddon.tsx
@@ -21,10 +21,11 @@
import { ComponentChildren, h, VNode } from "preact";
import { InputProps, useField } from "./useField.js";
import { Tooltip } from "../Tooltip.js";
+import { InternalTextInputSwitch, SupportedTextInputType } from "./Input.js";
export interface Props<T> extends InputProps<T> {
expand?: boolean;
- inputType?: "text" | "number" | "password";
+ inputType?: SupportedTextInputType;
addonBefore?: ComponentChildren;
addonBeforeLarge?: boolean;
addonAfter?: ComponentChildren;
@@ -70,7 +71,11 @@ export function InputWithAddon<T>({
*
</span>
)}
- {tooltip && <Tooltip text={tooltip} ><i class="icon mdi mdi-information" /></Tooltip>}
+ {tooltip && (
+ <Tooltip text={tooltip}>
+ <i class="icon mdi mdi-information" />
+ </Tooltip>
+ )}
</label>
</div>
@@ -92,16 +97,18 @@ export function InputWithAddon<T>({
required ? " has-icons-right" : ""
}`}
>
- <input
+ <InternalTextInputSwitch
{...(inputExtra || {})}
class={error ? "input is-danger" : "input"}
- type={inputType}
+ inputType={inputType}
placeholder={placeholder}
readonly={readonly}
disabled={readonly}
name={String(name)}
value={toStr(value)}
- onChange={(e): void => onChange(fromStr(e.currentTarget.value))}
+ onChange={(e: h.JSX.TargetedEvent<HTMLInputElement>): void =>
+ onChange(fromStr(e.currentTarget.value))
+ }
/>
{children}
</p>
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/update/UpdatePage.tsx
@@ -315,7 +315,7 @@ export function UpdatePage({ template, onUpdated, onBack }: Props): VNode {
name="amount"
label={i18n.str`Amount`}
addonBefore={state.currency}
- inputType="number"
+ inputType="decimal"
toStr={(v?: AmountString) => v?.split(":")[1] || ""}
fromStr={(v: string) =>
!v ? undefined : `${state.currency}:${v}`
diff --git a/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx b/packages/merchant-backoffice-ui/src/paths/instance/templates/use/UsePage.tsx
@@ -148,7 +148,7 @@ export function UsePage({
name="amount"
label={i18n.str`Amount`}
addonBefore={state.currency}
- inputType="number"
+ inputType="decimal"
toStr={(v?: AmountString) => v?.split(":")[1] || ""}
fromStr={(v: string) =>
!v ? undefined : `${state.currency}:${v}`