📝 Add Contribute docs

This commit is contained in:
Baptiste Arnaud
2024-01-03 16:29:41 +01:00
parent b3957295bd
commit 65f4fb0d7a
66 changed files with 1453 additions and 519 deletions

View File

@@ -51,7 +51,7 @@ export const DropdownList = <T extends readonly any[]>({
isRequired={isRequired}
as={direction === 'column' ? Stack : HStack}
justifyContent="space-between"
width={label ? 'full' : 'auto'}
width={props.width === 'full' || label ? 'full' : 'auto'}
spacing={direction === 'column' ? 2 : 3}
>
{label && (

View File

@@ -0,0 +1,135 @@
import { Box, Button, Fade, Flex, IconButton, Stack } from '@chakra-ui/react'
import { TrashIcon, PlusIcon } from '@/components/icons'
import React, { useEffect, useState } from 'react'
import { createId } from '@paralleldrive/cuid2'
type ItemWithId<T extends number | string | boolean> = { id: string; value?: T }
export type TableListItemProps<T> = {
item: T
onItemChange: (item: T) => void
}
type Props<T extends number | string | boolean> = {
initialItems?: T[]
addLabel?: string
newItemDefaultProps?: Partial<T>
hasDefaultItem?: boolean
ComponentBetweenItems?: (props: unknown) => JSX.Element
onItemsChange: (items: T[]) => void
children: (props: TableListItemProps<T>) => JSX.Element
}
const addIdToItems = <T extends number | string | boolean>(
items: T[]
): ItemWithId<T>[] => items.map((item) => ({ id: createId(), value: item }))
const removeIdFromItems = <T extends number | string | boolean>(
items: ItemWithId<T>[]
): T[] => items.map((item) => item.value as T)
export const PrimitiveList = <T extends number | string | boolean>({
initialItems,
addLabel = 'Add',
hasDefaultItem,
children,
ComponentBetweenItems,
onItemsChange,
}: Props<T>) => {
const [items, setItems] = useState<ItemWithId<T>[]>()
const [showDeleteIndex, setShowDeleteIndex] = useState<number | null>(null)
useEffect(() => {
if (items) return
if (initialItems) {
setItems(addIdToItems(initialItems))
} else if (hasDefaultItem) {
setItems(addIdToItems([]))
} else {
setItems([])
}
}, [hasDefaultItem, initialItems, items])
const createItem = () => {
if (!items) return
const newItems = [...items, { id: createId() }]
setItems(newItems)
onItemsChange(removeIdFromItems(newItems))
}
const updateItem = (itemIndex: number, newValue: T) => {
if (!items) return
const newItems = items.map((item, idx) =>
idx === itemIndex ? { ...item, value: newValue } : item
)
setItems(newItems)
onItemsChange(removeIdFromItems(newItems))
}
const deleteItem = (itemIndex: number) => () => {
if (!items) return
const newItems = [...items]
newItems.splice(itemIndex, 1)
setItems([...newItems])
onItemsChange(removeIdFromItems([...newItems]))
}
const handleMouseEnter = (itemIndex: number) => () =>
setShowDeleteIndex(itemIndex)
const handleCellChange = (itemIndex: number) => (item: T) =>
updateItem(itemIndex, item)
const handleMouseLeave = () => setShowDeleteIndex(null)
return (
<Stack spacing={0}>
{items?.map((item, itemIndex) => (
<Box key={item.id}>
{itemIndex !== 0 && ComponentBetweenItems && (
<ComponentBetweenItems />
)}
<Flex
pos="relative"
onMouseEnter={handleMouseEnter(itemIndex)}
onMouseLeave={handleMouseLeave}
mt={itemIndex !== 0 && ComponentBetweenItems ? 4 : 0}
justifyContent="center"
pb="4"
>
{children({
item: item.value as T,
onItemChange: handleCellChange(itemIndex),
})}
<Fade
in={showDeleteIndex === itemIndex}
style={{
position: 'absolute',
left: '-15px',
top: '-15px',
zIndex: 1,
}}
unmountOnExit
>
<IconButton
icon={<TrashIcon />}
aria-label="Remove cell"
onClick={deleteItem(itemIndex)}
size="sm"
shadow="md"
/>
</Fade>
</Flex>
</Box>
))}
<Button
leftIcon={<PlusIcon />}
onClick={createItem}
flexShrink={0}
colorScheme="blue"
>
{addLabel}
</Button>
</Stack>
)
}

View File

@@ -109,7 +109,7 @@ export const NumberInput = <HasVariable extends boolean>({
as={direction === 'column' ? Stack : HStack}
isRequired={isRequired}
justifyContent="space-between"
width={label ? 'full' : 'auto'}
width={label || props.width === 'full' ? 'full' : 'auto'}
spacing={direction === 'column' ? 2 : 3}
>
{label && (

View File

@@ -35,6 +35,7 @@ export type TextInputProps = {
placeholder?: string
isDisabled?: boolean
direction?: 'row' | 'column'
width?: 'full'
} & Pick<
InputProps,
| 'autoComplete'
@@ -66,6 +67,7 @@ export const TextInput = forwardRef(function TextInput(
size,
maxWidth,
direction = 'column',
width,
}: TextInputProps,
ref
) {
@@ -141,7 +143,7 @@ export const TextInput = forwardRef(function TextInput(
isRequired={isRequired}
as={direction === 'column' ? Stack : HStack}
justifyContent="space-between"
width={label ? 'full' : 'auto'}
width={label || width === 'full' ? 'full' : 'auto'}
spacing={direction === 'column' ? 2 : 3}
>
{label && (

View File

@@ -28,7 +28,7 @@ type Props = {
helperText?: ReactNode
onChange: (value: string) => void
direction?: 'row' | 'column'
} & Pick<TextareaProps, 'minH'>
} & Pick<TextareaProps, 'minH' | 'width'>
export const Textarea = ({
id,
@@ -43,6 +43,7 @@ export const Textarea = ({
minH,
helperText,
direction = 'column',
width,
}: Props) => {
const inputRef = useRef<HTMLTextAreaElement | null>(null)
const [isTouched, setIsTouched] = useState(false)
@@ -108,7 +109,7 @@ export const Textarea = ({
isRequired={isRequired}
as={direction === 'column' ? Stack : HStack}
justifyContent="space-between"
width={label ? 'full' : 'auto'}
width={label || width === 'full' ? 'full' : 'auto'}
spacing={direction === 'column' ? 2 : 3}
>
{label && (

View File

@@ -46,6 +46,7 @@ type Props = {
helperText?: ReactNode
moreInfoTooltip?: string
direction?: 'row' | 'column'
width?: 'full'
} & Omit<InputProps, 'placeholder'>
export const VariableSearchInput = ({
@@ -58,6 +59,7 @@ export const VariableSearchInput = ({
moreInfoTooltip,
direction = 'column',
isRequired,
width,
...inputProps
}: Props) => {
const focusedItemBgColor = useColorModeValue('gray.200', 'gray.700')
@@ -196,7 +198,7 @@ export const VariableSearchInput = ({
isRequired={isRequired}
as={direction === 'column' ? Stack : HStack}
justifyContent="space-between"
width={label ? 'full' : 'auto'}
width={label || width === 'full' ? 'full' : 'auto'}
spacing={direction === 'column' ? 2 : 3}
>
{label && (