feat: ability to pass uploadActions to the Upload component (#6941)
This commit is contained in:
@@ -1,5 +1,4 @@
|
||||
'use client'
|
||||
import { isImage } from 'payload/shared'
|
||||
import React from 'react'
|
||||
|
||||
import { UploadActions } from '../../elements/Upload/index.js'
|
||||
@@ -13,11 +12,12 @@ const baseClass = 'file-details'
|
||||
import type { Data, FileSizes, SanitizedCollectionConfig } from 'payload'
|
||||
|
||||
export type FileDetailsProps = {
|
||||
canEdit?: boolean
|
||||
collectionSlug: string
|
||||
customUploadActions?: React.ReactNode[]
|
||||
doc: Data & {
|
||||
sizes?: FileSizes
|
||||
}
|
||||
enableAdjustments?: boolean
|
||||
handleRemove?: () => void
|
||||
hasImageSizes?: boolean
|
||||
imageCacheTag?: string
|
||||
@@ -25,8 +25,16 @@ export type FileDetailsProps = {
|
||||
}
|
||||
|
||||
export const FileDetails: React.FC<FileDetailsProps> = (props) => {
|
||||
const { canEdit, collectionSlug, doc, handleRemove, hasImageSizes, imageCacheTag, uploadConfig } =
|
||||
props
|
||||
const {
|
||||
collectionSlug,
|
||||
customUploadActions,
|
||||
doc,
|
||||
enableAdjustments,
|
||||
handleRemove,
|
||||
hasImageSizes,
|
||||
imageCacheTag,
|
||||
uploadConfig,
|
||||
} = props
|
||||
|
||||
const { id, filename, filesize, height, mimeType, thumbnailURL, url, width } = doc
|
||||
|
||||
@@ -52,9 +60,12 @@ export const FileDetails: React.FC<FileDetailsProps> = (props) => {
|
||||
width={width as number}
|
||||
/>
|
||||
|
||||
{isImage(mimeType as string) && mimeType !== 'image/svg+xml' && (
|
||||
<UploadActions canEdit={canEdit} showSizePreviews={hasImageSizes && doc.filename} />
|
||||
)}
|
||||
<UploadActions
|
||||
customActions={customUploadActions}
|
||||
enableAdjustments={enableAdjustments}
|
||||
enablePreviewSizes={hasImageSizes && doc.filename}
|
||||
mimeType={mimeType}
|
||||
/>
|
||||
</div>
|
||||
{handleRemove && (
|
||||
<Button
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
background-color: var(--theme-bg);
|
||||
}
|
||||
|
||||
&__file-mutation {
|
||||
&__upload-actions {
|
||||
display: flex;
|
||||
gap: calc(var(--base) / 2);
|
||||
flex-wrap: wrap;
|
||||
|
||||
@@ -33,33 +33,60 @@ const validate = (value) => {
|
||||
return true
|
||||
}
|
||||
|
||||
export const UploadActions = ({ canEdit, showSizePreviews }) => {
|
||||
type UploadActionsArgs = {
|
||||
customActions?: React.ReactNode[]
|
||||
enableAdjustments: boolean
|
||||
enablePreviewSizes: boolean
|
||||
mimeType: string
|
||||
}
|
||||
|
||||
export const UploadActions = ({
|
||||
customActions,
|
||||
enableAdjustments,
|
||||
enablePreviewSizes,
|
||||
mimeType,
|
||||
}: UploadActionsArgs) => {
|
||||
const { t } = useTranslation()
|
||||
|
||||
const fileTypeIsAdjustable = isImage(mimeType) && mimeType !== 'image/svg+xml'
|
||||
|
||||
if (!fileTypeIsAdjustable && (!customActions || customActions.length === 0)) return null
|
||||
|
||||
return (
|
||||
<div className={`${baseClass}__file-mutation`}>
|
||||
{showSizePreviews && (
|
||||
<DrawerToggler className={`${baseClass}__previewSizes`} slug={sizePreviewSlug}>
|
||||
{t('upload:previewSizes')}
|
||||
</DrawerToggler>
|
||||
)}
|
||||
{canEdit && (
|
||||
<DrawerToggler className={`${baseClass}__edit`} slug={editDrawerSlug}>
|
||||
{t('upload:editImage')}
|
||||
</DrawerToggler>
|
||||
<div className={`${baseClass}__upload-actions`}>
|
||||
{fileTypeIsAdjustable && (
|
||||
<React.Fragment>
|
||||
{enablePreviewSizes && (
|
||||
<DrawerToggler className={`${baseClass}__previewSizes`} slug={sizePreviewSlug}>
|
||||
{t('upload:previewSizes')}
|
||||
</DrawerToggler>
|
||||
)}
|
||||
{enableAdjustments && (
|
||||
<DrawerToggler className={`${baseClass}__edit`} slug={editDrawerSlug}>
|
||||
{t('upload:editImage')}
|
||||
</DrawerToggler>
|
||||
)}
|
||||
</React.Fragment>
|
||||
)}
|
||||
|
||||
{customActions &&
|
||||
customActions.map((CustomAction, i) => {
|
||||
return <React.Fragment key={i}>{CustomAction}</React.Fragment>
|
||||
})}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export type UploadProps = {
|
||||
collectionSlug: string
|
||||
customActions?: React.ReactNode[]
|
||||
initialState?: FormState
|
||||
onChange?: (file?: File) => void
|
||||
uploadConfig: SanitizedCollectionConfig['upload']
|
||||
}
|
||||
|
||||
export const Upload: React.FC<UploadProps> = (props) => {
|
||||
const { collectionSlug, initialState, onChange, uploadConfig } = props
|
||||
const { collectionSlug, customActions, initialState, onChange, uploadConfig } = props
|
||||
|
||||
const [replacingFile, setReplacingFile] = useState(false)
|
||||
const [fileSrc, setFileSrc] = useState<null | string>(null)
|
||||
@@ -169,9 +196,9 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
||||
<FieldError message={errorMessage} showError={showError} />
|
||||
{doc.filename && !replacingFile && (
|
||||
<FileDetails
|
||||
canEdit={showCrop || showFocalPoint}
|
||||
collectionSlug={collectionSlug}
|
||||
doc={doc}
|
||||
enableAdjustments={showCrop || showFocalPoint}
|
||||
handleRemove={canRemoveUpload ? handleFileRemoval : undefined}
|
||||
hasImageSizes={hasImageSizes}
|
||||
imageCacheTag={doc.updatedAt}
|
||||
@@ -203,13 +230,12 @@ export const Upload: React.FC<UploadProps> = (props) => {
|
||||
type="text"
|
||||
value={value.name}
|
||||
/>
|
||||
|
||||
{isImage(value.type) && value.type !== 'image/svg+xml' && (
|
||||
<UploadActions
|
||||
canEdit={showCrop || showFocalPoint}
|
||||
showSizePreviews={hasImageSizes && doc.filename && !replacingFile}
|
||||
/>
|
||||
)}
|
||||
<UploadActions
|
||||
customActions={customActions}
|
||||
enableAdjustments={showCrop || showFocalPoint}
|
||||
enablePreviewSizes={hasImageSizes && doc.filename && !replacingFile}
|
||||
mimeType={value.type}
|
||||
/>
|
||||
</div>
|
||||
<Button
|
||||
buttonStyle="icon-label"
|
||||
|
||||
@@ -25,6 +25,7 @@ const baseClass = 'upload'
|
||||
export type UploadInputProps = Omit<UploadFieldProps, 'filterOptions'> & {
|
||||
api?: string
|
||||
collection?: ClientCollectionConfig
|
||||
customUploadActions?: React.ReactNode[]
|
||||
filterOptions?: FilterOptionsResult
|
||||
onChange?: (e) => void
|
||||
relationTo?: UploadField['relationTo']
|
||||
@@ -41,6 +42,7 @@ export const UploadInput: React.FC<UploadInputProps> = (props) => {
|
||||
api = '/api',
|
||||
className,
|
||||
collection,
|
||||
customUploadActions,
|
||||
descriptionProps,
|
||||
errorProps,
|
||||
filterOptions,
|
||||
@@ -147,6 +149,7 @@ export const UploadInput: React.FC<UploadInputProps> = (props) => {
|
||||
{fileDoc && !missingFile && (
|
||||
<FileDetails
|
||||
collectionSlug={relationTo}
|
||||
customUploadActions={customUploadActions}
|
||||
doc={fileDoc}
|
||||
handleRemove={
|
||||
readOnly
|
||||
|
||||
@@ -1,8 +1,28 @@
|
||||
'use client'
|
||||
|
||||
import { Upload, useDocumentInfo } from '@payloadcms/ui'
|
||||
import { Drawer, DrawerToggler, TextField, Upload, useDocumentInfo } from '@payloadcms/ui'
|
||||
import React from 'react'
|
||||
|
||||
const customDrawerSlug = 'custom-upload-drawer'
|
||||
|
||||
const CustomDrawer = () => {
|
||||
return (
|
||||
<Drawer slug={customDrawerSlug}>
|
||||
<h1>Custom Drawer</h1>
|
||||
<TextField name="alt" path="alt" />
|
||||
</Drawer>
|
||||
)
|
||||
}
|
||||
|
||||
const CustomDrawerToggler = () => {
|
||||
return (
|
||||
<React.Fragment>
|
||||
<DrawerToggler slug={customDrawerSlug}>Custom Drawer</DrawerToggler>
|
||||
<CustomDrawer />
|
||||
</React.Fragment>
|
||||
)
|
||||
}
|
||||
|
||||
export const CustomUploadClient = () => {
|
||||
const { collectionSlug, docConfig, initialState } = useDocumentInfo()
|
||||
|
||||
@@ -11,6 +31,7 @@ export const CustomUploadClient = () => {
|
||||
<h3>This text was rendered on the client</h3>
|
||||
<Upload
|
||||
collectionSlug={collectionSlug}
|
||||
customActions={[<CustomDrawerToggler />]}
|
||||
initialState={initialState}
|
||||
uploadConfig={'upload' in docConfig ? docConfig.upload : undefined}
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user