feat(engine): ✨ Improve variables in executed codes
This commit is contained in:
@ -1,4 +1,4 @@
|
||||
import { Box, BoxProps } from '@chakra-ui/react'
|
||||
import { Box, BoxProps, HStack } from '@chakra-ui/react'
|
||||
import { EditorState, EditorView, basicSetup } from '@codemirror/basic-setup'
|
||||
import { json, jsonParseLinter } from '@codemirror/lang-json'
|
||||
import { css } from '@codemirror/lang-css'
|
||||
@ -7,6 +7,8 @@ import { html } from '@codemirror/lang-html'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { useDebouncedCallback } from 'use-debounce'
|
||||
import { linter } from '@codemirror/lint'
|
||||
import { VariablesButton } from './buttons/VariablesButton'
|
||||
import { Variable } from 'models'
|
||||
|
||||
const linterExtension = linter(jsonParseLinter())
|
||||
|
||||
@ -15,12 +17,14 @@ type Props = {
|
||||
lang?: 'css' | 'json' | 'js' | 'html'
|
||||
isReadOnly?: boolean
|
||||
debounceTimeout?: number
|
||||
withVariableButton?: boolean
|
||||
onChange?: (value: string) => void
|
||||
}
|
||||
export const CodeEditor = ({
|
||||
value,
|
||||
lang,
|
||||
onChange,
|
||||
withVariableButton = true,
|
||||
isReadOnly = false,
|
||||
debounceTimeout = 1000,
|
||||
...props
|
||||
@ -28,6 +32,9 @@ export const CodeEditor = ({
|
||||
const editorContainer = useRef<HTMLDivElement | null>(null)
|
||||
const editorView = useRef<EditorView | null>(null)
|
||||
const [, setPlainTextValue] = useState(value)
|
||||
const [carretPosition, setCarretPosition] = useState<number>(0)
|
||||
const isVariableButtonDisplayed = withVariableButton && !isReadOnly
|
||||
|
||||
const debounced = useDebouncedCallback(
|
||||
(value) => {
|
||||
setPlainTextValue(value)
|
||||
@ -101,5 +108,35 @@ export const CodeEditor = ({
|
||||
return editor
|
||||
}
|
||||
|
||||
return <Box ref={editorContainer} data-testid="code-editor" {...props} />
|
||||
const handleVariableSelected = (variable?: Pick<Variable, 'id' | 'name'>) => {
|
||||
editorView.current?.focus()
|
||||
const insert = `{{${variable?.name}}}`
|
||||
editorView.current?.dispatch({
|
||||
changes: {
|
||||
from: carretPosition,
|
||||
insert,
|
||||
},
|
||||
selection: { anchor: carretPosition + insert.length },
|
||||
})
|
||||
}
|
||||
|
||||
const handleKeyUp = () => {
|
||||
if (!editorContainer.current) return
|
||||
setCarretPosition(editorView.current?.state.selection.main.from ?? 0)
|
||||
}
|
||||
|
||||
return (
|
||||
<HStack align="flex-end" spacing={0}>
|
||||
<Box
|
||||
w={isVariableButtonDisplayed ? 'calc(100% - 32px)' : '100%'}
|
||||
ref={editorContainer}
|
||||
data-testid="code-editor"
|
||||
{...props}
|
||||
onKeyUp={handleKeyUp}
|
||||
/>
|
||||
{isVariableButtonDisplayed && (
|
||||
<VariablesButton onSelectVariable={handleVariableSelected} size="sm" />
|
||||
)}
|
||||
</HStack>
|
||||
)
|
||||
}
|
||||
|
@ -144,7 +144,7 @@ export const BlockNode = ({ block, blockIndex }: Props) => {
|
||||
pointerEvents={isReadOnly || isStartBlock ? 'none' : 'auto'}
|
||||
>
|
||||
<EditablePreview
|
||||
_hover={{ bgColor: 'gray.300' }}
|
||||
_hover={{ bgColor: 'gray.200' }}
|
||||
px="1"
|
||||
userSelect={'none'}
|
||||
/>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { FormLabel, Stack } from '@chakra-ui/react'
|
||||
import { FormLabel, HStack, Stack, Switch, Text } from '@chakra-ui/react'
|
||||
import { CodeEditor } from 'components/shared/CodeEditor'
|
||||
import { Textarea } from 'components/shared/Textbox'
|
||||
import { VariableSearchInput } from 'components/shared/VariableSearchInput'
|
||||
import { SetVariableOptions, Variable } from 'models'
|
||||
@ -14,6 +15,11 @@ export const SetVariableSettings = ({ options, onOptionsChange }: Props) => {
|
||||
onOptionsChange({ ...options, variableId: variable?.id })
|
||||
const handleExpressionChange = (expressionToEvaluate: string) =>
|
||||
onOptionsChange({ ...options, expressionToEvaluate })
|
||||
const handleValueTypeChange = () =>
|
||||
onOptionsChange({
|
||||
...options,
|
||||
isCode: options.isCode ? !options.isCode : true,
|
||||
})
|
||||
|
||||
return (
|
||||
<Stack spacing={4}>
|
||||
@ -28,14 +34,34 @@ export const SetVariableSettings = ({ options, onOptionsChange }: Props) => {
|
||||
/>
|
||||
</Stack>
|
||||
<Stack>
|
||||
<FormLabel mb="0" htmlFor="expression">
|
||||
Value / Expression:
|
||||
</FormLabel>
|
||||
<Textarea
|
||||
id="expression"
|
||||
defaultValue={options.expressionToEvaluate ?? ''}
|
||||
onChange={handleExpressionChange}
|
||||
/>
|
||||
<HStack justify="space-between">
|
||||
<FormLabel mb="0" htmlFor="expression">
|
||||
Value:
|
||||
</FormLabel>
|
||||
<HStack>
|
||||
<Text fontSize="sm">Text</Text>
|
||||
<Switch
|
||||
size="sm"
|
||||
isChecked={options.isCode ?? false}
|
||||
onChange={handleValueTypeChange}
|
||||
/>
|
||||
<Text fontSize="sm">Code</Text>
|
||||
</HStack>
|
||||
</HStack>
|
||||
|
||||
{options.isCode ?? false ? (
|
||||
<CodeEditor
|
||||
value={options.expressionToEvaluate ?? ''}
|
||||
onChange={handleExpressionChange}
|
||||
lang="js"
|
||||
/>
|
||||
) : (
|
||||
<Textarea
|
||||
id="expression"
|
||||
defaultValue={options.expressionToEvaluate ?? ''}
|
||||
onChange={handleExpressionChange}
|
||||
/>
|
||||
)}
|
||||
</Stack>
|
||||
</Stack>
|
||||
)
|
||||
|
@ -23,7 +23,6 @@ export const BlocksDropdown = ({
|
||||
)
|
||||
|
||||
const handleBlockSelect = (title: string) => {
|
||||
console.log(title)
|
||||
const id = blocks?.find((b) => b.title === title)?.id
|
||||
if (id) onBlockIdSelected(id)
|
||||
}
|
||||
|
@ -1,20 +1,13 @@
|
||||
import {
|
||||
ComponentWithAs,
|
||||
Flex,
|
||||
HStack,
|
||||
IconButton,
|
||||
InputProps,
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
TextareaProps,
|
||||
Tooltip,
|
||||
} from '@chakra-ui/react'
|
||||
import { UserIcon } from 'assets/icons'
|
||||
import { Variable } from 'models'
|
||||
import React, { ChangeEvent, useEffect, useRef, useState } from 'react'
|
||||
import { useDebouncedCallback } from 'use-debounce'
|
||||
import { VariableSearchInput } from '../VariableSearchInput'
|
||||
import { VariablesButton } from '../buttons/VariablesButton'
|
||||
|
||||
export type TextBoxProps = {
|
||||
onChange: (value: string) => void
|
||||
@ -120,27 +113,7 @@ export const TextBox = ({
|
||||
bgColor={'white'}
|
||||
{...props}
|
||||
/>
|
||||
<Popover matchWidth isLazy>
|
||||
<PopoverTrigger>
|
||||
<Flex>
|
||||
<Tooltip label="Insert a variable">
|
||||
<IconButton
|
||||
aria-label="Insert a variable"
|
||||
icon={<UserIcon />}
|
||||
pos="relative"
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent w="full">
|
||||
<VariableSearchInput
|
||||
onSelectVariable={handleVariableSelected}
|
||||
placeholder="Search for a variable"
|
||||
shadow="lg"
|
||||
isDefaultOpen
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
<VariablesButton onSelectVariable={handleVariableSelected} />
|
||||
</HStack>
|
||||
)
|
||||
}
|
||||
|
46
apps/builder/components/shared/buttons/VariablesButton.tsx
Normal file
46
apps/builder/components/shared/buttons/VariablesButton.tsx
Normal file
@ -0,0 +1,46 @@
|
||||
import {
|
||||
Popover,
|
||||
PopoverTrigger,
|
||||
Flex,
|
||||
Tooltip,
|
||||
IconButton,
|
||||
PopoverContent,
|
||||
IconButtonProps,
|
||||
} from '@chakra-ui/react'
|
||||
import { UserIcon } from 'assets/icons'
|
||||
import { Variable } from 'models'
|
||||
import React from 'react'
|
||||
import { VariableSearchInput } from '../VariableSearchInput'
|
||||
|
||||
type Props = {
|
||||
onSelectVariable: (
|
||||
variable: Pick<Variable, 'name' | 'id'> | undefined
|
||||
) => void
|
||||
} & Omit<IconButtonProps, 'aria-label'>
|
||||
|
||||
export const VariablesButton = ({ onSelectVariable, ...props }: Props) => {
|
||||
return (
|
||||
<Popover matchWidth isLazy>
|
||||
<PopoverTrigger>
|
||||
<Flex>
|
||||
<Tooltip label="Insert a variable">
|
||||
<IconButton
|
||||
aria-label={'Insert a variable'}
|
||||
icon={<UserIcon />}
|
||||
pos="relative"
|
||||
{...props}
|
||||
/>
|
||||
</Tooltip>
|
||||
</Flex>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent w="full">
|
||||
<VariableSearchInput
|
||||
onSelectVariable={onSelectVariable}
|
||||
placeholder="Search for a variable"
|
||||
shadow="lg"
|
||||
isDefaultOpen
|
||||
/>
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
)
|
||||
}
|
Reference in New Issue
Block a user