feat(inputs): ✨ Add number input
This commit is contained in:
@ -0,0 +1,84 @@
|
||||
import { FormLabel, HStack, Stack } from '@chakra-ui/react'
|
||||
import { SmartNumberInput } from 'components/settings/SmartNumberInput'
|
||||
import { DebouncedInput } from 'components/shared/DebouncedInput'
|
||||
import { NumberInputOptions } from 'models'
|
||||
import React from 'react'
|
||||
import { removeUndefinedFields } from 'services/utils'
|
||||
|
||||
type NumberInputSettingsBodyProps = {
|
||||
options?: NumberInputOptions
|
||||
onOptionsChange: (options: NumberInputOptions) => void
|
||||
}
|
||||
|
||||
export const NumberInputSettingsBody = ({
|
||||
options,
|
||||
onOptionsChange,
|
||||
}: NumberInputSettingsBodyProps) => {
|
||||
const handlePlaceholderChange = (placeholder: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, placeholder } })
|
||||
const handleButtonLabelChange = (button: string) =>
|
||||
onOptionsChange({ ...options, labels: { ...options?.labels, button } })
|
||||
const handleMinChange = (min?: number) =>
|
||||
onOptionsChange(removeUndefinedFields({ ...options, min }))
|
||||
const handleMaxChange = (max?: number) =>
|
||||
onOptionsChange(removeUndefinedFields({ ...options, max }))
|
||||
const handleStepChange = (step?: number) =>
|
||||
onOptionsChange(removeUndefinedFields({ ...options, step }))
|
||||
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="placeholder">
|
||||
Placeholder:
|
||||
</FormLabel>
|
||||
<DebouncedInput
|
||||
id="placeholder"
|
||||
initialValue={options?.labels?.placeholder ?? 'Type your answer...'}
|
||||
delay={100}
|
||||
onChange={handlePlaceholderChange}
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="button">
|
||||
Button label:
|
||||
</FormLabel>
|
||||
<DebouncedInput
|
||||
id="button"
|
||||
initialValue={options?.labels?.button ?? 'Send'}
|
||||
delay={100}
|
||||
onChange={handleButtonLabelChange}
|
||||
/>
|
||||
</Stack>
|
||||
<HStack justifyContent="space-between">
|
||||
<FormLabel mb="0" htmlFor="min">
|
||||
Min:
|
||||
</FormLabel>
|
||||
<SmartNumberInput
|
||||
id="min"
|
||||
initialValue={options?.min}
|
||||
onValueChange={handleMinChange}
|
||||
/>
|
||||
</HStack>
|
||||
<HStack justifyContent="space-between">
|
||||
<FormLabel mb="0" htmlFor="max">
|
||||
Max:
|
||||
</FormLabel>
|
||||
<SmartNumberInput
|
||||
id="max"
|
||||
initialValue={options?.max}
|
||||
onValueChange={handleMaxChange}
|
||||
/>
|
||||
</HStack>
|
||||
<HStack justifyContent="space-between">
|
||||
<FormLabel mb="0" htmlFor="step">
|
||||
Step:
|
||||
</FormLabel>
|
||||
<SmartNumberInput
|
||||
id="step"
|
||||
initialValue={options?.step}
|
||||
onValueChange={handleStepChange}
|
||||
/>
|
||||
</HStack>
|
||||
</Stack>
|
||||
)
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { PopoverContent, PopoverArrow, PopoverBody } from '@chakra-ui/react'
|
||||
import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
|
||||
import { Step, StepType, TextInputOptions } from 'models'
|
||||
import { InputStepType, Step, TextInputOptions } from 'models'
|
||||
import { NumberInputSettingsBody } from './NumberInputSettingsBody'
|
||||
import { TextInputSettingsBody } from './TextInputSettingsBody'
|
||||
|
||||
type Props = {
|
||||
@ -25,7 +26,7 @@ const SettingsPopoverBodyContent = ({ step }: Props) => {
|
||||
updateStep(step.id, { options } as Partial<Step>)
|
||||
|
||||
switch (step.type) {
|
||||
case StepType.TEXT_INPUT: {
|
||||
case InputStepType.TEXT: {
|
||||
return (
|
||||
<TextInputSettingsBody
|
||||
options={step.options}
|
||||
@ -33,6 +34,14 @@ const SettingsPopoverBodyContent = ({ step }: Props) => {
|
||||
/>
|
||||
)
|
||||
}
|
||||
case InputStepType.NUMBER: {
|
||||
return (
|
||||
<NumberInputSettingsBody
|
||||
options={step.options}
|
||||
onOptionsChange={handleOptionsChange}
|
||||
/>
|
||||
)
|
||||
}
|
||||
default: {
|
||||
return <></>
|
||||
}
|
||||
|
@ -1,31 +0,0 @@
|
||||
import { Flex, Text } from '@chakra-ui/react'
|
||||
import { Step, StartStep, StepType } from 'models'
|
||||
|
||||
export const StepContent = (props: Step | StartStep) => {
|
||||
switch (props.type) {
|
||||
case StepType.TEXT: {
|
||||
return (
|
||||
<Flex
|
||||
flexDir={'column'}
|
||||
opacity={props.content.html === '' ? '0.5' : '1'}
|
||||
className="slate-html-container"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
props.content.html === ''
|
||||
? `<p>Click to edit...</p>`
|
||||
: props.content.html,
|
||||
}}
|
||||
></Flex>
|
||||
)
|
||||
}
|
||||
case StepType.TEXT_INPUT: {
|
||||
return <Text color={'gray.500'}>Type your answer...</Text>
|
||||
}
|
||||
case StepType.START: {
|
||||
return <Text>{props.label}</Text>
|
||||
}
|
||||
default: {
|
||||
return <Text>No input</Text>
|
||||
}
|
||||
}
|
||||
}
|
@ -11,15 +11,15 @@ import { Block, Step } from 'models'
|
||||
import { SourceEndpoint } from './SourceEndpoint'
|
||||
import { useGraph } from 'contexts/GraphContext'
|
||||
import { StepIcon } from 'components/board/StepTypesList/StepIcon'
|
||||
import { isDefined } from 'utils'
|
||||
import { isDefined, isTextBubbleStep } from 'utils'
|
||||
import { Coordinates } from '@dnd-kit/core/dist/types'
|
||||
import { TextEditor } from './TextEditor/TextEditor'
|
||||
import { StepContent } from './StepContent'
|
||||
import { StepNodeLabel } from './StepNodeLabel'
|
||||
import { useTypebot } from 'contexts/TypebotContext/TypebotContext'
|
||||
import { ContextMenu } from 'components/shared/ContextMenu'
|
||||
import { StepNodeContextMenu } from './RightClickMenu'
|
||||
import { SettingsPopoverContent } from './SettingsPopoverContent'
|
||||
import { isStepText } from 'services/typebots'
|
||||
import { DraggableStep } from 'contexts/DndContext'
|
||||
|
||||
export const StepNode = ({
|
||||
step,
|
||||
@ -34,7 +34,7 @@ export const StepNode = ({
|
||||
onMouseMoveTopOfElement?: () => void
|
||||
onMouseDown?: (
|
||||
stepNodePosition: { absolute: Coordinates; relative: Coordinates },
|
||||
step: Step
|
||||
step: DraggableStep
|
||||
) => void
|
||||
}) => {
|
||||
const { setConnectingIds, connectingIds } = useGraph()
|
||||
@ -43,7 +43,7 @@ export const StepNode = ({
|
||||
const [mouseDownEvent, setMouseDownEvent] =
|
||||
useState<{ absolute: Coordinates; relative: Coordinates }>()
|
||||
const [isEditing, setIsEditing] = useState<boolean>(
|
||||
isStepText(step) && step.content.plainText === ''
|
||||
isTextBubbleStep(step) && step.content.plainText === ''
|
||||
)
|
||||
|
||||
useEffect(() => {
|
||||
@ -102,8 +102,8 @@ export const StepNode = ({
|
||||
mouseDownEvent &&
|
||||
onMouseDown &&
|
||||
(event.movementX > 0 || event.movementY > 0)
|
||||
if (isMovingAndIsMouseDown) {
|
||||
onMouseDown(mouseDownEvent, step as Step)
|
||||
if (isMovingAndIsMouseDown && step.type !== 'start') {
|
||||
onMouseDown(mouseDownEvent, step)
|
||||
deleteStep(step.id)
|
||||
setMouseDownEvent(undefined)
|
||||
}
|
||||
@ -142,7 +142,7 @@ export const StepNode = ({
|
||||
connectingIds?.target?.blockId,
|
||||
])
|
||||
|
||||
return isEditing && isStepText(step) ? (
|
||||
return isEditing && isTextBubbleStep(step) ? (
|
||||
<TextEditor
|
||||
stepId={step.id}
|
||||
initialValue={step.content.richText}
|
||||
@ -186,7 +186,7 @@ export const StepNode = ({
|
||||
bgColor="white"
|
||||
>
|
||||
<StepIcon type={step.type} />
|
||||
<StepContent {...step} />
|
||||
<StepNodeLabel {...step} />
|
||||
{isConnectable && (
|
||||
<SourceEndpoint
|
||||
onConnectionDragStart={handleConnectionDragStart}
|
||||
|
@ -0,0 +1,42 @@
|
||||
import { Flex, Text } from '@chakra-ui/react'
|
||||
import { Step, StartStep, BubbleStepType, InputStepType } from 'models'
|
||||
|
||||
export const StepNodeLabel = (props: Step | StartStep) => {
|
||||
switch (props.type) {
|
||||
case BubbleStepType.TEXT: {
|
||||
return (
|
||||
<Flex
|
||||
flexDir={'column'}
|
||||
opacity={props.content.html === '' ? '0.5' : '1'}
|
||||
className="slate-html-container"
|
||||
dangerouslySetInnerHTML={{
|
||||
__html:
|
||||
props.content.html === ''
|
||||
? `<p>Click to edit...</p>`
|
||||
: props.content.html,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
case InputStepType.TEXT: {
|
||||
return (
|
||||
<Text color={'gray.500'}>
|
||||
{props.options?.labels?.placeholder ?? 'Type your answer...'}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
case InputStepType.NUMBER: {
|
||||
return (
|
||||
<Text color={'gray.500'}>
|
||||
{props.options?.labels?.placeholder ?? 'Type your answer...'}
|
||||
</Text>
|
||||
)
|
||||
}
|
||||
case 'start': {
|
||||
return <Text>{props.label}</Text>
|
||||
}
|
||||
default: {
|
||||
return <Text>No input</Text>
|
||||
}
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
import { StackProps, HStack } from '@chakra-ui/react'
|
||||
import { StartStep, Step } from 'models'
|
||||
import { StepIcon } from 'components/board/StepTypesList/StepIcon'
|
||||
import { StepContent } from './StepContent'
|
||||
import { StepNodeLabel } from './StepNodeLabel'
|
||||
|
||||
export const StepNodeOverlay = ({
|
||||
step,
|
||||
@ -19,7 +19,7 @@ export const StepNodeOverlay = ({
|
||||
{...props}
|
||||
>
|
||||
<StepIcon type={step.type} />
|
||||
<StepContent {...step} />
|
||||
<StepNodeLabel {...step} />
|
||||
</HStack>
|
||||
)
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { useEventListener, Stack, Flex, Portal } from '@chakra-ui/react'
|
||||
import { Step, Table } from 'models'
|
||||
import { useDnd } from 'contexts/DndContext'
|
||||
import { DraggableStep, useDnd } from 'contexts/DndContext'
|
||||
import { Coordinates } from 'contexts/GraphContext'
|
||||
import { useState } from 'react'
|
||||
import { StepNode, StepNodeOverlay } from './StepNode'
|
||||
@ -54,7 +54,7 @@ export const StepsList = ({
|
||||
|
||||
const handleStepMouseDown = (
|
||||
{ absolute, relative }: { absolute: Coordinates; relative: Coordinates },
|
||||
step: Step
|
||||
step: DraggableStep
|
||||
) => {
|
||||
setPosition(absolute)
|
||||
setRelativeCoordinates(relative)
|
||||
|
Reference in New Issue
Block a user