Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(playground): add SelectEnumField #705

Merged
merged 2 commits into from
May 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading