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

View File

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

View File

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