@wordpress/block-editor 10.0.0 → 10.0.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 (145) hide show
  1. package/build/components/autocomplete/index.js +2 -2
  2. package/build/components/autocomplete/index.js.map +1 -1
  3. package/build/components/block-inspector/index.js +1 -1
  4. package/build/components/block-inspector/index.js.map +1 -1
  5. package/build/components/block-list/block-list-compact.native.js +2 -1
  6. package/build/components/block-list/block-list-compact.native.js.map +1 -1
  7. package/build/components/block-list/block.js +1 -1
  8. package/build/components/block-list/block.js.map +1 -1
  9. package/build/components/block-lock/use-block-lock.js +1 -1
  10. package/build/components/block-lock/use-block-lock.js.map +1 -1
  11. package/build/components/block-popover/inbetween.js +37 -49
  12. package/build/components/block-popover/inbetween.js.map +1 -1
  13. package/build/components/block-popover/index.js +28 -5
  14. package/build/components/block-popover/index.js.map +1 -1
  15. package/build/components/border-radius-control/linked-button.js +5 -6
  16. package/build/components/border-radius-control/linked-button.js.map +1 -1
  17. package/build/components/convert-to-group-buttons/toolbar.js +8 -3
  18. package/build/components/convert-to-group-buttons/toolbar.js.map +1 -1
  19. package/build/components/inner-blocks/index.js +7 -1
  20. package/build/components/inner-blocks/index.js.map +1 -1
  21. package/build/components/inner-blocks/use-inner-block-template-sync.js +27 -16
  22. package/build/components/inner-blocks/use-inner-block-template-sync.js.map +1 -1
  23. package/build/components/inner-blocks/use-nested-settings-update.js +28 -4
  24. package/build/components/inner-blocks/use-nested-settings-update.js.map +1 -1
  25. package/build/components/list-view/branch.js +1 -1
  26. package/build/components/list-view/branch.js.map +1 -1
  27. package/build/components/list-view/drop-indicator.js +30 -28
  28. package/build/components/list-view/drop-indicator.js.map +1 -1
  29. package/build/components/rich-text/format-toolbar-container.js +9 -9
  30. package/build/components/rich-text/format-toolbar-container.js.map +1 -1
  31. package/build/components/rich-text/index.js +4 -2
  32. package/build/components/rich-text/index.js.map +1 -1
  33. package/build/components/spacing-sizes-control/linked-button.js +2 -3
  34. package/build/components/spacing-sizes-control/linked-button.js.map +1 -1
  35. package/build/components/spacing-sizes-control/utils.js +1 -4
  36. package/build/components/spacing-sizes-control/utils.js.map +1 -1
  37. package/build/components/text-decoration-control/index.js +19 -15
  38. package/build/components/text-decoration-control/index.js.map +1 -1
  39. package/build/components/text-transform-control/index.js +25 -17
  40. package/build/components/text-transform-control/index.js.map +1 -1
  41. package/build/components/url-popover/image-url-input-ui.js +6 -4
  42. package/build/components/url-popover/image-url-input-ui.js.map +1 -1
  43. package/build/components/use-block-drop-zone/index.js +1 -1
  44. package/build/components/use-block-drop-zone/index.js.map +1 -1
  45. package/build/hooks/content-lock-ui.js +3 -3
  46. package/build/hooks/content-lock-ui.js.map +1 -1
  47. package/build/hooks/typography.js +10 -11
  48. package/build/hooks/typography.js.map +1 -1
  49. package/build/layouts/constrained.js +1 -1
  50. package/build/layouts/constrained.js.map +1 -1
  51. package/build/store/reducer.js +4 -1
  52. package/build/store/reducer.js.map +1 -1
  53. package/build/store/selectors.js +2 -2
  54. package/build/store/selectors.js.map +1 -1
  55. package/build-module/components/autocomplete/index.js +2 -2
  56. package/build-module/components/autocomplete/index.js.map +1 -1
  57. package/build-module/components/block-inspector/index.js +1 -1
  58. package/build-module/components/block-inspector/index.js.map +1 -1
  59. package/build-module/components/block-list/block-list-compact.native.js +2 -1
  60. package/build-module/components/block-list/block-list-compact.native.js.map +1 -1
  61. package/build-module/components/block-list/block.js +1 -1
  62. package/build-module/components/block-list/block.js.map +1 -1
  63. package/build-module/components/block-lock/use-block-lock.js +1 -1
  64. package/build-module/components/block-lock/use-block-lock.js.map +1 -1
  65. package/build-module/components/block-popover/inbetween.js +38 -50
  66. package/build-module/components/block-popover/inbetween.js.map +1 -1
  67. package/build-module/components/block-popover/index.js +28 -5
  68. package/build-module/components/block-popover/index.js.map +1 -1
  69. package/build-module/components/border-radius-control/linked-button.js +5 -6
  70. package/build-module/components/border-radius-control/linked-button.js.map +1 -1
  71. package/build-module/components/convert-to-group-buttons/toolbar.js +8 -3
  72. package/build-module/components/convert-to-group-buttons/toolbar.js.map +1 -1
  73. package/build-module/components/inner-blocks/index.js +7 -1
  74. package/build-module/components/inner-blocks/index.js.map +1 -1
  75. package/build-module/components/inner-blocks/use-inner-block-template-sync.js +27 -16
  76. package/build-module/components/inner-blocks/use-inner-block-template-sync.js.map +1 -1
  77. package/build-module/components/inner-blocks/use-nested-settings-update.js +28 -4
  78. package/build-module/components/inner-blocks/use-nested-settings-update.js.map +1 -1
  79. package/build-module/components/list-view/branch.js +1 -1
  80. package/build-module/components/list-view/branch.js.map +1 -1
  81. package/build-module/components/list-view/drop-indicator.js +30 -28
  82. package/build-module/components/list-view/drop-indicator.js.map +1 -1
  83. package/build-module/components/rich-text/format-toolbar-container.js +10 -10
  84. package/build-module/components/rich-text/format-toolbar-container.js.map +1 -1
  85. package/build-module/components/rich-text/index.js +4 -2
  86. package/build-module/components/rich-text/index.js.map +1 -1
  87. package/build-module/components/spacing-sizes-control/linked-button.js +2 -3
  88. package/build-module/components/spacing-sizes-control/linked-button.js.map +1 -1
  89. package/build-module/components/spacing-sizes-control/utils.js +1 -4
  90. package/build-module/components/spacing-sizes-control/utils.js.map +1 -1
  91. package/build-module/components/text-decoration-control/index.js +21 -16
  92. package/build-module/components/text-decoration-control/index.js.map +1 -1
  93. package/build-module/components/text-transform-control/index.js +28 -20
  94. package/build-module/components/text-transform-control/index.js.map +1 -1
  95. package/build-module/components/url-popover/image-url-input-ui.js +6 -4
  96. package/build-module/components/url-popover/image-url-input-ui.js.map +1 -1
  97. package/build-module/components/use-block-drop-zone/index.js +1 -1
  98. package/build-module/components/use-block-drop-zone/index.js.map +1 -1
  99. package/build-module/hooks/content-lock-ui.js +3 -3
  100. package/build-module/hooks/content-lock-ui.js.map +1 -1
  101. package/build-module/hooks/typography.js +10 -11
  102. package/build-module/hooks/typography.js.map +1 -1
  103. package/build-module/layouts/constrained.js +1 -1
  104. package/build-module/layouts/constrained.js.map +1 -1
  105. package/build-module/store/reducer.js +4 -1
  106. package/build-module/store/reducer.js.map +1 -1
  107. package/build-module/store/selectors.js +2 -2
  108. package/build-module/store/selectors.js.map +1 -1
  109. package/build-style/style-rtl.css +49 -3
  110. package/build-style/style.css +49 -3
  111. package/package.json +28 -28
  112. package/src/components/autocomplete/index.js +2 -5
  113. package/src/components/block-inspector/index.js +1 -1
  114. package/src/components/block-list/block-list-compact.native.js +1 -1
  115. package/src/components/block-list/block.js +1 -1
  116. package/src/components/block-list/style.scss +22 -3
  117. package/src/components/block-lock/use-block-lock.js +1 -1
  118. package/src/components/block-popover/inbetween.js +50 -52
  119. package/src/components/block-popover/index.js +44 -6
  120. package/src/components/border-radius-control/linked-button.js +12 -11
  121. package/src/components/convert-to-group-buttons/toolbar.js +6 -2
  122. package/src/components/inner-blocks/README.md +2 -2
  123. package/src/components/inner-blocks/index.js +7 -0
  124. package/src/components/inner-blocks/use-inner-block-template-sync.js +39 -28
  125. package/src/components/inner-blocks/use-nested-settings-update.js +30 -3
  126. package/src/components/list-view/branch.js +1 -1
  127. package/src/components/list-view/drop-indicator.js +33 -32
  128. package/src/components/rich-text/format-toolbar-container.js +18 -10
  129. package/src/components/rich-text/index.js +2 -2
  130. package/src/components/spacing-sizes-control/linked-button.js +2 -3
  131. package/src/components/spacing-sizes-control/style.scss +4 -1
  132. package/src/components/spacing-sizes-control/utils.js +1 -8
  133. package/src/components/text-decoration-control/index.js +31 -23
  134. package/src/components/text-decoration-control/style.scss +18 -0
  135. package/src/components/text-transform-control/index.js +42 -26
  136. package/src/components/text-transform-control/style.scss +18 -0
  137. package/src/components/url-popover/image-url-input-ui.js +5 -3
  138. package/src/components/use-block-drop-zone/index.js +1 -1
  139. package/src/hooks/content-lock-ui.js +3 -3
  140. package/src/hooks/typography.js +13 -14
  141. package/src/layouts/constrained.js +1 -1
  142. package/src/store/reducer.js +3 -0
  143. package/src/store/selectors.js +2 -2
  144. package/src/store/test/selectors.js +4 -4
  145. package/src/style.scss +2 -0
@@ -19,7 +19,7 @@ import { store as blockEditorStore } from '../../store';
19
19
  * This hook makes sure that a block's inner blocks stay in sync with the given
20
20
  * block "template". The template is a block hierarchy to which inner blocks must
21
21
  * conform. If the blocks get "out of sync" with the template and the template
22
- * is meant to be locked (e.g. templateLock = "all" or templateLock = "noContent"),
22
+ * is meant to be locked (e.g. templateLock = "all" or templateLock = "contentOnly"),
23
23
  * then we replace the inner blocks with the correct value after synchronizing it with the template.
24
24
  *
25
25
  * @param {string} clientId The block client ID.
@@ -47,42 +47,53 @@ export default function useInnerBlockTemplateSync(
47
47
  ( select ) => select( blockEditorStore ).getBlocks( clientId ),
48
48
  [ clientId ]
49
49
  );
50
+ const { getBlocks } = useSelect( blockEditorStore );
50
51
 
51
52
  // Maintain a reference to the previous value so we can do a deep equality check.
52
53
  const existingTemplate = useRef( null );
53
54
  useLayoutEffect( () => {
54
- // Only synchronize innerBlocks with template if innerBlocks are empty
55
- // or a locking "all" or "noContent" exists directly on the block.
56
- if (
57
- innerBlocks.length === 0 ||
58
- templateLock === 'all' ||
59
- templateLock === 'noContent'
60
- ) {
55
+ // There's an implicit dependency between useInnerBlockTemplateSync and useNestedSettingsUpdate
56
+ // The former needs to happen after the latter and since the latter is using microtasks to batch updates (performance optimization),
57
+ // we need to schedule this one in a microtask as well.
58
+ // Exemple: If you remove queueMicrotask here, ctrl + click to insert quote block won't close the inserter.
59
+ window.queueMicrotask( () => {
60
+ // Only synchronize innerBlocks with template if innerBlocks are empty
61
+ // or a locking "all" or "contentOnly" exists directly on the block.
62
+ const currentInnerBlocks = getBlocks( clientId );
63
+ const shouldApplyTemplate =
64
+ currentInnerBlocks.length === 0 ||
65
+ templateLock === 'all' ||
66
+ templateLock === 'contentOnly';
67
+
61
68
  const hasTemplateChanged = ! isEqual(
62
69
  template,
63
70
  existingTemplate.current
64
71
  );
65
- if ( hasTemplateChanged ) {
66
- existingTemplate.current = template;
67
- const nextBlocks = synchronizeBlocksWithTemplate(
68
- innerBlocks,
69
- template
72
+
73
+ if ( ! shouldApplyTemplate || ! hasTemplateChanged ) {
74
+ return;
75
+ }
76
+
77
+ existingTemplate.current = template;
78
+ const nextBlocks = synchronizeBlocksWithTemplate(
79
+ currentInnerBlocks,
80
+ template
81
+ );
82
+
83
+ if ( ! isEqual( nextBlocks, currentInnerBlocks ) ) {
84
+ replaceInnerBlocks(
85
+ clientId,
86
+ nextBlocks,
87
+ currentInnerBlocks.length === 0 &&
88
+ templateInsertUpdatesSelection &&
89
+ nextBlocks.length !== 0,
90
+ // This ensures the "initialPosition" doesn't change when applying the template
91
+ // If we're supposed to focus the block, we'll focus the first inner block
92
+ // otherwise, we won't apply any auto-focus.
93
+ // This ensures for instance that the focus stays in the inserter when inserting the "buttons" block.
94
+ getSelectedBlocksInitialCaretPosition()
70
95
  );
71
- if ( ! isEqual( nextBlocks, innerBlocks ) ) {
72
- replaceInnerBlocks(
73
- clientId,
74
- nextBlocks,
75
- innerBlocks.length === 0 &&
76
- templateInsertUpdatesSelection &&
77
- nextBlocks.length !== 0,
78
- // This ensures the "initialPosition" doesn't change when applying the template
79
- // If we're supposed to focus the block, we'll focus the first inner block
80
- // otherwise, we won't apply any auto-focus.
81
- // This ensures for instance that the focus stays in the inserter when inserting the "buttons" block.
82
- getSelectedBlocksInitialCaretPosition()
83
- );
84
- }
85
96
  }
86
- }
97
+ } );
87
98
  }, [ innerBlocks, template, templateLock, clientId ] );
88
99
  }
@@ -2,7 +2,7 @@
2
2
  * WordPress dependencies
3
3
  */
4
4
  import { useLayoutEffect, useMemo } from '@wordpress/element';
5
- import { useSelect, useDispatch } from '@wordpress/data';
5
+ import { useSelect, useDispatch, useRegistry } from '@wordpress/data';
6
6
  import isShallowEqual from '@wordpress/is-shallow-equal';
7
7
 
8
8
  /**
@@ -13,6 +13,8 @@ import { getLayoutType } from '../../layouts';
13
13
 
14
14
  /** @typedef {import('../../selectors').WPDirectInsertBlock } WPDirectInsertBlock */
15
15
 
16
+ const pendingSettingsUpdates = new WeakMap();
17
+
16
18
  /**
17
19
  * This hook is a side effect which updates the block-editor store when changes
18
20
  * happen to inner block settings. The given props are transformed into a
@@ -46,6 +48,7 @@ export default function useNestedSettingsUpdate(
46
48
  layout
47
49
  ) {
48
50
  const { updateBlockListSettings } = useDispatch( blockEditorStore );
51
+ const registry = useRegistry();
49
52
 
50
53
  const { blockListSettings, parentLock } = useSelect(
51
54
  ( select ) => {
@@ -69,7 +72,7 @@ export default function useNestedSettingsUpdate(
69
72
  const newSettings = {
70
73
  allowedBlocks: _allowedBlocks,
71
74
  templateLock:
72
- templateLock === undefined || parentLock === 'noContent'
75
+ templateLock === undefined || parentLock === 'contentOnly'
73
76
  ? parentLock
74
77
  : templateLock,
75
78
  };
@@ -98,7 +101,30 @@ export default function useNestedSettingsUpdate(
98
101
  }
99
102
 
100
103
  if ( ! isShallowEqual( blockListSettings, newSettings ) ) {
101
- updateBlockListSettings( clientId, newSettings );
104
+ // Batch updates to block list settings to avoid triggering cascading renders
105
+ // for each container block included in a tree and optimize initial render.
106
+ // To avoid triggering updateBlockListSettings for each container block
107
+ // causing X re-renderings for X container blocks,
108
+ // we batch all the updatedBlockListSettings in a single "data" batch
109
+ // which results in a single re-render.
110
+ if ( ! pendingSettingsUpdates.get( registry ) ) {
111
+ pendingSettingsUpdates.set( registry, [] );
112
+ }
113
+ pendingSettingsUpdates
114
+ .get( registry )
115
+ .push( [ clientId, newSettings ] );
116
+ window.queueMicrotask( () => {
117
+ if ( pendingSettingsUpdates.get( registry )?.length ) {
118
+ registry.batch( () => {
119
+ pendingSettingsUpdates
120
+ .get( registry )
121
+ .forEach( ( args ) => {
122
+ updateBlockListSettings( ...args );
123
+ } );
124
+ pendingSettingsUpdates.set( registry, [] );
125
+ } );
126
+ }
127
+ } );
102
128
  }
103
129
  }, [
104
130
  clientId,
@@ -112,5 +138,6 @@ export default function useNestedSettingsUpdate(
112
138
  orientation,
113
139
  updateBlockListSettings,
114
140
  layout,
141
+ registry,
115
142
  ] );
116
143
  }
@@ -99,7 +99,7 @@ function ListViewBranch( props ) {
99
99
  return !! (
100
100
  parentId &&
101
101
  select( blockEditorStore ).getTemplateLock( parentId ) ===
102
- 'noContent'
102
+ 'contentOnly'
103
103
  );
104
104
  },
105
105
  [ parentId ]
@@ -68,40 +68,41 @@ export default function ListViewDropIndicator( {
68
68
  };
69
69
  }, [ getDropIndicatorIndent, targetElement ] );
70
70
 
71
- const getAnchorRect = useCallback( () => {
72
- if ( ! targetElement ) {
73
- return {};
71
+ const popoverAnchor = useMemo( () => {
72
+ const isValidDropPosition =
73
+ dropPosition === 'top' ||
74
+ dropPosition === 'bottom' ||
75
+ dropPosition === 'inside';
76
+ if ( ! targetElement || ! isValidDropPosition ) {
77
+ return undefined;
74
78
  }
75
79
 
76
- const ownerDocument = targetElement.ownerDocument;
77
- const rect = targetElement.getBoundingClientRect();
78
- const indent = getDropIndicatorIndent();
79
-
80
- const anchorRect = {
81
- left: rect.left + indent,
82
- right: rect.right,
83
- width: 0,
84
- height: 0,
85
- ownerDocument,
80
+ return {
81
+ ownerDocument: targetElement.ownerDocument,
82
+ getBoundingClientRect() {
83
+ const rect = targetElement.getBoundingClientRect();
84
+ const indent = getDropIndicatorIndent();
85
+
86
+ const left = rect.left + indent;
87
+ const right = rect.right;
88
+ let top = 0;
89
+ let bottom = 0;
90
+
91
+ if ( dropPosition === 'top' ) {
92
+ top = rect.top;
93
+ bottom = rect.top;
94
+ } else {
95
+ // `dropPosition` is either `bottom` or `inside`
96
+ top = rect.bottom;
97
+ bottom = rect.bottom;
98
+ }
99
+
100
+ const width = right - left;
101
+ const height = bottom - top;
102
+
103
+ return new window.DOMRect( left, top, width, height );
104
+ },
86
105
  };
87
-
88
- if ( dropPosition === 'top' ) {
89
- return {
90
- ...anchorRect,
91
- top: rect.top,
92
- bottom: rect.top,
93
- };
94
- }
95
-
96
- if ( dropPosition === 'bottom' || dropPosition === 'inside' ) {
97
- return {
98
- ...anchorRect,
99
- top: rect.bottom,
100
- bottom: rect.bottom,
101
- };
102
- }
103
-
104
- return {};
105
106
  }, [ targetElement, dropPosition, getDropIndicatorIndent ] );
106
107
 
107
108
  if ( ! targetElement ) {
@@ -111,7 +112,7 @@ export default function ListViewDropIndicator( {
111
112
  return (
112
113
  <Popover
113
114
  animate={ false }
114
- getAnchorRect={ getAnchorRect }
115
+ anchor={ popoverAnchor }
115
116
  focusOnMount={ false }
116
117
  className="block-editor-list-view-drop-indicator"
117
118
  >
@@ -6,7 +6,7 @@ import { useSelect } from '@wordpress/data';
6
6
  import {
7
7
  isCollapsed,
8
8
  getActiveFormats,
9
- useAnchorRef,
9
+ useAnchor,
10
10
  store as richTextStore,
11
11
  } from '@wordpress/rich-text';
12
12
 
@@ -17,28 +17,32 @@ import BlockControls from '../block-controls';
17
17
  import FormatToolbar from './format-toolbar';
18
18
  import { store as blockEditorStore } from '../../store';
19
19
 
20
- function InlineSelectionToolbar( { value, anchorRef, activeFormats } ) {
20
+ function InlineSelectionToolbar( {
21
+ value,
22
+ editableContentElement,
23
+ activeFormats,
24
+ } ) {
21
25
  const lastFormat = activeFormats[ activeFormats.length - 1 ];
22
26
  const lastFormatType = lastFormat?.type;
23
27
  const settings = useSelect(
24
28
  ( select ) => select( richTextStore ).getFormatType( lastFormatType ),
25
29
  [ lastFormatType ]
26
30
  );
27
- const selectionRef = useAnchorRef( {
28
- ref: anchorRef,
31
+ const popoverAnchor = useAnchor( {
32
+ editableContentElement,
29
33
  value,
30
34
  settings,
31
35
  } );
32
36
 
33
- return <InlineToolbar anchorRef={ selectionRef } />;
37
+ return <InlineToolbar popoverAnchor={ popoverAnchor } />;
34
38
  }
35
39
 
36
- function InlineToolbar( { anchorRef } ) {
40
+ function InlineToolbar( { popoverAnchor } ) {
37
41
  return (
38
42
  <Popover
39
43
  position="top center"
40
44
  focusOnMount={ false }
41
- anchorRef={ anchorRef }
45
+ anchor={ popoverAnchor }
42
46
  className="block-editor-rich-text__inline-format-toolbar"
43
47
  __unstableSlotName="block-toolbar"
44
48
  >
@@ -51,14 +55,18 @@ function InlineToolbar( { anchorRef } ) {
51
55
  );
52
56
  }
53
57
 
54
- const FormatToolbarContainer = ( { inline, anchorRef, value } ) => {
58
+ const FormatToolbarContainer = ( {
59
+ inline,
60
+ editableContentElement,
61
+ value,
62
+ } ) => {
55
63
  const hasInlineToolbar = useSelect(
56
64
  ( select ) => select( blockEditorStore ).getSettings().hasInlineToolbar,
57
65
  []
58
66
  );
59
67
 
60
68
  if ( inline ) {
61
- return <InlineToolbar anchorRef={ anchorRef } />;
69
+ return <InlineToolbar popoverAnchor={ editableContentElement } />;
62
70
  }
63
71
 
64
72
  if ( hasInlineToolbar ) {
@@ -70,7 +78,7 @@ const FormatToolbarContainer = ( { inline, anchorRef, value } ) => {
70
78
 
71
79
  return (
72
80
  <InlineSelectionToolbar
73
- anchorRef={ anchorRef }
81
+ editableContentElement={ editableContentElement }
74
82
  value={ value }
75
83
  activeFormats={ activeFormats }
76
84
  />
@@ -328,7 +328,7 @@ function RichTextWrapper(
328
328
  }
329
329
 
330
330
  function onFocus() {
331
- anchorRef.current.focus();
331
+ anchorRef.current?.focus();
332
332
  }
333
333
 
334
334
  const TagName = tagName;
@@ -354,7 +354,7 @@ function RichTextWrapper(
354
354
  { isSelected && hasFormats && (
355
355
  <FormatToolbarContainer
356
356
  inline={ inlineToolbar }
357
- anchorRef={ anchorRef }
357
+ editableContentElement={ anchorRef.current }
358
358
  value={ value }
359
359
  />
360
360
  ) }
@@ -6,16 +6,15 @@ import { __ } from '@wordpress/i18n';
6
6
  import { Button, Tooltip } from '@wordpress/components';
7
7
 
8
8
  export default function LinkedButton( { isLinked, onClick } ) {
9
- const label = isLinked ? __( 'Unlink Sides' ) : __( 'Link Sides' );
9
+ const label = isLinked ? __( 'Unlink sides' ) : __( 'Link sides' );
10
10
 
11
11
  return (
12
12
  <Tooltip text={ label }>
13
13
  <span className="component-spacing-sizes-control__linked-button">
14
14
  <Button
15
- variant={ isLinked ? 'primary' : 'secondary' }
16
15
  isSmall
17
16
  icon={ isLinked ? link : linkOff }
18
- iconSize={ 16 }
17
+ iconSize={ 24 }
19
18
  aria-label={ label }
20
19
  onClick={ onClick }
21
20
  />
@@ -46,10 +46,13 @@
46
46
  grid-column: 2 / 2;
47
47
  grid-row: 1 / 1;
48
48
  justify-self: end;
49
- margin-right: $grid-unit-05;
50
49
  padding: 0;
51
50
  }
52
51
 
52
+ .component-spacing-sizes-control__linked-button ~ .components-spacing-sizes-control__custom-toggle-all {
53
+ margin-right: $grid-unit-05;
54
+ }
55
+
53
56
  .components-spacing-sizes-control__custom-toggle-single {
54
57
  grid-column: 3 / 3;
55
58
  justify-self: end;
@@ -211,12 +211,5 @@ export function isValuesDefined( values ) {
211
211
  if ( values === undefined || values === null ) {
212
212
  return false;
213
213
  }
214
- return ! isEmpty(
215
- Object.values( values ).filter(
216
- // Switching units when input is empty causes values only
217
- // containing units. This gives false positive on mixed values
218
- // unless filtered.
219
- ( value ) => !! value && /\d/.test( value )
220
- )
221
- );
214
+ return ! isEmpty( Object.values( values ).filter( ( value ) => !! value ) );
222
215
  }
@@ -6,14 +6,16 @@ import classnames from 'classnames';
6
6
  /**
7
7
  * WordPress dependencies
8
8
  */
9
- import {
10
- __experimentalToggleGroupControl as ToggleGroupControl,
11
- __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon,
12
- } from '@wordpress/components';
13
- import { formatStrikethrough, formatUnderline } from '@wordpress/icons';
9
+ import { BaseControl, Button } from '@wordpress/components';
10
+ import { reset, formatStrikethrough, formatUnderline } from '@wordpress/icons';
14
11
  import { __ } from '@wordpress/i18n';
15
12
 
16
13
  const TEXT_DECORATIONS = [
14
+ {
15
+ name: __( 'None' ),
16
+ value: 'none',
17
+ icon: reset,
18
+ },
17
19
  {
18
20
  name: __( 'Underline' ),
19
21
  value: 'underline',
@@ -40,30 +42,36 @@ export default function TextDecorationControl( {
40
42
  value,
41
43
  onChange,
42
44
  className,
43
- ...props
44
45
  } ) {
45
46
  return (
46
- <ToggleGroupControl
47
- { ...props }
47
+ <fieldset
48
48
  className={ classnames(
49
49
  'block-editor-text-decoration-control',
50
50
  className
51
51
  ) }
52
- __experimentalIsBorderless
53
- label={ __( 'Decoration' ) }
54
- value={ value }
55
- onChange={ onChange }
56
52
  >
57
- { TEXT_DECORATIONS.map( ( textDecoration ) => {
58
- return (
59
- <ToggleGroupControlOptionIcon
60
- key={ textDecoration.value }
61
- value={ textDecoration.value }
62
- icon={ textDecoration.icon }
63
- label={ textDecoration.name }
64
- />
65
- );
66
- } ) }
67
- </ToggleGroupControl>
53
+ <BaseControl.VisualLabel as="legend">
54
+ { __( 'Decoration' ) }
55
+ </BaseControl.VisualLabel>
56
+ <div className="block-editor-text-decoration-control__buttons">
57
+ { TEXT_DECORATIONS.map( ( textDecoration ) => {
58
+ return (
59
+ <Button
60
+ key={ textDecoration.value }
61
+ icon={ textDecoration.icon }
62
+ label={ textDecoration.name }
63
+ isPressed={ textDecoration.value === value }
64
+ onClick={ () => {
65
+ onChange(
66
+ textDecoration.value === value
67
+ ? undefined
68
+ : textDecoration.value
69
+ );
70
+ } }
71
+ />
72
+ );
73
+ } ) }
74
+ </div>
75
+ </fieldset>
68
76
  );
69
77
  }
@@ -0,0 +1,18 @@
1
+ .block-editor-text-decoration-control {
2
+ border: 0;
3
+ margin: 0;
4
+ padding: 0;
5
+
6
+ .block-editor-text-decoration-control__buttons {
7
+ // 4px of padding makes the row 40px high, same as an input.
8
+ padding: $grid-unit-05 0;
9
+ display: flex;
10
+ }
11
+
12
+ .components-button.has-icon {
13
+ height: $grid-unit-40;
14
+ margin-right: $grid-unit-05;
15
+ min-width: $grid-unit-40;
16
+ padding: 0;
17
+ }
18
+ }
@@ -1,21 +1,26 @@
1
1
  /**
2
2
  * External dependencies
3
3
  */
4
+ import classnames from 'classnames';
5
+
4
6
  /**
5
7
  * WordPress dependencies
6
8
  */
7
- import {
8
- __experimentalToggleGroupControl as ToggleGroupControl,
9
- __experimentalToggleGroupControlOptionIcon as ToggleGroupControlOptionIcon,
10
- } from '@wordpress/components';
9
+ import { BaseControl, Button } from '@wordpress/components';
11
10
  import { __ } from '@wordpress/i18n';
12
11
  import {
12
+ reset,
13
13
  formatCapitalize,
14
14
  formatLowercase,
15
15
  formatUppercase,
16
16
  } from '@wordpress/icons';
17
17
 
18
18
  const TEXT_TRANSFORMS = [
19
+ {
20
+ name: __( 'None' ),
21
+ value: 'none',
22
+ icon: reset,
23
+ },
19
24
  {
20
25
  name: __( 'Uppercase' ),
21
26
  value: 'uppercase',
@@ -36,32 +41,43 @@ const TEXT_TRANSFORMS = [
36
41
  /**
37
42
  * Control to facilitate text transform selections.
38
43
  *
39
- * @param {Object} props Component props.
40
- * @param {string} props.value Currently selected text transform.
41
- * @param {Function} props.onChange Handles change in text transform selection.
44
+ * @param {Object} props Component props.
45
+ * @param {string} props.className Class name to add to the control.
46
+ * @param {string} props.value Currently selected text transform.
47
+ * @param {Function} props.onChange Handles change in text transform selection.
42
48
  *
43
49
  * @return {WPElement} Text transform control.
44
50
  */
45
- export default function TextTransformControl( { value, onChange, ...props } ) {
51
+ export default function TextTransformControl( { className, value, onChange } ) {
46
52
  return (
47
- <ToggleGroupControl
48
- { ...props }
49
- className="block-editor-text-transform-control"
50
- __experimentalIsBorderless
51
- label={ __( 'Letter case' ) }
52
- value={ value }
53
- onChange={ onChange }
53
+ <fieldset
54
+ className={ classnames(
55
+ 'block-editor-text-transform-control',
56
+ className
57
+ ) }
54
58
  >
55
- { TEXT_TRANSFORMS.map( ( textTransform ) => {
56
- return (
57
- <ToggleGroupControlOptionIcon
58
- key={ textTransform.value }
59
- value={ textTransform.value }
60
- icon={ textTransform.icon }
61
- label={ textTransform.name }
62
- />
63
- );
64
- } ) }
65
- </ToggleGroupControl>
59
+ <BaseControl.VisualLabel as="legend">
60
+ { __( 'Letter case' ) }
61
+ </BaseControl.VisualLabel>
62
+ <div className="block-editor-text-transform-control__buttons">
63
+ { TEXT_TRANSFORMS.map( ( textTransform ) => {
64
+ return (
65
+ <Button
66
+ key={ textTransform.value }
67
+ icon={ textTransform.icon }
68
+ label={ textTransform.name }
69
+ isPressed={ textTransform.value === value }
70
+ onClick={ () => {
71
+ onChange(
72
+ textTransform.value === value
73
+ ? undefined
74
+ : textTransform.value
75
+ );
76
+ } }
77
+ />
78
+ );
79
+ } ) }
80
+ </div>
81
+ </fieldset>
66
82
  );
67
83
  }
@@ -0,0 +1,18 @@
1
+ .block-editor-text-transform-control {
2
+ border: 0;
3
+ margin: 0;
4
+ padding: 0;
5
+
6
+ .block-editor-text-transform-control__buttons {
7
+ // 4px of padding makes the row 40px high, same as an input.
8
+ padding: $grid-unit-05 0;
9
+ display: flex;
10
+ }
11
+
12
+ .components-button.has-icon {
13
+ height: $grid-unit-40;
14
+ margin-right: $grid-unit-05;
15
+ min-width: $grid-unit-40;
16
+ padding: 0;
17
+ }
18
+ }
@@ -51,7 +51,9 @@ const ImageURLInputUI = ( {
51
51
  rel,
52
52
  } ) => {
53
53
  const [ isOpen, setIsOpen ] = useState( false );
54
- const buttonRef = useRef( null );
54
+ // Use internal state instead of a ref to make sure that the component
55
+ // re-renders when the popover's anchor updates.
56
+ const [ popoverAnchor, setPopoverAnchor ] = useState( null );
55
57
  const openLinkUI = useCallback( () => {
56
58
  setIsOpen( true );
57
59
  } );
@@ -246,11 +248,11 @@ const ImageURLInputUI = ( {
246
248
  label={ url ? __( 'Edit link' ) : __( 'Insert link' ) }
247
249
  aria-expanded={ isOpen }
248
250
  onClick={ openLinkUI }
249
- ref={ buttonRef }
251
+ ref={ setPopoverAnchor }
250
252
  />
251
253
  { isOpen && (
252
254
  <URLPopover
253
- anchorRef={ buttonRef }
255
+ anchor={ popoverAnchor }
254
256
  onFocusOutside={ onFocusOutside() }
255
257
  onClose={ closeLinkUI }
256
258
  renderSettings={ () => advancedOptions }
@@ -101,7 +101,7 @@ export default function useBlockDropZone( {
101
101
  } = select( blockEditorStore );
102
102
  const templateLock = getTemplateLock( targetRootClientId );
103
103
  return (
104
- [ 'all', 'noContent' ].some(
104
+ [ 'all', 'contentOnly' ].some(
105
105
  ( lock ) => lock === templateLock
106
106
  ) ||
107
107
  __unstableHasActiveBlockOverlayActive( targetRootClientId ) ||
@@ -72,7 +72,7 @@ export const withBlockControls = createHigherOrderComponent(
72
72
  __unstableSetTemporarilyEditingAsBlocks,
73
73
  } = useDispatch( blockEditorStore );
74
74
  const isContentLocked =
75
- ! isLockedByParent && templateLock === 'noContent';
75
+ ! isLockedByParent && templateLock === 'contentOnly';
76
76
  const {
77
77
  __unstableMarkNextChangeAsNotPersistent,
78
78
  updateBlockAttributes,
@@ -81,11 +81,11 @@ export const withBlockControls = createHigherOrderComponent(
81
81
  const stopEditingAsBlock = useCallback( () => {
82
82
  __unstableMarkNextChangeAsNotPersistent();
83
83
  updateBlockAttributes( props.clientId, {
84
- templateLock: 'noContent',
84
+ templateLock: 'contentOnly',
85
85
  } );
86
86
  updateBlockListSettings( props.clientId, {
87
87
  ...getBlockListSettings( props.clientId ),
88
- templateLock: 'noContent',
88
+ templateLock: 'contentOnly',
89
89
  } );
90
90
  updateSettings( { focusMode: focusModeToRevert.current } );
91
91
  __unstableSetTemporarilyEditingAsBlocks();