From 07ff181ccf5e455c97a4afa6d72bcbc173b1a76d Mon Sep 17 00:00:00 2001 From: Patrik Date: Thu, 9 Jan 2025 09:06:06 -0500 Subject: [PATCH] feat: adds `forceRenderAllFields` admin prop to force all fields in edit view to render immediately (#10464) ### What? Adds new `forceRenderAllFields` `admin` prop to `collection` & `global` configs. This new prop forces all fields in the `Edit` view to render immediately, regardless of scroll position. By default, this is set to `false` to improve performance, as fields are progressively rendered to balance load times. Enabling this option can make it easier to locate fields using browser search (e.g., CMD+F). ``` admin: { forceRenderAllFields: true, }, ``` ### Why? Previously, fields were only rendered to a certain viewport pixel height for performance purposes. As a result, this disallowed using the browser search on all fields in the edit view if they were not completely loaded in i.e in the proper viewport. --- docs/configuration/collections.mdx | 44 ++++++++++--------- docs/configuration/globals.mdx | 21 ++++----- .../elements/DocumentFields/index.tsx | 8 +++- .../components/forms/RenderFields/index.tsx | 4 +- .../components/forms/RenderFields/types.ts | 1 + .../forms/field-types/Array/index.tsx | 5 ++- .../forms/field-types/Array/types.ts | 1 + .../forms/field-types/Blocks/index.tsx | 13 +++--- .../forms/field-types/Blocks/types.ts | 1 + .../forms/field-types/Group/index.tsx | 4 +- .../forms/field-types/Group/types.ts | 1 + .../forms/field-types/Row/index.tsx | 5 ++- .../components/forms/field-types/Row/types.ts | 1 + .../forms/field-types/Tabs/index.tsx | 4 +- .../forms/field-types/Tabs/types.ts | 1 + .../components/utilities/Config/index.tsx | 2 +- .../components/views/Global/Default/index.tsx | 3 +- .../components/views/LivePreview/index.tsx | 5 +++ .../views/collections/Edit/Default/index.tsx | 3 +- .../payload/src/collections/config/schema.ts | 1 + .../payload/src/collections/config/types.ts | 5 +++ packages/payload/src/globals/config/schema.ts | 1 + packages/payload/src/globals/config/types.ts | 5 +++ 23 files changed, 92 insertions(+), 47 deletions(-) diff --git a/docs/configuration/collections.mdx b/docs/configuration/collections.mdx index 22f19e5244..1235e1cf0b 100644 --- a/docs/configuration/collections.mdx +++ b/docs/configuration/collections.mdx @@ -14,7 +14,7 @@ It's often best practice to write your Collections in separate files and then im ## Options | Option | Description | -|-------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | | **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Collection. | | **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Collection. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. | | **`labels`** | Singular and plural labels for use in identifying this Collection throughout Payload. Auto-generated from slug if not defined. | @@ -70,23 +70,24 @@ Demo source code on GitHub. You can customize the way that the Admin panel behaves on a collection-by-collection basis by defining the `admin` property on a collection's config. -| Option | Description | -|------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| `group` | Text used as a label for grouping collection and global links together in the navigation. | -| `hidden` | Set to true or a function, called with the current user, returning true to exclude this collection from navigation and admin routing. | -| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) | -| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin panel. If no field is defined, the ID of the document is used as the title. | -| `description` | Text or React component to display below the Collection label in the List view to give editors more information. | -| `defaultColumns` | Array of field names that correspond to which columns to show by default in this collection's List view. | -| `disableDuplicate ` | Disables the "Duplicate" button while editing documents within this collection. | -| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. | -| `enableRichTextLink` | The [Rich Text](/docs/fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. | -| `enableRichTextRelationship` | The [Rich Text](/docs/fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. | -| `preview` | Function to generate preview URLS within the Admin panel that can point to your app. [More](#preview). | -| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). | -| `components` | Swap in your own React components to be used within this collection. [More](/docs/admin/components#collections) | -| `listSearchableFields` | Specify which fields should be searched in the List search view. [More](#list-searchable-fields) | -| **`pagination`** | Set pagination-specific options for this collection. [More](#pagination) | +| Option | Description | +| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `group` | Text used as a label for grouping collection and global links together in the navigation. | +| `hidden` | Set to true or a function, called with the current user, returning true to exclude this collection from navigation and admin routing. | +| `hooks` | Admin-specific hooks for this collection. [More](#admin-hooks) | +| `useAsTitle` | Specify a top-level field to use for a document title throughout the Admin panel. If no field is defined, the ID of the document is used as the title. | +| `description` | Text or React component to display below the Collection label in the List view to give editors more information. | +| `defaultColumns` | Array of field names that correspond to which columns to show by default in this collection's List view. | +| `disableDuplicate ` | Disables the "Duplicate" button while editing documents within this collection. | +| `forceRenderAllFields ` | Forces all fields in the Edit view to render immediately, regardless of scroll position. By default, this is set to `false` to improve performance, as fields are progressively rendered to balance load times. Enabling this option can make it easier to locate fields using browser search (e.g., `CMD+F`). | +| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. | +| `enableRichTextLink` | The [Rich Text](/docs/fields/rich-text) field features a `Link` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. | +| `enableRichTextRelationship` | The [Rich Text](/docs/fields/rich-text) field features a `Relationship` element which allows for users to automatically reference related documents within their rich text. Set to `true` by default. | +| `preview` | Function to generate preview URLS within the Admin panel that can point to your app. [More](#preview). | +| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). | +| `components` | Swap in your own React components to be used within this collection. [More](/docs/admin/components#collections) | +| `listSearchableFields` | Specify which fields should be searched in the List search view. [More](#list-searchable-fields) | +| **`pagination`** | Set pagination-specific options for this collection. [More](#pagination) | ### Preview @@ -132,7 +133,7 @@ export const Posts: CollectionConfig = { Here are a few options that you can specify options for pagination on a collection-by-collection basis: | Option | Description | -|----------------|-----------------------------------------------------------------------------------------------------| +| -------------- | --------------------------------------------------------------------------------------------------- | | `defaultLimit` | Integer that specifies the default per-page limit that should be used. Defaults to 10. | | `limits` | Provide an array of integers to use as per-page options for admins to choose from in the List view. | @@ -166,8 +167,9 @@ those three fields plus the ID field. **Note:** - If you are adding **listSearchableFields**, make sure you index each of these fields - so your admin queries can remain performant. +If you are adding **listSearchableFields**, make sure you index each of these fields +so your admin queries can remain performant. + ### Admin Hooks diff --git a/docs/configuration/globals.mdx b/docs/configuration/globals.mdx index 1206d232a7..c0d5e068db 100644 --- a/docs/configuration/globals.mdx +++ b/docs/configuration/globals.mdx @@ -17,7 +17,7 @@ the main Payload config. ## Options | Option | Description | -|--------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **`slug`** \* | Unique, URL-friendly string that will act as an identifier for this Global. | | **`fields`** \* | Array of field types that will determine the structure and functionality of the data stored within this Global. [Click here](/docs/fields/overview) for a full list of field types as well as how to configure them. | | **`label`** | Text for the name in the Admin panel or an object with keys for each language. Auto-generated from slug if not defined. | @@ -30,7 +30,7 @@ the main Payload config. | **`graphQL.name`** | Text used in schema generation. Auto-generated from slug if not defined. | | **`typescript`** | An object with property `interface` as the text used in schema generation. Auto-generated from slug if not defined. | | **`custom`** | Extension point for adding custom data (e.g. for plugins) | -| **`dbName`** | Custom table or collection name for this global depending on the database adapter. Auto-generated from slug if not defined. +| **`dbName`** | Custom table or collection name for this global depending on the database adapter. Auto-generated from slug if not defined. | _\* An asterisk denotes that a property is required._ @@ -72,14 +72,15 @@ in the Public Demo source code on GitHub. You can customize the way that the Admin panel behaves on a Global-by-Global basis by defining the `admin` property on a Global's config. -| Option | Description | -|---------------|-----------------------------------------------------------------------------------------------------------------------------------| -| `group` | Text used as a label for grouping collection and global links together in the navigation. | -| `hidden` | Set to true or a function, called with the current user, returning true to exclude this global from navigation and admin routing. | -| `components` | Swap in your own React components to be used within this Global. [More](/docs/admin/components#globals) | -| `preview` | Function to generate a preview URL within the Admin panel for this global that can point to your app. [More](#preview). | -| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). | -| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. | +| Option | Description | +| ----------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | +| `group` | Text used as a label for grouping collection and global links together in the navigation. | +| `hidden` | Set to true or a function, called with the current user, returning true to exclude this global from navigation and admin routing. | +| `components` | Swap in your own React components to be used within this Global. [More](/docs/admin/components#globals) | +| `preview` | Function to generate a preview URL within the Admin panel for this global that can point to your app. [More](#preview). | +| `livePreview` | Enable real-time editing for instant visual feedback of your front-end application. [More](/docs/live-preview/overview). | +| `hideAPIURL` | Hides the "API URL" meta field while editing documents within this collection. | +| `forceRenderAllFields ` | Forces all fields in the Edit view to render immediately, regardless of scroll position. By default, this is set to `false` to improve performance, as fields are progressively rendered to balance load times. Enabling this option can make it easier to locate fields using browser search (e.g., `CMD+F`). | ### Preview diff --git a/packages/payload/src/admin/components/elements/DocumentFields/index.tsx b/packages/payload/src/admin/components/elements/DocumentFields/index.tsx index d8b5754320..19a496e73d 100644 --- a/packages/payload/src/admin/components/elements/DocumentFields/index.tsx +++ b/packages/payload/src/admin/components/elements/DocumentFields/index.tsx @@ -7,10 +7,10 @@ import type { FieldTypes } from '../../forms/field-types' import RenderFields from '../../forms/RenderFields' import { filterFields } from '../../forms/RenderFields/filterFields' +import { useOperation } from '../../utilities/OperationProvider' import { Gutter } from '../Gutter' import ViewDescription from '../ViewDescription' import './index.scss' -import { useOperation } from '../../utilities/OperationProvider' const baseClass = 'document-fields' @@ -20,6 +20,7 @@ export const DocumentFields: React.FC<{ description?: Description fieldTypes: FieldTypes fields: FieldWithPath[] + forceRenderAllFields?: boolean forceSidebarWrap?: boolean hasSavePermission: boolean permissions: CollectionPermission | GlobalPermission @@ -30,6 +31,7 @@ export const DocumentFields: React.FC<{ description, fieldTypes, fields, + forceRenderAllFields, forceSidebarWrap, hasSavePermission, permissions, @@ -41,9 +43,9 @@ export const DocumentFields: React.FC<{ fieldSchema: fields, fieldTypes, filter: (field) => field?.admin?.position === 'sidebar', + operation, permissions: permissions.fields, readOnly: !hasSavePermission, - operation, }) const hasSidebarFields = sidebarFields && sidebarFields.length > 0 @@ -77,6 +79,7 @@ export const DocumentFields: React.FC<{ !field.admin.position || (field.admin.position && field.admin.position !== 'sidebar') } + forceRenderAllFields={forceRenderAllFields} permissions={permissions.fields} readOnly={!hasSavePermission} /> @@ -90,6 +93,7 @@ export const DocumentFields: React.FC<{ diff --git a/packages/payload/src/admin/components/forms/RenderFields/index.tsx b/packages/payload/src/admin/components/forms/RenderFields/index.tsx index 851ef5ea0a..38a92a0ede 100644 --- a/packages/payload/src/admin/components/forms/RenderFields/index.tsx +++ b/packages/payload/src/admin/components/forms/RenderFields/index.tsx @@ -33,7 +33,7 @@ const intersectionObserverOptions = { * All this component does is render the field's Field Components, and pass them the props they need to function. **/ const RenderFields: React.FC = (props) => { - const { className, fieldTypes, forceRender, margins } = props + const { className, fieldTypes, forceRender, forceRenderAllFields, margins } = props const { i18n, t } = useTranslation('general') const [hasRendered, setHasRendered] = useState(Boolean(forceRender)) @@ -105,7 +105,7 @@ const RenderFields: React.FC = (props) => { readOnly, }, fieldTypes, - forceRender, + forceRender: forceRenderAllFields || forceRender, indexPath: 'indexPath' in props ? `${props?.indexPath}.${fieldIndex}` : `${fieldIndex}`, path: field.path || (isFieldAffectingData && 'name' in field ? field.name : ''), diff --git a/packages/payload/src/admin/components/forms/RenderFields/types.ts b/packages/payload/src/admin/components/forms/RenderFields/types.ts index cf44d14382..d74783fcd9 100644 --- a/packages/payload/src/admin/components/forms/RenderFields/types.ts +++ b/packages/payload/src/admin/components/forms/RenderFields/types.ts @@ -7,6 +7,7 @@ export type Props = { className?: string fieldTypes: FieldTypes forceRender?: boolean + forceRenderAllFields?: boolean margins?: 'small' | false permissions?: | { diff --git a/packages/payload/src/admin/components/forms/field-types/Array/index.tsx b/packages/payload/src/admin/components/forms/field-types/Array/index.tsx index 2bb57fc3ef..8d90794038 100644 --- a/packages/payload/src/admin/components/forms/field-types/Array/index.tsx +++ b/packages/payload/src/admin/components/forms/field-types/Array/index.tsx @@ -32,7 +32,8 @@ const ArrayFieldType: React.FC = (props) => { admin: { className, components, condition, description, isSortable = true, readOnly }, fieldTypes, fields, - forceRender = false, + forceRender: forceRenderFromProps = false, + forceRenderAllFields, indexPath, localized, maxRows, @@ -50,6 +51,8 @@ const ArrayFieldType: React.FC = (props) => { const CustomRowLabel = components?.RowLabel || undefined + const forceRender = forceRenderFromProps || forceRenderAllFields + const { setDocFieldPreferences } = useDocumentInfo() const { addFieldRow, dispatchFields, removeFieldRow, setModified } = useForm() const submitted = useFormSubmitted() diff --git a/packages/payload/src/admin/components/forms/field-types/Array/types.ts b/packages/payload/src/admin/components/forms/field-types/Array/types.ts index f3484ae615..5634815f32 100644 --- a/packages/payload/src/admin/components/forms/field-types/Array/types.ts +++ b/packages/payload/src/admin/components/forms/field-types/Array/types.ts @@ -5,6 +5,7 @@ import type { ArrayField } from '../../../../../fields/config/types' export type Props = Omit & { fieldTypes: FieldTypes forceRender?: boolean + forceRenderAllFields?: boolean indexPath: string label: false | string path?: string diff --git a/packages/payload/src/admin/components/forms/field-types/Blocks/index.tsx b/packages/payload/src/admin/components/forms/field-types/Blocks/index.tsx index 1a7a1a1252..f11afc4e8a 100644 --- a/packages/payload/src/admin/components/forms/field-types/Blocks/index.tsx +++ b/packages/payload/src/admin/components/forms/field-types/Blocks/index.tsx @@ -37,7 +37,8 @@ const BlocksField: React.FC = (props) => { admin: { className, condition, description, isSortable = true, readOnly }, blocks, fieldTypes, - forceRender = false, + forceRender: forceRenderFromProps = false, + forceRenderAllFields, indexPath, label, labels: labelsFromProps, @@ -59,6 +60,8 @@ const BlocksField: React.FC = (props) => { const drawerSlug = useDrawerSlug('blocks-drawer') const submitted = useFormSubmitted() + const forceRender = forceRenderFromProps || forceRenderAllFields + const labels = { plural: t('blocks'), singular: t('block'), @@ -118,7 +121,7 @@ const BlocksField: React.FC = (props) => { const duplicateRow = useCallback( (rowIndex: number) => { - dispatchFields({ path, rowIndex, type: 'DUPLICATE_ROW' }) + dispatchFields({ type: 'DUPLICATE_ROW', path, rowIndex }) setModified(true) setTimeout(() => { @@ -138,7 +141,7 @@ const BlocksField: React.FC = (props) => { const moveRow = useCallback( (moveFromIndex: number, moveToIndex: number) => { - dispatchFields({ moveFromIndex, moveToIndex, path, type: 'MOVE_ROW' }) + dispatchFields({ type: 'MOVE_ROW', moveFromIndex, moveToIndex, path }) setModified(true) }, [dispatchFields, path, setModified], @@ -146,14 +149,14 @@ const BlocksField: React.FC = (props) => { const toggleCollapseAll = useCallback( (collapsed: boolean) => { - dispatchFields({ collapsed, path, setDocFieldPreferences, type: 'SET_ALL_ROWS_COLLAPSED' }) + dispatchFields({ type: 'SET_ALL_ROWS_COLLAPSED', collapsed, path, setDocFieldPreferences }) }, [dispatchFields, path, setDocFieldPreferences], ) const setCollapse = useCallback( (rowID: string, collapsed: boolean) => { - dispatchFields({ collapsed, path, rowID, setDocFieldPreferences, type: 'SET_ROW_COLLAPSED' }) + dispatchFields({ type: 'SET_ROW_COLLAPSED', collapsed, path, rowID, setDocFieldPreferences }) }, [dispatchFields, path, setDocFieldPreferences], ) diff --git a/packages/payload/src/admin/components/forms/field-types/Blocks/types.ts b/packages/payload/src/admin/components/forms/field-types/Blocks/types.ts index 5378f64c9c..8fc1057c06 100644 --- a/packages/payload/src/admin/components/forms/field-types/Blocks/types.ts +++ b/packages/payload/src/admin/components/forms/field-types/Blocks/types.ts @@ -5,6 +5,7 @@ import type { BlockField } from '../../../../../fields/config/types' export type Props = Omit & { fieldTypes: FieldTypes forceRender?: boolean + forceRenderAllFields?: boolean indexPath: string path?: string permissions: FieldPermissions diff --git a/packages/payload/src/admin/components/forms/field-types/Group/index.tsx b/packages/payload/src/admin/components/forms/field-types/Group/index.tsx index bab5cd6edf..6143ea054e 100644 --- a/packages/payload/src/admin/components/forms/field-types/Group/index.tsx +++ b/packages/payload/src/admin/components/forms/field-types/Group/index.tsx @@ -26,7 +26,8 @@ const Group: React.FC = (props) => { admin: { className, description, hideGutter = false, readOnly, style, width }, fieldTypes, fields, - forceRender = false, + forceRender: forceRenderFromProps = false, + forceRenderAllFields, indexPath, label, path: pathFromProps, @@ -44,6 +45,7 @@ const Group: React.FC = (props) => { const path = pathFromProps || name const isTopLevel = !(withinCollapsible || isWithinGroup || isWithinRow) + const forceRender = forceRenderFromProps || forceRenderAllFields return (
& { fieldTypes: FieldTypes forceRender?: boolean + forceRenderAllFields?: boolean indexPath: string path?: string permissions: FieldPermissions diff --git a/packages/payload/src/admin/components/forms/field-types/Row/index.tsx b/packages/payload/src/admin/components/forms/field-types/Row/index.tsx index 69ec9fdfed..3b39e999d8 100644 --- a/packages/payload/src/admin/components/forms/field-types/Row/index.tsx +++ b/packages/payload/src/admin/components/forms/field-types/Row/index.tsx @@ -16,12 +16,15 @@ const Row: React.FC = (props) => { admin: { className, readOnly }, fieldTypes, fields, - forceRender = false, + forceRender: forceRenderFromProps = false, + forceRenderAllFields, indexPath, path, permissions, } = props + const forceRender = forceRenderFromProps || forceRenderAllFields + return (
diff --git a/packages/payload/src/admin/components/forms/field-types/Row/types.ts b/packages/payload/src/admin/components/forms/field-types/Row/types.ts index 9a2c05396b..b44eb36ded 100644 --- a/packages/payload/src/admin/components/forms/field-types/Row/types.ts +++ b/packages/payload/src/admin/components/forms/field-types/Row/types.ts @@ -5,6 +5,7 @@ import type { RowField } from '../../../../../fields/config/types' export type Props = Omit & { fieldTypes: FieldTypes forceRender?: boolean + forceRenderAllFields?: boolean indexPath: string path?: string permissions: FieldPermissions diff --git a/packages/payload/src/admin/components/forms/field-types/Tabs/index.tsx b/packages/payload/src/admin/components/forms/field-types/Tabs/index.tsx index 362fa6fece..036786b7a7 100644 --- a/packages/payload/src/admin/components/forms/field-types/Tabs/index.tsx +++ b/packages/payload/src/admin/components/forms/field-types/Tabs/index.tsx @@ -72,7 +72,8 @@ const TabsField: React.FC = (props) => { const { admin: { className, readOnly }, fieldTypes, - forceRender = false, + forceRender: forceRenderFromProps = false, + forceRenderAllFields, indexPath, path, permissions, @@ -86,6 +87,7 @@ const TabsField: React.FC = (props) => { const { withinCollapsible } = useCollapsible() const [activeTabIndex, setActiveTabIndex] = useState(0) const tabsPrefKey = `tabs-${indexPath}` + const forceRender = forceRenderFromProps || forceRenderAllFields useEffect(() => { if (preferencesKey) { diff --git a/packages/payload/src/admin/components/forms/field-types/Tabs/types.ts b/packages/payload/src/admin/components/forms/field-types/Tabs/types.ts index 243541b9db..10444c1659 100644 --- a/packages/payload/src/admin/components/forms/field-types/Tabs/types.ts +++ b/packages/payload/src/admin/components/forms/field-types/Tabs/types.ts @@ -5,6 +5,7 @@ import type { TabsField } from '../../../../../fields/config/types' export type Props = Omit & { fieldTypes: FieldTypes forceRender?: boolean + forceRenderAllFields?: boolean indexPath: string path?: string permissions: FieldPermissions diff --git a/packages/payload/src/admin/components/utilities/Config/index.tsx b/packages/payload/src/admin/components/utilities/Config/index.tsx index 2ed9c6cce3..8eb297aed6 100644 --- a/packages/payload/src/admin/components/utilities/Config/index.tsx +++ b/packages/payload/src/admin/components/utilities/Config/index.tsx @@ -19,7 +19,7 @@ export const ConfigProvider: React.FC<{ children: React.ReactNode; config: Sanit const resolvedConfig = await incomingConfig setConfig(resolvedConfig) } - awaitConfig() + void awaitConfig() } }, [incomingConfig]) diff --git a/packages/payload/src/admin/components/views/Global/Default/index.tsx b/packages/payload/src/admin/components/views/Global/Default/index.tsx index 0cefc90df7..50b227d973 100644 --- a/packages/payload/src/admin/components/views/Global/Default/index.tsx +++ b/packages/payload/src/admin/components/views/Global/Default/index.tsx @@ -19,7 +19,7 @@ export const DefaultGlobalEdit: React.FC< const { apiURL, data, fieldTypes, global, permissions } = props const { i18n } = useTranslation() - const { admin: { description } = {}, fields, label } = global + const { admin: { description, forceRenderAllFields } = {}, fields, label } = global const hasSavePermission = permissions?.update?.permission @@ -44,6 +44,7 @@ export const DefaultGlobalEdit: React.FC< description={description} fieldTypes={fieldTypes} fields={fields} + forceRenderAllFields={forceRenderAllFields} hasSavePermission={hasSavePermission} permissions={permissions} /> diff --git a/packages/payload/src/admin/components/views/LivePreview/index.tsx b/packages/payload/src/admin/components/views/LivePreview/index.tsx index 290fcf1dc1..05b2662206 100644 --- a/packages/payload/src/admin/components/views/LivePreview/index.tsx +++ b/packages/payload/src/admin/components/views/LivePreview/index.tsx @@ -122,6 +122,11 @@ const PreviewView: React.FC< description={description} fieldTypes={fieldTypes} fields={fields} + forceRenderAllFields={ + collection?.admin?.forceRenderAllFields ?? + global?.admin?.forceRenderAllFields ?? + false + } forceSidebarWrap hasSavePermission={hasSavePermission} permissions={permissions} diff --git a/packages/payload/src/admin/components/views/collections/Edit/Default/index.tsx b/packages/payload/src/admin/components/views/collections/Edit/Default/index.tsx index d38b2ba1b9..8250dc84b3 100644 --- a/packages/payload/src/admin/components/views/collections/Edit/Default/index.tsx +++ b/packages/payload/src/admin/components/views/collections/Edit/Default/index.tsx @@ -39,7 +39,7 @@ export const DefaultCollectionEdit: React.FC< permissions, } = props - const { auth, upload } = collection + const { admin: { forceRenderAllFields } = {}, auth, upload } = collection const [fields] = useState(() => formatFields(collection, isEditing)) @@ -92,6 +92,7 @@ export const DefaultCollectionEdit: React.FC< } fieldTypes={fieldTypes} fields={fields} + forceRenderAllFields={forceRenderAllFields} hasSavePermission={hasSavePermission} permissions={permissions} /> diff --git a/packages/payload/src/collections/config/schema.ts b/packages/payload/src/collections/config/schema.ts index 719e1df7ba..6df595ed00 100644 --- a/packages/payload/src/collections/config/schema.ts +++ b/packages/payload/src/collections/config/schema.ts @@ -62,6 +62,7 @@ const collectionSchema = joi.object().keys({ disableDuplicate: joi.bool(), enableRichTextLink: joi.boolean(), enableRichTextRelationship: joi.boolean(), + forceRenderAllFields: joi.boolean(), group: joi.alternatives().try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])), hidden: joi.alternatives().try(joi.boolean(), joi.func()), hideAPIURL: joi.bool(), diff --git a/packages/payload/src/collections/config/types.ts b/packages/payload/src/collections/config/types.ts index d3ce40a0eb..61ccdf45fd 100644 --- a/packages/payload/src/collections/config/types.ts +++ b/packages/payload/src/collections/config/types.ts @@ -317,6 +317,11 @@ export type CollectionAdminOptions = { disableDuplicate?: boolean enableRichTextLink?: boolean enableRichTextRelationship?: boolean + /** + * Forces all fields in the Edit view to render immediately, regardless of scroll position + * @default false + */ + forceRenderAllFields?: boolean /** * Place collections into a navigational group * */ diff --git a/packages/payload/src/globals/config/schema.ts b/packages/payload/src/globals/config/schema.ts index f337a89fb8..049723869c 100644 --- a/packages/payload/src/globals/config/schema.ts +++ b/packages/payload/src/globals/config/schema.ts @@ -40,6 +40,7 @@ const globalSchema = joi }), }), description: joi.alternatives().try(joi.string(), componentSchema), + forceRenderAllFields: joi.boolean(), group: joi .alternatives() .try(joi.string(), joi.object().pattern(joi.string(), [joi.string()])), diff --git a/packages/payload/src/globals/config/types.ts b/packages/payload/src/globals/config/types.ts index af41c11575..47537dcc3e 100644 --- a/packages/payload/src/globals/config/types.ts +++ b/packages/payload/src/globals/config/types.ts @@ -138,6 +138,11 @@ export type GlobalAdminOptions = { * Custom description for collection */ description?: EntityDescription + /** + * Forces all fields in the Edit view to render immediately, regardless of scroll position + * @default false + */ + forceRenderAllFields?: boolean /** * Place globals into a navigational group * */