Skip to content

Commit

Permalink
feat: show expression input fields multiline
Browse files Browse the repository at this point in the history
  • Loading branch information
Julusian committed May 21, 2024
1 parent 0a79ac3 commit 3af9fd6
Showing 1 changed file with 90 additions and 81 deletions.
171 changes: 90 additions & 81 deletions webui/src/Components/TextInputField.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React, { useEffect, useMemo, useState, useCallback, useContext, useRef } from 'react'
import { CInput } from '@coreui/react'
import { CInput, CTextarea } from '@coreui/react'
import { VariableDefinitionsContext } from '../util.js'
import Select, {
ControlProps,
Expand Down Expand Up @@ -125,7 +125,7 @@ export const TextInputField = observer(function TextInputField({
// Render the input
return (
<>
{useVariables ? (
{useVariables || isExpression ? (
<VariablesSelect
showValue={showValue}
style={extraStyle}
Expand All @@ -136,6 +136,7 @@ export const TextInputField = observer(function TextInputField({
placeholder={placeholder}
title={tooltip}
disabled={disabled}
multiline={isExpression}
/>
) : (
<CInput
Expand Down Expand Up @@ -196,6 +197,7 @@ interface VariablesSelectProps {
placeholder: string | undefined
title: string | undefined
disabled: boolean | undefined
multiline: boolean | undefined
}

function VariablesSelect({
Expand All @@ -208,6 +210,7 @@ function VariablesSelect({
placeholder,
title,
disabled,
multiline,
}: Readonly<VariablesSelectProps>) {
const variableDefinitionsContext = useContext(VariableDefinitionsContext)
const menuPortal = useContext(MenuPortalContext)
Expand Down Expand Up @@ -331,7 +334,7 @@ function VariablesSelect({
inputValue={searchValue}
onChange={onVariableSelect}
menuIsOpen={isPickerOpen}
components={CustomSelectComponents}
components={multiline ? CustomMultilineSelectComponents : CustomSelectComponents}
backspaceRemovesValue={false}
filterOption={createFilter({ ignoreAccents: false })}
/>
Expand Down Expand Up @@ -372,96 +375,102 @@ const CustomControl = React.memo((props: ControlProps<DropdownChoiceInt>) => {
)
})

const CustomValueContainer = React.memo((props: ValueContainerProps<DropdownChoiceInt>) => {
const context = useContext(VariablesSelectContext)

const checkCursor = useCallback(
(
e:
| React.KeyboardEvent<HTMLInputElement>
| React.MouseEvent<HTMLInputElement>
| React.TouchEvent<HTMLInputElement>
| React.ClipboardEvent<HTMLInputElement>
| React.FocusEvent<HTMLInputElement>
) => {
const target = e.currentTarget

if (document.activeElement !== target) {
context.setCursorPosition(null)
} else {
context.setCursorPosition(target.selectionStart)
}
},
[context.setCursorPosition]
)

const onFocus = useCallback(
(e: React.FocusEvent<HTMLInputElement>) => {
context.focusStoreValue()
const CustomValueContainerWrapper = (ChildComponent: (props: CTextarea | CInput) => JSX.Element) =>
React.memo((props: ValueContainerProps<DropdownChoiceInt>) => {
const context = useContext(VariablesSelectContext)

const checkCursor = useCallback(
(
e:
| React.KeyboardEvent<HTMLInputElement>
| React.MouseEvent<HTMLInputElement>
| React.TouchEvent<HTMLInputElement>
| React.ClipboardEvent<HTMLInputElement>
| React.FocusEvent<HTMLInputElement>
) => {
const target = e.currentTarget

if (document.activeElement !== target) {
context.setCursorPosition(null)
} else {
context.setCursorPosition(target.selectionStart)
}
},
[context.setCursorPosition]
)

checkCursor(e)
},
[context.focusStoreValue, checkCursor]
)
const onBlur = useCallback(
(e: React.FocusEvent<HTMLInputElement>) => {
context.blurClearValue()
const onFocus = useCallback(
(e: React.FocusEvent<HTMLInputElement>) => {
context.focusStoreValue()

checkCursor(e)
context.forceHideSuggestions(false)
},
[context.blurClearValue, context.forceHideSuggestions, checkCursor]
)
const onKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.code === 'Escape') {
context.forceHideSuggestions(true)
} else {
checkCursor(e)
}
},
[context, checkCursor]
)
},
[context.focusStoreValue, checkCursor]
)
const onBlur = useCallback(
(e: React.FocusEvent<HTMLInputElement>) => {
context.blurClearValue()

const doOnChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement> | React.FormEvent<HTMLInputElement>) =>
context.setValue(e.currentTarget.value),
[context.setValue]
)

return (
<SelectComponents.ValueContainer {...props} isDisabled>
<CInput
innerRef={context.inputRef}
type="text"
style={context.extraStyle}
title={context.title}
value={context.value}
onChange={doOnChange}
onFocus={onFocus}
onBlur={onBlur}
placeholder={context.placeholder}
onKeyUp={checkCursor}
onKeyDown={onKeyDown}
onMouseDown={checkCursor}
onTouchStart={checkCursor}
onInput={checkCursor}
onPaste={checkCursor}
onCut={checkCursor}
onSelect={checkCursor}
/>
</SelectComponents.ValueContainer>
)
})
checkCursor(e)
context.forceHideSuggestions(false)
},
[context.blurClearValue, context.forceHideSuggestions, checkCursor]
)
const onKeyDown = useCallback(
(e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.code === 'Escape') {
context.forceHideSuggestions(true)
} else {
checkCursor(e)
}
},
[context, checkCursor]
)

const doOnChange = useCallback(
(e: React.ChangeEvent<HTMLInputElement> | React.FormEvent<HTMLInputElement>) =>
context.setValue(e.currentTarget.value),
[context.setValue]
)

return (
<SelectComponents.ValueContainer {...props} isDisabled>
<ChildComponent
innerRef={context.inputRef}
type="text"
style={context.extraStyle}
title={context.title}
value={context.value}
onChange={doOnChange}
onFocus={onFocus}
onBlur={onBlur}
placeholder={context.placeholder}
onKeyUp={checkCursor}
onKeyDown={onKeyDown}
onMouseDown={checkCursor}
onTouchStart={checkCursor}
onInput={checkCursor}
onPaste={checkCursor}
onCut={checkCursor}
onSelect={checkCursor}
/>
</SelectComponents.ValueContainer>
)
})

const CustomSelectComponents = {
Option: CustomOption,
ValueContainer: CustomValueContainer,
ValueContainer: CustomValueContainerWrapper(CInput),
Control: CustomControl,
IndicatorsContainer: EmptyComponent,
MenuList: WindowedMenuList,
}

const CustomMultilineSelectComponents = {
...CustomSelectComponents,
ValueContainer: CustomValueContainerWrapper(CTextarea),
}

function FindVariableStartIndexFromCursor(text: string, cursor: number): number {
const previousOpen = cursor >= 2 ? text.lastIndexOf('$(', cursor - 2) : -1
const previousClose = cursor >= 1 ? text.lastIndexOf(')', cursor - 1) : -1
Expand Down

0 comments on commit 3af9fd6

Please sign in to comment.