@wordpress/block-editor 6.1.12 → 6.1.15

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 (55) hide show
  1. package/README.md +100 -98
  2. package/build/components/block-list/head.js +27 -0
  3. package/build/components/block-list/head.js.map +1 -0
  4. package/build/components/block-list/index.js +4 -2
  5. package/build/components/block-list/index.js.map +1 -1
  6. package/build/components/iframe/index.js +34 -5
  7. package/build/components/iframe/index.js.map +1 -1
  8. package/build/components/rich-text/use-input-rules.js +5 -2
  9. package/build/components/rich-text/use-input-rules.js.map +1 -1
  10. package/build/components/use-setting/index.js +1 -1
  11. package/build/components/use-setting/index.js.map +1 -1
  12. package/build/components/writing-flow/index.js +27 -14
  13. package/build/components/writing-flow/index.js.map +1 -1
  14. package/build/components/writing-flow/use-select-all.js +36 -34
  15. package/build/components/writing-flow/use-select-all.js.map +1 -1
  16. package/build/components/writing-flow/use-tab-nav.js +8 -0
  17. package/build/components/writing-flow/use-tab-nav.js.map +1 -1
  18. package/build/hooks/duotone.js +5 -2
  19. package/build/hooks/duotone.js.map +1 -1
  20. package/build/hooks/layout.js +5 -2
  21. package/build/hooks/layout.js.map +1 -1
  22. package/build-module/components/block-list/head.js +19 -0
  23. package/build-module/components/block-list/head.js.map +1 -0
  24. package/build-module/components/block-list/index.js +3 -2
  25. package/build-module/components/block-list/index.js.map +1 -1
  26. package/build-module/components/iframe/index.js +34 -5
  27. package/build-module/components/iframe/index.js.map +1 -1
  28. package/build-module/components/rich-text/use-input-rules.js +5 -2
  29. package/build-module/components/rich-text/use-input-rules.js.map +1 -1
  30. package/build-module/components/use-setting/index.js +1 -1
  31. package/build-module/components/use-setting/index.js.map +1 -1
  32. package/build-module/components/writing-flow/index.js +23 -12
  33. package/build-module/components/writing-flow/index.js.map +1 -1
  34. package/build-module/components/writing-flow/use-select-all.js +30 -28
  35. package/build-module/components/writing-flow/use-select-all.js.map +1 -1
  36. package/build-module/components/writing-flow/use-tab-nav.js +8 -0
  37. package/build-module/components/writing-flow/use-tab-nav.js.map +1 -1
  38. package/build-module/hooks/duotone.js +5 -2
  39. package/build-module/hooks/duotone.js.map +1 -1
  40. package/build-module/hooks/layout.js +5 -2
  41. package/build-module/hooks/layout.js.map +1 -1
  42. package/build-style/style-rtl.css +1 -1
  43. package/build-style/style.css +1 -1
  44. package/package.json +23 -23
  45. package/src/components/block-list/head.js +18 -0
  46. package/src/components/block-list/index.js +21 -18
  47. package/src/components/block-list-appender/style.scss +3 -4
  48. package/src/components/iframe/index.js +39 -7
  49. package/src/components/rich-text/use-input-rules.js +4 -2
  50. package/src/components/use-setting/index.js +1 -1
  51. package/src/components/writing-flow/index.js +23 -10
  52. package/src/components/writing-flow/use-select-all.js +33 -35
  53. package/src/components/writing-flow/use-tab-nav.js +8 -0
  54. package/src/hooks/duotone.js +13 -5
  55. package/src/hooks/layout.js +12 -4
@@ -0,0 +1,18 @@
1
+ /**
2
+ * WordPress dependencies
3
+ */
4
+ import { createContext, useState } from '@wordpress/element';
5
+
6
+ const context = createContext();
7
+
8
+ export function Head( { children } ) {
9
+ const [ element, setElement ] = useState();
10
+ return (
11
+ <context.Provider value={ element }>
12
+ <div ref={ setElement } />
13
+ { children }
14
+ </context.Provider>
15
+ );
16
+ }
17
+
18
+ Head.context = context;
@@ -22,6 +22,7 @@ import { usePreParsePatterns } from '../../utils/pre-parse-patterns';
22
22
  import { LayoutProvider, defaultLayout } from './layout';
23
23
  import BlockToolsBackCompat from '../block-tools/back-compat';
24
24
  import { useBlockSelectionClearer } from '../block-selection-clearer';
25
+ import { Head } from './head';
25
26
 
26
27
  export const IntersectionObserver = createContext();
27
28
 
@@ -42,24 +43,26 @@ function Root( { className, children } ) {
42
43
  []
43
44
  );
44
45
  return (
45
- <div
46
- ref={ useMergeRefs( [
47
- useBlockSelectionClearer(),
48
- useBlockDropZone(),
49
- useInBetweenInserter(),
50
- ] ) }
51
- className={ classnames(
52
- 'block-editor-block-list__layout is-root-container',
53
- className,
54
- {
55
- 'is-outline-mode': isOutlineMode,
56
- 'is-focus-mode': isFocusMode && isLargeViewport,
57
- 'is-navigate-mode': isNavigationMode,
58
- }
59
- ) }
60
- >
61
- { children }
62
- </div>
46
+ <Head>
47
+ <div
48
+ ref={ useMergeRefs( [
49
+ useBlockSelectionClearer(),
50
+ useBlockDropZone(),
51
+ useInBetweenInserter(),
52
+ ] ) }
53
+ className={ classnames(
54
+ 'block-editor-block-list__layout is-root-container',
55
+ className,
56
+ {
57
+ 'is-outline-mode': isOutlineMode,
58
+ 'is-focus-mode': isFocusMode && isLargeViewport,
59
+ 'is-navigate-mode': isNavigationMode,
60
+ }
61
+ ) }
62
+ >
63
+ { children }
64
+ </div>
65
+ </Head>
63
66
  );
64
67
  }
65
68
 
@@ -14,10 +14,9 @@
14
14
  margin: $grid-unit-10 0;
15
15
  }
16
16
 
17
- // Add an explicit left margin of zero and auto right margin to work in horizontal
18
- // flex containers. Without it, a "space-between"-like effect from two auto margins
19
- // will cause the black plus to sit in the center of what space is left.
20
- margin: 0 auto 0 0;
17
+ // Add a uniform margin around the block.
18
+ // This can hopefully avoid havoc in flex containers.
19
+ margin: $grid-unit-10;
21
20
 
22
21
  // Black square plus appender.
23
22
  .block-list-appender__toggle {
@@ -49,6 +49,19 @@ function styleSheetsCompat( doc ) {
49
49
  return;
50
50
  }
51
51
 
52
+ // Generally, ignore inline styles. We add inline styles belonging to a
53
+ // stylesheet later, which may or may not match the selectors.
54
+ if ( ownerNode.tagName !== 'LINK' ) {
55
+ return;
56
+ }
57
+
58
+ // Don't try to add the reset styles, which were removed as a dependency
59
+ // from `edit-blocks` for the iframe since we don't need to reset admin
60
+ // styles.
61
+ if ( ownerNode.id === 'wp-reset-editor-styles-css' ) {
62
+ return;
63
+ }
64
+
52
65
  const isMatch = Array.from( cssRules ).find(
53
66
  ( { selectorText } ) =>
54
67
  selectorText &&
@@ -62,9 +75,17 @@ function styleSheetsCompat( doc ) {
62
75
  `Stylesheet ${ ownerNode.id } was not properly added.
63
76
  For blocks, use the block API's style (https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#style) or editorStyle (https://developer.wordpress.org/block-editor/reference-guides/block-api/block-metadata/#editor-style).
64
77
  For themes, use add_editor_style (https://developer.wordpress.org/block-editor/how-to-guides/themes/theme-support/#editor-styles).`,
65
- ownerNode
78
+ ownerNode.outerHTML
66
79
  );
67
80
  doc.head.appendChild( ownerNode.cloneNode( true ) );
81
+
82
+ // Add inline styles belonging to the stylesheet.
83
+ const inlineCssId = ownerNode.id.replace( '-css', '-inline-css' );
84
+ const inlineCssElement = document.getElementById( inlineCssId );
85
+
86
+ if ( inlineCssElement ) {
87
+ doc.head.appendChild( inlineCssElement.cloneNode( true ) );
88
+ }
68
89
  }
69
90
  } );
70
91
  }
@@ -232,12 +253,23 @@ function Iframe( { contentRef, children, head, ...props }, ref ) {
232
253
  head = (
233
254
  <>
234
255
  <style>{ 'body{margin:0}' }</style>
235
- { styles.map( ( { tagName, href, id, rel, media }, index ) => {
236
- const TagName = tagName.toLowerCase();
237
- return (
238
- <TagName { ...{ href, id, rel, media } } key={ index } />
239
- );
240
- } ) }
256
+ { styles.map(
257
+ ( { tagName, href, id, rel, media, textContent } ) => {
258
+ const TagName = tagName.toLowerCase();
259
+
260
+ if ( TagName === 'style' ) {
261
+ return (
262
+ <TagName { ...{ id } } key={ id }>
263
+ { textContent }
264
+ </TagName>
265
+ );
266
+ }
267
+
268
+ return (
269
+ <TagName { ...{ href, id, rel, media } } key={ id } />
270
+ );
271
+ }
272
+ ) }
241
273
  { head }
242
274
  </>
243
275
  );
@@ -60,7 +60,7 @@ export function useInputRules( props ) {
60
60
  }
61
61
 
62
62
  function onInput( event ) {
63
- const { inputType } = event;
63
+ const { inputType, type } = event;
64
64
  const {
65
65
  value,
66
66
  onChange,
@@ -69,7 +69,7 @@ export function useInputRules( props ) {
69
69
  } = propsRef.current;
70
70
 
71
71
  // Only run input rules when inserting text.
72
- if ( inputType !== 'insertText' ) {
72
+ if ( inputType !== 'insertText' && type !== 'compositionend' ) {
73
73
  return;
74
74
  }
75
75
 
@@ -99,8 +99,10 @@ export function useInputRules( props ) {
99
99
  }
100
100
 
101
101
  element.addEventListener( 'input', onInput );
102
+ element.addEventListener( 'compositionend', onInput );
102
103
  return () => {
103
104
  element.removeEventListener( 'input', onInput );
105
+ element.removeEventListener( 'compositionend', onInput );
104
106
  };
105
107
  }, [] );
106
108
  }
@@ -41,7 +41,7 @@ const deprecatedFlags = {
41
41
  }
42
42
 
43
43
  if ( settings.enableCustomUnits === true ) {
44
- return [ 'px', 'em', 'rem', 'vh', 'vw' ];
44
+ return [ 'px', 'em', 'rem', 'vh', 'vw', '%' ];
45
45
  }
46
46
 
47
47
  return settings.enableCustomUnits;
@@ -1,9 +1,15 @@
1
+ /**
2
+ * External dependencies
3
+ */
4
+ import classNames from 'classnames';
5
+
1
6
  /**
2
7
  * WordPress dependencies
3
8
  */
4
9
  import { useSelect } from '@wordpress/data';
5
10
  import { __ } from '@wordpress/i18n';
6
11
  import { useMergeRefs } from '@wordpress/compose';
12
+ import { forwardRef } from '@wordpress/element';
7
13
 
8
14
  /**
9
15
  * Internal dependencies
@@ -14,14 +20,7 @@ import useArrowNav from './use-arrow-nav';
14
20
  import useSelectAll from './use-select-all';
15
21
  import { store as blockEditorStore } from '../../store';
16
22
 
17
- /**
18
- * Handles selection and navigation across blocks. This component should be
19
- * wrapped around BlockList.
20
- *
21
- * @param {Object} props Component properties.
22
- * @param {WPElement} props.children Children to be rendered.
23
- */
24
- export default function WritingFlow( { children } ) {
23
+ function WritingFlow( { children, ...props }, forwardedRef ) {
25
24
  const [ before, ref, after ] = useTabNav();
26
25
  const hasMultiSelection = useSelect(
27
26
  ( select ) => select( blockEditorStore ).hasMultiSelection(),
@@ -31,14 +30,19 @@ export default function WritingFlow( { children } ) {
31
30
  <>
32
31
  { before }
33
32
  <div
33
+ { ...props }
34
34
  ref={ useMergeRefs( [
35
+ forwardedRef,
35
36
  ref,
36
37
  useMultiSelection(),
37
38
  useSelectAll(),
38
39
  useArrowNav(),
39
40
  ] ) }
40
- className="block-editor-writing-flow"
41
- tabIndex={ hasMultiSelection ? '0' : undefined }
41
+ className={ classNames(
42
+ props.className,
43
+ 'block-editor-writing-flow'
44
+ ) }
45
+ tabIndex={ -1 }
42
46
  aria-label={
43
47
  hasMultiSelection
44
48
  ? __( 'Multiple selected blocks' )
@@ -51,3 +55,12 @@ export default function WritingFlow( { children } ) {
51
55
  </>
52
56
  );
53
57
  }
58
+
59
+ /**
60
+ * Handles selection and navigation across blocks. This component should be
61
+ * wrapped around BlockList.
62
+ *
63
+ * @param {Object} props Component properties.
64
+ * @param {WPElement} props.children Children to be rendered.
65
+ */
66
+ export default forwardRef( WritingFlow );
@@ -7,9 +7,9 @@ import { first, last } from 'lodash';
7
7
  * WordPress dependencies
8
8
  */
9
9
  import { isEntirelySelected } from '@wordpress/dom';
10
- import { useRef, useCallback } from '@wordpress/element';
11
10
  import { useSelect, useDispatch } from '@wordpress/data';
12
- import { useShortcut } from '@wordpress/keyboard-shortcuts';
11
+ import { __unstableUseShortcutEventMatch as useShortcutEventMatch } from '@wordpress/keyboard-shortcuts';
12
+ import { useRefEffect } from '@wordpress/compose';
13
13
 
14
14
  /**
15
15
  * Internal dependencies
@@ -17,54 +17,52 @@ import { useShortcut } from '@wordpress/keyboard-shortcuts';
17
17
  import { store as blockEditorStore } from '../../store';
18
18
 
19
19
  export default function useSelectAll() {
20
- const ref = useRef();
21
20
  const {
22
21
  getBlockOrder,
23
22
  getSelectedBlockClientIds,
24
23
  getBlockRootClientId,
25
24
  } = useSelect( blockEditorStore );
26
25
  const { multiSelect } = useDispatch( blockEditorStore );
26
+ const isMatch = useShortcutEventMatch();
27
27
 
28
- const callback = useCallback( ( event ) => {
29
- const selectedClientIds = getSelectedBlockClientIds();
28
+ return useRefEffect( ( node ) => {
29
+ function onKeyDown( event ) {
30
+ if ( ! isMatch( 'core/block-editor/select-all', event ) ) {
31
+ return;
32
+ }
30
33
 
31
- if ( ! selectedClientIds.length ) {
32
- return;
33
- }
34
+ if ( ! isEntirelySelected( event.target ) ) {
35
+ return;
36
+ }
34
37
 
35
- if (
36
- selectedClientIds.length === 1 &&
37
- ! isEntirelySelected( event.target )
38
- ) {
39
- return;
40
- }
38
+ const selectedClientIds = getSelectedBlockClientIds();
39
+ const [ firstSelectedClientId ] = selectedClientIds;
40
+ const rootClientId = getBlockRootClientId( firstSelectedClientId );
41
+ let blockClientIds = getBlockOrder( rootClientId );
41
42
 
42
- const [ firstSelectedClientId ] = selectedClientIds;
43
- const rootClientId = getBlockRootClientId( firstSelectedClientId );
44
- let blockClientIds = getBlockOrder( rootClientId );
43
+ // If we have selected all sibling nested blocks, try selecting up a
44
+ // level. See: https://github.com/WordPress/gutenberg/pull/31859/
45
+ if ( selectedClientIds.length === blockClientIds.length ) {
46
+ blockClientIds = getBlockOrder(
47
+ getBlockRootClientId( rootClientId )
48
+ );
49
+ }
45
50
 
46
- // If we have selected all sibling nested blocks, try selecting up a
47
- // level. See: https://github.com/WordPress/gutenberg/pull/31859/
48
- if ( selectedClientIds.length === blockClientIds.length ) {
49
- blockClientIds = getBlockOrder(
50
- getBlockRootClientId( rootClientId )
51
- );
52
- }
51
+ const firstClientId = first( blockClientIds );
52
+ const lastClientId = last( blockClientIds );
53
53
 
54
- const firstClientId = first( blockClientIds );
55
- const lastClientId = last( blockClientIds );
54
+ if ( firstClientId === lastClientId ) {
55
+ return;
56
+ }
56
57
 
57
- if ( firstClientId === lastClientId ) {
58
- return;
58
+ multiSelect( firstClientId, lastClientId );
59
+ event.preventDefault();
59
60
  }
60
61
 
61
- multiSelect( firstClientId, lastClientId );
62
- event.preventDefault();
63
- }, [] );
62
+ node.addEventListener( 'keydown', onKeyDown );
64
63
 
65
- useShortcut( 'core/block-editor/select-all', callback, {
66
- target: ref,
64
+ return () => {
65
+ node.removeEventListener( 'keydown', onKeyDown );
66
+ };
67
67
  } );
68
-
69
- return ref;
70
68
  }
@@ -84,6 +84,7 @@ export default function useTabNav() {
84
84
  function onKeyDown( event ) {
85
85
  if ( event.keyCode === ESCAPE && ! hasMultiSelection() ) {
86
86
  event.stopPropagation();
87
+ event.preventDefault();
87
88
  setNavigationMode( true );
88
89
  return;
89
90
  }
@@ -102,6 +103,13 @@ export default function useTabNav() {
102
103
  const direction = isShift ? 'findPrevious' : 'findNext';
103
104
 
104
105
  if ( ! hasMultiSelection() && ! getSelectedBlockClientId() ) {
106
+ // Preserve the behaviour of entering navigation mode when
107
+ // tabbing into the content without a block selection.
108
+ // `onFocusCapture` already did this previously, but we need to
109
+ // do it again here because after clearing block selection,
110
+ // focus land on the writing flow container and pressing Tab
111
+ // will no longer send focus through the focus capture element.
112
+ if ( event.target === node ) setNavigationMode( true );
105
113
  return;
106
114
  }
107
115
 
@@ -11,6 +11,7 @@ import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks';
11
11
  import { SVG } from '@wordpress/components';
12
12
  import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
13
13
  import { addFilter } from '@wordpress/hooks';
14
+ import { useContext, createPortal } from '@wordpress/element';
14
15
 
15
16
  /**
16
17
  * Internal dependencies
@@ -20,6 +21,7 @@ import {
20
21
  __experimentalDuotoneControl as DuotoneControl,
21
22
  useSetting,
22
23
  } from '../components';
24
+ import { Head } from '../components/block-list/head';
23
25
 
24
26
  const EMPTY_ARRAY = [];
25
27
 
@@ -236,13 +238,19 @@ const withDuotoneStyles = createHigherOrderComponent(
236
238
 
237
239
  const className = classnames( props?.className, id );
238
240
 
241
+ const element = useContext( Head.context );
242
+
239
243
  return (
240
244
  <>
241
- <DuotoneFilter
242
- selector={ selectorsGroup }
243
- id={ id }
244
- values={ getValuesFromColors( values ) }
245
- />
245
+ { element &&
246
+ createPortal(
247
+ <DuotoneFilter
248
+ selector={ selectorsGroup }
249
+ id={ id }
250
+ values={ getValuesFromColors( values ) }
251
+ />,
252
+ element
253
+ ) }
246
254
  <BlockListBlock { ...props } className={ className } />
247
255
  </>
248
256
  );
@@ -20,6 +20,7 @@ import {
20
20
  } from '@wordpress/components';
21
21
  import { __ } from '@wordpress/i18n';
22
22
  import { Icon, positionCenter, stretchWide } from '@wordpress/icons';
23
+ import { useContext, createPortal } from '@wordpress/element';
23
24
 
24
25
  /**
25
26
  * Internal dependencies
@@ -28,6 +29,7 @@ import { store as blockEditorStore } from '../store';
28
29
  import { InspectorControls } from '../components';
29
30
  import useSetting from '../components/use-setting';
30
31
  import { LayoutStyle } from '../components/block-list/layout';
32
+ import { Head } from '../components/block-list/head';
31
33
 
32
34
  function LayoutPanel( { setAttributes, attributes } ) {
33
35
  const { layout = {} } = attributes;
@@ -207,12 +209,18 @@ export const withLayoutStyles = createHigherOrderComponent(
207
209
  `wp-container-${ id }`
208
210
  );
209
211
 
212
+ const element = useContext( Head.context );
213
+
210
214
  return (
211
215
  <>
212
- <LayoutStyle
213
- selector={ `.wp-container-${ id }` }
214
- layout={ usedLayout }
215
- />
216
+ { element &&
217
+ createPortal(
218
+ <LayoutStyle
219
+ selector={ `.wp-container-${ id }` }
220
+ layout={ usedLayout }
221
+ />,
222
+ element
223
+ ) }
216
224
  <BlockListBlock { ...props } className={ className } />
217
225
  </>
218
226
  );