@@ -49,6 +49,7 @@ import {route} from 'preact-router';
4949import * as schema from '../../../core/schema.js' ;
5050import { useCollectionSchema } from '../../hooks/useCollectionSchema.js' ;
5151import {
52+ buildDeeplinkUrl ,
5253 DeeplinkProvider ,
5354 scrollToDeeplink ,
5455 useDeeplink ,
@@ -265,19 +266,20 @@ DocEditor.Field = (props: FieldProps) => {
265266 const ref = useRef < HTMLDivElement > ( null ) ;
266267 const [ value , setValue ] = useState ( null ) ;
267268
268- const fieldValueEmpty = testFieldEmpty ( field , value ) ;
269+ const fieldValueEmpty = useMemo ( ( ) => testFieldEmpty ( field , value ) , [ value ] ) ;
269270 const showTranslateIcon =
270271 ( field . type === 'string' || field . type === 'richtext' ) && field . translate ;
271272
272- let showFieldHeader = ! props . hideHeader && ! field . hideLabel ;
273- // The "drawer" variant shows the header within the accordion button.
274- if ( field . type === 'object' ) {
275- // Default to the "drawer" variant.
276- const variant = field . variant || 'drawer' ;
277- if ( variant === 'drawer' ) {
278- showFieldHeader = false ;
273+ const showFieldHeader = useMemo ( ( ) => {
274+ if ( field . type === 'object' ) {
275+ // Default to the "drawer" variant.
276+ const variant = field . variant || 'drawer' ;
277+ if ( variant === 'drawer' ) {
278+ return false ;
279+ }
279280 }
280- }
281+ return ! props . hideHeader && ! field . hideLabel ;
282+ } , [ props . deepKey ] ) ;
281283
282284 useEffect ( ( ) => {
283285 const unsubscribe = props . draft . subscribe (
@@ -287,7 +289,7 @@ DocEditor.Field = (props: FieldProps) => {
287289 }
288290 ) ;
289291 return unsubscribe ;
290- } , [ props . draft , props . deepKey ] ) ;
292+ } , [ props . deepKey ] ) ;
291293
292294 useEffect ( ( ) => {
293295 if ( targeted ) {
@@ -376,12 +378,6 @@ DocEditor.FieldHeader = (props: {
376378 /** Whether the field has translations to display (i.e. if the field is not empty). */
377379 hasTranslations ?: boolean ;
378380} ) => {
379- function buildDeeplinkUrl ( ) {
380- const url = new URL ( window . location . href ) ;
381- url . searchParams . set ( 'deeplink' , props . deepKey ! ) ;
382- return url . toString ( ) ;
383- }
384-
385381 const deeplink = useDeeplink ( ) ;
386382 const docData = useDocData ( ) || { } ;
387383 const l10nSheet = docData . sys ?. l10nSheet ;
@@ -390,6 +386,11 @@ DocEditor.FieldHeader = (props: {
390386 const i18nLocales = i18nConfig . locales || [ 'en' ] ;
391387 const editTranslationsModal = useEditTranslationsModal ( ) ;
392388
389+ const deeplinkUrl = useMemo (
390+ ( ) => buildDeeplinkUrl ( props . deepKey || '' ) ,
391+ [ props . deepKey ]
392+ ) ;
393+
393394 return (
394395 < div className = { joinClassNames ( props . className , 'DocEditor__FieldHeader' ) } >
395396 { props . deprecated ? (
@@ -402,11 +403,11 @@ DocEditor.FieldHeader = (props: {
402403 { props . deepKey && (
403404 < a
404405 className = "DocEditor__FieldHeader__label__deeplink"
405- href = { buildDeeplinkUrl ( ) }
406+ href = { deeplinkUrl }
406407 title = "Link to field"
407408 onClick = { ( e ) => {
408409 e . preventDefault ( ) ;
409- window . history . replaceState ( { } , '' , buildDeeplinkUrl ( ) ) ;
410+ window . history . replaceState ( { } , '' , deeplinkUrl ) ;
410411 deeplink . setValue ( props . deepKey ! ) ;
411412 } }
412413 >
@@ -865,7 +866,7 @@ DocEditor.ArrayField = (props: FieldProps) => {
865866 }
866867 ) ;
867868 return unsubscribe ;
868- } , [ props . draft , props . deepKey ] ) ;
869+ } , [ props . deepKey ] ) ;
869870
870871 // Focus the field that was just moved (for hotkey support).
871872 useEffect ( ( ) => {
@@ -878,89 +879,113 @@ DocEditor.ArrayField = (props: FieldProps) => {
878879 dispatch ( { type : 'add' , draft : draft , deepKey : props . deepKey } ) ;
879880 } ;
880881
881- const pasteBefore = ( index : number ) => {
882- dispatch ( {
883- type : 'pasteBefore' ,
884- draft : draft ,
885- deepKey : props . deepKey ,
886- index : index ,
887- virtualClipboard : virtualClipboard ,
888- } ) ;
889- } ;
890-
891- const pasteAfter = ( index : number ) => {
892- dispatch ( {
893- type : 'pasteAfter' ,
894- draft : draft ,
895- deepKey : props . deepKey ,
896- index : index ,
897- virtualClipboard : virtualClipboard ,
898- } ) ;
899- } ;
900-
901- const insertBefore = ( index : number ) => {
902- dispatch ( {
903- type : 'insertBefore' ,
904- draft : draft ,
905- deepKey : props . deepKey ,
906- index : index ,
907- } ) ;
908- } ;
909-
910- const insertAfter = ( index : number ) => {
911- dispatch ( {
912- type : 'insertAfter' ,
913- draft : draft ,
914- deepKey : props . deepKey ,
915- index : index ,
916- } ) ;
917- } ;
882+ const pasteBefore = useCallback (
883+ ( index : number ) => {
884+ dispatch ( {
885+ type : 'pasteBefore' ,
886+ draft : draft ,
887+ deepKey : props . deepKey ,
888+ index : index ,
889+ virtualClipboard : virtualClipboard ,
890+ } ) ;
891+ } ,
892+ [ props . deepKey ]
893+ ) ;
918894
919- const duplicate = ( index : number ) => {
920- dispatch ( {
921- type : 'duplicate' ,
922- draft : draft ,
923- deepKey : props . deepKey ,
924- index : index ,
925- } ) ;
926- } ;
895+ const pasteAfter = useCallback (
896+ ( index : number ) => {
897+ dispatch ( {
898+ type : 'pasteAfter' ,
899+ draft : draft ,
900+ deepKey : props . deepKey ,
901+ index : index ,
902+ virtualClipboard : virtualClipboard ,
903+ } ) ;
904+ } ,
905+ [ props . deepKey ]
906+ ) ;
927907
928- const removeAt = ( index : number ) => {
929- dispatch ( {
930- type : 'removeAt' ,
931- draft : draft ,
932- deepKey : props . deepKey ,
933- index : index ,
934- } ) ;
935- } ;
908+ const insertBefore = useCallback (
909+ ( index : number ) => {
910+ dispatch ( {
911+ type : 'insertBefore' ,
912+ draft : draft ,
913+ deepKey : props . deepKey ,
914+ index : index ,
915+ } ) ;
916+ } ,
917+ [ props . deepKey ]
918+ ) ;
936919
937- /** Focus the field header (the clickable "summary" part). */
938- const focusFieldHeader = ( deepKey : string , index : number ) => {
939- document . getElementById ( `summary-for-${ deepKey } .${ order [ index ] } ` ) ?. focus ( ) ;
940- } ;
920+ const insertAfter = useCallback (
921+ ( index : number ) => {
922+ dispatch ( {
923+ type : 'insertAfter' ,
924+ draft : draft ,
925+ deepKey : props . deepKey ,
926+ index : index ,
927+ } ) ;
928+ } ,
929+ [ props . deepKey ]
930+ ) ;
941931
942- const moveUp = ( index : number ) => {
943- if ( index > 0 ) {
932+ const duplicate = useCallback (
933+ ( index : number ) => {
944934 dispatch ( {
945- type : 'moveUp ' ,
935+ type : 'duplicate ' ,
946936 draft : draft ,
947937 deepKey : props . deepKey ,
948938 index : index ,
949939 } ) ;
950- }
951- } ;
940+ } ,
941+ [ props . deepKey ]
942+ ) ;
952943
953- const moveDown = ( index : number ) => {
954- if ( index < order . length - 1 ) {
944+ const removeAt = useCallback (
945+ ( index : number ) => {
955946 dispatch ( {
956- type : 'moveDown ' ,
947+ type : 'removeAt ' ,
957948 draft : draft ,
958949 deepKey : props . deepKey ,
959950 index : index ,
960951 } ) ;
961- }
952+ } ,
953+ [ props . deepKey ]
954+ ) ;
955+
956+ /** Focus the field header (the clickable "summary" part). */
957+ const focusFieldHeader = ( deepKey : string , index : number ) => {
958+ document . getElementById ( `summary-for-${ deepKey } .${ order [ index ] } ` ) ?. focus ( ) ;
962959 } ;
963960
961+ const moveUp = useCallback (
962+ ( index : number ) => {
963+ if ( index > 0 ) {
964+ dispatch ( {
965+ type : 'moveUp' ,
966+ draft : draft ,
967+ deepKey : props . deepKey ,
968+ index : index ,
969+ } ) ;
970+ }
971+ } ,
972+ [ props . deepKey ]
973+ ) ;
974+
975+ const moveDown = useCallback (
976+ ( index : number ) => {
977+ if ( index < order . length - 1 ) {
978+ dispatch ( {
979+ type : 'moveDown' ,
980+ draft : draft ,
981+ deepKey : props . deepKey ,
982+ index : index ,
983+ } ) ;
984+ }
985+ } ,
986+ [ props . deepKey ]
987+ ) ;
988+
964989 /** Copies the item data to the state so it can be "pasted" via the context menu later. */
965990 const copyToVirtualClipboard = ( index : number ) => {
966991 const key = order [ index ] ;
@@ -1014,24 +1039,27 @@ DocEditor.ArrayField = (props: FieldProps) => {
10141039 }
10151040
10161041 /** Handler for using the arrow keys when the array item's header is focused. */
1017- function handleKeyDown ( e : KeyboardEvent , arrayKey : string ) {
1018- if ( ! e . target ) {
1019- return ;
1020- }
1021- // Move the items up and down using the up/down arrow keys.
1022- // Collapse and expand the item using the left/right arrow keys.
1023- if ( e . key === 'ArrowUp' ) {
1024- e . preventDefault ( ) ;
1025- moveUp ( order . indexOf ( arrayKey ) ) ;
1026- } else if ( e . key === 'ArrowDown' ) {
1027- e . preventDefault ( ) ;
1028- moveDown ( order . indexOf ( arrayKey ) ) ;
1029- } else if ( e . key === 'ArrowLeft' ) {
1030- ( e . target as HTMLElement ) . closest ( 'details' ) ! . open = false ;
1031- } else if ( e . key === 'ArrowRight' ) {
1032- ( e . target as HTMLElement ) . closest ( 'details' ) ! . open = true ;
1033- }
1034- }
1042+ const handleKeyDown = useCallback (
1043+ ( e : KeyboardEvent , arrayKey : string ) => {
1044+ if ( ! e . target ) {
1045+ return ;
1046+ }
1047+ // Move the items up and down using the up/down arrow keys.
1048+ // Collapse and expand the item using the left/right arrow keys.
1049+ if ( e . key === 'ArrowUp' ) {
1050+ e . preventDefault ( ) ;
1051+ moveUp ( order . indexOf ( arrayKey ) ) ;
1052+ } else if ( e . key === 'ArrowDown' ) {
1053+ e . preventDefault ( ) ;
1054+ moveDown ( order . indexOf ( arrayKey ) ) ;
1055+ } else if ( e . key === 'ArrowLeft' ) {
1056+ ( e . target as HTMLElement ) . closest ( 'details' ) ! . open = false ;
1057+ } else if ( e . key === 'ArrowRight' ) {
1058+ ( e . target as HTMLElement ) . closest ( 'details' ) ! . open = true ;
1059+ }
1060+ } ,
1061+ [ props . deepKey ]
1062+ ) ;
10351063
10361064 const addButtonRow = (
10371065 < div className = "DocEditor__ArrayField__add" >
@@ -1313,7 +1341,7 @@ DocEditor.OneOfField = (props: FieldProps) => {
13131341 }
13141342 ) ;
13151343 return unsubscribe ;
1316- } , [ props . draft , props . deepKey ] ) ;
1344+ } , [ props . deepKey ] ) ;
13171345
13181346 // When the dropdown receives focus, highlight the <input> text so that it can
13191347 // be easily searched.
0 commit comments