mirror of
https://github.com/baptisteArno/typebot.io.git
synced 2026-06-05 21:04:43 +08:00
parent
c43ad4bfe7
commit
b76dad18b7
@ -1,6 +1,7 @@
|
||||
import { DropdownList } from "@/components/DropdownList";
|
||||
import { SwitchWithRelatedSettings } from "@/components/SwitchWithRelatedSettings";
|
||||
import { TextInput } from "@/components/inputs";
|
||||
import { Select } from "@/components/inputs/Select";
|
||||
import { SwitchWithLabel } from "@/components/inputs/SwitchWithLabel";
|
||||
import { VariableSearchInput } from "@/components/inputs/VariableSearchInput";
|
||||
import { FormLabel, Stack } from "@chakra-ui/react";
|
||||
@ -8,6 +9,7 @@ import { useTranslate } from "@tolgee/react";
|
||||
import { fileVisibilityOptions } from "@typebot.io/blocks-inputs/file/constants";
|
||||
import { defaultTextInputOptions } from "@typebot.io/blocks-inputs/text/constants";
|
||||
import type { TextInputBlock } from "@typebot.io/blocks-inputs/text/schema";
|
||||
import { inputModeOptions } from "@typebot.io/blocks-inputs/text/schema";
|
||||
import type { Variable } from "@typebot.io/variables/schemas";
|
||||
import React from "react";
|
||||
|
||||
@ -73,6 +75,12 @@ export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
audioClip: { ...options?.audioClip, visibility },
|
||||
});
|
||||
|
||||
const updateInputMode = (inputMode?: string) =>
|
||||
onOptionsChange({
|
||||
...options,
|
||||
inputMode: inputMode as (typeof inputModeOptions)[number] | undefined,
|
||||
});
|
||||
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<SwitchWithLabel
|
||||
@ -95,6 +103,17 @@ export const TextInputSettings = ({ options, onOptionsChange }: Props) => {
|
||||
}
|
||||
onChange={updateButtonLabel}
|
||||
/>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="input-mode">
|
||||
Input mode
|
||||
</FormLabel>
|
||||
<Select
|
||||
selectedItem={options?.inputMode ?? "text"}
|
||||
items={inputModeOptions}
|
||||
onSelect={updateInputMode}
|
||||
placeholder="Select input mode..."
|
||||
/>
|
||||
</Stack>
|
||||
<SwitchWithRelatedSettings
|
||||
label={"Allow audio clip"}
|
||||
initialValue={
|
||||
|
||||
@ -53,6 +53,25 @@ You can also ask your user for a longer text answer by enabling it in the input
|
||||
</Tab>
|
||||
</Tabs>
|
||||
|
||||
## Input mode
|
||||
|
||||
The input mode option allows you to specify the type of virtual keyboard that should be displayed on mobile devices. This provides a better user experience by showing the most appropriate keyboard for the expected input.
|
||||
|
||||
Available input modes:
|
||||
- **text**: Shows a standard keyboard
|
||||
- **decimal**: Shows a numeric keypad with decimal support
|
||||
- **numeric**: Shows a numeric keypad for whole numbers
|
||||
- **tel**: Shows a telephone keypad
|
||||
- **search**: Shows a keyboard optimized for search inputs
|
||||
- **email**: Shows a keyboard optimized for email addresses
|
||||
- **url**: Shows a keyboard optimized for URL entry
|
||||
|
||||
<Note>
|
||||
Input mode is a hint to the browser and may not be supported on all devices or browsers. It's particularly useful for mobile devices.
|
||||
</Note>
|
||||
|
||||
For more information, see the [MDN documentation](https://developer.mozilla.org/docs/Web/HTML/Reference/Global_attributes/inputmode).
|
||||
|
||||
## Allow attachments
|
||||
|
||||
This option, when enabled, allows users to attach files to their message. This is useful when you want to ask for a document or a picture attached to the user messages.
|
||||
|
||||
@ -14482,6 +14482,18 @@
|
||||
"isLong": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"inputMode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"text",
|
||||
"decimal",
|
||||
"numeric",
|
||||
"tel",
|
||||
"search",
|
||||
"email",
|
||||
"url"
|
||||
]
|
||||
},
|
||||
"audioClip": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@ -6790,6 +6790,18 @@
|
||||
"isLong": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"inputMode": {
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"text",
|
||||
"decimal",
|
||||
"numeric",
|
||||
"tel",
|
||||
"search",
|
||||
"email",
|
||||
"url"
|
||||
]
|
||||
},
|
||||
"audioClip": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
|
||||
@ -15,11 +15,22 @@ export const textInputOptionsBaseSchema = z.object({
|
||||
.optional(),
|
||||
});
|
||||
|
||||
export const inputModeOptions = [
|
||||
"text",
|
||||
"decimal",
|
||||
"numeric",
|
||||
"tel",
|
||||
"search",
|
||||
"email",
|
||||
"url",
|
||||
] as const;
|
||||
|
||||
export const textInputOptionsSchema = textInputOptionsBaseSchema
|
||||
.merge(optionBaseSchema)
|
||||
.merge(
|
||||
z.object({
|
||||
isLong: z.boolean().optional(),
|
||||
inputMode: z.enum(inputModeOptions).optional(),
|
||||
audioClip: z
|
||||
.object({
|
||||
isEnabled: z.boolean().optional(),
|
||||
|
||||
@ -4,16 +4,18 @@ import type { JSX } from "solid-js/jsx-runtime";
|
||||
type ShortTextInputProps = {
|
||||
ref: HTMLInputElement | undefined;
|
||||
onInput: (value: string) => void;
|
||||
inputmode?: string;
|
||||
} & Omit<JSX.InputHTMLAttributes<HTMLInputElement>, "onInput">;
|
||||
|
||||
export const ShortTextInput = (props: ShortTextInputProps) => {
|
||||
const [local, others] = splitProps(props, ["ref", "onInput"]);
|
||||
const [local, others] = splitProps(props, ["ref", "onInput", "inputmode"]);
|
||||
|
||||
return (
|
||||
<input
|
||||
ref={props.ref}
|
||||
class="focus:outline-none bg-transparent px-4 py-4 flex-1 w-full text-input"
|
||||
type="text"
|
||||
inputmode={local.inputmode}
|
||||
onInput={(e) => local.onInput(e.currentTarget.value)}
|
||||
{...others}
|
||||
/>
|
||||
|
||||
@ -4,10 +4,11 @@ import { type JSX, splitProps } from "solid-js";
|
||||
type TextareaProps = {
|
||||
ref: HTMLTextAreaElement | undefined;
|
||||
onInput: (value: string) => void;
|
||||
inputmode?: string;
|
||||
} & Omit<JSX.TextareaHTMLAttributes<HTMLTextAreaElement>, "onInput">;
|
||||
|
||||
export const Textarea = (props: TextareaProps) => {
|
||||
const [local, others] = splitProps(props, ["ref", "onInput"]);
|
||||
const [local, others] = splitProps(props, ["ref", "onInput", "inputmode"]);
|
||||
|
||||
const isMobile = guessDeviceIsMobile();
|
||||
|
||||
@ -19,6 +20,7 @@ export const Textarea = (props: TextareaProps) => {
|
||||
data-testid="textarea"
|
||||
required
|
||||
autofocus={!isMobile}
|
||||
inputmode={local.inputmode}
|
||||
onInput={(e) => local.onInput(e.currentTarget.value)}
|
||||
{...others}
|
||||
/>
|
||||
|
||||
@ -313,6 +313,7 @@ export const TextInput = (props: Props) => {
|
||||
onInput={handleInput}
|
||||
onKeyDown={submitIfCtrlEnter}
|
||||
value={inputValue()}
|
||||
inputmode={props.block.options?.inputMode}
|
||||
placeholder={
|
||||
props.block.options?.labels?.placeholder ??
|
||||
defaultTextInputOptions.labels.placeholder
|
||||
@ -323,6 +324,7 @@ export const TextInput = (props: Props) => {
|
||||
ref={inputRef as HTMLInputElement}
|
||||
onInput={handleInput}
|
||||
value={inputValue()}
|
||||
inputmode={props.block.options?.inputMode}
|
||||
placeholder={
|
||||
props.block.options?.labels?.placeholder ??
|
||||
defaultTextInputOptions.labels.placeholder
|
||||
|
||||
Loading…
Reference in New Issue
Block a user