Skip to content

Commit

Permalink
Merge pull request #705 from contember/feat/selectEnumField
Browse files Browse the repository at this point in the history
feat(playground): add SelectEnumField
  • Loading branch information
matej21 authored May 24, 2024
2 parents a0a58bb + 3dabe91 commit ea81d94
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 113 deletions.
9 changes: 5 additions & 4 deletions packages/playground/admin/app/components/navigation.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,10 @@ export const Navigation = () => {
<MenuItem icon={line} label={'Static columns'} to={'board/status'} />
</MenuItem>
<MenuItem icon={<GripVertical size={16} />} label={'Repeater'}>
<MenuItem icon={line} label={'Sortable repeater'} to={'repeater'} />
<MenuItem icon={line} label={'Non-sortable repeater'} to={'repeater/nonSortable'} />
<MenuItem icon={line} label={'Block repeater'} to={'blocks'} />
<MenuItem icon={line} label={'Block repeater w/o dual render'} to={'blocks/withoutDualRender'} />
<MenuItem icon={line} label={'Sortable repeater'} to={'repeater'} />
<MenuItem icon={line} label={'Non-sortable repeater'} to={'repeater/nonSortable'} />
<MenuItem icon={line} label={'Block repeater'} to={'blocks'} />
<MenuItem icon={line} label={'Block repeater w/o dual render'} to={'blocks/withoutDualRender'} />
</MenuItem>
<MenuItem icon={<TableIcon size={16} />} label={'Grid'}>
<MenuItem icon={line} label={'Complex grid'} to={'grid'} />
Expand All @@ -39,6 +39,7 @@ export const Navigation = () => {
<MenuItem icon={line} label={'Create new form'} to={'select/createNewForm'} />
<MenuItem icon={line} label={'Has many select'} to={'select/hasMany'} />
<MenuItem icon={line} label={'Has many sortable select'} to={'select/hasManySortable'} />
<MenuItem icon={line} label={'Enum select'} to={'select/enumSelect'} />
</MenuItem>
<MenuItem icon={<UploadIcon size={16} />} label={'Upload'}>
<MenuItem icon={line} label={'Image upload'} to={'upload/image'} />
Expand Down
19 changes: 18 additions & 1 deletion packages/playground/admin/app/pages/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { Binding, PersistButton } from '../../lib/components/binding'
import { EntitySubTree } from '@contember/interface'
import * as React from 'react'
import { Field } from '@contember/react-binding'
import { InputField, MultiSelectField, SelectField, SortableMultiSelectField } from '../../lib/components/form'
import { InputField, MultiSelectField, SelectEnumField, SelectField, SortableMultiSelectField } from '../../lib/components/form'


export const hasOne = () => <>
Expand Down Expand Up @@ -70,3 +70,20 @@ export const createNewForm = () => <>
</EntitySubTree>
</Binding>
</>

export const enumSelect = () => <>
<Binding>
<Slots.Actions>
<PersistButton />
</Slots.Actions>
<EntitySubTree entity={'InputRoot(unique=unique)'} setOnCreate={'(unique=unique)'}>
<div className={'space-y-4'}>
<SelectEnumField field={'enumValue'} label={'Some enum'} options={{
a: 'Option A',
b: 'Option B',
c: 'Option C',
}} />
</div>
</EntitySubTree>
</Binding>
</>
2 changes: 1 addition & 1 deletion packages/playground/admin/lib/components/form/inputs.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import { TextareaAutosize } from '../ui/textarea'
import { FormLabelUI } from './ui'
import { FormCheckbox, FormCheckboxProps, FormFieldScope, FormInput, FormInputProps, FormLabel, FormRadioInput, FormRadioItemProps } from '@contember/react-form'
import { FormContainer, FormContainerProps } from './container'
import { Component, Field, SugaredRelativeSingleField } from '@contember/interface'
import { Component } from '@contember/interface'


export type InputFieldProps =
Expand Down
75 changes: 72 additions & 3 deletions packages/playground/admin/lib/components/form/select.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import { MultiSelectInput, MultiSelectInputProps, SelectInput, SelectInputProps, SortableMultiSelectInput, SortableMultiSelectInputProps } from '../select'
import {
MultiSelectInput,
MultiSelectInputProps,
SelectDefaultPlaceholderUI,
SelectInput,
SelectInputActionsUI,
SelectInputProps,
SelectInputUI,
SelectInputWrapperUI,
SelectListItemUI,
SelectPopoverContent,
SortableMultiSelectInput,
SortableMultiSelectInputProps,
} from '../select'
import * as React from 'react'
import { FormContainer, FormContainerProps } from './container'
import { FormHasManyRelationScope, FormHasOneRelationScope } from '@contember/react-form'
import { Component } from '@contember/interface'
import { FormFieldScope, FormHasManyRelationScope, FormHasOneRelationScope, useFormFieldId } from '@contember/react-form'
import { Component, Field, SugaredRelativeSingleField, useField } from '@contember/interface'
import { Popover, PopoverTrigger } from '../ui/popover'
import { ChevronDownIcon, ChevronUpIcon } from 'lucide-react'


export type SelectFieldProps =
Expand Down Expand Up @@ -52,3 +67,57 @@ export const SortableMultiSelectField = Component<SortableMultiSelectFieldProps>
</FormHasManyRelationScope>
)
})

export type SelectEnumFieldProps =
& Omit<FormContainerProps, 'children'>
& {
field: SugaredRelativeSingleField['field']
options: Record<string, React.ReactNode>
placeholder?: React.ReactNode
defaultValue?: string
}

export const SelectEnumField = Component<SelectEnumFieldProps>(
({ field, label, description, options, placeholder }) => {
return (
<FormFieldScope field={field}>
<FormContainer description={description} label={label}>
<SelectEnumFieldInner field={field} options={options} placeholder={placeholder} />
</FormContainer>
</FormFieldScope>
)
},
({ field, defaultValue }) => <Field field={field} defaultValue={defaultValue} />,
'SelectEnumField',
)

const SelectEnumFieldInner = ({ field, options, placeholder }: SelectEnumFieldProps) => {
const [open, setOpen] = React.useState(false)
const fieldAccessor = useField<string>(field)
const id = useFormFieldId()
return (
<Popover open={open} onOpenChange={setOpen}>
<SelectInputWrapperUI>
<PopoverTrigger asChild>
<SelectInputUI id={id ? `${id}-input` : undefined}>
{fieldAccessor.value ? options[fieldAccessor.value] : placeholder ?? <SelectDefaultPlaceholderUI />}
<SelectInputActionsUI>
{open ? <ChevronUpIcon /> : <ChevronDownIcon />}
</SelectInputActionsUI>
</SelectInputUI>
</PopoverTrigger>
</SelectInputWrapperUI>
<SelectPopoverContent>
{Object.entries(options).map(([value, label]) => (
<SelectListItemUI key={value} onClick={() => {
fieldAccessor.updateValue(value)
setOpen(false)
}}>
{label}
</SelectListItemUI>
))}
</SelectPopoverContent>
</Popover>

)
}
64 changes: 43 additions & 21 deletions packages/playground/admin/lib/components/select/multi-select.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,17 @@
import * as React from 'react'
import { ReactNode } from 'react'
import { MultiSelectItemContentUI, MultiSelectItemRemoveButtonUI, MultiSelectItemUI, SelectCreateNewTrigger, SelectDefaultPlaceholderUI, SelectInputActionsUI, SelectInputUI, SelectListItemUI, SelectPopoverContent } from './ui'
import {
MultiSelectItemContentUI,
MultiSelectItemRemoveButtonUI,
MultiSelectItemUI,
SelectCreateNewTrigger,
SelectDefaultPlaceholderUI,
SelectInputActionsUI,
SelectInputUI,
SelectInputWrapperUI,
SelectListItemUI,
SelectPopoverContent,
} from './ui'
import { ChevronDownIcon } from 'lucide-react'
import { Popover, PopoverTrigger } from '../ui/popover'
import { Component, SugaredQualifiedEntityList, SugaredRelativeEntityList } from '@contember/interface'
Expand All @@ -9,6 +20,7 @@ import { SelectListInner } from './list'
import { MultiSelect, SelectDataView, SelectEachValue, SelectItemTrigger, SelectOption, SelectPlaceholder } from '@contember/react-select'
import { CreateEntityDialog } from './create-new'
import { DataViewUnionFilterFields } from '@contember/react-dataview'
import { useFormFieldId } from '@contember/react-form'

export type MultiSelectInputProps =
& {
Expand All @@ -21,32 +33,36 @@ export type MultiSelectInputProps =
}

export const MultiSelectInput = Component<MultiSelectInputProps>(({ field, queryField, options, children, placeholder, createNewForm }) => {
const id = useFormFieldId()
return (
<MultiSelect field={field} options={options}>
<div className="flex gap-1 items-center">
<Popover>
<PopoverTrigger asChild>
<SelectInputUI>
<SelectPlaceholder>
{placeholder ?? <SelectDefaultPlaceholderUI />}
</SelectPlaceholder>
<SelectInputWrapperUI>
<PopoverTrigger asChild>
<SelectInputUI id={id ? `${id}-input` : undefined}>
<SelectPlaceholder>
{placeholder ?? <SelectDefaultPlaceholderUI />}
</SelectPlaceholder>

<SelectEachValue>
<MultiSelectItemUI>
<MultiSelectItemContentUI>
{children}
</MultiSelectItemContentUI>
<SelectItemTrigger>
<MultiSelectItemRemoveButtonUI onClick={e => e.stopPropagation()} />
</SelectItemTrigger>
</MultiSelectItemUI>
</SelectEachValue>
<SelectEachValue>
<MultiSelectItemUI>
<MultiSelectItemContentUI>
{children}
</MultiSelectItemContentUI>
<SelectItemTrigger>
<MultiSelectItemRemoveButtonUI onClick={e => e.stopPropagation()} />
</SelectItemTrigger>
</MultiSelectItemUI>
</SelectEachValue>

<SelectInputActionsUI>
<ChevronDownIcon className={'w-4 h-4'} />
</SelectInputActionsUI>
</SelectInputUI>
</PopoverTrigger>

<SelectInputActionsUI>
<ChevronDownIcon className={'w-4 h-4'} />
</SelectInputActionsUI>
</SelectInputUI>
</PopoverTrigger>
</SelectInputWrapperUI>
<SelectPopoverContent>
<SelectDataView queryField={queryField}>
<SelectListInner filterToolbar={<SelectDefaultFilter />}>
Expand All @@ -69,4 +85,10 @@ export const MultiSelectInput = Component<MultiSelectInputProps>(({ field, query
</div>
</MultiSelect>
)
}, ({ field, options, children }) => {
return (
<MultiSelect field={field} options={options}>
{children}
</MultiSelect>
)
})
46 changes: 24 additions & 22 deletions packages/playground/admin/lib/components/select/select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,13 @@ import { Component, SugaredQualifiedEntityList } from '@contember/interface'
import { Button } from '../ui/button'
import { SugaredRelativeSingleEntity } from '@contember/react-binding'
import { ChevronDownIcon, XIcon } from 'lucide-react'
import { SelectCreateNewTrigger, SelectDefaultPlaceholderUI, SelectInputActionsUI, SelectInputUI, SelectListItemUI, SelectPopoverContent } from './ui'
import { SelectCreateNewTrigger, SelectDefaultPlaceholderUI, SelectInputActionsUI, SelectInputUI, SelectInputWrapperUI, SelectListItemUI, SelectPopoverContent } from './ui'
import { SelectListInner } from './list'
import { Select, SelectDataView, SelectEachValue, SelectItemTrigger, SelectOption, SelectPlaceholder } from '@contember/react-select'
import { CreateEntityDialog } from './create-new'
import { SelectDefaultFilter } from './filter'
import { DataViewUnionFilterFields } from '@contember/react-dataview'
import { useFormFieldId } from '@contember/react-form'

export type SelectInputProps =
& {
Expand All @@ -25,36 +26,37 @@ export type SelectInputProps =

export const SelectInput = Component<SelectInputProps>(({ field, queryField, options, children, placeholder, createNewForm }) => {
const [open, setOpen] = React.useState(false)
const id = useFormFieldId()

return (
<Select field={field} onSelect={() => setOpen(false)} options={options}>
<div className="flex gap-1 items-center">
<Popover open={open} onOpenChange={setOpen}>
<PopoverTrigger asChild>

<SelectInputUI>
<SelectPlaceholder>
{placeholder ?? <SelectDefaultPlaceholderUI />}
</SelectPlaceholder>
<SelectEachValue>
{children}
</SelectEachValue>
<SelectInputActionsUI>
<SelectInputWrapperUI>
<PopoverTrigger asChild>
<SelectInputUI id={id ? `${id}-input` : undefined}>
<SelectPlaceholder>
{placeholder ?? <SelectDefaultPlaceholderUI />}
</SelectPlaceholder>
<SelectEachValue>
<SelectItemTrigger>
<Button size={'xs'} variant={'ghost'}>
<XIcon className={'w-4 h-4'} />
</Button>
</SelectItemTrigger>
{children}
</SelectEachValue>
<ChevronDownIcon className={'w-4 h-4'} />
</SelectInputActionsUI>
</SelectInputUI>

</PopoverTrigger>
</SelectInputUI>
</PopoverTrigger>
<SelectInputActionsUI>
<SelectEachValue>
<SelectItemTrigger>
<Button size={'xs'} variant={'ghost'}>
<XIcon className={'w-4 h-4'} />
</Button>
</SelectItemTrigger>
</SelectEachValue>
<ChevronDownIcon className={'w-4 h-4'} />
</SelectInputActionsUI>
</SelectInputWrapperUI>
<SelectPopoverContent>
<SelectDataView queryField={queryField}>
<SelectListInner filterToolbar={<SelectDefaultFilter/>}>
<SelectListInner filterToolbar={<SelectDefaultFilter />}>
<SelectOption>
<SelectItemTrigger>
<SelectListItemUI>
Expand Down
Loading

0 comments on commit ea81d94

Please sign in to comment.