@wordpress/block-editor 11.1.0 → 11.2.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 (201) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/LICENSE.md +1 -1
  3. package/build/components/block-actions/index.js +9 -0
  4. package/build/components/block-actions/index.js.map +1 -1
  5. package/build/components/block-inspector/index.js +4 -2
  6. package/build/components/block-inspector/index.js.map +1 -1
  7. package/build/components/block-preview/auto.js +1 -4
  8. package/build/components/block-preview/auto.js.map +1 -1
  9. package/build/components/block-settings-menu/block-settings-dropdown.js +4 -1
  10. package/build/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  11. package/build/components/block-styles/index.js +3 -1
  12. package/build/components/block-styles/index.js.map +1 -1
  13. package/build/components/block-tools/use-block-toolbar-popover-props.js +43 -10
  14. package/build/components/block-tools/use-block-toolbar-popover-props.js.map +1 -1
  15. package/build/components/default-style-picker/index.js +1 -0
  16. package/build/components/default-style-picker/index.js.map +1 -1
  17. package/build/components/font-sizes/with-font-sizes.js +5 -8
  18. package/build/components/font-sizes/with-font-sizes.js.map +1 -1
  19. package/build/components/iframe/index.js +37 -8
  20. package/build/components/iframe/index.js.map +1 -1
  21. package/build/components/iframe/use-compatibility-styles.js +6 -1
  22. package/build/components/iframe/use-compatibility-styles.js.map +1 -1
  23. package/build/components/image-size-control/index.js +1 -0
  24. package/build/components/image-size-control/index.js.map +1 -1
  25. package/build/components/inserter/block-patterns-tab.js +4 -4
  26. package/build/components/inserter/block-patterns-tab.js.map +1 -1
  27. package/build/components/inserter/index.js +3 -2
  28. package/build/components/inserter/index.js.map +1 -1
  29. package/build/components/inserter/menu.js +11 -5
  30. package/build/components/inserter/menu.js.map +1 -1
  31. package/build/components/inspector-controls/groups.js +3 -1
  32. package/build/components/inspector-controls/groups.js.map +1 -1
  33. package/build/components/inspector-controls-tabs/position-controls-panel.js +46 -0
  34. package/build/components/inspector-controls-tabs/position-controls-panel.js.map +1 -0
  35. package/build/components/inspector-controls-tabs/settings-tab.js +3 -1
  36. package/build/components/inspector-controls-tabs/settings-tab.js.map +1 -1
  37. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js +4 -11
  38. package/build/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +1 -1
  39. package/build/components/link-control/search-input.js +1 -0
  40. package/build/components/link-control/search-input.js.map +1 -1
  41. package/build/components/off-canvas-editor/appender.js +2 -38
  42. package/build/components/off-canvas-editor/appender.js.map +1 -1
  43. package/build/components/off-canvas-editor/block-contents.js +38 -5
  44. package/build/components/off-canvas-editor/block-contents.js.map +1 -1
  45. package/build/components/off-canvas-editor/block.js +7 -25
  46. package/build/components/off-canvas-editor/block.js.map +1 -1
  47. package/build/components/off-canvas-editor/index.js +7 -4
  48. package/build/components/off-canvas-editor/index.js.map +1 -1
  49. package/build/components/provider/index.js +3 -1
  50. package/build/components/provider/index.js.map +1 -1
  51. package/build/components/rich-text/use-enter.js +4 -5
  52. package/build/components/rich-text/use-enter.js.map +1 -1
  53. package/build/components/url-input/button.js +1 -0
  54. package/build/components/url-input/button.js.map +1 -1
  55. package/build/components/url-input/index.js +15 -1
  56. package/build/components/url-input/index.js.map +1 -1
  57. package/build/components/url-popover/link-editor.js +1 -0
  58. package/build/components/url-popover/link-editor.js.map +1 -1
  59. package/build/components/use-paste-styles/index.js +188 -0
  60. package/build/components/use-paste-styles/index.js.map +1 -0
  61. package/build/components/writing-flow/use-arrow-nav.js +22 -29
  62. package/build/components/writing-flow/use-arrow-nav.js.map +1 -1
  63. package/build/hooks/index.js +2 -0
  64. package/build/hooks/index.js.map +1 -1
  65. package/build/hooks/metadata.js +1 -1
  66. package/build/hooks/metadata.js.map +1 -1
  67. package/build/hooks/position.js +376 -0
  68. package/build/hooks/position.js.map +1 -0
  69. package/build/hooks/supports.js +328 -0
  70. package/build/hooks/supports.js.map +1 -0
  71. package/build/store/reducer.js +6 -2
  72. package/build/store/reducer.js.map +1 -1
  73. package/build/store/selectors.js +8 -6
  74. package/build/store/selectors.js.map +1 -1
  75. package/build-module/components/block-actions/index.js +6 -0
  76. package/build-module/components/block-actions/index.js.map +1 -1
  77. package/build-module/components/block-inspector/index.js +3 -2
  78. package/build-module/components/block-inspector/index.js.map +1 -1
  79. package/build-module/components/block-preview/auto.js +1 -4
  80. package/build-module/components/block-preview/auto.js.map +1 -1
  81. package/build-module/components/block-settings-menu/block-settings-dropdown.js +4 -1
  82. package/build-module/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
  83. package/build-module/components/block-styles/index.js +2 -1
  84. package/build-module/components/block-styles/index.js.map +1 -1
  85. package/build-module/components/block-tools/use-block-toolbar-popover-props.js +42 -11
  86. package/build-module/components/block-tools/use-block-toolbar-popover-props.js.map +1 -1
  87. package/build-module/components/default-style-picker/index.js +1 -0
  88. package/build-module/components/default-style-picker/index.js.map +1 -1
  89. package/build-module/components/font-sizes/with-font-sizes.js +5 -7
  90. package/build-module/components/font-sizes/with-font-sizes.js.map +1 -1
  91. package/build-module/components/iframe/index.js +36 -9
  92. package/build-module/components/iframe/index.js.map +1 -1
  93. package/build-module/components/iframe/use-compatibility-styles.js +6 -1
  94. package/build-module/components/iframe/use-compatibility-styles.js.map +1 -1
  95. package/build-module/components/image-size-control/index.js +1 -0
  96. package/build-module/components/image-size-control/index.js.map +1 -1
  97. package/build-module/components/inserter/block-patterns-tab.js +4 -4
  98. package/build-module/components/inserter/block-patterns-tab.js.map +1 -1
  99. package/build-module/components/inserter/index.js +3 -2
  100. package/build-module/components/inserter/index.js.map +1 -1
  101. package/build-module/components/inserter/menu.js +11 -5
  102. package/build-module/components/inserter/menu.js.map +1 -1
  103. package/build-module/components/inspector-controls/groups.js +3 -1
  104. package/build-module/components/inspector-controls/groups.js.map +1 -1
  105. package/build-module/components/inspector-controls-tabs/position-controls-panel.js +33 -0
  106. package/build-module/components/inspector-controls-tabs/position-controls-panel.js.map +1 -0
  107. package/build-module/components/inspector-controls-tabs/settings-tab.js +2 -1
  108. package/build-module/components/inspector-controls-tabs/settings-tab.js.map +1 -1
  109. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js +4 -11
  110. package/build-module/components/inspector-controls-tabs/use-inspector-controls-tabs.js.map +1 -1
  111. package/build-module/components/link-control/search-input.js +1 -0
  112. package/build-module/components/link-control/search-input.js.map +1 -1
  113. package/build-module/components/off-canvas-editor/appender.js +3 -36
  114. package/build-module/components/off-canvas-editor/appender.js.map +1 -1
  115. package/build-module/components/off-canvas-editor/block-contents.js +37 -7
  116. package/build-module/components/off-canvas-editor/block-contents.js.map +1 -1
  117. package/build-module/components/off-canvas-editor/block.js +9 -27
  118. package/build-module/components/off-canvas-editor/block.js.map +1 -1
  119. package/build-module/components/off-canvas-editor/index.js +7 -4
  120. package/build-module/components/off-canvas-editor/index.js.map +1 -1
  121. package/build-module/components/provider/index.js +3 -1
  122. package/build-module/components/provider/index.js.map +1 -1
  123. package/build-module/components/rich-text/use-enter.js +4 -5
  124. package/build-module/components/rich-text/use-enter.js.map +1 -1
  125. package/build-module/components/url-input/button.js +1 -0
  126. package/build-module/components/url-input/button.js.map +1 -1
  127. package/build-module/components/url-input/index.js +14 -1
  128. package/build-module/components/url-input/index.js.map +1 -1
  129. package/build-module/components/url-popover/link-editor.js +1 -0
  130. package/build-module/components/url-popover/link-editor.js.map +1 -1
  131. package/build-module/components/use-paste-styles/index.js +174 -0
  132. package/build-module/components/use-paste-styles/index.js.map +1 -0
  133. package/build-module/components/writing-flow/use-arrow-nav.js +22 -29
  134. package/build-module/components/writing-flow/use-arrow-nav.js.map +1 -1
  135. package/build-module/hooks/index.js +1 -0
  136. package/build-module/hooks/index.js.map +1 -1
  137. package/build-module/hooks/metadata.js +1 -1
  138. package/build-module/hooks/metadata.js.map +1 -1
  139. package/build-module/hooks/position.js +337 -0
  140. package/build-module/hooks/position.js.map +1 -0
  141. package/build-module/hooks/supports.js +257 -0
  142. package/build-module/hooks/supports.js.map +1 -0
  143. package/build-module/store/reducer.js +6 -2
  144. package/build-module/store/reducer.js.map +1 -1
  145. package/build-module/store/selectors.js +7 -5
  146. package/build-module/store/selectors.js.map +1 -1
  147. package/build-style/content-rtl.css +57 -0
  148. package/build-style/content.css +57 -0
  149. package/build-style/style-rtl.css +27 -58
  150. package/build-style/style.css +27 -58
  151. package/package.json +29 -29
  152. package/src/components/block-actions/index.js +5 -0
  153. package/src/components/block-inspector/index.js +3 -1
  154. package/src/components/block-preview/auto.js +2 -4
  155. package/src/components/block-settings-menu/block-settings-dropdown.js +4 -0
  156. package/src/components/block-styles/index.js +4 -1
  157. package/src/components/block-tools/use-block-toolbar-popover-props.js +68 -12
  158. package/src/components/button-block-appender/{style.scss → content.scss} +0 -0
  159. package/src/components/default-style-picker/index.js +1 -0
  160. package/src/components/font-sizes/with-font-sizes.js +33 -33
  161. package/src/components/iframe/index.js +52 -19
  162. package/src/components/iframe/use-compatibility-styles.js +6 -0
  163. package/src/components/image-size-control/index.js +1 -0
  164. package/src/components/inserter/block-patterns-tab.js +7 -4
  165. package/src/components/inserter/index.js +46 -41
  166. package/src/components/inserter/menu.js +8 -4
  167. package/src/components/inserter/test/__snapshots__/index.native.js.snap +117 -0
  168. package/src/components/inserter/test/index.native.js +255 -1
  169. package/src/components/inspector-controls/groups.js +2 -0
  170. package/src/components/inspector-controls-tabs/position-controls-panel.js +37 -0
  171. package/src/components/inspector-controls-tabs/settings-tab.js +2 -0
  172. package/src/components/inspector-controls-tabs/style.scss +15 -0
  173. package/src/components/inspector-controls-tabs/use-inspector-controls-tabs.js +3 -8
  174. package/src/components/link-control/search-input.js +1 -0
  175. package/src/components/link-control/style.scss +1 -0
  176. package/src/components/list-view/style.scss +13 -3
  177. package/src/components/off-canvas-editor/appender.js +2 -52
  178. package/src/components/off-canvas-editor/block-contents.js +84 -23
  179. package/src/components/off-canvas-editor/block.js +28 -60
  180. package/src/components/off-canvas-editor/index.js +12 -2
  181. package/src/components/provider/index.js +4 -1
  182. package/src/components/rich-text/use-enter.js +4 -4
  183. package/src/components/url-input/README.md +5 -0
  184. package/src/components/url-input/button.js +1 -0
  185. package/src/components/url-input/index.js +15 -1
  186. package/src/components/url-popover/link-editor.js +1 -0
  187. package/src/components/use-paste-styles/index.js +230 -0
  188. package/src/components/writing-flow/use-arrow-nav.js +20 -28
  189. package/src/content.scss +1 -0
  190. package/src/hooks/index.js +1 -0
  191. package/src/hooks/metadata.js +1 -2
  192. package/src/hooks/position.js +375 -0
  193. package/src/hooks/position.scss +18 -0
  194. package/src/hooks/supports.js +302 -0
  195. package/src/hooks/test/__snapshots__/align.native.js.snap +73 -0
  196. package/src/hooks/test/align.native.js +133 -0
  197. package/src/store/reducer.js +7 -2
  198. package/src/store/selectors.js +5 -5
  199. package/src/store/test/reducer.js +45 -3
  200. package/src/store/test/selectors.js +12 -9
  201. package/src/style.scss +2 -1
@@ -6,11 +6,10 @@ import classnames from 'classnames';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import { createBlock, hasBlockSupport } from '@wordpress/blocks';
9
+ import { hasBlockSupport } from '@wordpress/blocks';
10
10
  import {
11
11
  __experimentalTreeGridCell as TreeGridCell,
12
12
  __experimentalTreeGridItem as TreeGridItem,
13
- MenuItem,
14
13
  } from '@wordpress/components';
15
14
  import { useInstanceId } from '@wordpress/compose';
16
15
  import { moreVertical } from '@wordpress/icons';
@@ -86,8 +85,7 @@ function ListViewBlock( {
86
85
  ( isSelected &&
87
86
  selectedClientIds[ selectedClientIds.length - 1 ] === clientId );
88
87
 
89
- const { insertBlock, replaceBlock, toggleBlockHighlight } =
90
- useDispatch( blockEditorStore );
88
+ const { toggleBlockHighlight } = useDispatch( blockEditorStore );
91
89
 
92
90
  const blockInformation = useBlockDisplayInformation( clientId );
93
91
  const block = useSelect(
@@ -128,7 +126,8 @@ function ListViewBlock( {
128
126
  [ selectBlock ]
129
127
  );
130
128
 
131
- const { isTreeGridMounted, expand, collapse } = useListViewContext();
129
+ const { isTreeGridMounted, expand, collapse, LeafMoreMenu } =
130
+ useListViewContext();
132
131
 
133
132
  const toggleExpanded = useCallback(
134
133
  ( event ) => {
@@ -237,6 +236,10 @@ function ListViewBlock( {
237
236
  ? selectedClientIds
238
237
  : [ clientId ];
239
238
 
239
+ const MoreMenuComponent = LeafMoreMenu
240
+ ? LeafMoreMenu
241
+ : BlockSettingsDropdown;
242
+
240
243
  return (
241
244
  <ListViewLeaf
242
245
  className={ classes }
@@ -352,61 +355,26 @@ function ListViewBlock( {
352
355
  colSpan={ isEditable ? 1 : 2 } // When an item is not editable then we don't output the cell for the edit button, so we need to adjust the colspan so that the HTML is valid.
353
356
  >
354
357
  { ( { ref, tabIndex, onFocus } ) => (
355
- <BlockSettingsDropdown
356
- clientIds={ dropdownClientIds }
357
- icon={ moreVertical }
358
- label={ settingsAriaLabel }
359
- toggleProps={ {
360
- ref,
361
- className:
362
- 'block-editor-list-view-block__menu',
363
- tabIndex,
364
- onFocus,
365
- } }
366
- disableOpenOnArrowDown
367
- __experimentalSelectBlock={ updateSelection }
368
- >
369
- { ( { onClose } ) => (
370
- <MenuItem
371
- onClick={ () => {
372
- const newLink = createBlock(
373
- 'core/navigation-link'
374
- );
375
- if (
376
- block.name ===
377
- 'core/navigation-submenu'
378
- ) {
379
- const updateSelectionOnInsert = false;
380
- insertBlock(
381
- newLink,
382
- block.innerBlocks.length,
383
- clientId,
384
- updateSelectionOnInsert
385
- );
386
- } else {
387
- // Convert to a submenu if the block currently isn't one.
388
- const newSubmenu = createBlock(
389
- 'core/navigation-submenu',
390
- block.attributes,
391
- block.innerBlocks
392
- ? [
393
- ...block.innerBlocks,
394
- newLink,
395
- ]
396
- : [ newLink ]
397
- );
398
- replaceBlock(
399
- clientId,
400
- newSubmenu
401
- );
402
- }
403
- onClose();
404
- } }
405
- >
406
- { __( 'Add submenu item' ) }
407
- </MenuItem>
408
- ) }
409
- </BlockSettingsDropdown>
358
+ <>
359
+ <MoreMenuComponent
360
+ clientIds={ dropdownClientIds }
361
+ block={ block }
362
+ clientId={ clientId }
363
+ icon={ moreVertical }
364
+ label={ settingsAriaLabel }
365
+ toggleProps={ {
366
+ ref,
367
+ className:
368
+ 'block-editor-list-view-block__menu',
369
+ tabIndex,
370
+ onFocus,
371
+ } }
372
+ disableOpenOnArrowDown
373
+ __experimentalSelectBlock={
374
+ updateSelection
375
+ }
376
+ />
377
+ </>
410
378
  ) }
411
379
  </TreeGridCell>
412
380
  </>
@@ -60,7 +60,8 @@ export const BLOCK_LIST_ITEM_HEIGHT = 36;
60
60
  * @param {Array} props.blocks Custom subset of block client IDs to be used instead of the default hierarchy.
61
61
  * @param {boolean} props.showBlockMovers Flag to enable block movers
62
62
  * @param {boolean} props.isExpanded Flag to determine whether nested levels are expanded by default.
63
- * @param {boolean} props.selectBlockInCanvas Flag to determine whether the list view should be a block selection mechanism,.
63
+ * @param {boolean} props.selectBlockInCanvas Flag to determine whether the list view should be a block selection mechanism.
64
+ * @param {Object} props.LeafMoreMenu Optional more menu substitution.
64
65
  * @param {Object} ref Forwarded ref
65
66
  */
66
67
  function __ExperimentalOffCanvasEditor(
@@ -70,6 +71,7 @@ function __ExperimentalOffCanvasEditor(
70
71
  showBlockMovers = false,
71
72
  isExpanded = false,
72
73
  selectBlockInCanvas = true,
74
+ LeafMoreMenu,
73
75
  },
74
76
  ref
75
77
  ) {
@@ -188,8 +190,16 @@ function __ExperimentalOffCanvasEditor(
188
190
  expandedState,
189
191
  expand,
190
192
  collapse,
193
+ LeafMoreMenu,
191
194
  } ),
192
- [ isMounted.current, draggedClientIds, expandedState, expand, collapse ]
195
+ [
196
+ isMounted.current,
197
+ draggedClientIds,
198
+ expandedState,
199
+ expand,
200
+ collapse,
201
+ LeafMoreMenu,
202
+ ]
193
203
  );
194
204
 
195
205
  return (
@@ -19,7 +19,10 @@ function BlockEditorProvider( props ) {
19
19
 
20
20
  const { updateSettings } = useDispatch( blockEditorStore );
21
21
  useEffect( () => {
22
- updateSettings( settings );
22
+ updateSettings( {
23
+ ...settings,
24
+ __internalIsInitialized: true,
25
+ } );
23
26
  }, [ settings ] );
24
27
 
25
28
  // Syncs the entity provider with changes in the block-editor store.
@@ -28,6 +28,10 @@ export function useEnter( props ) {
28
28
  return;
29
29
  }
30
30
 
31
+ if ( event.keyCode !== ENTER ) {
32
+ return;
33
+ }
34
+
31
35
  const {
32
36
  removeEditorOnlyFormats,
33
37
  value,
@@ -40,10 +44,6 @@ export function useEnter( props ) {
40
44
  onSplitAtEnd,
41
45
  } = propsRef.current;
42
46
 
43
- if ( event.keyCode !== ENTER ) {
44
- return;
45
- }
46
-
47
47
  event.preventDefault();
48
48
 
49
49
  const _value = { ...value };
@@ -160,6 +160,10 @@ When hiding the URLInput using CSS (as is sometimes done for accessibility purpo
160
160
 
161
161
  This prop allows the suggestions list to be programmatically not rendered by passing a boolean—it can be `true` to make sure suggestions aren't rendered, or `false`/`undefined` to fall back to the default behaviour of showing suggestions when matching autocompletion items are found.
162
162
 
163
+ ### `__nextHasNoMarginBottom: Boolean`
164
+
165
+ Start opting into the new margin-free styles that will become the default in a future version, currently scheduled to be WordPress 6.4. (The prop can be safely removed once this happens.)
166
+
163
167
  ## Example
164
168
 
165
169
  {% codetabs %}
@@ -217,6 +221,7 @@ registerBlockType( /* ... */, {
217
221
  edit( { className, attributes, setAttributes } ) {
218
222
  return (
219
223
  <URLInput
224
+ __nextHasNoMarginBottom
220
225
  className={ className }
221
226
  value={ attributes.url }
222
227
  onChange={ ( url, post ) => setAttributes( { url, text: (post && post.title) || 'Click here' } ) }
@@ -57,6 +57,7 @@ class URLInputButton extends Component {
57
57
  onClick={ this.toggle }
58
58
  />
59
59
  <URLInput
60
+ __nextHasNoMarginBottom
60
61
  value={ url || '' }
61
62
  onChange={ onChange }
62
63
  />
@@ -7,6 +7,7 @@ import scrollIntoView from 'dom-scroll-into-view';
7
7
  /**
8
8
  * WordPress dependencies
9
9
  */
10
+ import deprecated from '@wordpress/deprecated';
10
11
  import { __, sprintf, _n } from '@wordpress/i18n';
11
12
  import { Component, createRef } from '@wordpress/element';
12
13
  import { UP, DOWN, ENTER, TAB } from '@wordpress/keycodes';
@@ -424,6 +425,8 @@ class URLInput extends Component {
424
425
 
425
426
  renderControl() {
426
427
  const {
428
+ /** Start opting into the new margin-free styles that will become the default in a future version. */
429
+ __nextHasNoMarginBottom = false,
427
430
  label = null,
428
431
  className,
429
432
  isFullWidth,
@@ -477,8 +480,19 @@ class URLInput extends Component {
477
480
  return renderControl( controlProps, inputProps, loading );
478
481
  }
479
482
 
483
+ if ( ! __nextHasNoMarginBottom ) {
484
+ deprecated( 'Bottom margin styles for wp.blockEditor.URLInput', {
485
+ since: '6.2',
486
+ version: '6.5',
487
+ hint: 'Set the `__nextHasNoMarginBottom` prop to true to start opting into the new styles, which will become the default in a future version',
488
+ } );
489
+ }
490
+
480
491
  return (
481
- <BaseControl { ...controlProps }>
492
+ <BaseControl
493
+ __nextHasNoMarginBottom={ __nextHasNoMarginBottom }
494
+ { ...controlProps }
495
+ >
482
496
  <input { ...inputProps } />
483
497
  { loading && <Spinner /> }
484
498
  </BaseControl>
@@ -31,6 +31,7 @@ export default function LinkEditor( {
31
31
  { ...props }
32
32
  >
33
33
  <URLInput
34
+ __nextHasNoMarginBottom
34
35
  value={ value }
35
36
  onChange={ onChangeInputValue }
36
37
  autocompleteRef={ autocompleteRef }
@@ -0,0 +1,230 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { useCallback } from '@wordpress/element';
5
+ import { getBlockType, parse } from '@wordpress/blocks';
6
+ import { useDispatch, useRegistry } from '@wordpress/data';
7
+ import { store as noticesStore } from '@wordpress/notices';
8
+ import { __, sprintf } from '@wordpress/i18n';
9
+
10
+ /**
11
+ * Internal dependencies
12
+ */
13
+ import { store as blockEditorStore } from '../../store';
14
+ import {
15
+ hasAlignSupport,
16
+ hasBorderSupport,
17
+ hasBackgroundColorSupport,
18
+ hasTextColorSupport,
19
+ hasGradientSupport,
20
+ hasCustomClassNameSupport,
21
+ hasFontFamilySupport,
22
+ hasFontSizeSupport,
23
+ hasLayoutSupport,
24
+ hasStyleSupport,
25
+ } from '../../hooks/supports';
26
+
27
+ /**
28
+ * Determine if the copied text looks like serialized blocks or not.
29
+ * Since plain text will always get parsed into a freeform block,
30
+ * we check that if the parsed blocks is anything other than that.
31
+ *
32
+ * @param {string} text The copied text.
33
+ * @return {boolean} True if the text looks like serialized blocks, false otherwise.
34
+ */
35
+ function hasSerializedBlocks( text ) {
36
+ try {
37
+ const blocks = parse( text, {
38
+ __unstableSkipMigrationLogs: true,
39
+ __unstableSkipAutop: true,
40
+ } );
41
+ if ( blocks.length === 1 && blocks[ 0 ].name === 'core/freeform' ) {
42
+ // It's likely that the text is just plain text and not serialized blocks.
43
+ return false;
44
+ }
45
+ return true;
46
+ } catch ( err ) {
47
+ // Parsing error, the text is not serialized blocks.
48
+ // (Even though that it technically won't happen)
49
+ return false;
50
+ }
51
+ }
52
+
53
+ /**
54
+ * Style attributes are attributes being added in `block-editor/src/hooks/*`.
55
+ * (Except for some unrelated to style like `anchor` or `settings`.)
56
+ * They generally represent the default block supports.
57
+ */
58
+ const STYLE_ATTRIBUTES = {
59
+ align: hasAlignSupport,
60
+ borderColor: ( nameOrType ) => hasBorderSupport( nameOrType, 'color' ),
61
+ backgroundColor: hasBackgroundColorSupport,
62
+ textColor: hasTextColorSupport,
63
+ gradient: hasGradientSupport,
64
+ className: hasCustomClassNameSupport,
65
+ fontFamily: hasFontFamilySupport,
66
+ fontSize: hasFontSizeSupport,
67
+ layout: hasLayoutSupport,
68
+ style: hasStyleSupport,
69
+ };
70
+
71
+ /**
72
+ * Get the "style attributes" from a given block to a target block.
73
+ *
74
+ * @param {WPBlock} sourceBlock The source block.
75
+ * @param {WPBlock} targetBlock The target block.
76
+ * @return {Object} the filtered attributes object.
77
+ */
78
+ function getStyleAttributes( sourceBlock, targetBlock ) {
79
+ return Object.entries( STYLE_ATTRIBUTES ).reduce(
80
+ ( attributes, [ attributeKey, hasSupport ] ) => {
81
+ // Only apply the attribute if both blocks support it.
82
+ if (
83
+ hasSupport( sourceBlock.name ) &&
84
+ hasSupport( targetBlock.name )
85
+ ) {
86
+ // Override attributes that are not present in the block to their defaults.
87
+ attributes[ attributeKey ] =
88
+ sourceBlock.attributes[ attributeKey ];
89
+ }
90
+ return attributes;
91
+ },
92
+ {}
93
+ );
94
+ }
95
+
96
+ /**
97
+ * Update the target blocks with style attributes recursively.
98
+ *
99
+ * @param {WPBlock[]} targetBlocks The target blocks to be updated.
100
+ * @param {WPBlock[]} sourceBlocks The source blocks to get th style attributes from.
101
+ * @param {Function} updateBlockAttributes The function to update the attributes.
102
+ */
103
+ function recursivelyUpdateBlockAttributes(
104
+ targetBlocks,
105
+ sourceBlocks,
106
+ updateBlockAttributes
107
+ ) {
108
+ for (
109
+ let index = 0;
110
+ index < Math.min( sourceBlocks.length, targetBlocks.length );
111
+ index += 1
112
+ ) {
113
+ updateBlockAttributes(
114
+ targetBlocks[ index ].clientId,
115
+ getStyleAttributes( sourceBlocks[ index ], targetBlocks[ index ] )
116
+ );
117
+
118
+ recursivelyUpdateBlockAttributes(
119
+ targetBlocks[ index ].innerBlocks,
120
+ sourceBlocks[ index ].innerBlocks,
121
+ updateBlockAttributes
122
+ );
123
+ }
124
+ }
125
+
126
+ /**
127
+ * A hook to return a pasteStyles event function for handling pasting styles to blocks.
128
+ *
129
+ * @return {Function} A function to update the styles to the blocks.
130
+ */
131
+ export default function usePasteStyles() {
132
+ const registry = useRegistry();
133
+ const { updateBlockAttributes } = useDispatch( blockEditorStore );
134
+ const { createSuccessNotice, createWarningNotice, createErrorNotice } =
135
+ useDispatch( noticesStore );
136
+
137
+ return useCallback(
138
+ async ( targetBlocks ) => {
139
+ let html = '';
140
+ try {
141
+ // `http:` sites won't have the clipboard property on navigator.
142
+ // (with the exception of localhost.)
143
+ if ( ! window.navigator.clipboard ) {
144
+ createErrorNotice(
145
+ __(
146
+ 'Unable to paste styles. This feature is only available on secure (https) sites in supporting browsers.'
147
+ ),
148
+ { type: 'snackbar' }
149
+ );
150
+ return;
151
+ }
152
+
153
+ html = await window.navigator.clipboard.readText();
154
+ } catch ( error ) {
155
+ // Possibly the permission is denied.
156
+ createErrorNotice(
157
+ __(
158
+ 'Unable to paste styles. Please allow browser clipboard permissions before continuing.'
159
+ ),
160
+ {
161
+ type: 'snackbar',
162
+ }
163
+ );
164
+ return;
165
+ }
166
+
167
+ // Abort if the copied text is empty or doesn't look like serialized blocks.
168
+ if ( ! html || ! hasSerializedBlocks( html ) ) {
169
+ createWarningNotice(
170
+ __(
171
+ "Unable to paste styles. Block styles couldn't be found within the copied content."
172
+ ),
173
+ {
174
+ type: 'snackbar',
175
+ }
176
+ );
177
+ return;
178
+ }
179
+
180
+ const copiedBlocks = parse( html );
181
+
182
+ if ( copiedBlocks.length === 1 ) {
183
+ // Apply styles of the block to all the target blocks.
184
+ registry.batch( () => {
185
+ recursivelyUpdateBlockAttributes(
186
+ targetBlocks,
187
+ targetBlocks.map( () => copiedBlocks[ 0 ] ),
188
+ updateBlockAttributes
189
+ );
190
+ } );
191
+ } else {
192
+ registry.batch( () => {
193
+ recursivelyUpdateBlockAttributes(
194
+ targetBlocks,
195
+ copiedBlocks,
196
+ updateBlockAttributes
197
+ );
198
+ } );
199
+ }
200
+
201
+ if ( targetBlocks.length === 1 ) {
202
+ const title = getBlockType( targetBlocks[ 0 ].name )?.title;
203
+ createSuccessNotice(
204
+ sprintf(
205
+ // Translators: Name of the block being pasted, e.g. "Paragraph".
206
+ __( 'Pasted styles to %s.' ),
207
+ title
208
+ ),
209
+ { type: 'snackbar' }
210
+ );
211
+ } else {
212
+ createSuccessNotice(
213
+ sprintf(
214
+ // Translators: The number of the blocks.
215
+ __( 'Pasted styles to %d blocks.' ),
216
+ targetBlocks.length
217
+ ),
218
+ { type: 'snackbar' }
219
+ );
220
+ }
221
+ },
222
+ [
223
+ registry.batch,
224
+ updateBlockAttributes,
225
+ createSuccessNotice,
226
+ createWarningNotice,
227
+ createErrorNotice,
228
+ ]
229
+ );
230
+ }
@@ -167,6 +167,12 @@ export default function useArrowNav() {
167
167
  }
168
168
 
169
169
  function onKeyDown( event ) {
170
+ // Abort if navigation has already been handled (e.g. RichText
171
+ // inline boundaries).
172
+ if ( event.defaultPrevented ) {
173
+ return;
174
+ }
175
+
170
176
  const { keyCode, target, shiftKey, ctrlKey, altKey, metaKey } =
171
177
  event;
172
178
  const isUp = keyCode === UP;
@@ -182,24 +188,20 @@ export default function useArrowNav() {
182
188
  const { ownerDocument } = node;
183
189
  const { defaultView } = ownerDocument;
184
190
 
191
+ if ( ! isNav ) {
192
+ return;
193
+ }
194
+
185
195
  // If there is a multi-selection, the arrow keys should collapse the
186
196
  // selection to the start or end of the selection.
187
197
  if ( hasMultiSelection() ) {
188
- // Only handle if we have a full selection (not a native partial
189
- // selection).
190
- if ( ! __unstableIsFullySelected() ) {
191
- return;
192
- }
193
-
194
- if ( event.defaultPrevented ) {
195
- return;
196
- }
197
-
198
- if ( ! isNav ) {
198
+ if ( shiftKey ) {
199
199
  return;
200
200
  }
201
201
 
202
- if ( shiftKey ) {
202
+ // Only handle if we have a full selection (not a native partial
203
+ // selection).
204
+ if ( ! __unstableIsFullySelected() ) {
203
205
  return;
204
206
  }
205
207
 
@@ -214,6 +216,12 @@ export default function useArrowNav() {
214
216
  return;
215
217
  }
216
218
 
219
+ // Abort if our current target is not a candidate for navigation
220
+ // (e.g. preserve native input behaviors).
221
+ if ( ! isNavigationCandidate( target, keyCode, hasModifier ) ) {
222
+ return;
223
+ }
224
+
217
225
  // When presing any key other than up or down, the initial vertical
218
226
  // position must ALWAYS be reset. The vertical position is saved so
219
227
  // it can be restored as well as possible on sebsequent vertical
@@ -227,22 +235,6 @@ export default function useArrowNav() {
227
235
  verticalRect = computeCaretRect( defaultView );
228
236
  }
229
237
 
230
- // Abort if navigation has already been handled (e.g. RichText
231
- // inline boundaries).
232
- if ( event.defaultPrevented ) {
233
- return;
234
- }
235
-
236
- if ( ! isNav ) {
237
- return;
238
- }
239
-
240
- // Abort if our current target is not a candidate for navigation
241
- // (e.g. preserve native input behaviors).
242
- if ( ! isNavigationCandidate( target, keyCode, hasModifier ) ) {
243
- return;
244
- }
245
-
246
238
  // In the case of RTL scripts, right means previous and left means
247
239
  // next, which is the exact reverse of LTR.
248
240
  const isReverseDir = isRTL( target ) ? ! isReverse : isReverse;
package/src/content.scss CHANGED
@@ -3,6 +3,7 @@
3
3
  @import "./components/block-content-overlay/content.scss";
4
4
  @import "./components/block-draggable/content.scss";
5
5
  @import "./components/block-preview/content.scss";
6
+ @import "./components/button-block-appender/content.scss";
6
7
  @import "./components/default-block-appender/content.scss";
7
8
  @import "./components/inner-blocks/content.scss";
8
9
  @import "./components/media-placeholder/content.scss";
@@ -14,6 +14,7 @@ import './color';
14
14
  import './duotone';
15
15
  import './font-size';
16
16
  import './border';
17
+ import './position';
17
18
  import './layout';
18
19
  import './content-lock-ui';
19
20
  import './metadata';
@@ -27,8 +27,7 @@ export function addMetaAttribute( blockTypeSettings ) {
27
27
 
28
28
  const supportsBlockNaming = hasBlockMetadataSupport(
29
29
  blockTypeSettings,
30
- 'name',
31
- false
30
+ 'name'
32
31
  );
33
32
 
34
33
  if ( supportsBlockNaming ) {