1
1
'use client'
2
2
import type { DiffMethod } from 'react-diff-viewer-continued'
3
3
4
+ import { ShimmerEffect , StaggeredShimmers } from '@payloadcms/ui'
4
5
import { fieldAffectsData , fieldIsID } from 'payload/shared'
5
- import React from 'react'
6
+ import React , { Fragment , useEffect } from 'react'
6
7
7
8
import type { diffComponents as _diffComponents } from './fields/index.js'
8
9
import type { FieldDiffProps , Props } from './types.js'
@@ -25,129 +26,145 @@ export const RenderFieldsToDiff: React.FC<Props> = ({
25
26
// Without it, you could pass a UI field to the Tabs component, without it erroring
26
27
const diffComponents : typeof _diffComponents = __diffComponents as typeof _diffComponents
27
28
28
- return (
29
- < div className = { baseClass } >
30
- { fields ?. map ( ( field , i ) => {
31
- if ( fieldIsID ( field ) ) {
32
- return null
33
- }
34
-
35
- const Component = diffComponents [ field . type ]
36
-
37
- const isRichText = field . type === 'richText'
38
- const diffMethod : DiffMethod = diffMethods [ field . type ] || 'CHARS'
39
-
40
- if ( Component ) {
41
- if ( fieldAffectsData ( field ) ) {
42
- const fieldName = field . name
43
- const valueIsObject = field . type === 'code' || field . type === 'json'
44
-
45
- const versionValue = valueIsObject
46
- ? JSON . stringify ( version ?. [ fieldName ] )
47
- : version ?. [ fieldName ]
29
+ const [ hasMounted , setHasMounted ] = React . useState ( false )
48
30
49
- const comparisonValue = valueIsObject
50
- ? JSON . stringify ( comparison ?. [ fieldName ] )
51
- : comparison ?. [ fieldName ]
31
+ // defer rendering until after the first mount as the CSS is loaded with Emotion
32
+ // this will ensure that the CSS is loaded before rendering the diffs and prevent CLS
33
+ useEffect ( ( ) => {
34
+ setHasMounted ( true )
35
+ } , [ ] )
52
36
53
- const hasPermission =
54
- fieldPermissions === true ||
55
- fieldPermissions ?. [ fieldName ] === true ||
56
- fieldPermissions ?. [ fieldName ] ?. read
57
-
58
- const subFieldPermissions =
59
- fieldPermissions === true ||
60
- fieldPermissions ?. [ fieldName ] === true ||
61
- fieldPermissions ?. [ fieldName ] ?. fields
62
-
63
- if ( ! hasPermission ) {
37
+ return (
38
+ < div className = { baseClass } >
39
+ { ! hasMounted ? (
40
+ < Fragment >
41
+ < ShimmerEffect height = "8rem" width = "100%" />
42
+ </ Fragment >
43
+ ) : (
44
+ < Fragment >
45
+ { fields ?. map ( ( field , i ) => {
46
+ if ( fieldIsID ( field ) ) {
64
47
return null
65
48
}
66
49
67
- const baseCellProps : FieldDiffProps = {
68
- comparison : comparisonValue ,
69
- diffComponents,
70
- diffMethod,
71
- field,
72
- fieldPermissions : subFieldPermissions ,
73
- fields : 'fields' in field ? field ?. fields : fields ,
74
- i18n,
75
- isRichText,
76
- locales,
77
- version : versionValue ,
78
- }
79
-
80
- if ( field . localized ) {
81
- return (
82
- < div className = { `${ baseClass } __field` } key = { i } >
83
- { locales . map ( ( locale , index ) => {
84
- const versionLocaleValue = versionValue ?. [ locale ]
85
- const comparisonLocaleValue = comparisonValue ?. [ locale ]
86
-
87
- const cellProps = {
88
- ...baseCellProps ,
89
- comparison : comparisonLocaleValue ,
90
- version : versionLocaleValue ,
91
- }
92
-
93
- return (
94
- < div className = { `${ baseClass } __locale` } key = { [ locale , index ] . join ( '-' ) } >
95
- < div className = { `${ baseClass } __locale-value` } >
96
- < Component { ...cellProps } locale = { locale } />
97
- </ div >
98
- </ div >
99
- )
100
- } ) }
101
- </ div >
102
- )
50
+ const Component = diffComponents [ field . type ]
51
+
52
+ const isRichText = field . type === 'richText'
53
+ const diffMethod : DiffMethod = diffMethods [ field . type ] || 'CHARS'
54
+
55
+ if ( Component ) {
56
+ if ( fieldAffectsData ( field ) ) {
57
+ const fieldName = field . name
58
+ const valueIsObject = field . type === 'code' || field . type === 'json'
59
+
60
+ const versionValue = valueIsObject
61
+ ? JSON . stringify ( version ?. [ fieldName ] )
62
+ : version ?. [ fieldName ]
63
+
64
+ const comparisonValue = valueIsObject
65
+ ? JSON . stringify ( comparison ?. [ fieldName ] )
66
+ : comparison ?. [ fieldName ]
67
+
68
+ const hasPermission =
69
+ fieldPermissions === true ||
70
+ fieldPermissions ?. [ fieldName ] === true ||
71
+ fieldPermissions ?. [ fieldName ] ?. read
72
+
73
+ const subFieldPermissions =
74
+ fieldPermissions === true ||
75
+ fieldPermissions ?. [ fieldName ] === true ||
76
+ fieldPermissions ?. [ fieldName ] ?. fields
77
+
78
+ if ( ! hasPermission ) {
79
+ return null
80
+ }
81
+
82
+ const baseCellProps : FieldDiffProps = {
83
+ comparison : comparisonValue ,
84
+ diffComponents,
85
+ diffMethod,
86
+ field,
87
+ fieldPermissions : subFieldPermissions ,
88
+ fields : 'fields' in field ? field ?. fields : fields ,
89
+ i18n,
90
+ isRichText,
91
+ locales,
92
+ version : versionValue ,
93
+ }
94
+
95
+ if ( field . localized ) {
96
+ return (
97
+ < div className = { `${ baseClass } __field` } key = { i } >
98
+ { locales . map ( ( locale , index ) => {
99
+ const versionLocaleValue = versionValue ?. [ locale ]
100
+ const comparisonLocaleValue = comparisonValue ?. [ locale ]
101
+
102
+ const cellProps = {
103
+ ...baseCellProps ,
104
+ comparison : comparisonLocaleValue ,
105
+ version : versionLocaleValue ,
106
+ }
107
+
108
+ return (
109
+ < div className = { `${ baseClass } __locale` } key = { [ locale , index ] . join ( '-' ) } >
110
+ < div className = { `${ baseClass } __locale-value` } >
111
+ < Component { ...cellProps } locale = { locale } />
112
+ </ div >
113
+ </ div >
114
+ )
115
+ } ) }
116
+ </ div >
117
+ )
118
+ }
119
+
120
+ return (
121
+ < div className = { `${ baseClass } __field` } key = { i } >
122
+ < Component { ...baseCellProps } />
123
+ </ div >
124
+ )
125
+ }
126
+
127
+ if ( field . type === 'tabs' && 'tabs' in field ) {
128
+ const Tabs = diffComponents . tabs
129
+
130
+ return (
131
+ < Tabs
132
+ comparison = { comparison }
133
+ diffComponents = { diffComponents }
134
+ field = { field }
135
+ fieldPermissions = { fieldPermissions }
136
+ fields = { [ ] }
137
+ i18n = { i18n }
138
+ key = { i }
139
+ locales = { locales }
140
+ version = { version }
141
+ />
142
+ )
143
+ }
144
+
145
+ // At this point, we are dealing with a field with subfields but no
146
+ // nested data, eg. row, collapsible, etc.
147
+ if ( 'fields' in field ) {
148
+ return (
149
+ < Component
150
+ comparison = { comparison }
151
+ diffComponents = { diffComponents }
152
+ field = { field }
153
+ fieldPermissions = { fieldPermissions }
154
+ fields = { field . fields }
155
+ i18n = { i18n }
156
+ key = { i }
157
+ locales = { locales }
158
+ version = { version }
159
+ />
160
+ )
161
+ }
103
162
}
104
163
105
- return (
106
- < div className = { `${ baseClass } __field` } key = { i } >
107
- < Component { ...baseCellProps } />
108
- </ div >
109
- )
110
- }
111
-
112
- if ( field . type === 'tabs' && 'tabs' in field ) {
113
- const Tabs = diffComponents . tabs
114
-
115
- return (
116
- < Tabs
117
- comparison = { comparison }
118
- diffComponents = { diffComponents }
119
- field = { field }
120
- fieldPermissions = { fieldPermissions }
121
- fields = { [ ] }
122
- i18n = { i18n }
123
- key = { i }
124
- locales = { locales }
125
- version = { version }
126
- />
127
- )
128
- }
129
-
130
- // At this point, we are dealing with a field with subfields but no
131
- // nested data, eg. row, collapsible, etc.
132
- if ( 'fields' in field ) {
133
- return (
134
- < Component
135
- comparison = { comparison }
136
- diffComponents = { diffComponents }
137
- field = { field }
138
- fieldPermissions = { fieldPermissions }
139
- fields = { field . fields }
140
- i18n = { i18n }
141
- key = { i }
142
- locales = { locales }
143
- version = { version }
144
- />
145
- )
146
- }
147
- }
148
-
149
- return null
150
- } ) }
164
+ return null
165
+ } ) }
166
+ </ Fragment >
167
+ ) }
151
168
</ div >
152
169
)
153
170
}
0 commit comments