fix(ui): allow selectinputs to reset to their initial values if theres no provided value (#11252)
When reusing the SelectInput component from the UI package, if you set value to `''` it will continue to display the previously selected value instead of clearing out the field as expected. The ReactSelect component doesn't behave in this way and instead will clear out the field. This fix addresses this difference by resetting `valueToRender` inside the SelectInput to null.
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
'use client'
|
||||
|
||||
import type { OptionObject, UIField } from 'payload'
|
||||
|
||||
import { SelectInput, useField } from '@payloadcms/ui'
|
||||
import { useEffect, useMemo } from 'react'
|
||||
|
||||
interface Props {
|
||||
field: UIField
|
||||
path: string
|
||||
required?: boolean
|
||||
}
|
||||
|
||||
const selectOptions = [
|
||||
{
|
||||
label: 'Option 1',
|
||||
value: 'option-1',
|
||||
},
|
||||
{
|
||||
label: 'Option 2',
|
||||
value: 'option-2',
|
||||
},
|
||||
]
|
||||
export function CustomInput({ field, path, required = false }: Props) {
|
||||
const { setValue, value } = useField<string>({ path })
|
||||
|
||||
const options = useMemo(() => {
|
||||
const internal: OptionObject[] = []
|
||||
|
||||
internal.push(...selectOptions)
|
||||
|
||||
return internal
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div className="custom-select-input">
|
||||
<SelectInput
|
||||
label={field.label}
|
||||
name={field.name}
|
||||
onChange={(option) => {
|
||||
const selectedValue = (Array.isArray(option) ? option[0]?.value : option?.value) || ''
|
||||
setValue(selectedValue)
|
||||
}}
|
||||
options={options}
|
||||
path={path}
|
||||
required={required}
|
||||
value={value}
|
||||
/>
|
||||
<button
|
||||
className="clear-value"
|
||||
onClick={(e) => {
|
||||
e.preventDefault()
|
||||
setValue('')
|
||||
}}
|
||||
type="button"
|
||||
>
|
||||
Click me to reset value
|
||||
</button>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -73,6 +73,15 @@ export const CustomFields: CollectionConfig = {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'customSelectInput',
|
||||
type: 'text',
|
||||
admin: {
|
||||
components: {
|
||||
Field: '/collections/CustomFields/fields/Select/CustomInput.js#CustomInput',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: 'relationshipFieldWithBeforeAfterInputs',
|
||||
type: 'relationship',
|
||||
|
||||
@@ -21,10 +21,10 @@ import {
|
||||
customEditLabel,
|
||||
customNestedTabViewPath,
|
||||
customNestedTabViewTitle,
|
||||
customTabAdminDescription,
|
||||
customTabLabel,
|
||||
customTabViewPath,
|
||||
customTabViewTitle,
|
||||
customTabAdminDescription,
|
||||
} from '../../shared.js'
|
||||
import {
|
||||
customFieldsSlug,
|
||||
@@ -274,9 +274,7 @@ describe('Document View', () => {
|
||||
test('List drawer should not effect underlying breadcrumbs', async () => {
|
||||
await navigateToDoc(page, postsUrl)
|
||||
|
||||
expect(await page.locator('.step-nav.app-header__step-nav a').nth(1).innerText()).toBe(
|
||||
'Posts',
|
||||
)
|
||||
await expect(page.locator('.step-nav.app-header__step-nav a').nth(1)).toHaveText('Posts')
|
||||
|
||||
await page.locator('#field-upload button.upload__listToggler').click()
|
||||
await expect(page.locator('[id^=list-drawer_1_]')).toBeVisible()
|
||||
@@ -286,9 +284,7 @@ describe('Document View', () => {
|
||||
page.locator('.step-nav.app-header__step-nav .step-nav__last'),
|
||||
).not.toContainText('Uploads')
|
||||
|
||||
expect(await page.locator('.step-nav.app-header__step-nav a').nth(1).innerText()).toBe(
|
||||
'Posts',
|
||||
)
|
||||
await expect(page.locator('.step-nav.app-header__step-nav a').nth(1)).toHaveText('Posts')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -400,9 +396,9 @@ describe('Document View', () => {
|
||||
await page.waitForURL(postsUrl.create)
|
||||
|
||||
const secondTab = page.locator('.tabs-field__tab-button').nth(1)
|
||||
secondTab.click()
|
||||
await secondTab.click()
|
||||
|
||||
wait(500)
|
||||
await wait(500)
|
||||
|
||||
const tabsContent = page.locator('.tabs-field__content-wrap')
|
||||
await expect(
|
||||
@@ -463,6 +459,24 @@ describe('Document View', () => {
|
||||
).toBeVisible()
|
||||
})
|
||||
|
||||
test('custom select input can have its value cleared', async () => {
|
||||
await page.goto(customFieldsURL.create)
|
||||
await page.waitForURL(customFieldsURL.create)
|
||||
await expect(page.locator('#field-customSelectInput')).toBeVisible()
|
||||
|
||||
await page.locator('#field-customSelectInput .rs__control').click()
|
||||
await page.locator('#field-customSelectInput .rs__option').first().click()
|
||||
|
||||
await expect(page.locator('#field-customSelectInput .rs__single-value')).toHaveText(
|
||||
'Option 1',
|
||||
)
|
||||
|
||||
await page.locator('.clear-value').click()
|
||||
await expect(page.locator('#field-customSelectInput .rs__placeholder')).toHaveText(
|
||||
'Select a value',
|
||||
)
|
||||
})
|
||||
|
||||
describe('field descriptions', () => {
|
||||
test('should render static field description', async () => {
|
||||
await page.goto(customFieldsURL.create)
|
||||
@@ -535,7 +549,7 @@ describe('Document View', () => {
|
||||
describe('publish button', () => {
|
||||
test('should show publish active locale button with defaultLocalePublishOption', async () => {
|
||||
await navigateToDoc(page, postsUrl)
|
||||
const publishButton = await page.locator('#action-save')
|
||||
const publishButton = page.locator('#action-save')
|
||||
await expect(publishButton).toBeVisible()
|
||||
await expect(publishButton).toContainText('Publish in English')
|
||||
})
|
||||
|
||||
@@ -334,6 +334,7 @@ export interface CustomField {
|
||||
descriptionAsFunction?: string | null;
|
||||
descriptionAsComponent?: string | null;
|
||||
customSelectField?: string | null;
|
||||
customSelectInput?: string | null;
|
||||
relationshipFieldWithBeforeAfterInputs?: (string | null) | Post;
|
||||
arrayFieldWithBeforeAfterInputs?:
|
||||
| {
|
||||
@@ -717,6 +718,7 @@ export interface CustomFieldsSelect<T extends boolean = true> {
|
||||
descriptionAsFunction?: T;
|
||||
descriptionAsComponent?: T;
|
||||
customSelectField?: T;
|
||||
customSelectInput?: T;
|
||||
relationshipFieldWithBeforeAfterInputs?: T;
|
||||
arrayFieldWithBeforeAfterInputs?:
|
||||
| T
|
||||
|
||||
Reference in New Issue
Block a user