Skip to content

Commit d766b19

Browse files
authored
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.
1 parent f31568c commit d766b19

File tree

10 files changed

+47
-29
lines changed

10 files changed

+47
-29
lines changed

packages/richtext-lexical/src/features/relationship/client/drawer/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use client'
2+
import type { ListDrawerProps } from '@payloadcms/ui'
23
import type { LexicalEditor } from 'lexical'
34

45
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
@@ -67,13 +68,13 @@ const RelationshipDrawerComponent: React.FC<Props> = ({ enabledCollectionSlugs }
6768
)
6869
}, [editor, openListDrawer])
6970

70-
const onSelect = useCallback(
71-
({ collectionSlug, docID }: { collectionSlug: string; docID: number | string }) => {
71+
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
72+
({ collectionSlug, doc }) => {
7273
insertRelationship({
7374
editor,
7475
relationTo: collectionSlug,
7576
replaceNodeKey,
76-
value: docID,
77+
value: doc.id,
7778
})
7879
closeListDrawer()
7980
},

packages/richtext-lexical/src/features/upload/client/drawer/index.tsx

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use client'
2+
import type { ListDrawerProps } from '@payloadcms/ui'
23
import type { LexicalEditor } from 'lexical'
34

45
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext.js'
@@ -77,14 +78,14 @@ const UploadDrawerComponent: React.FC<Props> = ({ enabledCollectionSlugs }) => {
7778
)
7879
}, [editor, openListDrawer])
7980

80-
const onSelect = useCallback(
81-
({ collectionSlug, docID }: { collectionSlug: string; docID: number | string }) => {
81+
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
82+
({ collectionSlug, doc }) => {
8283
closeListDrawer()
8384
insertUpload({
8485
editor,
8586
relationTo: collectionSlug,
8687
replaceNodeKey,
87-
value: docID,
88+
value: doc.id,
8889
})
8990
},
9091
[editor, closeListDrawer, replaceNodeKey],

packages/richtext-slate/src/field/elements/relationship/Button/index.tsx

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
'use client'
2+
import type { ListDrawerProps } from '@payloadcms/ui'
23

34
import { useListDrawer, useTranslation } from '@payloadcms/ui'
4-
import React, { Fragment, useCallback, useEffect, useState } from 'react'
5+
import React, { Fragment, useCallback, useState } from 'react'
56
import { ReactEditor, useSlate } from 'slate-react'
67

78
import { RelationshipIcon } from '../../../icons/Relationship/index.js'
@@ -34,15 +35,13 @@ type Props = {
3435
const RelationshipButtonComponent: React.FC<Props> = ({ enabledCollectionSlugs }) => {
3536
const { t } = useTranslation()
3637
const editor = useSlate()
37-
const [selectedCollectionSlug, setSelectedCollectionSlug] = useState(
38-
() => enabledCollectionSlugs[0],
39-
)
40-
const [ListDrawer, ListDrawerToggler, { closeDrawer, isDrawerOpen }] = useListDrawer({
38+
const [selectedCollectionSlug] = useState(() => enabledCollectionSlugs[0])
39+
const [ListDrawer, ListDrawerToggler, { closeDrawer }] = useListDrawer({
4140
collectionSlugs: enabledCollectionSlugs,
4241
selectedCollection: selectedCollectionSlug,
4342
})
4443

45-
const onSelect = useCallback(
44+
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
4645
({ collectionSlug, docID }) => {
4746
insertRelationship(editor, {
4847
relationTo: collectionSlug,

packages/richtext-slate/src/field/elements/relationship/Element/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use client'
22

3+
import type { ListDrawerProps } from '@payloadcms/ui'
4+
35
import { getTranslation } from '@payloadcms/translations'
46
import {
57
Button,
@@ -103,8 +105,8 @@ const RelationshipElementComponent: React.FC = () => {
103105
[editor, element, relatedCollection, cacheBust, setParams, closeDrawer],
104106
)
105107

106-
const swapRelationship = React.useCallback(
107-
({ collectionSlug, docID }) => {
108+
const swapRelationship = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
109+
({ collectionSlug, doc }) => {
108110
const elementPath = ReactEditor.findPath(editor, element)
109111

110112
Transforms.setNodes(
@@ -113,7 +115,7 @@ const RelationshipElementComponent: React.FC = () => {
113115
type: 'relationship',
114116
children: [{ text: ' ' }],
115117
relationTo: collectionSlug,
116-
value: { id: docID },
118+
value: { id: doc.id },
117119
},
118120
{ at: elementPath },
119121
)

packages/richtext-slate/src/field/elements/upload/Button/index.tsx

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
'use client'
22

3+
import type { ListDrawerProps } from '@payloadcms/ui'
4+
35
import { useListDrawer, useTranslation } from '@payloadcms/ui'
46
import React, { Fragment, useCallback } from 'react'
57
import { ReactEditor, useSlate } from 'slate-react'
@@ -41,12 +43,12 @@ const UploadButton: React.FC<ButtonProps> = ({ enabledCollectionSlugs }) => {
4143
uploads: true,
4244
})
4345

44-
const onSelect = useCallback(
45-
({ collectionSlug, docID }) => {
46+
const onSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
47+
({ collectionSlug, doc }) => {
4648
insertUpload(editor, {
4749
relationTo: collectionSlug,
4850
value: {
49-
id: docID,
51+
id: doc.id,
5052
},
5153
})
5254
closeDrawer()

packages/richtext-slate/src/field/elements/upload/Element/index.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
'use client'
22

3+
import type { ListDrawerProps } from '@payloadcms/ui'
34
import type { ClientCollectionConfig } from 'payload'
45

56
import { getTranslation } from '@payloadcms/translations'
@@ -23,8 +24,8 @@ import type { UploadElementType } from '../types.js'
2324
import { useElement } from '../../../providers/ElementProvider.js'
2425
import { EnabledRelationshipsCondition } from '../../EnabledRelationshipsCondition.js'
2526
import { uploadFieldsSchemaPath, uploadName } from '../shared.js'
26-
import './index.scss'
2727
import { UploadDrawer } from './UploadDrawer/index.js'
28+
import './index.scss'
2829

2930
const baseClass = 'rich-text-upload'
3031

@@ -110,13 +111,13 @@ const UploadElementComponent: React.FC<{ enabledCollectionSlugs?: string[] }> =
110111
[editor, element, setParams, cacheBust, closeDrawer],
111112
)
112113

113-
const swapUpload = React.useCallback(
114-
({ collectionSlug, docID }) => {
114+
const swapUpload = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
115+
({ collectionSlug, doc }) => {
115116
const newNode = {
116117
type: uploadName,
117118
children: [{ text: ' ' }],
118119
relationTo: collectionSlug,
119-
value: { id: docID },
120+
value: { id: doc.id },
120121
}
121122

122123
const elementPath = ReactEditor.findPath(editor, element)

packages/ui/src/elements/ListDrawer/DrawerContent.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,7 @@ export const ListDrawerContent: React.FC<ListDrawerProps> = ({
111111
[
112112
serverFunction,
113113
closeModal,
114+
allowCreate,
114115
drawerSlug,
115116
isOpen,
116117
enableRowSelections,
@@ -130,6 +131,7 @@ export const ListDrawerContent: React.FC<ListDrawerProps> = ({
130131
if (typeof onSelect === 'function') {
131132
onSelect({
132133
collectionSlug: selectedOption.value,
134+
doc,
133135
docID: doc.id,
134136
})
135137
}

packages/ui/src/elements/ListDrawer/Provider.tsx

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { CollectionSlug, ListQuery } from 'payload'
1+
import type { CollectionSlug, Data, ListQuery } from 'payload'
22

33
import { createContext, useContext } from 'react'
44

@@ -14,7 +14,16 @@ export type ListDrawerContextProps = {
1414
readonly enabledCollections?: CollectionSlug[]
1515
readonly onBulkSelect?: (selected: ReturnType<typeof useSelection>['selected']) => void
1616
readonly onQueryChange?: (query: ListQuery) => void
17-
readonly onSelect?: (args: { collectionSlug: CollectionSlug; docID: string }) => void
17+
readonly onSelect?: (args: {
18+
collectionSlug: CollectionSlug
19+
doc: Data
20+
/**
21+
* @deprecated
22+
* The `docID` property is deprecated and will be removed in the next major version of Payload.
23+
* Use `doc.id` instead.
24+
*/
25+
docID: string
26+
}) => void
1827
readonly selectedOption?: Option<string>
1928
readonly setSelectedOption?: (option: Option<string>) => void
2029
}

packages/ui/src/elements/TableColumns/RenderDefaultCell/index.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export const RenderDefaultCell: React.FC<{
3636
if (typeof onSelect === 'function') {
3737
onSelect({
3838
collectionSlug: rowColl,
39+
doc: rowData,
3940
docID: rowData.id as string,
4041
})
4142
}

packages/ui/src/fields/Upload/Input.tsx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -350,9 +350,9 @@ export function UploadInput(props: UploadInputProps) {
350350
[closeCreateDocDrawer, activeRelationTo, onChange],
351351
)
352352

353-
const onListSelect = React.useCallback<NonNullable<ListDrawerProps['onSelect']>>(
354-
async ({ collectionSlug, docID }) => {
355-
const loadedDocs = await populateDocs([docID], collectionSlug)
353+
const onListSelect = useCallback<NonNullable<ListDrawerProps['onSelect']>>(
354+
async ({ collectionSlug, doc }) => {
355+
const loadedDocs = await populateDocs([doc.id], collectionSlug)
356356
const selectedDoc = loadedDocs ? loadedDocs.docs?.[0] : null
357357
setPopulatedDocs((currentDocs) => {
358358
if (selectedDoc) {
@@ -375,9 +375,9 @@ export function UploadInput(props: UploadInputProps) {
375375
return currentDocs
376376
})
377377
if (hasMany) {
378-
onChange([...(Array.isArray(value) ? value : []), docID])
378+
onChange([...(Array.isArray(value) ? value : []), doc.id])
379379
} else {
380-
onChange(docID)
380+
onChange(doc.id)
381381
}
382382
closeListDrawer()
383383
},

0 commit comments

Comments
 (0)