@wordpress/block-editor 12.3.1 → 12.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (102) hide show
  1. package/README.md +1 -0
  2. package/build/components/block-lock/toolbar.js +25 -6
  3. package/build/components/block-lock/toolbar.js.map +1 -1
  4. package/build/components/block-toolbar/index.js +8 -5
  5. package/build/components/block-toolbar/index.js.map +1 -1
  6. package/build/components/dimensions-tool/aspect-ratio-tool.js +99 -0
  7. package/build/components/dimensions-tool/aspect-ratio-tool.js.map +1 -0
  8. package/build/components/dimensions-tool/index.js +207 -0
  9. package/build/components/dimensions-tool/index.js.map +1 -0
  10. package/build/components/dimensions-tool/scale-tool.js +111 -0
  11. package/build/components/dimensions-tool/scale-tool.js.map +1 -0
  12. package/build/components/dimensions-tool/width-height-tool.js +125 -0
  13. package/build/components/dimensions-tool/width-height-tool.js.map +1 -0
  14. package/build/components/image-editor/aspect-ratio-dropdown.js +1 -1
  15. package/build/components/image-editor/aspect-ratio-dropdown.js.map +1 -1
  16. package/build/components/image-editor/use-save-image.js +1 -2
  17. package/build/components/image-editor/use-save-image.js.map +1 -1
  18. package/build/components/image-size-control/index.js +6 -0
  19. package/build/components/image-size-control/index.js.map +1 -1
  20. package/build/components/link-control/index.js +17 -15
  21. package/build/components/link-control/index.js.map +1 -1
  22. package/build/components/link-control/search-input.js +4 -4
  23. package/build/components/link-control/search-input.js.map +1 -1
  24. package/build/components/link-control/settings-drawer.js +2 -3
  25. package/build/components/link-control/settings-drawer.js.map +1 -1
  26. package/build/components/provider/use-block-sync.js +21 -0
  27. package/build/components/provider/use-block-sync.js.map +1 -1
  28. package/build/components/resolution-tool/index.js +55 -0
  29. package/build/components/resolution-tool/index.js.map +1 -0
  30. package/build/components/url-input/index.js +4 -2
  31. package/build/components/url-input/index.js.map +1 -1
  32. package/build/private-apis.js +7 -1
  33. package/build/private-apis.js.map +1 -1
  34. package/build/store/defaults.js +1 -0
  35. package/build/store/defaults.js.map +1 -1
  36. package/build-module/components/block-lock/toolbar.js +25 -7
  37. package/build-module/components/block-lock/toolbar.js.map +1 -1
  38. package/build-module/components/block-toolbar/index.js +8 -5
  39. package/build-module/components/block-toolbar/index.js.map +1 -1
  40. package/build-module/components/dimensions-tool/aspect-ratio-tool.js +87 -0
  41. package/build-module/components/dimensions-tool/aspect-ratio-tool.js.map +1 -0
  42. package/build-module/components/dimensions-tool/index.js +195 -0
  43. package/build-module/components/dimensions-tool/index.js.map +1 -0
  44. package/build-module/components/dimensions-tool/scale-tool.js +103 -0
  45. package/build-module/components/dimensions-tool/scale-tool.js.map +1 -0
  46. package/build-module/components/dimensions-tool/width-height-tool.js +122 -0
  47. package/build-module/components/dimensions-tool/width-height-tool.js.map +1 -0
  48. package/build-module/components/image-editor/aspect-ratio-dropdown.js +1 -1
  49. package/build-module/components/image-editor/aspect-ratio-dropdown.js.map +1 -1
  50. package/build-module/components/image-editor/use-save-image.js +1 -2
  51. package/build-module/components/image-editor/use-save-image.js.map +1 -1
  52. package/build-module/components/image-size-control/index.js +5 -0
  53. package/build-module/components/image-size-control/index.js.map +1 -1
  54. package/build-module/components/link-control/index.js +17 -15
  55. package/build-module/components/link-control/index.js.map +1 -1
  56. package/build-module/components/link-control/search-input.js +4 -4
  57. package/build-module/components/link-control/search-input.js.map +1 -1
  58. package/build-module/components/link-control/settings-drawer.js +4 -5
  59. package/build-module/components/link-control/settings-drawer.js.map +1 -1
  60. package/build-module/components/provider/use-block-sync.js +21 -0
  61. package/build-module/components/provider/use-block-sync.js.map +1 -1
  62. package/build-module/components/resolution-tool/index.js +45 -0
  63. package/build-module/components/resolution-tool/index.js.map +1 -0
  64. package/build-module/components/url-input/index.js +4 -2
  65. package/build-module/components/url-input/index.js.map +1 -1
  66. package/build-module/private-apis.js +5 -1
  67. package/build-module/private-apis.js.map +1 -1
  68. package/build-module/store/defaults.js +1 -0
  69. package/build-module/store/defaults.js.map +1 -1
  70. package/build-style/style-rtl.css +42 -46
  71. package/build-style/style.css +42 -46
  72. package/package.json +6 -5
  73. package/src/components/alignment-control/test/__snapshots__/index.js.snap +6 -6
  74. package/src/components/block-alignment-control/test/__snapshots__/index.js.snap +5 -5
  75. package/src/components/block-lock/toolbar.js +34 -6
  76. package/src/components/block-toolbar/index.js +9 -6
  77. package/src/components/block-tools/style.scss +4 -0
  78. package/src/components/dimensions-tool/aspect-ratio-tool.js +124 -0
  79. package/src/components/dimensions-tool/index.js +212 -0
  80. package/src/components/dimensions-tool/scale-tool.js +124 -0
  81. package/src/components/dimensions-tool/stories/aspect-ratio-tool.js +52 -0
  82. package/src/components/dimensions-tool/stories/index.js +54 -0
  83. package/src/components/dimensions-tool/stories/scale-tool.js +48 -0
  84. package/src/components/dimensions-tool/stories/width-height-tool.js +54 -0
  85. package/src/components/dimensions-tool/test/index.js +641 -0
  86. package/src/components/dimensions-tool/width-height-tool.js +113 -0
  87. package/src/components/image-editor/aspect-ratio-dropdown.js +1 -1
  88. package/src/components/image-editor/use-save-image.js +0 -1
  89. package/src/components/image-size-control/index.js +6 -0
  90. package/src/components/link-control/index.js +32 -28
  91. package/src/components/link-control/search-input.js +4 -3
  92. package/src/components/link-control/settings-drawer.js +6 -5
  93. package/src/components/link-control/style.scss +33 -55
  94. package/src/components/link-control/test/index.js +129 -116
  95. package/src/components/media-replace-flow/test/index.js +1 -1
  96. package/src/components/provider/test/use-block-sync.js +21 -6
  97. package/src/components/provider/use-block-sync.js +19 -0
  98. package/src/components/resolution-tool/index.js +56 -0
  99. package/src/components/resolution-tool/stories/index.js +48 -0
  100. package/src/components/url-input/index.js +2 -0
  101. package/src/private-apis.js +4 -0
  102. package/src/store/defaults.js +1 -0
@@ -138,7 +138,7 @@ describe( 'Basic rendering', () => {
138
138
  render( <LinkControl /> );
139
139
 
140
140
  // Search Input UI.
141
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
141
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
142
142
 
143
143
  expect( searchInput ).toBeVisible();
144
144
  } );
@@ -147,7 +147,7 @@ describe( 'Basic rendering', () => {
147
147
  render( <LinkControl /> );
148
148
 
149
149
  // Search Input UI.
150
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
150
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
151
151
 
152
152
  expect( searchInput ).toBeVisible();
153
153
  // Make sure we use the ARIA 1.0 pattern with aria-owns.
@@ -170,7 +170,7 @@ describe( 'Basic rendering', () => {
170
170
  render( <LinkControl /> );
171
171
 
172
172
  // Search Input UI.
173
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
173
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
174
174
 
175
175
  // Simulate searching for a term.
176
176
  await user.type( searchInput, 'Hello' );
@@ -283,7 +283,7 @@ describe( 'Basic rendering', () => {
283
283
  render( <LinkControl /> );
284
284
 
285
285
  // Search Input UI.
286
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
286
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
287
287
 
288
288
  // Simulate searching for a term.
289
289
  await user.type( searchInput, searchTerm );
@@ -296,7 +296,7 @@ describe( 'Basic rendering', () => {
296
296
  render( <LinkControl value={ { url: 'https://example.com' } } /> );
297
297
 
298
298
  expect(
299
- screen.queryByRole( 'combobox', { name: 'URL' } )
299
+ screen.queryByRole( 'combobox', { name: 'Link' } )
300
300
  ).not.toBeInTheDocument();
301
301
  } );
302
302
 
@@ -309,7 +309,7 @@ describe( 'Basic rendering', () => {
309
309
  );
310
310
 
311
311
  expect(
312
- screen.getByRole( 'combobox', { name: 'URL' } )
312
+ screen.getByRole( 'combobox', { name: 'Link' } )
313
313
  ).toBeVisible();
314
314
  } );
315
315
 
@@ -327,7 +327,7 @@ describe( 'Basic rendering', () => {
327
327
  await user.click( editButton );
328
328
 
329
329
  expect(
330
- screen.getByRole( 'combobox', { name: 'URL' } )
330
+ screen.getByRole( 'combobox', { name: 'Link' } )
331
331
  ).toBeVisible();
332
332
 
333
333
  // If passed `forceIsEditingLink` of `false` while editing, should
@@ -340,7 +340,7 @@ describe( 'Basic rendering', () => {
340
340
  );
341
341
 
342
342
  expect(
343
- screen.queryByRole( 'combobox', { name: 'URL' } )
343
+ screen.queryByRole( 'combobox', { name: 'Link' } )
344
344
  ).not.toBeInTheDocument();
345
345
  } );
346
346
 
@@ -424,7 +424,7 @@ describe( 'Searching for a link', () => {
424
424
  render( <LinkControl /> );
425
425
 
426
426
  // Search Input UI.
427
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
427
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
428
428
 
429
429
  // Simulate searching for a term.
430
430
  await user.type( searchInput, searchTerm );
@@ -448,7 +448,9 @@ describe( 'Searching for a link', () => {
448
448
  render( <LinkControl /> );
449
449
 
450
450
  // Search Input UI.
451
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
451
+ const searchInput = screen.getByRole( 'combobox', {
452
+ name: 'Link',
453
+ } );
452
454
 
453
455
  // Simulate searching for a term.
454
456
  await user.type( searchInput, searchTerm );
@@ -497,7 +499,9 @@ describe( 'Searching for a link', () => {
497
499
  render( <LinkControl /> );
498
500
 
499
501
  // Search Input UI.
500
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
502
+ const searchInput = screen.getByRole( 'combobox', {
503
+ name: 'Link',
504
+ } );
501
505
 
502
506
  // Simulate searching for a term.
503
507
  await user.type( searchInput, searchTerm );
@@ -528,7 +532,7 @@ describe( 'Searching for a link', () => {
528
532
  render( <LinkControl /> );
529
533
 
530
534
  // Search Input UI.
531
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
535
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
532
536
 
533
537
  // Simulate searching for a term.
534
538
  await user.type( searchInput, searchTerm );
@@ -571,7 +575,7 @@ describe( 'Searching for a link', () => {
571
575
  render( <LinkControl showSuggestions={ false } /> );
572
576
 
573
577
  // Search Input UI.
574
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
578
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
575
579
 
576
580
  // Simulate searching for a term.
577
581
  await user.type( searchInput, 'anything' );
@@ -582,12 +586,43 @@ describe( 'Searching for a link', () => {
582
586
  expect( mockFetchSearchSuggestions ).not.toHaveBeenCalled();
583
587
  } );
584
588
 
589
+ it( 'should not display a URL suggestion when input is not likely to be a URL.', async () => {
590
+ const searchTerm = 'unlikelytobeaURL';
591
+ const user = userEvent.setup();
592
+ render( <LinkControl /> );
593
+
594
+ // Search Input UI.
595
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
596
+
597
+ // Simulate searching for a term.
598
+ await user.type( searchInput, searchTerm );
599
+
600
+ const searchResultElements = within(
601
+ await screen.findByRole( 'listbox', {
602
+ name: /Search results for.*/,
603
+ } )
604
+ ).getAllByRole( 'option' );
605
+
606
+ const lastSearchResultItem =
607
+ searchResultElements[ searchResultElements.length - 1 ];
608
+
609
+ // We should see a search result for each of the expect search suggestions.
610
+ expect( searchResultElements ).toHaveLength(
611
+ fauxEntitySuggestions.length
612
+ );
613
+
614
+ // The URL search suggestion should not exist.
615
+ expect( lastSearchResultItem ).not.toHaveTextContent(
616
+ 'Press ENTER to add this link'
617
+ );
618
+ } );
619
+
585
620
  it( 'should not display a URL suggestion as a default fallback when noURLSuggestion is passed.', async () => {
586
621
  const user = userEvent.setup();
587
622
  render( <LinkControl noURLSuggestion /> );
588
623
 
589
624
  // Search Input UI.
590
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
625
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
591
626
 
592
627
  // Simulate searching for a term.
593
628
  await user.type( searchInput, 'couldbeurlorentitysearchterm' );
@@ -617,7 +652,9 @@ describe( 'Manual link entry', () => {
617
652
  render( <LinkControl /> );
618
653
 
619
654
  // Search Input UI.
620
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
655
+ const searchInput = screen.getByRole( 'combobox', {
656
+ name: 'Link',
657
+ } );
621
658
 
622
659
  // Simulate searching for a term.
623
660
  await user.type( searchInput, searchTerm );
@@ -653,19 +690,9 @@ describe( 'Manual link entry', () => {
653
690
 
654
691
  // Search Input UI.
655
692
  const searchInput = screen.getByRole( 'combobox', {
656
- name: 'URL',
657
- } );
658
-
659
- let submitButton = screen.getByRole( 'button', {
660
- name: 'Save',
693
+ name: 'Link',
661
694
  } );
662
695
 
663
- expect( submitButton ).toHaveAttribute(
664
- 'aria-disabled',
665
- 'true'
666
- );
667
- expect( submitButton ).toBeVisible();
668
-
669
696
  if ( searchString.length ) {
670
697
  // Simulate searching for a term.
671
698
  await user.type( searchInput, searchString );
@@ -677,102 +704,74 @@ describe( 'Manual link entry', () => {
677
704
  // Attempt to submit the empty search value in the input.
678
705
  await user.keyboard( '[Enter]' );
679
706
 
680
- submitButton = screen.getByRole( 'button', {
681
- name: 'Save',
682
- } );
683
-
684
- // Verify the UI hasn't allowed submission.
707
+ // Verify the UI hasn't allowed submission because
708
+ // the search input is still visible.
685
709
  expect( searchInput ).toBeVisible();
686
- expect( submitButton ).toHaveAttribute(
687
- 'aria-disabled',
688
- 'true'
689
- );
690
- expect( submitButton ).toBeVisible();
691
710
  }
692
711
  );
693
712
 
694
713
  it.each( testTable )(
695
- 'should not allow creation of links %s via the UI "submit" button',
714
+ 'should not allow editing of links to a new link %s via the UI "submit" button',
696
715
  async ( _desc, searchString ) => {
697
716
  const user = userEvent.setup();
698
717
 
699
- render( <LinkControl /> );
718
+ render(
719
+ <LinkControl
720
+ value={ fauxEntitySuggestions[ 0 ] }
721
+ forceIsEditingLink
722
+ />
723
+ );
700
724
 
701
725
  // Search Input UI.
702
726
  const searchInput = screen.getByRole( 'combobox', {
703
- name: 'URL',
727
+ name: 'Link',
704
728
  } );
705
729
 
706
- let submitButton = screen.queryByRole( 'button', {
707
- name: 'Save',
708
- } );
730
+ // Remove the existing link.
731
+ await user.clear( searchInput );
709
732
 
710
- expect( submitButton ).toHaveAttribute(
711
- 'aria-disabled',
712
- 'true'
713
- );
714
- expect( submitButton ).toBeVisible();
715
-
716
- // Simulate searching for a term.
717
733
  if ( searchString.length ) {
718
- // Simulate searching for a term.
719
734
  await user.type( searchInput, searchString );
720
735
  } else {
721
736
  // Simulate clearing the search term.
722
737
  await user.clear( searchInput );
723
738
  }
724
739
 
725
- // Attempt to submit the empty search value in the input.
726
- await user.click( submitButton );
727
-
728
- submitButton = screen.queryByRole( 'button', {
740
+ const submitButton = screen.queryByRole( 'button', {
729
741
  name: 'Save',
730
742
  } );
731
743
 
732
- // Verify the UI hasn't allowed submission.
733
- expect( searchInput ).toBeVisible();
744
+ // debug the UI state
745
+ // screen.debug();
746
+
747
+ // Verify the submission UI is disabled.
748
+ expect( submitButton ).toBeVisible();
734
749
  expect( submitButton ).toHaveAttribute(
735
750
  'aria-disabled',
736
751
  'true'
737
752
  );
738
- expect( submitButton ).toBeVisible();
753
+
754
+ // Attempt to submit the empty search value in the input.
755
+ await user.click( submitButton );
756
+
757
+ // Verify the UI hasn't allowed submission because
758
+ // the search input is still visible.
759
+ expect( searchInput ).toBeVisible();
739
760
  }
740
761
  );
741
762
  } );
742
763
 
743
764
  describe( 'Handling cancellation', () => {
744
- it( 'should allow cancellation of the link creation process and reset any entered values', async () => {
745
- const user = userEvent.setup();
765
+ it( 'should not show cancellation button during link creation', async () => {
746
766
  const mockOnRemove = jest.fn();
747
- const mockOnCancel = jest.fn();
748
767
 
749
768
  render( <LinkControl onRemove={ mockOnRemove } /> );
750
769
 
751
- // Search Input UI.
752
- const searchInput = screen.getByRole( 'combobox', {
753
- name: 'URL',
754
- } );
755
-
756
770
  const cancelButton = screen.queryByRole( 'button', {
757
771
  name: 'Cancel',
758
772
  } );
759
773
 
760
- expect( cancelButton ).toBeEnabled();
761
- expect( cancelButton ).toBeVisible();
762
-
763
- // Simulate adding a link for a term.
764
- await user.type( searchInput, 'https://www.wordpress.org' );
765
-
766
- // Attempt to submit the empty search value in the input.
767
- await user.click( cancelButton );
768
-
769
- // Verify the consumer can handle the cancellation.
770
- expect( mockOnRemove ).toHaveBeenCalled();
771
-
772
- // Ensure optional callback is not called.
773
- expect( mockOnCancel ).not.toHaveBeenCalled();
774
-
775
- expect( searchInput ).toHaveValue( '' );
774
+ expect( cancelButton ).not.toBeInTheDocument();
776
775
  } );
777
776
 
778
777
  it( 'should allow cancellation of the link editing process and reset any entered values', async () => {
@@ -809,7 +808,7 @@ describe( 'Manual link entry', () => {
809
808
  await toggleSettingsDrawer( user );
810
809
 
811
810
  let searchInput = screen.getByRole( 'combobox', {
812
- name: 'URL',
811
+ name: 'Link',
813
812
  } );
814
813
 
815
814
  let textInput = screen.getByRole( 'textbox', {
@@ -844,7 +843,7 @@ describe( 'Manual link entry', () => {
844
843
 
845
844
  // Re-query the inputs as they have been replaced.
846
845
  searchInput = screen.getByRole( 'combobox', {
847
- name: 'URL',
846
+ name: 'Link',
848
847
  } );
849
848
 
850
849
  textInput = screen.getByRole( 'textbox', {
@@ -860,7 +859,13 @@ describe( 'Manual link entry', () => {
860
859
  const user = userEvent.setup();
861
860
  const mockOnCancel = jest.fn();
862
861
 
863
- render( <LinkControl onCancel={ mockOnCancel } /> );
862
+ render(
863
+ <LinkControl
864
+ value={ fauxEntitySuggestions[ 0 ] }
865
+ onCancel={ mockOnCancel }
866
+ forceIsEditingLink
867
+ />
868
+ );
864
869
 
865
870
  const cancelButton = screen.queryByRole( 'button', {
866
871
  name: 'Cancel',
@@ -886,7 +891,7 @@ describe( 'Manual link entry', () => {
886
891
 
887
892
  // Search Input UI.
888
893
  const searchInput = screen.getByRole( 'combobox', {
889
- name: 'URL',
894
+ name: 'Link',
890
895
  } );
891
896
 
892
897
  // Simulate searching for a term.
@@ -922,7 +927,7 @@ describe( 'Default search suggestions', () => {
922
927
  // Verify input has no value has default suggestions should only show
923
928
  // when this does not have a value.
924
929
  // Search Input UI.
925
- expect( screen.getByRole( 'combobox', { name: 'URL' } ) ).toHaveValue(
930
+ expect( screen.getByRole( 'combobox', { name: 'Link' } ) ).toHaveValue(
926
931
  ''
927
932
  );
928
933
 
@@ -951,7 +956,7 @@ describe( 'Default search suggestions', () => {
951
956
  } );
952
957
  await user.click( currentLinkBtn );
953
958
 
954
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
959
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
955
960
 
956
961
  // Search input is set to the URL value.
957
962
  expect( searchInput ).toHaveValue( initialValue.url );
@@ -973,7 +978,7 @@ describe( 'Default search suggestions', () => {
973
978
  render( <LinkControl showInitialSuggestions /> );
974
979
 
975
980
  // Search Input UI.
976
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
981
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
977
982
 
978
983
  // Simulate searching for a term.
979
984
  await user.type( searchInput, searchTerm );
@@ -1011,7 +1016,7 @@ describe( 'Default search suggestions', () => {
1011
1016
 
1012
1017
  render( <LinkControl showInitialSuggestions /> );
1013
1018
 
1014
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1019
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1015
1020
 
1016
1021
  const searchResultsField = screen.queryByRole( 'listbox', {
1017
1022
  name: 'Suggestions',
@@ -1069,7 +1074,9 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1069
1074
  render( <LinkControlConsumer /> );
1070
1075
 
1071
1076
  // Search Input UI.
1072
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1077
+ const searchInput = screen.getByRole( 'combobox', {
1078
+ name: 'Link',
1079
+ } );
1073
1080
 
1074
1081
  // Simulate searching for a term.
1075
1082
  await user.type( searchInput, entityNameText );
@@ -1136,7 +1143,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1136
1143
  render( <LinkControlConsumer /> );
1137
1144
 
1138
1145
  // Search Input UI.
1139
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1146
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1140
1147
 
1141
1148
  // Simulate searching for a term.
1142
1149
  await user.type( searchInput, 'Some new page to create' );
@@ -1185,7 +1192,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1185
1192
  render( <LinkControlConsumer /> );
1186
1193
 
1187
1194
  // Search Input UI.
1188
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1195
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1189
1196
 
1190
1197
  // Simulate searching for a term.
1191
1198
  await user.type( searchInput, entityNameText );
@@ -1228,7 +1235,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1228
1235
  render( <LinkControlConsumer /> );
1229
1236
 
1230
1237
  // Search Input UI.
1231
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1238
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1232
1239
 
1233
1240
  // Simulate searching for a term.
1234
1241
  await user.type( searchInput, entityNameText );
@@ -1252,7 +1259,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1252
1259
 
1253
1260
  // Search Input UI.
1254
1261
  const searchInput = screen.getByRole( 'combobox', {
1255
- name: 'URL',
1262
+ name: 'Link',
1256
1263
  } );
1257
1264
 
1258
1265
  const searchResultsField = screen.queryByRole( 'listbox' );
@@ -1272,7 +1279,9 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1272
1279
  );
1273
1280
 
1274
1281
  // Search Input UI.
1275
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1282
+ const searchInput = screen.getByRole( 'combobox', {
1283
+ name: 'Link',
1284
+ } );
1276
1285
 
1277
1286
  const searchResultsField = screen.queryByRole( 'listbox' );
1278
1287
 
@@ -1295,7 +1304,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1295
1304
 
1296
1305
  // Search Input UI.
1297
1306
  const searchInput = screen.getByRole( 'combobox', {
1298
- name: 'URL',
1307
+ name: 'Link',
1299
1308
  } );
1300
1309
 
1301
1310
  // Simulate searching for a term.
@@ -1329,7 +1338,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1329
1338
  render( <LinkControl createSuggestion={ createSuggestion } /> );
1330
1339
 
1331
1340
  // Search Input UI.
1332
- searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1341
+ searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1333
1342
 
1334
1343
  // Simulate searching for a term.
1335
1344
  await user.type( searchInput, searchText );
@@ -1344,7 +1353,7 @@ describe( 'Creating Entities (eg: Posts, Pages)', () => {
1344
1353
 
1345
1354
  await user.click( createButton );
1346
1355
 
1347
- searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1356
+ searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1348
1357
 
1349
1358
  const errorNotice = screen.getAllByText(
1350
1359
  'API response returned invalid entity.'
@@ -1417,7 +1426,7 @@ describe( 'Selecting links', () => {
1417
1426
  // Simulate searching for a term.
1418
1427
  await user.click( currentLinkBtn );
1419
1428
 
1420
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1429
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1421
1430
  currentLinkUI = screen.queryByLabelText( 'Currently selected' );
1422
1431
 
1423
1432
  // We should be back to showing the search input.
@@ -1458,7 +1467,7 @@ describe( 'Selecting links', () => {
1458
1467
 
1459
1468
  // Search Input UI.
1460
1469
  const searchInput = screen.getByRole( 'combobox', {
1461
- name: 'URL',
1470
+ name: 'Link',
1462
1471
  } );
1463
1472
 
1464
1473
  // Simulate searching for a term.
@@ -1520,7 +1529,7 @@ describe( 'Selecting links', () => {
1520
1529
 
1521
1530
  // Search Input UI.
1522
1531
  const searchInput = screen.getByRole( 'combobox', {
1523
- name: 'URL',
1532
+ name: 'Link',
1524
1533
  } );
1525
1534
 
1526
1535
  // Simulate searching for a term.
@@ -1609,7 +1618,9 @@ describe( 'Selecting links', () => {
1609
1618
  ).toBeVisible();
1610
1619
 
1611
1620
  // Search Input UI.
1612
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1621
+ const searchInput = screen.getByRole( 'combobox', {
1622
+ name: 'Link',
1623
+ } );
1613
1624
 
1614
1625
  // Step down into the search results, highlighting the first result item.
1615
1626
  triggerArrowDown( searchInput );
@@ -1665,7 +1676,9 @@ describe( 'Selecting links', () => {
1665
1676
  render( <LinkControl value={ selectedLink } forceIsEditingLink /> );
1666
1677
 
1667
1678
  // focus the search input
1668
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1679
+ const searchInput = screen.getByRole( 'combobox', {
1680
+ name: 'Link',
1681
+ } );
1669
1682
 
1670
1683
  fireEvent.focus( searchInput );
1671
1684
 
@@ -1707,10 +1720,7 @@ describe( 'Addition Settings UI', () => {
1707
1720
 
1708
1721
  render( <LinkControlConsumer /> );
1709
1722
 
1710
- const settingsToggle = screen.queryByRole( 'button', {
1711
- name: 'Link Settings',
1712
- ariaControls: 'link-settings-1',
1713
- } );
1723
+ const settingsToggle = getSettingsDrawerToggle();
1714
1724
 
1715
1725
  expect( settingsToggle ).not.toBeInTheDocument();
1716
1726
  } );
@@ -1727,10 +1737,7 @@ describe( 'Addition Settings UI', () => {
1727
1737
 
1728
1738
  const user = userEvent.setup();
1729
1739
 
1730
- const settingsToggle = screen.queryByRole( 'button', {
1731
- name: 'Link Settings',
1732
- ariaControls: 'link-settings-1',
1733
- } );
1740
+ const settingsToggle = getSettingsDrawerToggle();
1734
1741
 
1735
1742
  expect( settingsToggle ).toHaveAttribute( 'aria-expanded', 'false' );
1736
1743
 
@@ -1891,7 +1898,7 @@ describe( 'Post types', () => {
1891
1898
  render( <LinkControl /> );
1892
1899
 
1893
1900
  // Search Input UI.
1894
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1901
+ const searchInput = screen.getByRole( 'combobox', { name: 'Link' } );
1895
1902
 
1896
1903
  // Simulate searching for a term.
1897
1904
  await user.type( searchInput, searchTerm );
@@ -1918,7 +1925,9 @@ describe( 'Post types', () => {
1918
1925
  render( <LinkControl suggestionsQuery={ { type: postType } } /> );
1919
1926
 
1920
1927
  // Search Input UI.
1921
- const searchInput = screen.getByRole( 'combobox', { name: 'URL' } );
1928
+ const searchInput = screen.getByRole( 'combobox', {
1929
+ name: 'Link',
1930
+ } );
1922
1931
 
1923
1932
  // Simulate searching for a term.
1924
1933
  await user.type( searchInput, searchTerm );
@@ -2376,10 +2385,14 @@ describe( 'Controlling link title text', () => {
2376
2385
  } );
2377
2386
  } );
2378
2387
 
2379
- async function toggleSettingsDrawer( user ) {
2380
- const settingsToggle = screen.queryByRole( 'button', {
2381
- name: 'Link Settings',
2388
+ function getSettingsDrawerToggle() {
2389
+ return screen.queryByRole( 'button', {
2390
+ name: 'Advanced',
2382
2391
  } );
2392
+ }
2393
+
2394
+ async function toggleSettingsDrawer( user ) {
2395
+ const settingsToggle = getSettingsDrawerToggle();
2383
2396
 
2384
2397
  await user.click( settingsToggle );
2385
2398
  }
@@ -128,7 +128,7 @@ describe( 'General media replace flow', () => {
128
128
  );
129
129
 
130
130
  const mediaURLInput = screen.getByRole( 'combobox', {
131
- name: 'URL',
131
+ name: 'Link',
132
132
  expanded: false,
133
133
  } );
134
134
 
@@ -48,7 +48,7 @@ describe( 'useBlockSync hook', () => {
48
48
  jest.clearAllMocks();
49
49
  } );
50
50
 
51
- it( 'resets the block-editor blocks when the controll value changes', async () => {
51
+ it( 'resets the block-editor blocks when the controlled value changes', async () => {
52
52
  const fakeBlocks = [];
53
53
  const resetBlocks = jest.spyOn( blockEditorActions, 'resetBlocks' );
54
54
  const replaceInnerBlocks = jest.spyOn(
@@ -58,7 +58,7 @@ describe( 'useBlockSync hook', () => {
58
58
  const onChange = jest.fn();
59
59
  const onInput = jest.fn();
60
60
 
61
- const { rerender } = render(
61
+ const { rerender, unmount } = render(
62
62
  <TestWrapper
63
63
  value={ fakeBlocks }
64
64
  onChange={ onChange }
@@ -88,9 +88,16 @@ describe( 'useBlockSync hook', () => {
88
88
  expect( onInput ).not.toHaveBeenCalled();
89
89
  expect( replaceInnerBlocks ).not.toHaveBeenCalled();
90
90
  expect( resetBlocks ).toHaveBeenCalledWith( testBlocks );
91
+
92
+ unmount();
93
+
94
+ expect( onChange ).not.toHaveBeenCalled();
95
+ expect( onInput ).not.toHaveBeenCalled();
96
+ expect( replaceInnerBlocks ).not.toHaveBeenCalled();
97
+ expect( resetBlocks ).toHaveBeenCalledWith( [] );
91
98
  } );
92
99
 
93
- it( 'replaces the inner blocks of a block when the control value changes if a clientId is passed', async () => {
100
+ it( 'replaces the inner blocks of a block when the controlled value changes if a clientId is passed', async () => {
94
101
  const fakeBlocks = [];
95
102
  const replaceInnerBlocks = jest.spyOn(
96
103
  blockEditorActions,
@@ -100,7 +107,7 @@ describe( 'useBlockSync hook', () => {
100
107
  const onChange = jest.fn();
101
108
  const onInput = jest.fn();
102
109
 
103
- const { rerender } = render(
110
+ const { rerender, unmount } = render(
104
111
  <TestWrapper
105
112
  clientId="test"
106
113
  value={ fakeBlocks }
@@ -138,8 +145,16 @@ describe( 'useBlockSync hook', () => {
138
145
  expect( onChange ).not.toHaveBeenCalled();
139
146
  expect( onInput ).not.toHaveBeenCalled();
140
147
  expect( resetBlocks ).not.toHaveBeenCalled();
141
- // We can't check the args because the blocks are cloned.
142
- expect( replaceInnerBlocks ).toHaveBeenCalled();
148
+ expect( replaceInnerBlocks ).toHaveBeenCalledWith( 'test', [
149
+ expect.objectContaining( { name: 'test/test-block' } ),
150
+ ] );
151
+
152
+ unmount();
153
+
154
+ expect( onChange ).not.toHaveBeenCalled();
155
+ expect( onInput ).not.toHaveBeenCalled();
156
+ expect( resetBlocks ).not.toHaveBeenCalled();
157
+ expect( replaceInnerBlocks ).toHaveBeenCalledWith( 'test', [] );
143
158
  } );
144
159
 
145
160
  it( 'does not add the controlled blocks to the block-editor store if the store already contains them', async () => {
@@ -134,6 +134,19 @@ export default function useBlockSync( {
134
134
  }
135
135
  };
136
136
 
137
+ // Clean up the changes made by setControlledBlocks() when the component
138
+ // containing useBlockSync() unmounts.
139
+ const unsetControlledBlocks = () => {
140
+ __unstableMarkNextChangeAsNotPersistent();
141
+ if ( clientId ) {
142
+ setHasControlledInnerBlocks( clientId, false );
143
+ __unstableMarkNextChangeAsNotPersistent();
144
+ replaceInnerBlocks( clientId, [] );
145
+ } else {
146
+ resetBlocks( [] );
147
+ }
148
+ };
149
+
137
150
  // Add a subscription to the block-editor registry to detect when changes
138
151
  // have been made. This lets us inform the data source of changes. This
139
152
  // is an effect so that the subscriber can run synchronously without
@@ -287,4 +300,10 @@ export default function useBlockSync( {
287
300
  unsubscribe();
288
301
  };
289
302
  }, [ registry, clientId ] );
303
+
304
+ useEffect( () => {
305
+ return () => {
306
+ unsetControlledBlocks();
307
+ };
308
+ }, [] );
290
309
  }