@wordpress/block-library 9.36.1-next.738bb1424.0 → 9.36.2-next.8fd3f8831.0

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 (168) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/build/accordion-heading/deprecated.cjs +120 -1
  3. package/build/accordion-heading/deprecated.cjs.map +2 -2
  4. package/build/accordion-heading/edit.cjs +9 -1
  5. package/build/accordion-heading/edit.cjs.map +3 -3
  6. package/build/accordion-heading/save.cjs +1 -0
  7. package/build/accordion-heading/save.cjs.map +2 -2
  8. package/build/accordion-item/block.json +3 -0
  9. package/build/accordion-item/edit.cjs +3 -37
  10. package/build/accordion-item/edit.cjs.map +2 -2
  11. package/build/accordion-panel/block.json +1 -4
  12. package/build/accordion-panel/edit.cjs +3 -2
  13. package/build/accordion-panel/edit.cjs.map +2 -2
  14. package/build/breadcrumbs/block.json +1 -2
  15. package/build/breadcrumbs/edit.cjs +2 -1
  16. package/build/breadcrumbs/edit.cjs.map +2 -2
  17. package/build/button/index.cjs +9 -1
  18. package/build/button/index.cjs.map +2 -2
  19. package/build/buttons/block.json +1 -0
  20. package/build/comment-author-name/block.json +1 -3
  21. package/build/comment-author-name/deprecated.cjs +57 -1
  22. package/build/comment-author-name/deprecated.cjs.map +3 -3
  23. package/build/comment-author-name/edit.cjs +9 -19
  24. package/build/comment-author-name/edit.cjs.map +3 -3
  25. package/build/freeform/edit.cjs +48 -174
  26. package/build/freeform/edit.cjs.map +2 -2
  27. package/build/freeform/modal.cjs +51 -67
  28. package/build/freeform/modal.cjs.map +2 -2
  29. package/build/index.cjs +2 -2
  30. package/build/index.cjs.map +2 -2
  31. package/build/list/block.json +2 -1
  32. package/build/query/edit/query-content.cjs +4 -3
  33. package/build/query/edit/query-content.cjs.map +2 -2
  34. package/build/query/edit/query-placeholder.cjs +4 -3
  35. package/build/query/edit/query-placeholder.cjs.map +2 -2
  36. package/build/query/edit/query-toolbar.cjs +19 -7
  37. package/build/query/edit/query-toolbar.cjs.map +3 -3
  38. package/build/social-links/block.json +2 -1
  39. package/build-module/accordion-heading/deprecated.js +122 -2
  40. package/build-module/accordion-heading/deprecated.js.map +2 -2
  41. package/build-module/accordion-heading/edit.js +11 -2
  42. package/build-module/accordion-heading/edit.js.map +2 -2
  43. package/build-module/accordion-heading/save.js +1 -0
  44. package/build-module/accordion-heading/save.js.map +2 -2
  45. package/build-module/accordion-item/block.json +3 -0
  46. package/build-module/accordion-item/edit.js +3 -37
  47. package/build-module/accordion-item/edit.js.map +2 -2
  48. package/build-module/accordion-panel/block.json +1 -4
  49. package/build-module/accordion-panel/edit.js +3 -2
  50. package/build-module/accordion-panel/edit.js.map +2 -2
  51. package/build-module/breadcrumbs/block.json +1 -2
  52. package/build-module/breadcrumbs/edit.js +2 -1
  53. package/build-module/breadcrumbs/edit.js.map +2 -2
  54. package/build-module/button/index.js +9 -1
  55. package/build-module/button/index.js.map +2 -2
  56. package/build-module/buttons/block.json +1 -0
  57. package/build-module/comment-author-name/block.json +1 -3
  58. package/build-module/comment-author-name/deprecated.js +57 -1
  59. package/build-module/comment-author-name/deprecated.js.map +2 -2
  60. package/build-module/comment-author-name/edit.js +10 -25
  61. package/build-module/comment-author-name/edit.js.map +2 -2
  62. package/build-module/freeform/edit.js +56 -176
  63. package/build-module/freeform/edit.js.map +2 -2
  64. package/build-module/freeform/modal.js +55 -78
  65. package/build-module/freeform/modal.js.map +2 -2
  66. package/build-module/index.js +2 -2
  67. package/build-module/index.js.map +2 -2
  68. package/build-module/list/block.json +2 -1
  69. package/build-module/query/edit/query-content.js +5 -5
  70. package/build-module/query/edit/query-content.js.map +2 -2
  71. package/build-module/query/edit/query-placeholder.js +4 -4
  72. package/build-module/query/edit/query-placeholder.js.map +2 -2
  73. package/build-module/query/edit/query-toolbar.js +22 -7
  74. package/build-module/query/edit/query-toolbar.js.map +2 -2
  75. package/build-module/social-links/block.json +2 -1
  76. package/build-style/audio/style-rtl.css +4 -0
  77. package/build-style/audio/style.css +4 -0
  78. package/build-style/audio/theme-rtl.css +4 -0
  79. package/build-style/audio/theme.css +4 -0
  80. package/build-style/columns/style-rtl.css +4 -0
  81. package/build-style/columns/style.css +4 -0
  82. package/build-style/common-rtl.css +4 -0
  83. package/build-style/common.css +4 -0
  84. package/build-style/editor-rtl.css +9 -324
  85. package/build-style/editor.css +9 -328
  86. package/build-style/embed/style-rtl.css +4 -0
  87. package/build-style/embed/style.css +4 -0
  88. package/build-style/embed/theme-rtl.css +4 -0
  89. package/build-style/embed/theme.css +4 -0
  90. package/build-style/freeform/editor-rtl.css +10 -330
  91. package/build-style/freeform/editor.css +10 -334
  92. package/build-style/gallery/editor-rtl.css +4 -0
  93. package/build-style/gallery/editor.css +4 -0
  94. package/build-style/gallery/style-rtl.css +4 -0
  95. package/build-style/gallery/style.css +4 -0
  96. package/build-style/gallery/theme-rtl.css +4 -0
  97. package/build-style/gallery/theme.css +4 -0
  98. package/build-style/html/editor-rtl.css +4 -0
  99. package/build-style/html/editor.css +4 -0
  100. package/build-style/image/editor-rtl.css +4 -0
  101. package/build-style/image/editor.css +4 -0
  102. package/build-style/image/style-rtl.css +4 -0
  103. package/build-style/image/style.css +4 -0
  104. package/build-style/image/theme-rtl.css +4 -0
  105. package/build-style/image/theme.css +4 -0
  106. package/build-style/latest-posts/style-rtl.css +4 -0
  107. package/build-style/latest-posts/style.css +4 -0
  108. package/build-style/navigation/editor-rtl.css +4 -0
  109. package/build-style/navigation/editor.css +4 -0
  110. package/build-style/navigation/style-rtl.css +4 -0
  111. package/build-style/navigation/style.css +4 -0
  112. package/build-style/navigation-submenu/editor-rtl.css +4 -0
  113. package/build-style/navigation-submenu/editor.css +4 -0
  114. package/build-style/page-list/editor-rtl.css +4 -0
  115. package/build-style/page-list/editor.css +4 -0
  116. package/build-style/paragraph/editor-rtl.css +5 -0
  117. package/build-style/paragraph/editor.css +5 -0
  118. package/build-style/post-template/style-rtl.css +4 -0
  119. package/build-style/post-template/style.css +4 -0
  120. package/build-style/query/editor-rtl.css +4 -0
  121. package/build-style/query/editor.css +4 -0
  122. package/build-style/rss/style-rtl.css +4 -0
  123. package/build-style/rss/style.css +4 -0
  124. package/build-style/shortcode/editor-rtl.css +4 -0
  125. package/build-style/shortcode/editor.css +4 -0
  126. package/build-style/style-rtl.css +4 -0
  127. package/build-style/style.css +4 -0
  128. package/build-style/table/editor-rtl.css +4 -0
  129. package/build-style/table/editor.css +4 -0
  130. package/build-style/table/theme-rtl.css +4 -0
  131. package/build-style/table/theme.css +4 -0
  132. package/build-style/template-part/editor-rtl.css +4 -0
  133. package/build-style/template-part/editor.css +4 -0
  134. package/build-style/theme-rtl.css +4 -0
  135. package/build-style/theme.css +4 -0
  136. package/build-style/video/style-rtl.css +4 -0
  137. package/build-style/video/style.css +4 -0
  138. package/build-style/video/theme-rtl.css +4 -0
  139. package/build-style/video/theme.css +4 -0
  140. package/package.json +37 -37
  141. package/src/accordion-heading/deprecated.js +122 -1
  142. package/src/accordion-heading/edit.js +11 -1
  143. package/src/accordion-heading/save.js +1 -0
  144. package/src/accordion-item/block.json +3 -0
  145. package/src/accordion-item/edit.js +4 -38
  146. package/src/accordion-panel/block.json +1 -4
  147. package/src/accordion-panel/edit.js +3 -4
  148. package/src/breadcrumbs/block.json +1 -2
  149. package/src/breadcrumbs/edit.js +2 -1
  150. package/src/breadcrumbs/index.php +23 -1
  151. package/src/button/index.js +12 -0
  152. package/src/button/test/get-experimental-label.js +50 -0
  153. package/src/buttons/block.json +1 -0
  154. package/src/comment-author-name/block.json +1 -3
  155. package/src/comment-author-name/deprecated.js +61 -1
  156. package/src/comment-author-name/edit.js +10 -34
  157. package/src/freeform/edit.js +60 -245
  158. package/src/freeform/editor.scss +1 -382
  159. package/src/freeform/modal.js +47 -80
  160. package/src/index.js +1 -1
  161. package/src/list/block.json +2 -1
  162. package/src/paragraph/editor.scss +8 -0
  163. package/src/post-date/index.php +4 -7
  164. package/src/query/edit/query-content.js +3 -3
  165. package/src/query/edit/query-placeholder.js +3 -3
  166. package/src/query/edit/query-toolbar.js +47 -31
  167. package/src/social-links/block.json +2 -1
  168. package/src/term-template/index.php +1 -1
@@ -3,9 +3,8 @@
3
3
  "apiVersion": 3,
4
4
  "name": "core/breadcrumbs",
5
5
  "title": "Breadcrumbs",
6
- "__experimental": true,
7
6
  "category": "theme",
8
- "description": "Display a breadcrumb trail for hierarchical post types or based on taxonomy terms.",
7
+ "description": "Display a breadcrumb trail showing the path to the current page.",
9
8
  "textdomain": "default",
10
9
  "attributes": {
11
10
  "prefersTaxonomy": {
@@ -26,6 +26,7 @@ const separatorDefaultValue = '/';
26
26
  export default function BreadcrumbEdit( {
27
27
  attributes,
28
28
  setAttributes,
29
+ name,
29
30
  context: { postId, postType, templateSlug },
30
31
  } ) {
31
32
  const {
@@ -104,7 +105,7 @@ export default function BreadcrumbEdit( {
104
105
  const { content } = useServerSideRender( {
105
106
  attributes,
106
107
  skipBlockSupportAttributes: true,
107
- block: 'core/breadcrumbs',
108
+ block: name,
108
109
  urlQueryArgs: { post_id: postId, invalidationKey },
109
110
  } );
110
111
 
@@ -159,6 +159,26 @@ function render_block_core_breadcrumbs( $attributes, $content, $block ) {
159
159
  array_pop( $breadcrumb_items );
160
160
  }
161
161
 
162
+ /**
163
+ * Filters the breadcrumb items array before rendering.
164
+ *
165
+ * Allows developers to modify, add, or remove breadcrumb items.
166
+ *
167
+ * @since 7.0.0
168
+ *
169
+ * @param array[] $breadcrumb_items {
170
+ * Array of breadcrumb item data.
171
+ *
172
+ * @type string $label The breadcrumb text.
173
+ * @type string $url Optional. The breadcrumb link URL.
174
+ * @type bool $allow_html Optional. Whether to allow HTML in the label.
175
+ * When true, the label will be sanitized with wp_kses_post(),
176
+ * allowing only safe HTML tags. When false or omitted, all HTML
177
+ * will be escaped with esc_html(). Default false.
178
+ * }
179
+ */
180
+ $breadcrumb_items = apply_filters( 'block_core_breadcrumbs_items', $breadcrumb_items );
181
+
162
182
  if ( empty( $breadcrumb_items ) ) {
163
183
  return '';
164
184
  }
@@ -435,7 +455,9 @@ function block_core_breadcrumbs_get_archive_breadcrumbs() {
435
455
  $post_type = reset( $post_type );
436
456
  }
437
457
  $post_type_object = get_post_type_object( $post_type );
438
- $title = apply_filters( 'post_type_archive_title', $post_type_object->labels->archives, $post_type );
458
+
459
+ /** This filter is documented in wp-includes/general-template.php */
460
+ $title = apply_filters( 'post_type_archive_title', $post_type_object->labels->archives, $post_type ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound
439
461
 
440
462
  if ( $post_type_object ) {
441
463
  // Add post type (current if not paginated, link if paginated).
@@ -36,6 +36,18 @@ export const settings = {
36
36
  ...a,
37
37
  text: ( a.text || '' ) + text,
38
38
  } ),
39
+ __experimentalLabel( attributes, { context } ) {
40
+ const { text } = attributes;
41
+
42
+ const customName = attributes?.metadata?.name;
43
+ const hasContent = text?.trim().length > 0;
44
+
45
+ // In the list view, use the block's text as the label.
46
+ // If the text is empty, fall back to the default label.
47
+ if ( context === 'list-view' && ( customName || hasContent ) ) {
48
+ return customName || text;
49
+ }
50
+ },
39
51
  };
40
52
 
41
53
  if ( window.__experimentalContentOnlyInspectorFields ) {
@@ -0,0 +1,50 @@
1
+ /**
2
+ * Internal dependencies
3
+ */
4
+ import { settings } from '..';
5
+
6
+ describe( 'Button block __experimentalLabel', () => {
7
+ const { __experimentalLabel: getLabel } = settings;
8
+
9
+ it( 'returns custom name when metadata.name exists', () => {
10
+ const attributes = {
11
+ metadata: { name: 'My Custom Button' },
12
+ text: 'Click me',
13
+ };
14
+ expect( getLabel( attributes, { context: 'list-view' } ) ).toBe(
15
+ 'My Custom Button'
16
+ );
17
+ } );
18
+
19
+ it( 'returns text when no custom name is set', () => {
20
+ const attributes = {
21
+ text: 'My Custom Button',
22
+ };
23
+ expect( getLabel( attributes, { context: 'list-view' } ) ).toBe(
24
+ 'My Custom Button'
25
+ );
26
+ } );
27
+
28
+ it( 'returns undefined when text is empty', () => {
29
+ const attributes = {
30
+ text: '',
31
+ };
32
+ expect(
33
+ getLabel( attributes, { context: 'list-view' } )
34
+ ).toBeUndefined();
35
+ } );
36
+
37
+ it( 'returns undefined when empty attributes', () => {
38
+ const attributes = {};
39
+ expect(
40
+ getLabel( attributes, { context: 'list-view' } )
41
+ ).toBeUndefined();
42
+ } );
43
+
44
+ it( 'returns undefined when context is not list-view', () => {
45
+ const attributes = {
46
+ text: 'Click me',
47
+ };
48
+ expect( getLabel( attributes, { context: 'other' } ) ).toBeUndefined();
49
+ } );
50
+ } );
@@ -63,6 +63,7 @@
63
63
  "interactivity": {
64
64
  "clientNavigation": true
65
65
  },
66
+ "listView": true,
66
67
  "contentRole": true
67
68
  },
68
69
  "editorStyle": "wp-block-buttons-editor",
@@ -15,9 +15,6 @@
15
15
  "linkTarget": {
16
16
  "type": "string",
17
17
  "default": "_self"
18
- },
19
- "textAlign": {
20
- "type": "string"
21
18
  }
22
19
  },
23
20
  "usesContext": [ "commentId" ],
@@ -39,6 +36,7 @@
39
36
  "typography": {
40
37
  "fontSize": true,
41
38
  "lineHeight": true,
39
+ "textAlign": true,
42
40
  "__experimentalFontFamily": true,
43
41
  "__experimentalFontWeight": true,
44
42
  "__experimentalFontStyle": true,
@@ -2,6 +2,66 @@
2
2
  * Internal dependencies
3
3
  */
4
4
  import migrateFontFamily from '../utils/migrate-font-family';
5
+ import migrateTextAlign from '../utils/migrate-text-align';
6
+
7
+ const v2 = {
8
+ attributes: {
9
+ isLink: {
10
+ type: 'boolean',
11
+ default: true,
12
+ },
13
+ linkTarget: {
14
+ type: 'string',
15
+ default: '_self',
16
+ },
17
+ textAlign: {
18
+ type: 'string',
19
+ },
20
+ },
21
+ usesContext: [ 'commentId' ],
22
+ supports: {
23
+ html: false,
24
+ spacing: {
25
+ margin: true,
26
+ padding: true,
27
+ },
28
+ color: {
29
+ gradients: true,
30
+ link: true,
31
+ },
32
+ typography: {
33
+ fontSize: true,
34
+ lineHeight: true,
35
+ __experimentalFontFamily: true,
36
+ __experimentalFontWeight: true,
37
+ __experimentalFontStyle: true,
38
+ __experimentalTextTransform: true,
39
+ __experimentalTextDecoration: true,
40
+ __experimentalLetterSpacing: true,
41
+ },
42
+ interactivity: {
43
+ clientNavigation: true,
44
+ },
45
+ __experimentalBorder: {
46
+ radius: true,
47
+ color: true,
48
+ width: true,
49
+ style: true,
50
+ },
51
+ },
52
+ save() {
53
+ return null;
54
+ },
55
+ migrate: migrateTextAlign,
56
+ isEligible( attributes ) {
57
+ return (
58
+ !! attributes.textAlign ||
59
+ !! attributes.className?.match(
60
+ /\bhas-text-align-(left|center|right)\b/
61
+ )
62
+ );
63
+ },
64
+ };
5
65
 
6
66
  const v1 = {
7
67
  attributes: {
@@ -47,4 +107,4 @@ const v1 = {
47
107
  *
48
108
  * See block-deprecation.md
49
109
  */
50
- export default [ v1 ];
110
+ export default [ v2, v1 ];
@@ -1,19 +1,9 @@
1
- /**
2
- * External dependencies
3
- */
4
- import clsx from 'clsx';
5
-
6
1
  /**
7
2
  * WordPress dependencies
8
3
  */
9
4
  import { __, _x } from '@wordpress/i18n';
10
5
  import { useSelect } from '@wordpress/data';
11
- import {
12
- AlignmentControl,
13
- BlockControls,
14
- InspectorControls,
15
- useBlockProps,
16
- } from '@wordpress/block-editor';
6
+ import { InspectorControls, useBlockProps } from '@wordpress/block-editor';
17
7
  import { store as coreStore } from '@wordpress/core-data';
18
8
  import {
19
9
  ToggleControl,
@@ -25,6 +15,7 @@ import {
25
15
  * Internal dependencies
26
16
  */
27
17
  import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
18
+ import useDeprecatedTextAlign from '../utils/deprecated-text-align-attributes';
28
19
 
29
20
  /**
30
21
  * Renders the `core/comment-author-name` block on the editor.
@@ -34,23 +25,20 @@ import { useToolsPanelDropdownMenuProps } from '../utils/hooks';
34
25
  * @param {Object} props.attributes Block attributes.
35
26
  * @param {string} props.attributes.isLink Whether the author name should be linked.
36
27
  * @param {string} props.attributes.linkTarget Target of the link.
37
- * @param {string} props.attributes.textAlign Text alignment.
38
28
  * @param {Object} props.context Inherited context.
39
29
  * @param {string} props.context.commentId The comment ID.
40
30
  *
41
31
  * @return {JSX.Element} React element.
42
32
  */
43
- export default function Edit( {
44
- attributes: { isLink, linkTarget, textAlign },
45
- context: { commentId },
46
- setAttributes,
47
- } ) {
33
+ export default function Edit( props ) {
34
+ const {
35
+ attributes: { isLink, linkTarget },
36
+ context: { commentId },
37
+ setAttributes,
38
+ } = props;
39
+ useDeprecatedTextAlign( props );
48
40
  const dropdownMenuProps = useToolsPanelDropdownMenuProps();
49
- const blockProps = useBlockProps( {
50
- className: clsx( {
51
- [ `has-text-align-${ textAlign }` ]: textAlign,
52
- } ),
53
- } );
41
+ const blockProps = useBlockProps();
54
42
  let displayName = useSelect(
55
43
  ( select ) => {
56
44
  const { getEntityRecord } = select( coreStore );
@@ -67,17 +55,6 @@ export default function Edit( {
67
55
  [ commentId ]
68
56
  );
69
57
 
70
- const blockControls = (
71
- <BlockControls group="block">
72
- <AlignmentControl
73
- value={ textAlign }
74
- onChange={ ( newAlign ) =>
75
- setAttributes( { textAlign: newAlign } )
76
- }
77
- />
78
- </BlockControls>
79
- );
80
-
81
58
  const inspectorControls = (
82
59
  <InspectorControls>
83
60
  <ToolsPanel
@@ -149,7 +126,6 @@ export default function Edit( {
149
126
  return (
150
127
  <>
151
128
  { inspectorControls }
152
- { blockControls }
153
129
  <div { ...blockProps }>{ displayAuthor }</div>
154
130
  </>
155
131
  );
@@ -3,15 +3,20 @@
3
3
  */
4
4
  import {
5
5
  BlockControls,
6
+ BlockIcon,
6
7
  useBlockProps,
7
8
  store as blockEditorStore,
8
9
  } from '@wordpress/block-editor';
9
- import { debounce, useRefEffect } from '@wordpress/compose';
10
10
  import { useSelect } from '@wordpress/data';
11
- import { ToolbarGroup } from '@wordpress/components';
12
- import { useEffect, useRef, useState } from '@wordpress/element';
11
+ import {
12
+ Button,
13
+ Placeholder,
14
+ ToolbarGroup,
15
+ ToolbarButton,
16
+ } from '@wordpress/components';
17
+ import { useState, useRef, RawHTML } from '@wordpress/element';
13
18
  import { __ } from '@wordpress/i18n';
14
- import { BACKSPACE, DELETE, F10, isKeyboardEvent } from '@wordpress/keycodes';
19
+ import { classic } from '@wordpress/icons';
15
20
 
16
21
  /**
17
22
  * Internal dependencies
@@ -19,34 +24,19 @@ import { BACKSPACE, DELETE, F10, isKeyboardEvent } from '@wordpress/keycodes';
19
24
  import ConvertToBlocksButton from './convert-to-blocks-button';
20
25
  import ModalEdit from './modal';
21
26
 
22
- const { wp } = window;
23
-
24
- function isTmceEmpty( editor ) {
25
- // When tinyMce is empty the content seems to be:
26
- // <p><br data-mce-bogus="1"></p>
27
- // avoid expensive checks for large documents
28
- const body = editor.getBody();
29
- if ( body.childNodes.length > 1 ) {
30
- return false;
31
- } else if ( body.childNodes.length === 0 ) {
32
- return true;
33
- }
34
- if ( body.childNodes[ 0 ].childNodes.length > 1 ) {
35
- return false;
36
- }
37
- return /^\n?$/.test( body.innerText || body.textContent );
38
- }
27
+ export default function FreeformEdit( {
28
+ attributes,
29
+ setAttributes,
30
+ clientId,
31
+ } ) {
32
+ const { content } = attributes;
33
+ const [ isOpen, setOpen ] = useState( false );
34
+ const editButtonRef = useRef( null );
39
35
 
40
- export default function FreeformEdit( props ) {
41
- const { clientId } = props;
42
36
  const canRemove = useSelect(
43
37
  ( select ) => select( blockEditorStore ).canRemoveBlock( clientId ),
44
38
  [ clientId ]
45
39
  );
46
- const [ isIframed, setIsIframed ] = useState( false );
47
- const ref = useRefEffect( ( element ) => {
48
- setIsIframed( element.ownerDocument !== document );
49
- }, [] );
50
40
 
51
41
  return (
52
42
  <>
@@ -57,227 +47,52 @@ export default function FreeformEdit( props ) {
57
47
  </ToolbarGroup>
58
48
  </BlockControls>
59
49
  ) }
60
- <div { ...useBlockProps( { ref } ) }>
61
- { isIframed ? (
62
- <ModalEdit { ...props } />
50
+ <BlockControls>
51
+ <ToolbarGroup>
52
+ <ToolbarButton
53
+ ref={ editButtonRef }
54
+ onClick={ () => setOpen( true ) }
55
+ >
56
+ { __( 'Edit' ) }
57
+ </ToolbarButton>
58
+ </ToolbarGroup>
59
+ </BlockControls>
60
+ <div { ...useBlockProps() }>
61
+ { content ? (
62
+ <RawHTML>{ content }</RawHTML>
63
63
  ) : (
64
- <ClassicEdit { ...props } />
64
+ <Placeholder
65
+ icon={ <BlockIcon icon={ classic } /> }
66
+ label={ __( 'Classic' ) }
67
+ instructions={ __(
68
+ 'Use the classic editor to add content.'
69
+ ) }
70
+ >
71
+ <Button
72
+ __next40pxDefaultSize
73
+ variant="primary"
74
+ onClick={ () => setOpen( true ) }
75
+ >
76
+ { __( 'Edit contents' ) }
77
+ </Button>
78
+ </Placeholder>
65
79
  ) }
66
- </div>
67
- </>
68
- );
69
- }
70
-
71
- function ClassicEdit( {
72
- clientId,
73
- attributes: { content },
74
- setAttributes,
75
- onReplace,
76
- } ) {
77
- const { getMultiSelectedBlockClientIds } = useSelect( blockEditorStore );
78
- const didMountRef = useRef( false );
79
-
80
- useEffect( () => {
81
- if ( ! didMountRef.current ) {
82
- return;
83
- }
84
-
85
- const editor = window.tinymce.get( `editor-${ clientId }` );
86
- if ( ! editor ) {
87
- return;
88
- }
89
-
90
- const currentContent = editor.getContent();
91
- if ( currentContent !== content ) {
92
- editor.setContent( content || '' );
93
- }
94
- }, [ clientId, content ] );
95
-
96
- useEffect( () => {
97
- const { baseURL, suffix } = window.wpEditorL10n.tinymce;
98
-
99
- didMountRef.current = true;
100
-
101
- window.tinymce.EditorManager.overrideDefaults( {
102
- base_url: baseURL,
103
- suffix,
104
- } );
105
-
106
- function onSetup( editor ) {
107
- let bookmark;
108
-
109
- if ( content ) {
110
- editor.on( 'loadContent', () => editor.setContent( content ) );
111
- }
112
-
113
- editor.on( 'blur', () => {
114
- bookmark = editor.selection.getBookmark( 2, true );
115
- // There is an issue with Chrome and the editor.focus call in core at https://core.trac.wordpress.org/browser/trunk/src/js/_enqueues/lib/link.js#L451.
116
- // This causes a scroll to the top of editor content on return from some content updating dialogs so tracking
117
- // scroll position until this is fixed in core.
118
- const scrollContainer = document.querySelector(
119
- '.interface-interface-skeleton__content'
120
- );
121
- const scrollPosition = scrollContainer.scrollTop;
122
-
123
- // Only update attributes if we aren't multi-selecting blocks.
124
- // Updating during multi-selection can overwrite attributes of other blocks.
125
- if ( ! getMultiSelectedBlockClientIds()?.length ) {
126
- setAttributes( {
127
- content: editor.getContent(),
128
- } );
129
- }
130
-
131
- editor.once( 'focus', () => {
132
- if ( bookmark ) {
133
- editor.selection.moveToBookmark( bookmark );
134
- if ( scrollContainer.scrollTop !== scrollPosition ) {
135
- scrollContainer.scrollTop = scrollPosition;
80
+ { isOpen && (
81
+ <ModalEdit
82
+ clientId={ clientId }
83
+ content={ content }
84
+ onClose={ () => {
85
+ setOpen( false );
86
+ if ( editButtonRef.current ) {
87
+ editButtonRef.current.focus();
88
+ }
89
+ } }
90
+ onChange={ ( newContent ) =>
91
+ setAttributes( { content: newContent } )
136
92
  }
137
- }
138
- } );
139
-
140
- return false;
141
- } );
142
-
143
- editor.on( 'mousedown touchstart', () => {
144
- bookmark = null;
145
- } );
146
-
147
- const debouncedOnChange = debounce( () => {
148
- const value = editor.getContent();
149
-
150
- if ( value !== editor._lastChange ) {
151
- editor._lastChange = value;
152
- setAttributes( {
153
- content: value,
154
- } );
155
- }
156
- }, 250 );
157
- editor.on( 'Paste Change input Undo Redo', debouncedOnChange );
158
-
159
- // We need to cancel the debounce call because when we remove
160
- // the editor (onUnmount) this callback is executed in
161
- // another tick. This results in setting the content to empty.
162
- editor.on( 'remove', debouncedOnChange.cancel );
163
-
164
- editor.on( 'keydown', ( event ) => {
165
- if ( isKeyboardEvent.primary( event, 'z' ) ) {
166
- // Prevent the gutenberg undo kicking in so TinyMCE undo stack works as expected.
167
- event.stopPropagation();
168
- }
169
-
170
- if (
171
- ( event.keyCode === BACKSPACE ||
172
- event.keyCode === DELETE ) &&
173
- isTmceEmpty( editor )
174
- ) {
175
- // Delete the block.
176
- onReplace( [] );
177
- event.preventDefault();
178
- event.stopImmediatePropagation();
179
- }
180
-
181
- const { altKey } = event;
182
- /*
183
- * Prevent Mousetrap from kicking in: TinyMCE already uses its own
184
- * `alt+f10` shortcut to focus its toolbar.
185
- */
186
- if ( altKey && event.keyCode === F10 ) {
187
- event.stopPropagation();
188
- }
189
- } );
190
-
191
- editor.on( 'paste', ( event ) => {
192
- // TinyMCE selection isn’t synced with the block editor selection store.
193
- // This event handler prevents paste from bubbling so the useClipboardHandler
194
- // won’t replace the block.
195
- event.stopPropagation();
196
- } );
197
-
198
- editor.on( 'init', () => {
199
- const rootNode = editor.getBody();
200
-
201
- // Create the toolbar by refocussing the editor.
202
- if ( rootNode.ownerDocument.activeElement === rootNode ) {
203
- rootNode.blur();
204
- editor.focus();
205
- }
206
- } );
207
- }
208
-
209
- function initialize() {
210
- const { settings } = window.wpEditorL10n.tinymce;
211
- wp.oldEditor.initialize( `editor-${ clientId }`, {
212
- tinymce: {
213
- ...settings,
214
- inline: true,
215
- content_css: false,
216
- fixed_toolbar_container: `#toolbar-${ clientId }`,
217
- setup: onSetup,
218
- },
219
- } );
220
- }
221
-
222
- function onReadyStateChange() {
223
- if ( document.readyState === 'complete' ) {
224
- initialize();
225
- }
226
- }
227
-
228
- if ( document.readyState === 'complete' ) {
229
- initialize();
230
- } else {
231
- document.addEventListener( 'readystatechange', onReadyStateChange );
232
- }
233
-
234
- return () => {
235
- document.removeEventListener(
236
- 'readystatechange',
237
- onReadyStateChange
238
- );
239
- wp.oldEditor.remove( `editor-${ clientId }` );
240
- didMountRef.current = false;
241
- };
242
- }, [] );
243
-
244
- function focus() {
245
- const editor = window.tinymce.get( `editor-${ clientId }` );
246
- if ( editor ) {
247
- editor.focus();
248
- }
249
- }
250
-
251
- function onToolbarKeyDown( event ) {
252
- // Prevent WritingFlow from kicking in and allow arrows navigation on the toolbar.
253
- event.stopPropagation();
254
- // Prevent Mousetrap from moving focus to the top toolbar when pressing `alt+f10` on this block toolbar.
255
- event.nativeEvent.stopImmediatePropagation();
256
- }
257
-
258
- // Disable reasons:
259
- //
260
- // jsx-a11y/no-static-element-interactions
261
- // - the toolbar itself is non-interactive, but must capture events
262
- // from the KeyboardShortcuts component to stop their propagation.
263
-
264
- /* eslint-disable jsx-a11y/no-static-element-interactions */
265
- return (
266
- <>
267
- <div
268
- key="toolbar"
269
- id={ `toolbar-${ clientId }` }
270
- className="block-library-classic__toolbar"
271
- onClick={ focus }
272
- data-placeholder={ __( 'Classic' ) }
273
- onKeyDown={ onToolbarKeyDown }
274
- />
275
- <div
276
- key="editor"
277
- id={ `editor-${ clientId }` }
278
- className="wp-block-freeform block-library-rich-text__tinymce"
279
- />
93
+ />
94
+ ) }
95
+ </div>
280
96
  </>
281
97
  );
282
- /* eslint-enable jsx-a11y/no-static-element-interactions */
283
98
  }