diff --git a/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormNumberFieldInput.tsx b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormNumberFieldInput.tsx new file mode 100644 index 000000000..9ad8c98e5 --- /dev/null +++ b/packages/twenty-front/src/modules/object-record/record-field/form-types/components/FormNumberFieldInput.tsx @@ -0,0 +1,196 @@ +import SearchVariablesDropdown from '@/workflow/search-variables/components/SearchVariablesDropdown'; +import { VARIABLE_TAG_STYLES } from '@/workflow/search-variables/components/VariableTagInput'; +import { useTheme } from '@emotion/react'; +import styled from '@emotion/styled'; +import { useId, useState } from 'react'; +import { IconX, TEXT_INPUT_STYLE, VisibilityHidden } from 'twenty-ui'; +import { + canBeCastAsNumberOrNull, + castAsNumberOrNull, +} from '~/utils/cast-as-number-or-null'; + +const LINE_HEIGHT = 24; + +const StyledContainer = styled.div` + display: flex; + flex-direction: column; +`; + +const StyledInputContainer = styled.div<{ + multiline?: boolean; +}>` + display: flex; + flex-direction: row; + position: relative; + line-height: ${({ multiline }) => (multiline ? `${LINE_HEIGHT}px` : 'auto')}; + min-height: ${({ multiline }) => + multiline ? `${3 * LINE_HEIGHT}px` : 'auto'}; + max-height: ${({ multiline }) => + multiline ? `${5 * LINE_HEIGHT}px` : 'auto'}; +`; + +const StyledInputContainer2 = styled.div<{ + multiline?: boolean; + readonly?: boolean; +}>` + background-color: ${({ theme }) => theme.background.transparent.lighter}; + border: 1px solid ${({ theme }) => theme.border.color.medium}; + border-bottom-left-radius: ${({ theme }) => theme.border.radius.sm}; + border-bottom-right-radius: ${({ multiline, theme }) => + multiline ? theme.border.radius.sm : 'none'}; + border-right: ${({ multiline }) => (multiline ? 'auto' : 'none')}; + border-top-left-radius: ${({ theme }) => theme.border.radius.sm}; + border-top-right-radius: ${({ multiline, theme }) => + multiline ? theme.border.radius.sm : 'none'}; + box-sizing: border-box; + display: flex; + height: ${({ multiline }) => (multiline ? 'auto' : `${1.5 * LINE_HEIGHT}px`)}; + overflow: ${({ multiline }) => (multiline ? 'auto' : 'hidden')}; + /* padding-right: ${({ multiline, theme }) => + multiline ? theme.spacing(6) : theme.spacing(2)}; */ + width: 100%; +`; + +const StyledInput = styled.input` + ${TEXT_INPUT_STYLE} + + padding: ${({ theme }) => `${theme.spacing(1)} ${theme.spacing(2)}`}; + width: 100%; +`; + +const StyledVariableContainer = styled.div` + ${VARIABLE_TAG_STYLES} + + margin: ${({ theme }) => `${theme.spacing(1)} ${theme.spacing(2)}`}; + align-self: center; + + display: flex; + align-items: center; +`; + +const StyledSearchVariablesDropdownContainer = styled.div<{ + multiline?: boolean; + readonly?: boolean; +}>` + align-items: center; + display: flex; + justify-content: center; + + ${({ theme, readonly }) => + !readonly && + ` + :hover { + background-color: ${theme.background.transparent.light}; + }`} + + ${({ theme, multiline }) => + multiline + ? ` + position: absolute; + top: ${theme.spacing(0)}; + right: ${theme.spacing(0)}; + padding: ${theme.spacing(0.5)} ${theme.spacing(0)}; + border-radius: ${theme.border.radius.sm}; + ` + : ` + background-color: ${theme.background.transparent.lighter}; + border-top-right-radius: ${theme.border.radius.sm}; + border-bottom-right-radius: ${theme.border.radius.sm}; + border: 1px solid ${theme.border.color.medium}; + `} +`; + +type EditingMode = 'input' | 'variable'; + +type FormNumberFieldInputProps = { + placeholder: string; + defaultValue: string | undefined; + onPersist: (value: number | null | string) => void; +}; + +export const FormNumberFieldInput = ({ + placeholder, + defaultValue, + onPersist, +}: FormNumberFieldInputProps) => { + const theme = useTheme(); + + const id = useId(); + + const [draftValue, setDraftValue] = useState(defaultValue ?? ''); + const [editingMode, setEditingMode] = useState(() => { + return defaultValue?.startsWith('{{') ? 'variable' : 'input'; + }); + + const persistNumber = (newValue: string) => { + if (!canBeCastAsNumberOrNull(newValue)) { + return; + } + + const castedValue = castAsNumberOrNull(newValue); + + onPersist(castedValue); + }; + + const handleChange = (newText: string) => { + setDraftValue(newText); + + persistNumber(newText.trim()); + }; + + return ( + + + + {editingMode === 'input' ? ( + { + handleChange(event.target.value); + }} + /> + ) : ( + + {draftValue} + + + + )} + + + + { + setDraftValue(variable); + setEditingMode('variable'); + onPersist(variable); + }} + disabled={false} + /> + + + + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormField.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormField.tsx new file mode 100644 index 000000000..fccbf785c --- /dev/null +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormField.tsx @@ -0,0 +1,19 @@ +import { FormNumberFieldInput } from '@/object-record/record-field/form-types/components/FormNumberFieldInput'; + +type WorkflowEditActionFormFieldProps = { + defaultValue: string; +}; + +export const WorkflowEditActionFormField = ({ + defaultValue, +}: WorkflowEditActionFormFieldProps) => { + return ( + { + console.log('save value to database', value); + }} + /> + ); +}; diff --git a/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormRecordCreate.tsx b/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormRecordCreate.tsx index 647dfe240..ec599cf28 100644 --- a/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormRecordCreate.tsx +++ b/packages/twenty-front/src/modules/workflow/components/WorkflowEditActionFormRecordCreate.tsx @@ -1,6 +1,6 @@ import { useFilteredObjectMetadataItems } from '@/object-metadata/hooks/useFilteredObjectMetadataItems'; -import { FormFieldInput } from '@/object-record/record-field/components/FormFieldInput'; import { Select, SelectOption } from '@/ui/input/components/Select'; +import { WorkflowEditActionFormField } from '@/workflow/components/WorkflowEditActionFormField'; import { WorkflowEditGenericFormBase } from '@/workflow/components/WorkflowEditGenericFormBase'; import { WorkflowRecordCreateAction } from '@/workflow/types/Workflow'; import { useTheme } from '@emotion/react'; @@ -152,15 +152,20 @@ export const WorkflowEditActionFormRecordCreate = ({ {editableFields.map((field) => ( - { - handleFieldChange(field.name, value); - }} + defaultValue={formData[field.name] as string} /> + + // { + // handleFieldChange(field.name, value); + // }} + // /> ))} ); diff --git a/packages/twenty-front/src/modules/workflow/search-variables/components/VariableTagInput.tsx b/packages/twenty-front/src/modules/workflow/search-variables/components/VariableTagInput.tsx index 905fe79b5..673567bba 100644 --- a/packages/twenty-front/src/modules/workflow/search-variables/components/VariableTagInput.tsx +++ b/packages/twenty-front/src/modules/workflow/search-variables/components/VariableTagInput.tsx @@ -2,6 +2,7 @@ import SearchVariablesDropdown from '@/workflow/search-variables/components/Sear import { initializeEditorContent } from '@/workflow/search-variables/utils/initializeEditorContent'; import { parseEditorContent } from '@/workflow/search-variables/utils/parseEditorContent'; import { VariableTag } from '@/workflow/search-variables/utils/variableTag'; +import { css } from '@emotion/react'; import styled from '@emotion/styled'; import Document from '@tiptap/extension-document'; import HardBreak from '@tiptap/extension-hard-break'; @@ -9,7 +10,7 @@ import Paragraph from '@tiptap/extension-paragraph'; import Placeholder from '@tiptap/extension-placeholder'; import Text from '@tiptap/extension-text'; import { EditorContent, useEditor } from '@tiptap/react'; -import { isDefined } from 'twenty-ui'; +import { isDefined, ThemeType } from 'twenty-ui'; import { useDebouncedCallback } from 'use-debounce'; const LINE_HEIGHT = 24; @@ -71,6 +72,13 @@ const StyledSearchVariablesDropdownContainer = styled.div<{ `} `; +export const VARIABLE_TAG_STYLES = ({ theme }: { theme: ThemeType }) => css` + background-color: ${theme.color.blue10}; + border-radius: ${theme.border.radius.sm}; + color: ${theme.color.blue}; + padding: ${theme.spacing(1)}; +`; + const StyledEditor = styled.div<{ multiline?: boolean; readonly?: boolean }>` display: flex; width: 100%; @@ -119,10 +127,7 @@ const StyledEditor = styled.div<{ multiline?: boolean; readonly?: boolean }>` } .variable-tag { - color: ${({ theme }) => theme.color.blue}; - background-color: ${({ theme }) => theme.color.blue10}; - padding: ${({ theme }) => theme.spacing(1)}; - border-radius: ${({ theme }) => theme.border.radius.sm}; + ${VARIABLE_TAG_STYLES} } }