diff --git a/src/client/components/forms/RenderFields/index.js b/src/client/components/forms/RenderFields/index.js index 7f67c91561..f261350872 100644 --- a/src/client/components/forms/RenderFields/index.js +++ b/src/client/components/forms/RenderFields/index.js @@ -1,9 +1,14 @@ import React, { createContext, useEffect, useContext, useState } from 'react'; import PropTypes from 'prop-types'; import RenderCustomComponent from '../../utilities/RenderCustomComponent'; +import useIntersect from '../../../hooks/useIntersect'; import './index.scss'; +const intersectionObserverOptions = { + rootMargin: '1000px', +}; + const RenderedFieldContext = createContext({}); export const useRenderedFields = () => useContext(RenderedFieldContext); @@ -20,6 +25,10 @@ const RenderFields = (props) => { operation: operationFromProps, } = props; + const [hasIntersected, setHasIntersected] = useState(false); + const [intersectionRef, entry] = useIntersect(intersectionObserverOptions); + const isIntersecting = Boolean(entry?.isIntersecting); + const { customComponentsPath: customComponentsPathFromContext, operation: operationFromContext } = useRenderedFields(); const operation = operationFromProps || operationFromContext; @@ -37,75 +46,85 @@ const RenderFields = (props) => { }); }, [operation, customComponentsPath]); + useEffect(() => { + if (isIntersecting && !hasIntersected) { + setHasIntersected(true); + } + }, [isIntersecting, hasIntersected]); + if (fieldSchema) { return ( - - {fieldSchema.map((field, i) => { - if (!field?.hidden && field?.admin?.disabled !== true) { - if ((filter && typeof filter === 'function' && filter(field)) || !filter) { - const FieldComponent = field?.admin?.hidden ? fieldTypes.hidden : fieldTypes[field.type]; +
+ {hasIntersected && ( + + {fieldSchema.map((field, i) => { + if (!field?.hidden && field?.admin?.disabled !== true) { + if ((filter && typeof filter === 'function' && filter(field)) || !filter) { + const FieldComponent = field?.admin?.hidden ? fieldTypes.hidden : fieldTypes[field.type]; - let initialFieldData; - let fieldPermissions = permissions[field.name]; + let initialFieldData; + let fieldPermissions = permissions[field.name]; - if (!field.name) { - initialFieldData = initialData; - fieldPermissions = permissions; - } else if (initialData?.[field.name] !== undefined) { - initialFieldData = initialData[field.name]; - } + if (!field.name) { + initialFieldData = initialData; + fieldPermissions = permissions; + } else if (initialData?.[field.name] !== undefined) { + initialFieldData = initialData[field.name]; + } - let { admin: { readOnly } = {} } = field; + let { admin: { readOnly } = {} } = field; - if (readOnlyOverride) readOnly = true; + if (readOnlyOverride) readOnly = true; - if (permissions?.[field?.name]?.read?.permission !== false) { - if (permissions?.[field?.name]?.[operation]?.permission === false) { - readOnly = true; + if (permissions?.[field?.name]?.read?.permission !== false) { + if (permissions?.[field?.name]?.[operation]?.permission === false) { + readOnly = true; + } + + if (FieldComponent) { + return ( + + ); + } + + return ( +
+ No matched field found for + {' '} + " + {field.label} + " +
+ ); + } } - if (FieldComponent) { - return ( - - ); - } - - return ( -
- No matched field found for - {' '} - " - {field.label} - " -
- ); + return null; } - } - return null; - } - - return null; - })} -
+ return null; + })} + + )} +
); } diff --git a/src/client/hooks/useIntersect.js b/src/client/hooks/useIntersect.js new file mode 100644 index 0000000000..b3ae43460c --- /dev/null +++ b/src/client/hooks/useIntersect.js @@ -0,0 +1,29 @@ +/* eslint-disable no-shadow */ +import { useEffect, useRef, useState } from 'react'; + +export default ({ root = null, rootMargin, threshold = 0 } = {}) => { + const [entry, updateEntry] = useState({}); + const [node, setNode] = useState(null); + + const observer = useRef( + new window.IntersectionObserver(([entry]) => updateEntry(entry), { + root, + rootMargin, + threshold, + }), + ); + + useEffect( + () => { + const { current: currentObserver } = observer; + currentObserver.disconnect(); + + if (node) currentObserver.observe(node); + + return () => currentObserver.disconnect(); + }, + [node], + ); + + return [setNode, entry]; +};