From 6abb37ebee029c10c5e36c2e325f52dc1af304a4 Mon Sep 17 00:00:00 2001 From: Tomas Langer Date: Thu, 23 May 2024 17:46:16 +0200 Subject: [PATCH 1/2] feat(playground): add SelectEnumField --- .../admin/app/components/navigation.tsx | 9 ++-- .../playground/admin/app/pages/select.tsx | 19 ++++++- .../admin/lib/components/form/select.tsx | 54 +++++++++++++++++-- 3 files changed, 74 insertions(+), 8 deletions(-) diff --git a/packages/playground/admin/app/components/navigation.tsx b/packages/playground/admin/app/components/navigation.tsx index 279fb84bd..88de28ffd 100644 --- a/packages/playground/admin/app/components/navigation.tsx +++ b/packages/playground/admin/app/components/navigation.tsx @@ -17,10 +17,10 @@ export const Navigation = () => { } label={'Repeater'}> - - - - + + + + } label={'Grid'}> @@ -39,6 +39,7 @@ export const Navigation = () => { + } label={'Upload'}> diff --git a/packages/playground/admin/app/pages/select.tsx b/packages/playground/admin/app/pages/select.tsx index b7557bc08..14ed77b7f 100644 --- a/packages/playground/admin/app/pages/select.tsx +++ b/packages/playground/admin/app/pages/select.tsx @@ -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 = () => <> @@ -70,3 +70,20 @@ export const createNewForm = () => <> + +export const enumSelect = () => <> + + + + + +
+ +
+
+
+ diff --git a/packages/playground/admin/lib/components/form/select.tsx b/packages/playground/admin/lib/components/form/select.tsx index a81292962..a244c1955 100644 --- a/packages/playground/admin/lib/components/form/select.tsx +++ b/packages/playground/admin/lib/components/form/select.tsx @@ -1,8 +1,10 @@ -import { MultiSelectInput, MultiSelectInputProps, SelectInput, SelectInputProps, SortableMultiSelectInput, SortableMultiSelectInputProps } from '../select' +import { MultiSelectInput, MultiSelectInputProps, SelectDefaultPlaceholderUI, SelectInput, SelectInputActionsUI, SelectInputProps, SelectInputUI, 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 } 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 = @@ -52,3 +54,49 @@ export const SortableMultiSelectField = Component ) }) + +export type SelectEnumFieldProps = + & Omit + & { + field: SugaredRelativeSingleField['field'] + options: Record + placeholder?: React.ReactNode + defaultValue?: string + } + +export const SelectEnumField = Component( + ({ field, label, description, options, placeholder }) => { + const [open, setOpen] = React.useState(false) + const fieldAccessor = useField(field) + + return ( + + + + + + {fieldAccessor.value ? options[fieldAccessor.value] : placeholder ?? } + + {open ? : } + + + + + {Object.entries(options).map(([value, label]) => ( + { + fieldAccessor.updateValue(value) + setOpen(false) + }}> + {label} + + ))} + + + + + + ) + }, + ({ field, defaultValue }) => , + 'SelectEnumField', +) From 3dabe9171423017f5bb325cea77cc09f5c85290f Mon Sep 17 00:00:00 2001 From: David Matejka Date: Fri, 24 May 2024 13:37:03 +0200 Subject: [PATCH 2/2] feat(playground): improve tab navigation in selects --- .../admin/lib/components/form/inputs.tsx | 2 +- .../admin/lib/components/form/select.tsx | 73 +++++++----- .../lib/components/select/multi-select.tsx | 64 +++++++---- .../admin/lib/components/select/select.tsx | 46 ++++---- .../lib/components/select/sortable-select.tsx | 104 +++++++++--------- .../admin/lib/components/select/ui.tsx | 51 +++++++-- 6 files changed, 209 insertions(+), 131 deletions(-) diff --git a/packages/playground/admin/lib/components/form/inputs.tsx b/packages/playground/admin/lib/components/form/inputs.tsx index 4472f11ac..3b38e45b5 100644 --- a/packages/playground/admin/lib/components/form/inputs.tsx +++ b/packages/playground/admin/lib/components/form/inputs.tsx @@ -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 = diff --git a/packages/playground/admin/lib/components/form/select.tsx b/packages/playground/admin/lib/components/form/select.tsx index a244c1955..b1625ff49 100644 --- a/packages/playground/admin/lib/components/form/select.tsx +++ b/packages/playground/admin/lib/components/form/select.tsx @@ -1,7 +1,20 @@ -import { MultiSelectInput, MultiSelectInputProps, SelectDefaultPlaceholderUI, SelectInput, SelectInputActionsUI, SelectInputProps, SelectInputUI, SelectListItemUI, SelectPopoverContent, 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 { FormFieldScope, FormHasManyRelationScope, FormHasOneRelationScope } from '@contember/react-form' +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' @@ -66,33 +79,10 @@ export type SelectEnumFieldProps = export const SelectEnumField = Component( ({ field, label, description, options, placeholder }) => { - const [open, setOpen] = React.useState(false) - const fieldAccessor = useField(field) - return ( - - - - {fieldAccessor.value ? options[fieldAccessor.value] : placeholder ?? } - - {open ? : } - - - - - {Object.entries(options).map(([value, label]) => ( - { - fieldAccessor.updateValue(value) - setOpen(false) - }}> - {label} - - ))} - - - + ) @@ -100,3 +90,34 @@ export const SelectEnumField = Component( ({ field, defaultValue }) => , 'SelectEnumField', ) + +const SelectEnumFieldInner = ({ field, options, placeholder }: SelectEnumFieldProps) => { + const [open, setOpen] = React.useState(false) + const fieldAccessor = useField(field) + const id = useFormFieldId() + return ( + + + + + {fieldAccessor.value ? options[fieldAccessor.value] : placeholder ?? } + + {open ? : } + + + + + + {Object.entries(options).map(([value, label]) => ( + { + fieldAccessor.updateValue(value) + setOpen(false) + }}> + {label} + + ))} + + + + ) +} diff --git a/packages/playground/admin/lib/components/select/multi-select.tsx b/packages/playground/admin/lib/components/select/multi-select.tsx index aaf340a90..fa11e0b57 100644 --- a/packages/playground/admin/lib/components/select/multi-select.tsx +++ b/packages/playground/admin/lib/components/select/multi-select.tsx @@ -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' @@ -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 = & { @@ -21,32 +33,36 @@ export type MultiSelectInputProps = } export const MultiSelectInput = Component(({ field, queryField, options, children, placeholder, createNewForm }) => { + const id = useFormFieldId() return (
- - - - {placeholder ?? } - + + + + + {placeholder ?? } + - - - - {children} - - - e.stopPropagation()} /> - - - + + + + {children} + + + e.stopPropagation()} /> + + + + + + + + + - - - - - + }> @@ -69,4 +85,10 @@ export const MultiSelectInput = Component(({ field, query
) +}, ({ field, options, children }) => { + return ( + + {children} + + ) }) diff --git a/packages/playground/admin/lib/components/select/select.tsx b/packages/playground/admin/lib/components/select/select.tsx index 25ab09de3..2e7a32873 100644 --- a/packages/playground/admin/lib/components/select/select.tsx +++ b/packages/playground/admin/lib/components/select/select.tsx @@ -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 = & { @@ -25,36 +26,37 @@ export type SelectInputProps = export const SelectInput = Component(({ field, queryField, options, children, placeholder, createNewForm }) => { const [open, setOpen] = React.useState(false) + const id = useFormFieldId() return (