@@ -12,21 +12,23 @@ import {
|
||||
import { ChevronLeftIcon } from '@/components/icons'
|
||||
import React, { ReactNode } from 'react'
|
||||
|
||||
type Props<T> = {
|
||||
currentItem?: T
|
||||
onItemSelect: (item: T) => void
|
||||
items: T[]
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type Props<T extends readonly any[]> = {
|
||||
currentItem: T[number] | undefined
|
||||
onItemSelect: (item: T[number]) => void
|
||||
items: T
|
||||
placeholder?: string
|
||||
}
|
||||
|
||||
export const DropdownList = <T,>({
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
export const DropdownList = <T extends readonly any[]>({
|
||||
currentItem,
|
||||
onItemSelect,
|
||||
items,
|
||||
placeholder = '',
|
||||
...props
|
||||
}: Props<T> & MenuButtonProps) => {
|
||||
const handleMenuItemClick = (operator: T) => () => {
|
||||
const handleMenuItemClick = (operator: T[number]) => () => {
|
||||
onItemSelect(operator)
|
||||
}
|
||||
return (
|
||||
|
||||
27
apps/builder/src/components/SetVariableLabel.tsx
Normal file
27
apps/builder/src/components/SetVariableLabel.tsx
Normal file
@@ -0,0 +1,27 @@
|
||||
import { useColorModeValue, HStack, Tag, Text } from '@chakra-ui/react'
|
||||
import { Variable } from 'models'
|
||||
|
||||
export const SetVariableLabel = ({
|
||||
variableId,
|
||||
variables,
|
||||
}: {
|
||||
variableId: string
|
||||
variables?: Variable[]
|
||||
}) => {
|
||||
const textColor = useColorModeValue('gray.600', 'gray.400')
|
||||
const variableName = variables?.find(
|
||||
(variable) => variable.id === variableId
|
||||
)?.name
|
||||
|
||||
if (!variableName) return null
|
||||
return (
|
||||
<HStack fontStyle="italic" spacing={1}>
|
||||
<Text fontSize="sm" color={textColor}>
|
||||
Set
|
||||
</Text>
|
||||
<Tag bg="orange.400" color="white" size="sm">
|
||||
{variableName}
|
||||
</Tag>
|
||||
</HStack>
|
||||
)
|
||||
}
|
||||
@@ -1,4 +1,12 @@
|
||||
import { Box, Button, Fade, Flex, IconButton, Stack } from '@chakra-ui/react'
|
||||
import {
|
||||
Box,
|
||||
Button,
|
||||
Fade,
|
||||
Flex,
|
||||
IconButton,
|
||||
SlideFade,
|
||||
Stack,
|
||||
} from '@chakra-ui/react'
|
||||
import { TrashIcon, PlusIcon } from '@/components/icons'
|
||||
import { createId } from '@paralleldrive/cuid2'
|
||||
import React, { useState } from 'react'
|
||||
@@ -7,26 +15,25 @@ type ItemWithId<T> = T & { id: string }
|
||||
|
||||
export type TableListItemProps<T> = {
|
||||
item: T
|
||||
debounceTimeout?: number
|
||||
onItemChange: (item: T) => void
|
||||
}
|
||||
|
||||
type Props<T> = {
|
||||
initialItems: ItemWithId<T>[]
|
||||
isOrdered?: boolean
|
||||
addLabel?: string
|
||||
debounceTimeout?: number
|
||||
onItemsChange: (items: ItemWithId<T>[]) => void
|
||||
Item: (props: TableListItemProps<T>) => JSX.Element
|
||||
ComponentBetweenItems?: (props: unknown) => JSX.Element
|
||||
onItemsChange: (items: ItemWithId<T>[]) => void
|
||||
}
|
||||
|
||||
export const TableList = <T,>({
|
||||
initialItems,
|
||||
onItemsChange,
|
||||
isOrdered,
|
||||
addLabel = 'Add',
|
||||
debounceTimeout,
|
||||
Item,
|
||||
ComponentBetweenItems,
|
||||
onItemsChange,
|
||||
}: Props<T>) => {
|
||||
const [items, setItems] = useState(initialItems)
|
||||
const [showDeleteIndex, setShowDeleteIndex] = useState<number | null>(null)
|
||||
@@ -38,6 +45,15 @@ export const TableList = <T,>({
|
||||
onItemsChange([...items, newItem])
|
||||
}
|
||||
|
||||
const insertItem = (itemIndex: number) => () => {
|
||||
const id = createId()
|
||||
const newItem = { id } as ItemWithId<T>
|
||||
const newItems = [...items]
|
||||
newItems.splice(itemIndex + 1, 0, newItem)
|
||||
setItems(newItems)
|
||||
onItemsChange(newItems)
|
||||
}
|
||||
|
||||
const updateItem = (itemIndex: number, updates: Partial<T>) => {
|
||||
const newItems = items.map((item, idx) =>
|
||||
idx === itemIndex ? { ...item, ...updates } : item
|
||||
@@ -62,7 +78,7 @@ export const TableList = <T,>({
|
||||
const handleMouseLeave = () => setShowDeleteIndex(null)
|
||||
|
||||
return (
|
||||
<Stack spacing="4">
|
||||
<Stack spacing={0} pt="2">
|
||||
{items.map((item, itemIndex) => (
|
||||
<Box key={item.id}>
|
||||
{itemIndex !== 0 && ComponentBetweenItems && (
|
||||
@@ -73,35 +89,82 @@ export const TableList = <T,>({
|
||||
onMouseEnter={handleMouseEnter(itemIndex)}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
mt={itemIndex !== 0 && ComponentBetweenItems ? 4 : 0}
|
||||
justifyContent="center"
|
||||
pb="4"
|
||||
>
|
||||
<Item
|
||||
item={item}
|
||||
onItemChange={handleCellChange(itemIndex)}
|
||||
debounceTimeout={debounceTimeout}
|
||||
/>
|
||||
<Fade in={showDeleteIndex === itemIndex}>
|
||||
<Item item={item} onItemChange={handleCellChange(itemIndex)} />
|
||||
<Fade
|
||||
in={showDeleteIndex === itemIndex}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
left: '-15px',
|
||||
top: '-15px',
|
||||
}}
|
||||
unmountOnExit
|
||||
>
|
||||
<IconButton
|
||||
icon={<TrashIcon />}
|
||||
aria-label="Remove cell"
|
||||
onClick={deleteItem(itemIndex)}
|
||||
pos="absolute"
|
||||
left="-15px"
|
||||
top="-15px"
|
||||
size="sm"
|
||||
shadow="md"
|
||||
/>
|
||||
</Fade>
|
||||
{isOrdered && (
|
||||
<>
|
||||
{itemIndex === 0 && (
|
||||
<SlideFade
|
||||
offsetY="-5px"
|
||||
in={showDeleteIndex === itemIndex}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
top: '-15px',
|
||||
}}
|
||||
unmountOnExit
|
||||
>
|
||||
<IconButton
|
||||
aria-label={addLabel}
|
||||
icon={<PlusIcon />}
|
||||
size="xs"
|
||||
shadow="md"
|
||||
colorScheme="blue"
|
||||
onClick={insertItem(itemIndex - 1)}
|
||||
/>
|
||||
</SlideFade>
|
||||
)}
|
||||
<SlideFade
|
||||
offsetY="5px"
|
||||
in={showDeleteIndex === itemIndex}
|
||||
style={{
|
||||
position: 'absolute',
|
||||
bottom: '5px',
|
||||
}}
|
||||
unmountOnExit
|
||||
>
|
||||
<IconButton
|
||||
aria-label={addLabel}
|
||||
icon={<PlusIcon />}
|
||||
size="xs"
|
||||
shadow="md"
|
||||
colorScheme="blue"
|
||||
onClick={insertItem(itemIndex)}
|
||||
/>
|
||||
</SlideFade>
|
||||
</>
|
||||
)}
|
||||
</Flex>
|
||||
</Box>
|
||||
))}
|
||||
<Button
|
||||
leftIcon={<PlusIcon />}
|
||||
onClick={createItem}
|
||||
flexShrink={0}
|
||||
colorScheme="blue"
|
||||
>
|
||||
{addLabel}
|
||||
</Button>
|
||||
{!isOrdered && (
|
||||
<Button
|
||||
leftIcon={<PlusIcon />}
|
||||
onClick={createItem}
|
||||
flexShrink={0}
|
||||
colorScheme="blue"
|
||||
>
|
||||
{addLabel}
|
||||
</Button>
|
||||
)}
|
||||
</Stack>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -16,12 +16,12 @@ import { useDebouncedCallback } from 'use-debounce'
|
||||
import { env } from 'utils'
|
||||
import { MoreInfoTooltip } from '../MoreInfoTooltip'
|
||||
|
||||
type Value<HasVariable> = HasVariable extends undefined | true
|
||||
type Value<HasVariable> = HasVariable extends true | undefined
|
||||
? number | VariableString
|
||||
: number
|
||||
|
||||
type Props<HasVariable extends boolean> = {
|
||||
defaultValue?: Value<HasVariable>
|
||||
defaultValue: Value<HasVariable> | undefined
|
||||
debounceTimeout?: number
|
||||
withVariableButton?: HasVariable
|
||||
label?: string
|
||||
|
||||
@@ -3,6 +3,7 @@ import { injectVariableInText } from '@/features/variables/utils/injectVariableI
|
||||
import { focusInput } from '@/utils/focusInput'
|
||||
import {
|
||||
FormControl,
|
||||
FormHelperText,
|
||||
FormLabel,
|
||||
HStack,
|
||||
Input as ChakraInput,
|
||||
@@ -26,6 +27,7 @@ export type TextInputProps = {
|
||||
onChange: (value: string) => void
|
||||
debounceTimeout?: number
|
||||
label?: ReactNode
|
||||
helperText?: ReactNode
|
||||
moreInfoTooltip?: string
|
||||
withVariableButton?: boolean
|
||||
isRequired?: boolean
|
||||
@@ -42,6 +44,7 @@ export const TextInput = forwardRef(function TextInput(
|
||||
defaultValue,
|
||||
debounceTimeout = 1000,
|
||||
label,
|
||||
helperText,
|
||||
moreInfoTooltip,
|
||||
withVariableButton = true,
|
||||
isRequired,
|
||||
@@ -137,6 +140,7 @@ export const TextInput = forwardRef(function TextInput(
|
||||
) : (
|
||||
Input
|
||||
)}
|
||||
{helperText && <FormHelperText>{helperText}</FormHelperText>}
|
||||
</FormControl>
|
||||
)
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user