feat(ui): threads row data through list drawer onSelect callback (#11339)
When rendering a list drawer, you can pass a custom `onSelect` callback to execute when the user clicks on the linked cell within the table. The underlying handler, however, only passes the `docID` and `collectionSlug` args through the callback, rather than the document itself. This makes it impossible to perform side-effects that require the data of the row that was selected. Instances of this callback were also largely untyped. Needed for #11330.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
import type { ListDrawerProps } from '@payloadcms/ui'
|
||||
import type { LexicalEditor } from 'lexical'
|
||||
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
|
||||
@@ -67,13 +68,13 @@ const RelationshipDrawerComponent: React.FC<Props> = ({ enabledCollectionSlugs }
|
||||
)
|
||||
}, [editor, openListDrawer])
|
||||
|
||||
const onSelect = useCallback(
|
||||
({ collectionSlug, docID }: { collectionSlug: string; docID: number | string }) => {
|
||||
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
({ collectionSlug, doc }) => {
|
||||
insertRelationship({
|
||||
editor,
|
||||
relationTo: collectionSlug,
|
||||
replaceNodeKey,
|
||||
value: docID,
|
||||
value: doc.id,
|
||||
})
|
||||
closeListDrawer()
|
||||
},
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
'use client'
|
||||
import type { ListDrawerProps } from '@payloadcms/ui'
|
||||
import type { LexicalEditor } from 'lexical'
|
||||
|
||||
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
|
||||
@@ -77,14 +78,14 @@ const UploadDrawerComponent: React.FC<Props> = ({ enabledCollectionSlugs }) => {
|
||||
)
|
||||
}, [editor, openListDrawer])
|
||||
|
||||
const onSelect = useCallback(
|
||||
({ collectionSlug, docID }: { collectionSlug: string; docID: number | string }) => {
|
||||
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
({ collectionSlug, doc }) => {
|
||||
closeListDrawer()
|
||||
insertUpload({
|
||||
editor,
|
||||
relationTo: collectionSlug,
|
||||
replaceNodeKey,
|
||||
value: docID,
|
||||
value: doc.id,
|
||||
})
|
||||
},
|
||||
[editor, closeListDrawer, replaceNodeKey],
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
'use client'
|
||||
import type { ListDrawerProps } from '@payloadcms/ui'
|
||||
|
||||
import { useListDrawer, useTranslation } from '@payloadcms/ui'
|
||||
import React, { Fragment, useCallback, useEffect, useState } from 'react'
|
||||
import React, { Fragment, useCallback, useState } from 'react'
|
||||
import { ReactEditor, useSlate } from 'slate-react'
|
||||
|
||||
import { RelationshipIcon } from '../../../icons/Relationship/index.js'
|
||||
@@ -34,15 +35,13 @@ type Props = {
|
||||
const RelationshipButtonComponent: React.FC<Props> = ({ enabledCollectionSlugs }) => {
|
||||
const { t } = useTranslation()
|
||||
const editor = useSlate()
|
||||
const [selectedCollectionSlug, setSelectedCollectionSlug] = useState(
|
||||
() => enabledCollectionSlugs[0],
|
||||
)
|
||||
const [ListDrawer, ListDrawerToggler, { closeDrawer, isDrawerOpen }] = useListDrawer({
|
||||
const [selectedCollectionSlug] = useState(() => enabledCollectionSlugs[0])
|
||||
const [ListDrawer, ListDrawerToggler, { closeDrawer }] = useListDrawer({
|
||||
collectionSlugs: enabledCollectionSlugs,
|
||||
selectedCollection: selectedCollectionSlug,
|
||||
})
|
||||
|
||||
const onSelect = useCallback(
|
||||
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
({ collectionSlug, docID }) => {
|
||||
insertRelationship(editor, {
|
||||
relationTo: collectionSlug,
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import type { ListDrawerProps } from '@payloadcms/ui'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
import {
|
||||
Button,
|
||||
@@ -103,8 +105,8 @@ const RelationshipElementComponent: React.FC = () => {
|
||||
[editor, element, relatedCollection, cacheBust, setParams, closeDrawer],
|
||||
)
|
||||
|
||||
const swapRelationship = React.useCallback(
|
||||
({ collectionSlug, docID }) => {
|
||||
const swapRelationship = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
({ collectionSlug, doc }) => {
|
||||
const elementPath = ReactEditor.findPath(editor, element)
|
||||
|
||||
Transforms.setNodes(
|
||||
@@ -113,7 +115,7 @@ const RelationshipElementComponent: React.FC = () => {
|
||||
type: 'relationship',
|
||||
children: [{ text: ' ' }],
|
||||
relationTo: collectionSlug,
|
||||
value: { id: docID },
|
||||
value: { id: doc.id },
|
||||
},
|
||||
{ at: elementPath },
|
||||
)
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
'use client'
|
||||
|
||||
import type { ListDrawerProps } from '@payloadcms/ui'
|
||||
|
||||
import { useListDrawer, useTranslation } from '@payloadcms/ui'
|
||||
import React, { Fragment, useCallback } from 'react'
|
||||
import { ReactEditor, useSlate } from 'slate-react'
|
||||
@@ -41,12 +43,12 @@ const UploadButton: React.FC<ButtonProps> = ({ enabledCollectionSlugs }) => {
|
||||
uploads: true,
|
||||
})
|
||||
|
||||
const onSelect = useCallback(
|
||||
({ collectionSlug, docID }) => {
|
||||
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
({ collectionSlug, doc }) => {
|
||||
insertUpload(editor, {
|
||||
relationTo: collectionSlug,
|
||||
value: {
|
||||
id: docID,
|
||||
id: doc.id,
|
||||
},
|
||||
})
|
||||
closeDrawer()
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
|
||||
import type { ListDrawerProps } from '@payloadcms/ui'
|
||||
import type { ClientCollectionConfig } from 'payload'
|
||||
|
||||
import { getTranslation } from '@payloadcms/translations'
|
||||
@@ -23,8 +24,8 @@ import type { UploadElementType } from '../types.js'
|
||||
import { useElement } from '../../../providers/ElementProvider.js'
|
||||
import { EnabledRelationshipsCondition } from '../../EnabledRelationshipsCondition.js'
|
||||
import { uploadFieldsSchemaPath, uploadName } from '../shared.js'
|
||||
import './index.scss'
|
||||
import { UploadDrawer } from './UploadDrawer/index.js'
|
||||
import './index.scss'
|
||||
|
||||
const baseClass = 'rich-text-upload'
|
||||
|
||||
@@ -110,13 +111,13 @@ const UploadElementComponent: React.FC<{ enabledCollectionSlugs?: string[] }> =
|
||||
[editor, element, setParams, cacheBust, closeDrawer],
|
||||
)
|
||||
|
||||
const swapUpload = React.useCallback(
|
||||
({ collectionSlug, docID }) => {
|
||||
const swapUpload = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
({ collectionSlug, doc }) => {
|
||||
const newNode = {
|
||||
type: uploadName,
|
||||
children: [{ text: ' ' }],
|
||||
relationTo: collectionSlug,
|
||||
value: { id: docID },
|
||||
value: { id: doc.id },
|
||||
}
|
||||
|
||||
const elementPath = ReactEditor.findPath(editor, element)
|
||||
|
||||
@@ -111,6 +111,7 @@ export const ListDrawerContent: React.FC<ListDrawerProps> = ({
|
||||
[
|
||||
serverFunction,
|
||||
closeModal,
|
||||
allowCreate,
|
||||
drawerSlug,
|
||||
isOpen,
|
||||
enableRowSelections,
|
||||
@@ -130,6 +131,7 @@ export const ListDrawerContent: React.FC<ListDrawerProps> = ({
|
||||
if (typeof onSelect === 'function') {
|
||||
onSelect({
|
||||
collectionSlug: selectedOption.value,
|
||||
doc,
|
||||
docID: doc.id,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { CollectionSlug, ListQuery } from 'payload'
|
||||
import type { CollectionSlug, Data, ListQuery } from 'payload'
|
||||
|
||||
import { createContext, useContext } from 'react'
|
||||
|
||||
@@ -14,7 +14,16 @@ export type ListDrawerContextProps = {
|
||||
readonly enabledCollections?: CollectionSlug[]
|
||||
readonly onBulkSelect?: (selected: ReturnType<typeof useSelection>['selected']) => void
|
||||
readonly onQueryChange?: (query: ListQuery) => void
|
||||
readonly onSelect?: (args: { collectionSlug: CollectionSlug; docID: string }) => void
|
||||
readonly onSelect?: (args: {
|
||||
collectionSlug: CollectionSlug
|
||||
doc: Data
|
||||
/**
|
||||
* @deprecated
|
||||
* The `docID` property is deprecated and will be removed in the next major version of Payload.
|
||||
* Use `doc.id` instead.
|
||||
*/
|
||||
docID: string
|
||||
}) => void
|
||||
readonly selectedOption?: Option<string>
|
||||
readonly setSelectedOption?: (option: Option<string>) => void
|
||||
}
|
||||
|
||||
@@ -36,6 +36,7 @@ export const RenderDefaultCell: React.FC<{
|
||||
if (typeof onSelect === 'function') {
|
||||
onSelect({
|
||||
collectionSlug: rowColl,
|
||||
doc: rowData,
|
||||
docID: rowData.id as string,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -350,9 +350,9 @@ export function UploadInput(props: UploadInputProps) {
|
||||
[closeCreateDocDrawer, activeRelationTo, onChange],
|
||||
)
|
||||
|
||||
const onListSelect = React.useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
async ({ collectionSlug, docID }) => {
|
||||
const loadedDocs = await populateDocs([docID], collectionSlug)
|
||||
const onListSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
|
||||
async ({ collectionSlug, doc }) => {
|
||||
const loadedDocs = await populateDocs([doc.id], collectionSlug)
|
||||
const selectedDoc = loadedDocs ? loadedDocs.docs?.[0] : null
|
||||
setPopulatedDocs((currentDocs) => {
|
||||
if (selectedDoc) {
|
||||
@@ -375,9 +375,9 @@ export function UploadInput(props: UploadInputProps) {
|
||||
return currentDocs
|
||||
})
|
||||
if (hasMany) {
|
||||
onChange([...(Array.isArray(value) ? value : []), docID])
|
||||
onChange([...(Array.isArray(value) ? value : []), doc.id])
|
||||
} else {
|
||||
onChange(docID)
|
||||
onChange(doc.id)
|
||||
}
|
||||
closeListDrawer()
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user