Skip to content

Commit 002e921

Browse files
authored
chore(richtext-lexical): improve types of UploadData (#10982)
One step closer to being able to remove `noUncheckedIndexedAccess` in `packages/richtext-lexical/tsconfig.json`. I'm introducing UploadData_P4 which is a more precise version of UploadData. I'm doing it as a different type because there's a chance it'll be a breaking change for some users. UploadData is used in many places, but I'm currently replacing it only in `packages/richtext-lexical/src/exports/react/components/RichText/converter/converters/upload.tsx`, because in the other files it's too rooted to other types like UploadNode.
1 parent 3098f35 commit 002e921

File tree

3 files changed

+50
-26
lines changed
  • packages

3 files changed

+50
-26
lines changed

packages/payload/src/uploads/types.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,16 @@ export type FileSize = {
1212
width: null | number
1313
}
1414

15+
// TODO: deprecate in Payload v4.
16+
/**
17+
* FileSizeImproved is a more precise type, and will replace FileSize in Payload v4.
18+
* This type is for internal use only as it will be deprecated in the future.
19+
* @internal
20+
*/
21+
export type FileSizeImproved = {
22+
url: null | string
23+
} & FileSize
24+
1525
export type FileSizes = {
1626
[size: string]: FileSize
1727
}

packages/richtext-lexical/src/exports/react/components/RichText/converter/converters/upload.tsx

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,37 +1,39 @@
1-
import type { FileData, FileSize, TypeWithID } from 'payload'
1+
import type { FileSizeImproved } from 'payload'
22

3+
import type { UploadDataImproved } from '../../../../../../features/upload/server/nodes/UploadNode.js'
34
import type { SerializedUploadNode } from '../../../../../../nodeTypes.js'
45
import type { JSXConverters } from '../types.js'
56

67
export const UploadJSXConverter: JSXConverters<SerializedUploadNode> = {
78
upload: ({ node }) => {
8-
const uploadDocument: {
9-
value?: FileData & TypeWithID
10-
} = node as any
11-
12-
const url = uploadDocument?.value?.url
9+
// TO-DO (v4): SerializedUploadNode should use UploadData_P4
10+
const uploadDocument = node as UploadDataImproved
11+
if (typeof uploadDocument.value !== 'object') {
12+
return null
13+
}
14+
const url = uploadDocument.value.url
1315

1416
/**
1517
* If the upload is not an image, return a link to the upload
1618
*/
17-
if (!uploadDocument?.value?.mimeType?.startsWith('image')) {
19+
if (!uploadDocument.value.mimeType.startsWith('image')) {
1820
return (
1921
<a href={url} rel="noopener noreferrer">
20-
{uploadDocument.value?.filename}
22+
{uploadDocument.value.filename}
2123
</a>
2224
)
2325
}
2426

2527
/**
2628
* If the upload is a simple image with no different sizes, return a simple img tag
2729
*/
28-
if (!uploadDocument?.value?.sizes || !Object.keys(uploadDocument?.value?.sizes).length) {
30+
if (!Object.keys(uploadDocument.value.sizes).length) {
2931
return (
3032
<img
31-
alt={uploadDocument?.value?.filename}
32-
height={uploadDocument?.value?.height}
33+
alt={uploadDocument.value.filename}
34+
height={uploadDocument.value.height}
3335
src={url}
34-
width={uploadDocument?.value?.width}
36+
width={uploadDocument.value.width}
3537
/>
3638
)
3739
}
@@ -42,13 +44,12 @@ export const UploadJSXConverter: JSXConverters<SerializedUploadNode> = {
4244
const pictureJSX: React.ReactNode[] = []
4345

4446
// Iterate through each size in the data.sizes object
45-
for (const size in uploadDocument.value?.sizes) {
46-
const imageSize: {
47-
url?: string
48-
} & FileSize = uploadDocument.value?.sizes[size]
47+
for (const size in uploadDocument.value.sizes) {
48+
const imageSize = uploadDocument.value.sizes[size] as FileSizeImproved
4949

5050
// Skip if any property of the size object is null
5151
if (
52+
!imageSize ||
5253
!imageSize.width ||
5354
!imageSize.height ||
5455
!imageSize.mimeType ||

packages/richtext-lexical/src/features/upload/server/nodes/UploadNode.tsx

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import type {
88
NodeKey,
99
Spread,
1010
} from 'lexical'
11-
import type { CollectionSlug, DataFromCollectionSlug, JsonObject } from 'payload'
11+
import type { FileData, JsonObject, TypedCollection, TypeWithID } from 'payload'
1212
import type { JSX } from 'react'
1313

1414
import { DecoratorBlockNode } from '@lexical/react/LexicalDecoratorBlockNode.js'
@@ -17,15 +17,28 @@ import { $applyNodeReplacement } from 'lexical'
1717
import * as React from 'react'
1818

1919
export type UploadData<TUploadExtraFieldsData extends JsonObject = JsonObject> = {
20-
[TCollectionSlug in CollectionSlug]: {
21-
fields: TUploadExtraFieldsData
22-
// Every lexical node that has sub-fields needs to have a unique ID. This is the ID of this upload node, not the ID of the linked upload document
23-
id: string
24-
relationTo: TCollectionSlug
25-
// Value can be just the document ID, or the full, populated document
26-
value: DataFromCollectionSlug<TCollectionSlug> | number | string
27-
}
28-
}[CollectionSlug]
20+
fields: TUploadExtraFieldsData
21+
/** Every lexical node that has sub-fields needs to have a unique ID. This is the ID of this upload node, not the ID of the linked upload document */
22+
id: string
23+
relationTo: string
24+
/** Value can be just the document ID, or the full, populated document */
25+
value: number | string | TypedCollection
26+
}
27+
28+
// TODO: deprecate in Payload v4.
29+
/**
30+
* UploadDataImproved is a more precise type, and will replace UploadData in Payload v4.
31+
* This type is for internal use only as it will be deprecated in the future.
32+
* @internal
33+
*/
34+
export type UploadDataImproved<TUploadExtraFieldsData extends JsonObject = JsonObject> = {
35+
fields: TUploadExtraFieldsData
36+
// Every lexical node that has sub-fields needs to have a unique ID. This is the ID of this upload node, not the ID of the linked upload document
37+
id: string
38+
relationTo: string
39+
// Value can be just the document ID, or the full, populated document
40+
value: (FileData & TypeWithID) | number | string
41+
}
2942

3043
export function isGoogleDocCheckboxImg(img: HTMLImageElement): boolean {
3144
return (

0 commit comments

Comments
 (0)