@wordpress/block-library 9.40.2-next.v.202602271551.0 → 9.40.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 (250) hide show
  1. package/build/accordion/view.cjs +34 -0
  2. package/build/accordion/view.cjs.map +2 -2
  3. package/build/comment-reply-link/edit.cjs +2 -1
  4. package/build/comment-reply-link/edit.cjs.map +2 -2
  5. package/build/comments/edit/placeholder.cjs +2 -1
  6. package/build/comments/edit/placeholder.cjs.map +2 -2
  7. package/build/cover/edit/index.cjs +39 -26
  8. package/build/cover/edit/index.cjs.map +2 -2
  9. package/build/cover/embed-video-utils.cjs +8 -6
  10. package/build/cover/embed-video-utils.cjs.map +2 -2
  11. package/build/embed/embed-preview.cjs +2 -1
  12. package/build/embed/embed-preview.cjs.map +2 -2
  13. package/build/html/block.json +2 -1
  14. package/build/html/modal.cjs +147 -230
  15. package/build/html/modal.cjs.map +3 -3
  16. package/build/icon/block.json +3 -12
  17. package/build/image/image.cjs +1 -1
  18. package/build/image/image.cjs.map +2 -2
  19. package/build/latest-comments/deprecated.cjs +33 -0
  20. package/build/latest-comments/deprecated.cjs.map +2 -2
  21. package/build/navigation/edit/index.cjs +125 -123
  22. package/build/navigation/edit/index.cjs.map +3 -3
  23. package/build/navigation/edit/leaf-more-menu.cjs +6 -68
  24. package/build/navigation/edit/leaf-more-menu.cjs.map +3 -3
  25. package/build/navigation/edit/menu-inspector-controls.cjs +91 -20
  26. package/build/navigation/edit/menu-inspector-controls.cjs.map +3 -3
  27. package/build/navigation/edit/navigation-menu-selector.cjs +4 -5
  28. package/build/navigation/edit/navigation-menu-selector.cjs.map +3 -3
  29. package/build/navigation/edit/placeholder/index.cjs +2 -2
  30. package/build/navigation/edit/placeholder/index.cjs.map +3 -3
  31. package/build/navigation/use-navigation-entities.cjs +67 -0
  32. package/build/navigation/use-navigation-entities.cjs.map +7 -0
  33. package/build/navigation/view.cjs +9 -2
  34. package/build/navigation/view.cjs.map +2 -2
  35. package/build/navigation-link/edit.cjs +2 -1
  36. package/build/navigation-link/edit.cjs.map +2 -2
  37. package/build/navigation-link/shared/use-handle-link-change.cjs +19 -3
  38. package/build/navigation-link/shared/use-handle-link-change.cjs.map +3 -3
  39. package/build/navigation-link/shared/use-link-preview.cjs +2 -2
  40. package/build/navigation-link/shared/use-link-preview.cjs.map +2 -2
  41. package/build/navigation-submenu/edit.cjs +8 -22
  42. package/build/navigation-submenu/edit.cjs.map +2 -2
  43. package/build/nextpage/block.json +0 -1
  44. package/build/paragraph/edit.cjs +1 -1
  45. package/build/paragraph/edit.cjs.map +1 -1
  46. package/build/post-navigation-link/block.json +3 -1
  47. package/build/post-navigation-link/edit.cjs +36 -2
  48. package/build/post-navigation-link/edit.cjs.map +3 -3
  49. package/build/post-navigation-link/index.cjs +0 -2
  50. package/build/post-navigation-link/index.cjs.map +3 -3
  51. package/build/post-title/block.json +3 -1
  52. package/build/post-title/deprecated.cjs +1 -82
  53. package/build/post-title/deprecated.cjs.map +3 -3
  54. package/build/post-title/edit.cjs +36 -10
  55. package/build/post-title/edit.cjs.map +3 -3
  56. package/build/query-title/block.json +3 -1
  57. package/build/query-title/deprecated.cjs +1 -70
  58. package/build/query-title/deprecated.cjs.map +3 -3
  59. package/build/query-title/edit.cjs +35 -17
  60. package/build/query-title/edit.cjs.map +3 -3
  61. package/build/shortcode/block.json +2 -1
  62. package/build/site-tagline/block.json +4 -6
  63. package/build/site-tagline/deprecated.cjs +1 -66
  64. package/build/site-tagline/deprecated.cjs.map +3 -3
  65. package/build/site-tagline/edit.cjs +28 -14
  66. package/build/site-tagline/edit.cjs.map +3 -3
  67. package/build/site-title/block.json +3 -1
  68. package/build/site-title/deprecated.cjs +1 -79
  69. package/build/site-title/deprecated.cjs.map +3 -3
  70. package/build/site-title/edit.cjs +30 -14
  71. package/build/site-title/edit.cjs.map +3 -3
  72. package/build/tabs-menu-item/block.json +26 -1
  73. package/build/tabs-menu-item/controls.cjs +100 -2
  74. package/build/tabs-menu-item/controls.cjs.map +3 -3
  75. package/build/tabs-menu-item/edit.cjs +65 -6
  76. package/build/tabs-menu-item/edit.cjs.map +2 -2
  77. package/build/tabs-menu-item/save.cjs +15 -1
  78. package/build/tabs-menu-item/save.cjs.map +2 -2
  79. package/build-module/accordion/view.mjs +35 -1
  80. package/build-module/accordion/view.mjs.map +2 -2
  81. package/build-module/comment-reply-link/edit.mjs +3 -2
  82. package/build-module/comment-reply-link/edit.mjs.map +2 -2
  83. package/build-module/comments/edit/placeholder.mjs +3 -2
  84. package/build-module/comments/edit/placeholder.mjs.map +2 -2
  85. package/build-module/cover/edit/index.mjs +47 -29
  86. package/build-module/cover/edit/index.mjs.map +2 -2
  87. package/build-module/cover/embed-video-utils.mjs +7 -5
  88. package/build-module/cover/embed-video-utils.mjs.map +2 -2
  89. package/build-module/embed/embed-preview.mjs +2 -1
  90. package/build-module/embed/embed-preview.mjs.map +2 -2
  91. package/build-module/html/block.json +2 -1
  92. package/build-module/html/modal.mjs +149 -232
  93. package/build-module/html/modal.mjs.map +2 -2
  94. package/build-module/icon/block.json +3 -12
  95. package/build-module/image/image.mjs +1 -1
  96. package/build-module/image/image.mjs.map +2 -2
  97. package/build-module/latest-comments/deprecated.mjs +33 -0
  98. package/build-module/latest-comments/deprecated.mjs.map +2 -2
  99. package/build-module/navigation/edit/index.mjs +125 -123
  100. package/build-module/navigation/edit/index.mjs.map +2 -2
  101. package/build-module/navigation/edit/leaf-more-menu.mjs +7 -73
  102. package/build-module/navigation/edit/leaf-more-menu.mjs.map +2 -2
  103. package/build-module/navigation/edit/menu-inspector-controls.mjs +101 -21
  104. package/build-module/navigation/edit/menu-inspector-controls.mjs.map +2 -2
  105. package/build-module/navigation/edit/navigation-menu-selector.mjs +5 -6
  106. package/build-module/navigation/edit/navigation-menu-selector.mjs.map +2 -2
  107. package/build-module/navigation/edit/placeholder/index.mjs +2 -2
  108. package/build-module/navigation/edit/placeholder/index.mjs.map +2 -2
  109. package/build-module/navigation/use-navigation-entities.mjs +46 -0
  110. package/build-module/navigation/use-navigation-entities.mjs.map +7 -0
  111. package/build-module/navigation/view.mjs +9 -2
  112. package/build-module/navigation/view.mjs.map +2 -2
  113. package/build-module/navigation-link/edit.mjs +2 -1
  114. package/build-module/navigation-link/edit.mjs.map +2 -2
  115. package/build-module/navigation-link/shared/use-handle-link-change.mjs +19 -3
  116. package/build-module/navigation-link/shared/use-handle-link-change.mjs.map +2 -2
  117. package/build-module/navigation-link/shared/use-link-preview.mjs +2 -2
  118. package/build-module/navigation-link/shared/use-link-preview.mjs.map +2 -2
  119. package/build-module/navigation-submenu/edit.mjs +9 -23
  120. package/build-module/navigation-submenu/edit.mjs.map +2 -2
  121. package/build-module/nextpage/block.json +0 -1
  122. package/build-module/paragraph/edit.mjs +2 -2
  123. package/build-module/paragraph/edit.mjs.map +1 -1
  124. package/build-module/post-navigation-link/block.json +3 -1
  125. package/build-module/post-navigation-link/edit.mjs +30 -3
  126. package/build-module/post-navigation-link/edit.mjs.map +2 -2
  127. package/build-module/post-navigation-link/index.mjs +0 -2
  128. package/build-module/post-navigation-link/index.mjs.map +2 -2
  129. package/build-module/post-title/block.json +3 -1
  130. package/build-module/post-title/deprecated.mjs +1 -82
  131. package/build-module/post-title/deprecated.mjs.map +2 -2
  132. package/build-module/post-title/edit.mjs +27 -10
  133. package/build-module/post-title/edit.mjs.map +2 -2
  134. package/build-module/query-title/block.json +3 -1
  135. package/build-module/query-title/deprecated.mjs +1 -70
  136. package/build-module/query-title/deprecated.mjs.map +2 -2
  137. package/build-module/query-title/edit.mjs +36 -17
  138. package/build-module/query-title/edit.mjs.map +2 -2
  139. package/build-module/shortcode/block.json +2 -1
  140. package/build-module/site-tagline/block.json +4 -6
  141. package/build-module/site-tagline/deprecated.mjs +1 -66
  142. package/build-module/site-tagline/deprecated.mjs.map +2 -2
  143. package/build-module/site-tagline/edit.mjs +29 -14
  144. package/build-module/site-tagline/edit.mjs.map +2 -2
  145. package/build-module/site-title/block.json +3 -1
  146. package/build-module/site-title/deprecated.mjs +1 -79
  147. package/build-module/site-title/deprecated.mjs.map +2 -2
  148. package/build-module/site-title/edit.mjs +31 -14
  149. package/build-module/site-title/edit.mjs.map +2 -2
  150. package/build-module/tabs-menu-item/block.json +26 -1
  151. package/build-module/tabs-menu-item/controls.mjs +104 -3
  152. package/build-module/tabs-menu-item/controls.mjs.map +2 -2
  153. package/build-module/tabs-menu-item/edit.mjs +66 -6
  154. package/build-module/tabs-menu-item/edit.mjs.map +2 -2
  155. package/build-module/tabs-menu-item/save.mjs +15 -1
  156. package/build-module/tabs-menu-item/save.mjs.map +2 -2
  157. package/build-style/editor-rtl.css +20 -6
  158. package/build-style/editor.css +20 -6
  159. package/build-style/html/editor-rtl.css +10 -6
  160. package/build-style/html/editor.css +10 -6
  161. package/build-style/icon/editor-rtl.css +5 -0
  162. package/build-style/icon/editor.css +5 -0
  163. package/build-style/navigation/style-rtl.css +15 -1
  164. package/build-style/navigation/style.css +15 -1
  165. package/build-style/navigation-overlay-close/style-rtl.css +3 -3
  166. package/build-style/navigation-overlay-close/style.css +3 -3
  167. package/build-style/style-rtl.css +30 -7
  168. package/build-style/style.css +30 -7
  169. package/build-style/tabs-menu-item/editor-rtl.css +5 -0
  170. package/build-style/tabs-menu-item/editor.css +5 -0
  171. package/build-style/tabs-menu-item/style-rtl.css +12 -3
  172. package/build-style/tabs-menu-item/style.css +12 -3
  173. package/package.json +38 -38
  174. package/src/accordion/view.js +44 -1
  175. package/src/accordion-item/index.php +18 -5
  176. package/src/comment-reply-link/edit.js +5 -2
  177. package/src/comments/edit/placeholder.js +5 -2
  178. package/src/cover/edit/index.js +72 -35
  179. package/src/cover/embed-video-utils.js +9 -7
  180. package/src/cover/index.php +12 -4
  181. package/src/details/index.php +47 -0
  182. package/src/embed/embed-preview.js +6 -5
  183. package/src/html/block.json +2 -1
  184. package/src/html/editor.scss +15 -5
  185. package/src/html/modal.js +32 -99
  186. package/src/icon/block.json +3 -12
  187. package/src/icon/editor.scss +5 -0
  188. package/src/icon/index.php +3 -1
  189. package/src/image/image.js +14 -15
  190. package/src/image/index.php +7 -5
  191. package/src/latest-comments/deprecated.js +33 -0
  192. package/src/navigation/edit/index.js +136 -134
  193. package/src/navigation/edit/leaf-more-menu.js +11 -86
  194. package/src/navigation/edit/menu-inspector-controls.js +142 -23
  195. package/src/navigation/edit/navigation-menu-selector.js +5 -6
  196. package/src/navigation/edit/placeholder/index.js +2 -3
  197. package/src/navigation/edit/test/navigation-menu-selector.js +20 -23
  198. package/src/navigation/index.php +62 -9
  199. package/src/navigation/style.scss +17 -1
  200. package/src/navigation/use-navigation-entities.js +72 -0
  201. package/src/navigation/view.js +14 -2
  202. package/src/navigation-link/edit.js +1 -0
  203. package/src/navigation-link/shared/test/use-handle-link-change.test.js +212 -0
  204. package/src/navigation-link/shared/test/use-link-preview.test.js +9 -0
  205. package/src/navigation-link/shared/use-handle-link-change.js +36 -9
  206. package/src/navigation-link/shared/use-link-preview.js +6 -9
  207. package/src/navigation-overlay-close/style.scss +3 -3
  208. package/src/navigation-submenu/edit.js +11 -28
  209. package/src/nextpage/block.json +0 -1
  210. package/src/page-list/index.php +1 -1
  211. package/src/paragraph/edit.js +2 -2
  212. package/src/post-featured-image/index.php +4 -2
  213. package/src/post-navigation-link/block.json +3 -1
  214. package/src/post-navigation-link/edit.js +35 -2
  215. package/src/post-navigation-link/index.js +0 -2
  216. package/src/post-title/block.json +3 -1
  217. package/src/post-title/deprecated.js +1 -86
  218. package/src/post-title/edit.js +18 -2
  219. package/src/query-title/block.json +3 -1
  220. package/src/query-title/deprecated.js +1 -74
  221. package/src/query-title/edit.js +27 -11
  222. package/src/query-title/index.php +1 -1
  223. package/src/shortcode/block.json +2 -1
  224. package/src/site-tagline/block.json +4 -6
  225. package/src/site-tagline/deprecated.js +1 -70
  226. package/src/site-tagline/edit.js +22 -9
  227. package/src/site-title/block.json +3 -1
  228. package/src/site-title/deprecated.js +1 -83
  229. package/src/site-title/edit.js +22 -9
  230. package/src/tabs-menu-item/block.json +26 -1
  231. package/src/tabs-menu-item/controls.js +108 -0
  232. package/src/tabs-menu-item/edit.js +79 -6
  233. package/src/tabs-menu-item/editor.scss +6 -0
  234. package/src/tabs-menu-item/save.js +26 -1
  235. package/src/tabs-menu-item/style.scss +14 -3
  236. package/build/navigation/edit/navigation-link-ui.cjs +0 -97
  237. package/build/navigation/edit/navigation-link-ui.cjs.map +0 -7
  238. package/build/navigation/edit/navigation-list-view-header.cjs +0 -86
  239. package/build/navigation/edit/navigation-list-view-header.cjs.map +0 -7
  240. package/build/post-navigation-link/deprecated.cjs +0 -100
  241. package/build/post-navigation-link/deprecated.cjs.map +0 -7
  242. package/build-module/navigation/edit/navigation-link-ui.mjs +0 -76
  243. package/build-module/navigation/edit/navigation-link-ui.mjs.map +0 -7
  244. package/build-module/navigation/edit/navigation-list-view-header.mjs +0 -58
  245. package/build-module/navigation/edit/navigation-list-view-header.mjs.map +0 -7
  246. package/build-module/post-navigation-link/deprecated.mjs +0 -69
  247. package/build-module/post-navigation-link/deprecated.mjs.map +0 -7
  248. package/src/navigation/edit/navigation-link-ui.js +0 -115
  249. package/src/navigation/edit/navigation-list-view-header.js +0 -62
  250. package/src/post-navigation-link/deprecated.js +0 -72
@@ -423,6 +423,51 @@ describe( 'useHandleLinkChange', () => {
423
423
  } )
424
424
  );
425
425
  } );
426
+
427
+ it( 'should update text when editing text and changing a bound entity link to a custom URL in the link editing UI', () => {
428
+ useEntityBinding.mockReturnValue( {
429
+ hasUrlBinding: true,
430
+ createBinding: mockCreateBinding,
431
+ clearBinding: mockClearBinding,
432
+ } );
433
+
434
+ const attributes = {
435
+ id: 456,
436
+ url: 'https://example.com/my-page',
437
+ label: 'My Page',
438
+ kind: 'post-type',
439
+ type: 'page',
440
+ };
441
+
442
+ const { result } = renderHook( () =>
443
+ useHandleLinkChange( {
444
+ clientId,
445
+ attributes,
446
+ setAttributes: mockSetAttributes,
447
+ allowTextUpdate: true,
448
+ } )
449
+ );
450
+
451
+ const updatedLink = {
452
+ url: 'https://external-site.com',
453
+ title: 'Updated Navigation Text',
454
+ };
455
+
456
+ result.current( updatedLink );
457
+
458
+ expect( mockClearBinding ).toHaveBeenCalled();
459
+ expect( mockUpdateBlockAttributes ).toHaveBeenCalledWith(
460
+ clientId,
461
+ expect.objectContaining( {
462
+ url: 'https://external-site.com',
463
+ kind: 'custom',
464
+ type: 'custom',
465
+ id: undefined,
466
+ label: 'Updated Navigation Text',
467
+ } )
468
+ );
469
+ expect( updateAttributes ).not.toHaveBeenCalled();
470
+ } );
426
471
  } );
427
472
 
428
473
  describe( 'updating existing links', () => {
@@ -503,6 +548,87 @@ describe( 'useHandleLinkChange', () => {
503
548
  );
504
549
  } );
505
550
 
551
+ it( 'should preserve label when changing the link without editing text in the link editing UI', () => {
552
+ const attributes = {
553
+ id: 123,
554
+ url: 'https://example.com/page',
555
+ label: 'Custom Label',
556
+ kind: 'post-type',
557
+ type: 'page',
558
+ };
559
+
560
+ const { result } = renderHook( () =>
561
+ useHandleLinkChange( {
562
+ clientId,
563
+ attributes,
564
+ setAttributes: mockSetAttributes,
565
+ allowTextUpdate: true,
566
+ } )
567
+ );
568
+
569
+ const updatedLink = {
570
+ id: 456,
571
+ url: 'https://example.com/new-page',
572
+ title: 'Custom Label',
573
+ kind: 'post-type',
574
+ type: 'page',
575
+ };
576
+
577
+ result.current( updatedLink );
578
+
579
+ expect( updateAttributes ).toHaveBeenCalledWith(
580
+ expect.not.objectContaining( {
581
+ title: 'Custom Label',
582
+ } ),
583
+ mockSetAttributes,
584
+ attributes
585
+ );
586
+ expect( mockUpdateBlockAttributes ).not.toHaveBeenCalled();
587
+ } );
588
+
589
+ it( 'should include title when editing text and changing the entity link in the link editing UI', () => {
590
+ const attributes = {
591
+ id: 123,
592
+ url: 'https://example.com/page',
593
+ label: 'Sample Page',
594
+ kind: 'post-type',
595
+ type: 'page',
596
+ };
597
+
598
+ const { result } = renderHook( () =>
599
+ useHandleLinkChange( {
600
+ clientId,
601
+ attributes,
602
+ setAttributes: mockSetAttributes,
603
+ allowTextUpdate: true,
604
+ } )
605
+ );
606
+
607
+ const updatedLink = {
608
+ id: 456,
609
+ url: 'https://example.com/new-page',
610
+ title: 'Updated Navigation Text',
611
+ kind: 'post-type',
612
+ type: 'page',
613
+ };
614
+
615
+ result.current( updatedLink );
616
+
617
+ expect( updateAttributes ).toHaveBeenCalledWith(
618
+ expect.objectContaining( {
619
+ title: 'Updated Navigation Text',
620
+ } ),
621
+ mockSetAttributes,
622
+ attributes
623
+ );
624
+ expect( mockUpdateBlockAttributes ).toHaveBeenCalledWith(
625
+ clientId,
626
+ {
627
+ label: 'Updated Navigation Text',
628
+ }
629
+ );
630
+ } );
631
+
506
632
  it( 'should include title when creating link without existing label', () => {
507
633
  const attributes = {};
508
634
 
@@ -606,6 +732,92 @@ describe( 'useHandleLinkChange', () => {
606
732
  );
607
733
  } );
608
734
 
735
+ it( 'should include title when editing text for the same existing entity link', () => {
736
+ const attributes = {
737
+ id: 123,
738
+ url: 'https://example.com/page',
739
+ label: 'Sample Page',
740
+ kind: 'post-type',
741
+ type: 'page',
742
+ };
743
+
744
+ const { result } = renderHook( () =>
745
+ useHandleLinkChange( {
746
+ clientId,
747
+ attributes,
748
+ setAttributes: mockSetAttributes,
749
+ allowTextUpdate: true,
750
+ } )
751
+ );
752
+
753
+ const updatedLink = {
754
+ id: 123,
755
+ url: 'https://example.com/page',
756
+ title: 'Updated Sample Page',
757
+ kind: 'post-type',
758
+ type: 'page',
759
+ };
760
+
761
+ result.current( updatedLink );
762
+
763
+ expect( updateAttributes ).toHaveBeenCalledWith(
764
+ expect.objectContaining( {
765
+ title: 'Updated Sample Page',
766
+ } ),
767
+ mockSetAttributes,
768
+ attributes
769
+ );
770
+ expect( mockUpdateBlockAttributes ).toHaveBeenCalledWith(
771
+ clientId,
772
+ {
773
+ label: 'Updated Sample Page',
774
+ }
775
+ );
776
+ } );
777
+
778
+ it( 'should clear text when the inline link editing UI title is emptied', () => {
779
+ const attributes = {
780
+ id: 123,
781
+ url: 'https://example.com/page',
782
+ label: 'Sample Page',
783
+ kind: 'post-type',
784
+ type: 'page',
785
+ };
786
+
787
+ const { result } = renderHook( () =>
788
+ useHandleLinkChange( {
789
+ clientId,
790
+ attributes,
791
+ setAttributes: mockSetAttributes,
792
+ allowTextUpdate: true,
793
+ } )
794
+ );
795
+
796
+ const updatedLink = {
797
+ id: 123,
798
+ url: 'https://example.com/page',
799
+ title: '',
800
+ kind: 'post-type',
801
+ type: 'page',
802
+ };
803
+
804
+ result.current( updatedLink );
805
+
806
+ expect( updateAttributes ).toHaveBeenCalledWith(
807
+ expect.objectContaining( {
808
+ title: '',
809
+ } ),
810
+ mockSetAttributes,
811
+ attributes
812
+ );
813
+ expect( mockUpdateBlockAttributes ).toHaveBeenCalledWith(
814
+ clientId,
815
+ {
816
+ label: '',
817
+ }
818
+ );
819
+ } );
820
+
609
821
  it( 'should update custom link to another custom link', () => {
610
822
  updateAttributes.mockImplementation( ( attrs ) => ( {
611
823
  isEntityLink: false,
@@ -105,6 +105,15 @@ describe( 'computeDisplayUrl', () => {
105
105
  expect( result.isExternal ).toBe( false );
106
106
  expect( result.displayUrl ).toBe( '/my-page' );
107
107
  } );
108
+
109
+ it( 'should treat http and https to same host as internal (compare by host, not origin)', () => {
110
+ const result = computeDisplayUrl( {
111
+ linkUrl: 'http://example.com/my-page',
112
+ homeUrl: 'https://example.com',
113
+ } );
114
+ expect( result.isExternal ).toBe( false );
115
+ expect( result.displayUrl ).toBe( '/my-page' );
116
+ } );
108
117
  } );
109
118
 
110
119
  describe( 'special protocols and edge cases', () => {
@@ -4,6 +4,8 @@
4
4
  import { useCallback } from '@wordpress/element';
5
5
  import { useDispatch } from '@wordpress/data';
6
6
  import { store as blockEditorStore } from '@wordpress/block-editor';
7
+ import { __unstableStripHTML as stripHTML } from '@wordpress/dom';
8
+ import { escapeHTML } from '@wordpress/escape-html';
7
9
 
8
10
  /**
9
11
  * Internal dependencies
@@ -16,13 +18,19 @@ import { useEntityBinding } from './use-entity-binding';
16
18
  * Manages the transition between entity links and custom links,
17
19
  * including proper binding creation and cleanup.
18
20
  *
19
- * @param {Object} options - Configuration options
20
- * @param {string} options.clientId - Block client ID
21
- * @param {Object} options.attributes - Current block attributes
22
- * @param {Function} options.setAttributes - Standard setAttribute function
21
+ * @param {Object} options - Configuration options
22
+ * @param {string} options.clientId - Block client ID
23
+ * @param {Object} options.attributes - Current block attributes
24
+ * @param {Function} options.setAttributes - Standard setAttribute function
25
+ * @param {boolean} options.allowTextUpdate - Whether this control can update the link text
23
26
  * @return {Function} Callback function to handle link changes
24
27
  */
25
- export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
28
+ export function useHandleLinkChange( {
29
+ clientId,
30
+ attributes,
31
+ setAttributes,
32
+ allowTextUpdate = false,
33
+ } ) {
26
34
  const { updateBlockAttributes } = useDispatch( blockEditorStore );
27
35
  const { hasUrlBinding, createBinding, clearBinding } = useEntityBinding( {
28
36
  clientId,
@@ -42,12 +50,25 @@ export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
42
50
  id: updatedLink.id,
43
51
  };
44
52
 
45
- // Only include title when there's no existing label
46
- // This preserves user-customized labels when updating links
47
- if ( ! attributes.label || attributes.label === '' ) {
53
+ const currentText = attributes.label
54
+ ? stripHTML( attributes.label )
55
+ : '';
56
+ const updatedText = updatedLink.title ?? '';
57
+ const hasTextUpdate =
58
+ allowTextUpdate &&
59
+ updatedLink.title !== undefined &&
60
+ updatedText !== currentText;
61
+ const textUpdateAttributes = hasTextUpdate
62
+ ? { label: escapeHTML( updatedText ) }
63
+ : {};
64
+
65
+ if (
66
+ ! attributes.label ||
67
+ attributes.label === '' ||
68
+ hasTextUpdate
69
+ ) {
48
70
  attrs.title = updatedLink.title;
49
71
  }
50
-
51
72
  // Check if transitioning from entity to custom link
52
73
  const willBeCustomLink = ! updatedLink.id && hasUrlBinding;
53
74
 
@@ -62,6 +83,7 @@ export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
62
83
  kind: 'custom',
63
84
  type: 'custom',
64
85
  id: undefined,
86
+ ...textUpdateAttributes,
65
87
  } );
66
88
  } else {
67
89
  // Normal flow for entity links or unbound custom links
@@ -76,10 +98,15 @@ export function useHandleLinkChange( { clientId, attributes, setAttributes } ) {
76
98
  } else {
77
99
  clearBinding();
78
100
  }
101
+
102
+ if ( Object.keys( textUpdateAttributes ).length ) {
103
+ updateBlockAttributes( clientId, textUpdateAttributes );
104
+ }
79
105
  }
80
106
  },
81
107
  [
82
108
  attributes,
109
+ allowTextUpdate,
83
110
  clientId,
84
111
  hasUrlBinding,
85
112
  createBinding,
@@ -31,7 +31,7 @@ function capitalize( str ) {
31
31
  *
32
32
  * @param {Object} options - Parameters object
33
33
  * @param {string} options.linkUrl - The URL to process
34
- * @param {string} options.homeUrl - The WordPress site URL (falls back to window.location.origin)
34
+ * @param {string} options.homeUrl - The WordPress site URL (required for internal/external detection)
35
35
  * @return {Object} Object with displayUrl and isExternal flag
36
36
  */
37
37
  export function computeDisplayUrl( { linkUrl, homeUrl } = {} ) {
@@ -51,12 +51,10 @@ export function computeDisplayUrl( { linkUrl, homeUrl } = {} ) {
51
51
  // This must happen before trusting the type attribute
52
52
  try {
53
53
  const parsedUrl = new URL( linkUrl );
54
- // Use provided homeUrl or fall back to window.location.origin
55
- const siteDomain = homeUrl
56
- ? new URL( homeUrl ).origin
57
- : window.location.origin;
54
+ // Compare by host (not origin) so http/https to same site both count as internal
55
+ const siteHost = new URL( homeUrl ).host;
58
56
 
59
- if ( parsedUrl.origin === siteDomain ) {
57
+ if ( parsedUrl.host === siteHost ) {
60
58
  // Show only the pathname (and search/hash if present)
61
59
  let path = parsedUrl.pathname + parsedUrl.search + parsedUrl.hash;
62
60
  // Remove trailing slash
@@ -65,12 +63,11 @@ export function computeDisplayUrl( { linkUrl, homeUrl } = {} ) {
65
63
  }
66
64
  displayUrl = path;
67
65
  } else {
68
- // Different origin - this is an external link
66
+ // Different host - this is an external link
69
67
  isExternal = true;
70
68
  }
71
69
  } catch ( e ) {
72
- // URL parsing failed - this means it's likely a URL without a protocol (e.g., "www.example.com")
73
- // Since we already checked for relative paths and hash links above, treat as external
70
+ // URL parsing failed - treat as external (e.g. no homeUrl, or URL without protocol)
74
71
  isExternal = true;
75
72
  }
76
73
 
@@ -3,7 +3,7 @@
3
3
  align-items: center;
4
4
  justify-content: center;
5
5
  gap: 0.5em;
6
- padding: 0.5em;
6
+ padding: 0;
7
7
  border: none;
8
8
  background: transparent;
9
9
  cursor: pointer;
@@ -14,8 +14,8 @@
14
14
  }
15
15
 
16
16
  svg {
17
- width: 1.5em;
18
- height: 1.5em;
17
+ width: 24px;
18
+ height: 24px;
19
19
  fill: currentColor;
20
20
  display: block;
21
21
  flex-shrink: 0;
@@ -35,8 +35,8 @@ import { ItemSubmenuIcon } from './icons';
35
35
  import {
36
36
  Controls,
37
37
  LinkUI,
38
- updateAttributes,
39
38
  useEntityBinding,
39
+ useHandleLinkChange,
40
40
  useIsInvalidLink,
41
41
  InvalidDraftDisplay,
42
42
  useEnableLinkStatusValidation,
@@ -92,15 +92,17 @@ export default function NavigationSubmenuEdit( {
92
92
  blockEditingMode !== 'default' ? true : submenuVisibility === 'click';
93
93
 
94
94
  // URL binding logic
95
- const {
96
- clearBinding,
97
- createBinding,
98
- hasUrlBinding,
99
- isBoundEntityAvailable,
100
- entityRecord,
101
- } = useEntityBinding( {
95
+ const { hasUrlBinding, isBoundEntityAvailable, entityRecord } =
96
+ useEntityBinding( {
97
+ clientId,
98
+ attributes,
99
+ } );
100
+
101
+ const handleLinkChange = useHandleLinkChange( {
102
102
  clientId,
103
103
  attributes,
104
+ setAttributes,
105
+ allowTextUpdate: true,
104
106
  } );
105
107
 
106
108
  const { __unstableMarkNextChangeAsNotPersistent, replaceBlock } =
@@ -398,26 +400,7 @@ export default function NavigationSubmenuEdit( {
398
400
  setAttributes( { url: '' } );
399
401
  speak( __( 'Link removed.' ), 'assertive' );
400
402
  } }
401
- onChange={ ( updatedValue ) => {
402
- // updateAttributes determines the final state and returns metadata
403
- const {
404
- isEntityLink,
405
- attributes: updatedAttributes,
406
- } = updateAttributes(
407
- updatedValue,
408
- setAttributes,
409
- attributes
410
- );
411
-
412
- // Handle URL binding based on the final computed state
413
- // Only create bindings for entity links (posts, pages, taxonomies)
414
- // Never create bindings for custom links (manual URLs)
415
- if ( isEntityLink ) {
416
- createBinding( updatedAttributes );
417
- } else {
418
- clearBinding();
419
- }
420
- } }
403
+ onChange={ handleLinkChange }
421
404
  />
422
405
  ) }
423
406
  </ParentElement>
@@ -9,7 +9,6 @@
9
9
  "parent": [ "core/post-content" ],
10
10
  "textdomain": "default",
11
11
  "supports": {
12
- "anchor": true,
13
12
  "customClassName": false,
14
13
  "className": false,
15
14
  "html": false,
@@ -166,7 +166,7 @@ function block_core_page_list_build_css_font_sizes( $context ) {
166
166
  *
167
167
  * @since 5.8.0
168
168
  *
169
- * @param string $submenu_visibility The submenu visibility mode: 'hover', 'click', or 'always'.
169
+ * @param boolean $open_submenus_on_click Whether to open submenus on click instead of hover.
170
170
  * @param boolean $show_submenu_icons Whether to show submenu indicator icons.
171
171
  * @param boolean $is_navigation_child If block is a child of Navigation block.
172
172
  * @param array $nested_pages The array of nested pages.
@@ -21,7 +21,7 @@ import {
21
21
  useBlockEditingMode,
22
22
  } from '@wordpress/block-editor';
23
23
  import { getBlockSupport } from '@wordpress/blocks';
24
- import { formatLtr } from '@wordpress/icons';
24
+ import { formatLTR } from '@wordpress/icons';
25
25
  /**
26
26
  * Internal dependencies
27
27
  */
@@ -32,7 +32,7 @@ function ParagraphRTLControl( { direction, setDirection } ) {
32
32
  return (
33
33
  isRTL() && (
34
34
  <ToolbarButton
35
- icon={ formatLtr }
35
+ icon={ formatLTR }
36
36
  title={ _x( 'Left to right', 'editor button' ) }
37
37
  isActive={ direction === 'ltr' }
38
38
  onClick={ () => {
@@ -166,8 +166,10 @@ function get_block_core_post_featured_image_overlay_element_markup( $attributes
166
166
  }
167
167
 
168
168
  // Apply overlay and gradient classes.
169
- $class_names[] = 'has-background-dim';
170
- $class_names[] = "has-background-dim-{$attributes['dimRatio']}";
169
+ if ( $has_dim_background ) {
170
+ $class_names[] = 'has-background-dim';
171
+ $class_names[] = "has-background-dim-{$attributes['dimRatio']}";
172
+ }
171
173
 
172
174
  if ( $has_solid_overlay ) {
173
175
  $class_names[] = "has-{$attributes['overlayColor']}-background-color";
@@ -7,6 +7,9 @@
7
7
  "description": "Displays the next or previous post link that is adjacent to the current post.",
8
8
  "textdomain": "default",
9
9
  "attributes": {
10
+ "textAlign": {
11
+ "type": "string"
12
+ },
10
13
  "type": {
11
14
  "type": "string",
12
15
  "default": "next"
@@ -43,7 +46,6 @@
43
46
  "typography": {
44
47
  "fontSize": true,
45
48
  "lineHeight": true,
46
- "textAlign": true,
47
49
  "__experimentalFontFamily": true,
48
50
  "__experimentalFontWeight": true,
49
51
  "__experimentalFontStyle": true,
@@ -1,3 +1,8 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import clsx from 'clsx';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
@@ -12,7 +17,10 @@ import {
12
17
  import {
13
18
  InspectorControls,
14
19
  RichText,
20
+ BlockControls,
21
+ AlignmentToolbar,
15
22
  useBlockProps,
23
+ useBlockEditingMode,
16
24
  } from '@wordpress/block-editor';
17
25
  import { __, _x } from '@wordpress/i18n';
18
26
  import { useSelect } from '@wordpress/data';
@@ -25,9 +33,19 @@ import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
25
33
 
26
34
  export default function PostNavigationLinkEdit( {
27
35
  context: { postType },
28
- attributes: { type, label, showTitle, linkLabel, arrow, taxonomy },
36
+ attributes: {
37
+ type,
38
+ label,
39
+ showTitle,
40
+ textAlign,
41
+ linkLabel,
42
+ arrow,
43
+ taxonomy,
44
+ },
29
45
  setAttributes,
30
46
  } ) {
47
+ const blockEditingMode = useBlockEditingMode();
48
+ const showControls = blockEditingMode === 'default';
31
49
  const isNext = type === 'next';
32
50
  let placeholder = isNext ? __( 'Next' ) : __( 'Previous' );
33
51
 
@@ -48,7 +66,12 @@ export default function PostNavigationLinkEdit( {
48
66
  }
49
67
 
50
68
  const ariaLabel = isNext ? __( 'Next post' ) : __( 'Previous post' );
51
- const blockProps = useBlockProps();
69
+ const blockProps = useBlockProps( {
70
+ className: clsx( {
71
+ [ `has-text-align-${ textAlign }` ]: textAlign,
72
+ } ),
73
+ } );
74
+
52
75
  const taxonomies = useSelect(
53
76
  ( select ) => {
54
77
  const { getTaxonomies } = select( coreStore );
@@ -197,6 +220,16 @@ export default function PostNavigationLinkEdit( {
197
220
  ) }
198
221
  />
199
222
  </InspectorControls>
223
+ { showControls && (
224
+ <BlockControls>
225
+ <AlignmentToolbar
226
+ value={ textAlign }
227
+ onChange={ ( nextAlign ) => {
228
+ setAttributes( { textAlign: nextAlign } );
229
+ } }
230
+ />
231
+ </BlockControls>
232
+ ) }
200
233
  <div { ...blockProps }>
201
234
  { ! isNext && displayArrow && (
202
235
  <span
@@ -10,7 +10,6 @@ import initBlock from '../utils/init-block';
10
10
  import metadata from './block.json';
11
11
  import edit from './edit';
12
12
  import variations from './variations';
13
- import deprecated from './deprecated';
14
13
 
15
14
  const { name } = metadata;
16
15
  export { metadata, name };
@@ -18,7 +17,6 @@ export { metadata, name };
18
17
  export const settings = {
19
18
  edit,
20
19
  variations,
21
- deprecated,
22
20
  example: {
23
21
  attributes: {
24
22
  label: __( 'Next post' ),
@@ -8,6 +8,9 @@
8
8
  "textdomain": "default",
9
9
  "usesContext": [ "postId", "postType", "queryId" ],
10
10
  "attributes": {
11
+ "textAlign": {
12
+ "type": "string"
13
+ },
11
14
  "level": {
12
15
  "type": "number",
13
16
  "default": 2
@@ -55,7 +58,6 @@
55
58
  "typography": {
56
59
  "fontSize": true,
57
60
  "lineHeight": true,
58
- "textAlign": true,
59
61
  "__experimentalFontFamily": true,
60
62
  "__experimentalFontWeight": true,
61
63
  "__experimentalFontStyle": true,