feat: add clear button to relation widget

This commit is contained in:
Daniel Lautzenheiser 2023-08-31 11:50:28 -04:00
parent 3d02a6b180
commit ff81002628
3 changed files with 61 additions and 17 deletions

View File

@ -1,9 +1,11 @@
import { Combobox, Transition } from '@headlessui/react'; import { Combobox, Transition } from '@headlessui/react';
import { Check as CheckIcon } from '@styled-icons/material/Check'; import { Check as CheckIcon } from '@styled-icons/material/Check';
import { Close as CloseIcon } from '@styled-icons/material/Close';
import { KeyboardArrowDown as KeyboardArrowDownIcon } from '@styled-icons/material/KeyboardArrowDown'; import { KeyboardArrowDown as KeyboardArrowDownIcon } from '@styled-icons/material/KeyboardArrowDown';
import React, { forwardRef, Fragment, useCallback } from 'react'; import React, { Fragment, forwardRef, useCallback } from 'react';
import classNames from '@staticcms/core/lib/util/classNames.util'; import classNames from '@staticcms/core/lib/util/classNames.util';
import IconButton from '../button/IconButton';
import type { ReactNode, Ref } from 'react'; import type { ReactNode, Ref } from 'react';
@ -27,13 +29,23 @@ export interface AutocompleteProps<T> {
value: T | T[] | null; value: T | T[] | null;
options: T[] | Option<T>[]; options: T[] | Option<T>[];
disabled?: boolean; disabled?: boolean;
required?: boolean;
displayValue: (item: T | T[] | null) => string; displayValue: (item: T | T[] | null) => string;
onQuery: (query: string) => void; onQuery: (query: string) => void;
onChange: AutocompleteChangeEventHandler<T>; onChange: AutocompleteChangeEventHandler<T | undefined>;
} }
const Autocomplete = function <T>( const Autocomplete = function <T>(
{ label, value, options, disabled, displayValue, onQuery, onChange }: AutocompleteProps<T>, {
label,
value,
options,
disabled,
required,
displayValue,
onQuery,
onChange,
}: AutocompleteProps<T>,
ref: Ref<HTMLInputElement>, ref: Ref<HTMLInputElement>,
) { ) {
const handleChange = useCallback( const handleChange = useCallback(
@ -56,6 +68,10 @@ const Autocomplete = function <T>(
[onChange, value], [onChange, value],
); );
const clear = useCallback(() => {
onChange(undefined);
}, [onChange]);
return ( return (
<div className="relative w-full"> <div className="relative w-full">
<Combobox value={value} onChange={handleChange} disabled={disabled}> <Combobox value={value} onChange={handleChange} disabled={disabled}>
@ -108,7 +124,8 @@ const Autocomplete = function <T>(
displayValue={displayValue} displayValue={displayValue}
onChange={event => onQuery(event.target.value)} onChange={event => onQuery(event.target.value)}
/> />
<Combobox.Button className="absolute inset-y-0 right-0 flex items-center pr-2"> <div className="absolute inset-y-0 right-0 flex items-center pr-2 gap-1">
<Combobox.Button>
<KeyboardArrowDownIcon <KeyboardArrowDownIcon
className={classNames( className={classNames(
` `
@ -125,6 +142,26 @@ const Autocomplete = function <T>(
aria-hidden="true" aria-hidden="true"
/> />
</Combobox.Button> </Combobox.Button>
{!required && !Array.isArray(value) ? (
<IconButton variant="text" disabled={disabled} onClick={clear}>
<CloseIcon
className={classNames(
`
h-5
w-5
text-gray-400
`,
disabled &&
`
text-gray-300/75
dark:text-gray-600/75
`,
)}
aria-hidden="true"
/>
</IconButton>
) : null}
</div>
</div> </div>
<Transition <Transition
as={Fragment} as={Fragment}

View File

@ -323,6 +323,10 @@ const RelationControl: FC<WidgetControlProps<string | string[], RelationField>>
[onChange, uniqueOptionsByValue], [onChange, uniqueOptionsByValue],
); );
const isRequired = useMemo(() => field.required ?? true, [field.required]);
console.log('field.required', field.required);
return ( return (
<Field <Field
inputRef={ref} inputRef={ref}
@ -363,6 +367,7 @@ const RelationControl: FC<WidgetControlProps<string | string[], RelationField>>
value={selectedValue} value={selectedValue}
options={uniqueOptions} options={uniqueOptions}
disabled={disabled} disabled={disabled}
required={isRequired}
displayValue={item => { displayValue={item => {
if (!item || Array.isArray(item)) { if (!item || Array.isArray(item)) {
return ''; return '';

View File

@ -77,7 +77,9 @@ const SelectControl: FC<WidgetControlProps<string | number | (string | number)[]
? !selectedValue?.length ? !selectedValue?.length
: isNullish(selectedValue); : isNullish(selectedValue);
if (field.required && isEmpty && isMultiple) { const isRequired = field.required ?? true;
if (isRequired && isEmpty && isMultiple) {
setInternalValue([]); setInternalValue([]);
onChange([]); onChange([]);
} else if (isEmpty) { } else if (isEmpty) {