Skip to content

Commit 35eb16b

Browse files
feat: ability to pass uploadActions to the Upload component (#6941)
1 parent f47d6cb commit 35eb16b

File tree

5 files changed

+90
-29
lines changed

5 files changed

+90
-29
lines changed

packages/ui/src/elements/FileDetails/index.tsx

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
'use client'
2-
import { isImage } from 'payload/shared'
32
import React from 'react'
43

54
import { UploadActions } from '../../elements/Upload/index.js'
@@ -13,20 +12,29 @@ const baseClass = 'file-details'
1312
import type { Data, FileSizes, SanitizedCollectionConfig } from 'payload'
1413

1514
export type FileDetailsProps = {
16-
canEdit?: boolean
1715
collectionSlug: string
16+
customUploadActions?: React.ReactNode[]
1817
doc: Data & {
1918
sizes?: FileSizes
2019
}
20+
enableAdjustments?: boolean
2121
handleRemove?: () => void
2222
hasImageSizes?: boolean
2323
imageCacheTag?: string
2424
uploadConfig: SanitizedCollectionConfig['upload']
2525
}
2626

2727
export const FileDetails: React.FC<FileDetailsProps> = (props) => {
28-
const { canEdit, collectionSlug, doc, handleRemove, hasImageSizes, imageCacheTag, uploadConfig } =
29-
props
28+
const {
29+
collectionSlug,
30+
customUploadActions,
31+
doc,
32+
enableAdjustments,
33+
handleRemove,
34+
hasImageSizes,
35+
imageCacheTag,
36+
uploadConfig,
37+
} = props
3038

3139
const { id, filename, filesize, height, mimeType, thumbnailURL, url, width } = doc
3240

@@ -52,9 +60,12 @@ export const FileDetails: React.FC<FileDetailsProps> = (props) => {
5260
width={width as number}
5361
/>
5462

55-
{isImage(mimeType as string) && mimeType !== 'image/svg+xml' && (
56-
<UploadActions canEdit={canEdit} showSizePreviews={hasImageSizes && doc.filename} />
57-
)}
63+
<UploadActions
64+
customActions={customUploadActions}
65+
enableAdjustments={enableAdjustments}
66+
enablePreviewSizes={hasImageSizes && doc.filename}
67+
mimeType={mimeType}
68+
/>
5869
</div>
5970
{handleRemove && (
6071
<Button

packages/ui/src/elements/Upload/index.scss

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
background-color: var(--theme-bg);
4949
}
5050

51-
&__file-mutation {
51+
&__upload-actions {
5252
display: flex;
5353
gap: calc(var(--base) / 2);
5454
flex-wrap: wrap;

packages/ui/src/elements/Upload/index.tsx

Lines changed: 46 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -33,33 +33,60 @@ const validate = (value) => {
3333
return true
3434
}
3535

36-
export const UploadActions = ({ canEdit, showSizePreviews }) => {
36+
type UploadActionsArgs = {
37+
customActions?: React.ReactNode[]
38+
enableAdjustments: boolean
39+
enablePreviewSizes: boolean
40+
mimeType: string
41+
}
42+
43+
export const UploadActions = ({
44+
customActions,
45+
enableAdjustments,
46+
enablePreviewSizes,
47+
mimeType,
48+
}: UploadActionsArgs) => {
3749
const { t } = useTranslation()
50+
51+
const fileTypeIsAdjustable = isImage(mimeType) && mimeType !== 'image/svg+xml'
52+
53+
if (!fileTypeIsAdjustable && (!customActions || customActions.length === 0)) return null
54+
3855
return (
39-
<div className={`${baseClass}__file-mutation`}>
40-
{showSizePreviews && (
41-
<DrawerToggler className={`${baseClass}__previewSizes`} slug={sizePreviewSlug}>
42-
{t('upload:previewSizes')}
43-
</DrawerToggler>
44-
)}
45-
{canEdit && (
46-
<DrawerToggler className={`${baseClass}__edit`} slug={editDrawerSlug}>
47-
{t('upload:editImage')}
48-
</DrawerToggler>
56+
<div className={`${baseClass}__upload-actions`}>
57+
{fileTypeIsAdjustable && (
58+
<React.Fragment>
59+
{enablePreviewSizes && (
60+
<DrawerToggler className={`${baseClass}__previewSizes`} slug={sizePreviewSlug}>
61+
{t('upload:previewSizes')}
62+
</DrawerToggler>
63+
)}
64+
{enableAdjustments && (
65+
<DrawerToggler className={`${baseClass}__edit`} slug={editDrawerSlug}>
66+
{t('upload:editImage')}
67+
</DrawerToggler>
68+
)}
69+
</React.Fragment>
4970
)}
71+
72+
{customActions &&
73+
customActions.map((CustomAction, i) => {
74+
return <React.Fragment key={i}>{CustomAction}</React.Fragment>
75+
})}
5076
</div>
5177
)
5278
}
5379

5480
export type UploadProps = {
5581
collectionSlug: string
82+
customActions?: React.ReactNode[]
5683
initialState?: FormState
5784
onChange?: (file?: File) => void
5885
uploadConfig: SanitizedCollectionConfig['upload']
5986
}
6087

6188
export const Upload: React.FC<UploadProps> = (props) => {
62-
const { collectionSlug, initialState, onChange, uploadConfig } = props
89+
const { collectionSlug, customActions, initialState, onChange, uploadConfig } = props
6390

6491
const [replacingFile, setReplacingFile] = useState(false)
6592
const [fileSrc, setFileSrc] = useState<null | string>(null)
@@ -169,9 +196,9 @@ export const Upload: React.FC<UploadProps> = (props) => {
169196
<FieldError message={errorMessage} showError={showError} />
170197
{doc.filename && !replacingFile && (
171198
<FileDetails
172-
canEdit={showCrop || showFocalPoint}
173199
collectionSlug={collectionSlug}
174200
doc={doc}
201+
enableAdjustments={showCrop || showFocalPoint}
175202
handleRemove={canRemoveUpload ? handleFileRemoval : undefined}
176203
hasImageSizes={hasImageSizes}
177204
imageCacheTag={doc.updatedAt}
@@ -203,13 +230,12 @@ export const Upload: React.FC<UploadProps> = (props) => {
203230
type="text"
204231
value={value.name}
205232
/>
206-
207-
{isImage(value.type) && value.type !== 'image/svg+xml' && (
208-
<UploadActions
209-
canEdit={showCrop || showFocalPoint}
210-
showSizePreviews={hasImageSizes && doc.filename && !replacingFile}
211-
/>
212-
)}
233+
<UploadActions
234+
customActions={customActions}
235+
enableAdjustments={showCrop || showFocalPoint}
236+
enablePreviewSizes={hasImageSizes && doc.filename && !replacingFile}
237+
mimeType={value.type}
238+
/>
213239
</div>
214240
<Button
215241
buttonStyle="icon-label"

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ const baseClass = 'upload'
2525
export type UploadInputProps = Omit<UploadFieldProps, 'filterOptions'> & {
2626
api?: string
2727
collection?: ClientCollectionConfig
28+
customUploadActions?: React.ReactNode[]
2829
filterOptions?: FilterOptionsResult
2930
onChange?: (e) => void
3031
relationTo?: UploadField['relationTo']
@@ -41,6 +42,7 @@ export const UploadInput: React.FC<UploadInputProps> = (props) => {
4142
api = '/api',
4243
className,
4344
collection,
45+
customUploadActions,
4446
descriptionProps,
4547
errorProps,
4648
filterOptions,
@@ -147,6 +149,7 @@ export const UploadInput: React.FC<UploadInputProps> = (props) => {
147149
{fileDoc && !missingFile && (
148150
<FileDetails
149151
collectionSlug={relationTo}
152+
customUploadActions={customUploadActions}
150153
doc={fileDoc}
151154
handleRemove={
152155
readOnly

test/uploads/collections/CustomUploadField/components/CustomUpload/index.client.tsx

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,28 @@
11
'use client'
22

3-
import { Upload, useDocumentInfo } from '@payloadcms/ui'
3+
import { Drawer, DrawerToggler, TextField, Upload, useDocumentInfo } from '@payloadcms/ui'
44
import React from 'react'
55

6+
const customDrawerSlug = 'custom-upload-drawer'
7+
8+
const CustomDrawer = () => {
9+
return (
10+
<Drawer slug={customDrawerSlug}>
11+
<h1>Custom Drawer</h1>
12+
<TextField name="alt" path="alt" />
13+
</Drawer>
14+
)
15+
}
16+
17+
const CustomDrawerToggler = () => {
18+
return (
19+
<React.Fragment>
20+
<DrawerToggler slug={customDrawerSlug}>Custom Drawer</DrawerToggler>
21+
<CustomDrawer />
22+
</React.Fragment>
23+
)
24+
}
25+
626
export const CustomUploadClient = () => {
727
const { collectionSlug, docConfig, initialState } = useDocumentInfo()
828

@@ -11,6 +31,7 @@ export const CustomUploadClient = () => {
1131
<h3>This text was rendered on the client</h3>
1232
<Upload
1333
collectionSlug={collectionSlug}
34+
customActions={[<CustomDrawerToggler />]}
1435
initialState={initialState}
1536
uploadConfig={'upload' in docConfig ? docConfig.upload : undefined}
1637
/>

0 commit comments

Comments
 (0)