@wordpress/block-editor 8.3.0-next.e230fbab09.0 → 8.4.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.
- package/CHANGELOG.md +4 -0
- package/README.md +1 -0
- package/build/components/block-list/block-html.js +4 -1
- package/build/components/block-list/block-html.js.map +1 -1
- package/build/components/block-list/block.js +4 -1
- package/build/components/block-list/block.js.map +1 -1
- package/build/components/block-list/use-block-props/use-focus-first-element.js +19 -0
- package/build/components/block-list/use-block-props/use-focus-first-element.js.map +1 -1
- package/build/components/block-lock/index.js +32 -0
- package/build/components/block-lock/index.js.map +1 -0
- package/build/components/block-lock/menu-item.js +58 -0
- package/build/components/block-lock/menu-item.js.map +1 -0
- package/build/components/block-lock/modal.js +143 -0
- package/build/components/block-lock/modal.js.map +1 -0
- package/build/components/block-lock/toolbar.js +70 -0
- package/build/components/block-lock/toolbar.js.map +1 -0
- package/build/components/block-settings-menu/block-settings-dropdown.js +26 -6
- package/build/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
- package/build/components/block-settings-menu-controls/index.js +19 -9
- package/build/components/block-settings-menu-controls/index.js.map +1 -1
- package/build/components/block-title/use-block-display-title.js +7 -5
- package/build/components/block-title/use-block-display-title.js.map +1 -1
- package/build/components/block-toolbar/index.js +4 -0
- package/build/components/block-toolbar/index.js.map +1 -1
- package/build/components/border-radius-control/index.js +0 -1
- package/build/components/border-radius-control/index.js.map +1 -1
- package/build/components/border-radius-control/utils.js +1 -1
- package/build/components/border-radius-control/utils.js.map +1 -1
- package/build/components/colors-gradients/control.js +3 -1
- package/build/components/colors-gradients/control.js.map +1 -1
- package/build/components/date-format-picker/index.js +132 -0
- package/build/components/date-format-picker/index.js.map +1 -0
- package/build/components/index.js +9 -0
- package/build/components/index.js.map +1 -1
- package/build/components/line-height-control/index.js +5 -3
- package/build/components/line-height-control/index.js.map +1 -1
- package/build/components/list-view/block-select-button.js +4 -22
- package/build/components/list-view/block-select-button.js.map +1 -1
- package/build/components/list-view/block.js +33 -12
- package/build/components/list-view/block.js.map +1 -1
- package/build/components/list-view/branch.js +16 -13
- package/build/components/list-view/branch.js.map +1 -1
- package/build/components/list-view/index.js +7 -1
- package/build/components/list-view/index.js.map +1 -1
- package/build/components/list-view/use-block-selection.js +9 -2
- package/build/components/list-view/use-block-selection.js.map +1 -1
- package/build/components/rich-text/index.js +2 -2
- package/build/components/rich-text/index.js.map +1 -1
- package/build/components/rich-text/index.native.js +13 -9
- package/build/components/rich-text/index.native.js.map +1 -1
- package/build/components/url-popover/image-url-input-ui.js +11 -27
- package/build/components/url-popover/image-url-input-ui.js.map +1 -1
- package/build/hooks/anchor.js +7 -6
- package/build/hooks/anchor.js.map +1 -1
- package/build/hooks/gap.js +70 -5
- package/build/hooks/gap.js.map +1 -1
- package/build/layouts/flex.js +8 -5
- package/build/layouts/flex.js.map +1 -1
- package/build/layouts/flow.js +16 -12
- package/build/layouts/flow.js.map +1 -1
- package/build/store/defaults.js +1 -0
- package/build/store/defaults.js.map +1 -1
- package/build/store/selectors.js +29 -3
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/block-list/block-html.js +5 -2
- package/build-module/components/block-list/block-html.js.map +1 -1
- package/build-module/components/block-list/block.js +5 -2
- package/build-module/components/block-list/block.js.map +1 -1
- package/build-module/components/block-list/use-block-props/use-focus-first-element.js +18 -0
- package/build-module/components/block-list/use-block-props/use-focus-first-element.js.map +1 -1
- package/build-module/components/block-lock/index.js +4 -0
- package/build-module/components/block-lock/index.js.map +1 -0
- package/build-module/components/block-lock/menu-item.js +44 -0
- package/build-module/components/block-lock/menu-item.js.map +1 -0
- package/build-module/components/block-lock/modal.js +128 -0
- package/build-module/components/block-lock/modal.js.map +1 -0
- package/build-module/components/block-lock/toolbar.js +55 -0
- package/build-module/components/block-lock/toolbar.js.map +1 -0
- package/build-module/components/block-settings-menu/block-settings-dropdown.js +26 -6
- package/build-module/components/block-settings-menu/block-settings-dropdown.js.map +1 -1
- package/build-module/components/block-settings-menu-controls/index.js +18 -9
- package/build-module/components/block-settings-menu-controls/index.js.map +1 -1
- package/build-module/components/block-title/use-block-display-title.js +7 -5
- package/build-module/components/block-title/use-block-display-title.js.map +1 -1
- package/build-module/components/block-toolbar/index.js +3 -0
- package/build-module/components/block-toolbar/index.js.map +1 -1
- package/build-module/components/border-radius-control/index.js +0 -1
- package/build-module/components/border-radius-control/index.js.map +1 -1
- package/build-module/components/border-radius-control/utils.js +1 -1
- package/build-module/components/border-radius-control/utils.js.map +1 -1
- package/build-module/components/colors-gradients/control.js +3 -1
- package/build-module/components/colors-gradients/control.js.map +1 -1
- package/build-module/components/date-format-picker/index.js +122 -0
- package/build-module/components/date-format-picker/index.js.map +1 -0
- package/build-module/components/index.js +1 -0
- package/build-module/components/index.js.map +1 -1
- package/build-module/components/line-height-control/index.js +5 -3
- package/build-module/components/line-height-control/index.js.map +1 -1
- package/build-module/components/list-view/block-select-button.js +5 -20
- package/build-module/components/list-view/block-select-button.js.map +1 -1
- package/build-module/components/list-view/block.js +31 -12
- package/build-module/components/list-view/block.js.map +1 -1
- package/build-module/components/list-view/branch.js +16 -13
- package/build-module/components/list-view/branch.js.map +1 -1
- package/build-module/components/list-view/index.js +7 -1
- package/build-module/components/list-view/index.js.map +1 -1
- package/build-module/components/list-view/use-block-selection.js +10 -3
- package/build-module/components/list-view/use-block-selection.js.map +1 -1
- package/build-module/components/rich-text/index.js +2 -2
- package/build-module/components/rich-text/index.js.map +1 -1
- package/build-module/components/rich-text/index.native.js +13 -9
- package/build-module/components/rich-text/index.native.js.map +1 -1
- package/build-module/components/url-popover/image-url-input-ui.js +12 -28
- package/build-module/components/url-popover/image-url-input-ui.js.map +1 -1
- package/build-module/hooks/anchor.js +7 -6
- package/build-module/hooks/anchor.js.map +1 -1
- package/build-module/hooks/gap.js +68 -7
- package/build-module/hooks/gap.js.map +1 -1
- package/build-module/layouts/flex.js +7 -5
- package/build-module/layouts/flex.js.map +1 -1
- package/build-module/layouts/flow.js +15 -12
- package/build-module/layouts/flow.js.map +1 -1
- package/build-module/store/defaults.js +1 -0
- package/build-module/store/defaults.js.map +1 -1
- package/build-module/store/selectors.js +24 -1
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +157 -0
- package/build-style/style.css +157 -0
- package/package.json +28 -27
- package/src/components/block-list/block-html.js +8 -4
- package/src/components/block-list/block.js +5 -1
- package/src/components/block-list/use-block-props/use-focus-first-element.js +28 -0
- package/src/components/block-lock/index.js +3 -0
- package/src/components/block-lock/menu-item.js +52 -0
- package/src/components/block-lock/modal.js +165 -0
- package/src/components/block-lock/style.scss +67 -0
- package/src/components/block-lock/toolbar.js +58 -0
- package/src/components/block-settings-menu/block-settings-dropdown.js +47 -5
- package/src/components/block-settings-menu-controls/index.js +33 -12
- package/src/components/block-title/README.md +6 -1
- package/src/components/block-title/test/index.js +43 -1
- package/src/components/block-title/use-block-display-title.js +9 -6
- package/src/components/block-toolbar/index.js +6 -0
- package/src/components/block-toolbar/style.scss +4 -0
- package/src/components/block-tools/style.scss +29 -0
- package/src/components/border-radius-control/index.js +0 -1
- package/src/components/border-radius-control/test/utils.js +4 -0
- package/src/components/border-radius-control/utils.js +2 -1
- package/src/components/color-palette/test/__snapshots__/control.js.snap +70 -4
- package/src/components/colors-gradients/control.js +1 -1
- package/src/components/colors-gradients/style.scss +6 -0
- package/src/components/date-format-picker/README.md +58 -0
- package/src/components/date-format-picker/index.js +161 -0
- package/src/components/date-format-picker/style.scss +31 -0
- package/src/components/index.js +1 -0
- package/src/components/line-height-control/index.js +3 -3
- package/src/components/link-control/README.md +1 -1
- package/src/components/list-view/block-select-button.js +2 -29
- package/src/components/list-view/block.js +47 -12
- package/src/components/list-view/branch.js +37 -15
- package/src/components/list-view/index.js +6 -0
- package/src/components/list-view/use-block-selection.js +15 -2
- package/src/components/rich-text/index.js +1 -1
- package/src/components/rich-text/index.native.js +24 -8
- package/src/components/url-popover/image-url-input-ui.js +16 -29
- package/src/hooks/anchor.js +8 -6
- package/src/hooks/gap.js +83 -12
- package/src/hooks/test/gap.js +42 -0
- package/src/layouts/flex.js +6 -3
- package/src/layouts/flow.js +16 -11
- package/src/store/defaults.js +1 -0
- package/src/store/selectors.js +26 -1
- package/src/store/test/selectors.js +63 -0
- package/src/style.scss +2 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
5
|
+
import { useEffect, useState } from '@wordpress/element';
|
|
6
|
+
import {
|
|
7
|
+
Button,
|
|
8
|
+
CheckboxControl,
|
|
9
|
+
Flex,
|
|
10
|
+
FlexItem,
|
|
11
|
+
Icon,
|
|
12
|
+
Modal,
|
|
13
|
+
} from '@wordpress/components';
|
|
14
|
+
import { dragHandle, trash } from '@wordpress/icons';
|
|
15
|
+
import { useInstanceId } from '@wordpress/compose';
|
|
16
|
+
import { useDispatch, useSelect } from '@wordpress/data';
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Internal dependencies
|
|
20
|
+
*/
|
|
21
|
+
import useBlockDisplayInformation from '../use-block-display-information';
|
|
22
|
+
import { store as blockEditorStore } from '../../store';
|
|
23
|
+
|
|
24
|
+
export default function BlockLockModal( { clientId, onClose } ) {
|
|
25
|
+
const [ lock, setLock ] = useState( { move: false, remove: false } );
|
|
26
|
+
const { canMove, canRemove } = useSelect(
|
|
27
|
+
( select ) => {
|
|
28
|
+
const {
|
|
29
|
+
canMoveBlock,
|
|
30
|
+
canRemoveBlock,
|
|
31
|
+
getBlockRootClientId,
|
|
32
|
+
} = select( blockEditorStore );
|
|
33
|
+
const rootClientId = getBlockRootClientId( clientId );
|
|
34
|
+
|
|
35
|
+
return {
|
|
36
|
+
canMove: canMoveBlock( clientId, rootClientId ),
|
|
37
|
+
canRemove: canRemoveBlock( clientId, rootClientId ),
|
|
38
|
+
};
|
|
39
|
+
},
|
|
40
|
+
[ clientId ]
|
|
41
|
+
);
|
|
42
|
+
const { updateBlockAttributes } = useDispatch( blockEditorStore );
|
|
43
|
+
const blockInformation = useBlockDisplayInformation( clientId );
|
|
44
|
+
const instanceId = useInstanceId(
|
|
45
|
+
BlockLockModal,
|
|
46
|
+
'block-editor-block-lock-modal__options-title'
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
useEffect( () => {
|
|
50
|
+
setLock( {
|
|
51
|
+
move: ! canMove,
|
|
52
|
+
remove: ! canRemove,
|
|
53
|
+
} );
|
|
54
|
+
}, [ canMove, canRemove ] );
|
|
55
|
+
|
|
56
|
+
const isAllChecked = Object.values( lock ).every( Boolean );
|
|
57
|
+
|
|
58
|
+
let ariaChecked;
|
|
59
|
+
if ( isAllChecked ) {
|
|
60
|
+
ariaChecked = 'true';
|
|
61
|
+
} else if ( Object.values( lock ).some( Boolean ) ) {
|
|
62
|
+
ariaChecked = 'mixed';
|
|
63
|
+
} else {
|
|
64
|
+
ariaChecked = 'false';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return (
|
|
68
|
+
<Modal
|
|
69
|
+
title={ sprintf(
|
|
70
|
+
/* translators: %s: Name of the block. */
|
|
71
|
+
__( 'Lock %s' ),
|
|
72
|
+
blockInformation.title
|
|
73
|
+
) }
|
|
74
|
+
overlayClassName="block-editor-block-lock-modal"
|
|
75
|
+
closeLabel={ __( 'Close' ) }
|
|
76
|
+
onRequestClose={ onClose }
|
|
77
|
+
>
|
|
78
|
+
<form
|
|
79
|
+
onSubmit={ ( event ) => {
|
|
80
|
+
event.preventDefault();
|
|
81
|
+
updateBlockAttributes( [ clientId ], { lock } );
|
|
82
|
+
onClose();
|
|
83
|
+
} }
|
|
84
|
+
>
|
|
85
|
+
<p>
|
|
86
|
+
{ __(
|
|
87
|
+
'Choose specific attributes to restrict or lock all available options.'
|
|
88
|
+
) }
|
|
89
|
+
</p>
|
|
90
|
+
<div
|
|
91
|
+
role="group"
|
|
92
|
+
aria-labelledby={ instanceId }
|
|
93
|
+
className="block-editor-block-lock-modal__options"
|
|
94
|
+
>
|
|
95
|
+
<CheckboxControl
|
|
96
|
+
className="block-editor-block-lock-modal__options-title"
|
|
97
|
+
label={
|
|
98
|
+
<span id={ instanceId }>{ __( 'Lock all' ) }</span>
|
|
99
|
+
}
|
|
100
|
+
checked={ isAllChecked }
|
|
101
|
+
aria-checked={ ariaChecked }
|
|
102
|
+
onChange={ ( newValue ) =>
|
|
103
|
+
setLock( {
|
|
104
|
+
move: newValue,
|
|
105
|
+
remove: newValue,
|
|
106
|
+
} )
|
|
107
|
+
}
|
|
108
|
+
/>
|
|
109
|
+
<ul className="block-editor-block-lock-modal__checklist">
|
|
110
|
+
<li className="block-editor-block-lock-modal__checklist-item">
|
|
111
|
+
<CheckboxControl
|
|
112
|
+
label={
|
|
113
|
+
<>
|
|
114
|
+
{ __( 'Disable movement' ) }
|
|
115
|
+
<Icon icon={ dragHandle } />
|
|
116
|
+
</>
|
|
117
|
+
}
|
|
118
|
+
checked={ lock.move }
|
|
119
|
+
onChange={ ( move ) =>
|
|
120
|
+
setLock( ( prevLock ) => ( {
|
|
121
|
+
...prevLock,
|
|
122
|
+
move,
|
|
123
|
+
} ) )
|
|
124
|
+
}
|
|
125
|
+
/>
|
|
126
|
+
</li>
|
|
127
|
+
<li className="block-editor-block-lock-modal__checklist-item">
|
|
128
|
+
<CheckboxControl
|
|
129
|
+
label={
|
|
130
|
+
<>
|
|
131
|
+
{ __( 'Prevent removal' ) }
|
|
132
|
+
<Icon icon={ trash } />
|
|
133
|
+
</>
|
|
134
|
+
}
|
|
135
|
+
checked={ lock.remove }
|
|
136
|
+
onChange={ ( remove ) =>
|
|
137
|
+
setLock( ( prevLock ) => ( {
|
|
138
|
+
...prevLock,
|
|
139
|
+
remove,
|
|
140
|
+
} ) )
|
|
141
|
+
}
|
|
142
|
+
/>
|
|
143
|
+
</li>
|
|
144
|
+
</ul>
|
|
145
|
+
</div>
|
|
146
|
+
<Flex
|
|
147
|
+
className="block-editor-block-lock-modal__actions"
|
|
148
|
+
justify="flex-end"
|
|
149
|
+
expanded={ false }
|
|
150
|
+
>
|
|
151
|
+
<FlexItem>
|
|
152
|
+
<Button variant="tertiary" onClick={ onClose }>
|
|
153
|
+
{ __( 'Cancel' ) }
|
|
154
|
+
</Button>
|
|
155
|
+
</FlexItem>
|
|
156
|
+
<FlexItem>
|
|
157
|
+
<Button variant="primary" type="submit">
|
|
158
|
+
{ __( 'Apply' ) }
|
|
159
|
+
</Button>
|
|
160
|
+
</FlexItem>
|
|
161
|
+
</Flex>
|
|
162
|
+
</form>
|
|
163
|
+
</Modal>
|
|
164
|
+
);
|
|
165
|
+
}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
.block-editor-block-lock-modal {
|
|
2
|
+
z-index: z-index(".block-editor-block-lock-modal");
|
|
3
|
+
|
|
4
|
+
.components-modal__frame {
|
|
5
|
+
@include break-small() {
|
|
6
|
+
max-width: $break-mobile;
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
.block-editor-block-lock-modal__checklist {
|
|
12
|
+
margin: 0;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.block-editor-block-lock-modal__options-title {
|
|
16
|
+
border-bottom: 1px solid $gray-300;
|
|
17
|
+
padding: $grid-unit-15 0;
|
|
18
|
+
|
|
19
|
+
.components-checkbox-control__label {
|
|
20
|
+
font-weight: 600;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
.components-base-control__field {
|
|
24
|
+
align-items: center;
|
|
25
|
+
display: flex;
|
|
26
|
+
margin: 0;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
.block-editor-block-lock-modal__checklist-item {
|
|
30
|
+
border-bottom: 1px solid $gray-300;
|
|
31
|
+
margin-bottom: 0;
|
|
32
|
+
padding: $grid-unit-15 0 $grid-unit-15 $grid-unit-15;
|
|
33
|
+
|
|
34
|
+
.components-base-control__field {
|
|
35
|
+
align-items: center;
|
|
36
|
+
display: flex;
|
|
37
|
+
margin: 0;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
.components-checkbox-control__label {
|
|
41
|
+
display: flex;
|
|
42
|
+
align-items: center;
|
|
43
|
+
justify-content: space-between;
|
|
44
|
+
flex-grow: 1;
|
|
45
|
+
|
|
46
|
+
svg {
|
|
47
|
+
margin-right: $grid-unit-15;
|
|
48
|
+
fill: $gray-900;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.block-editor-block-lock-modal__actions {
|
|
54
|
+
margin-top: $grid-unit-30;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.block-editor-block-lock-toolbar {
|
|
58
|
+
.components-button.has-icon {
|
|
59
|
+
min-width: $button-size-small + $grid-unit-15 !important;
|
|
60
|
+
padding-left: 0 !important;
|
|
61
|
+
|
|
62
|
+
&:focus::before {
|
|
63
|
+
left: 0 !important;
|
|
64
|
+
right: $grid-unit-15 !important;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { __, sprintf } from '@wordpress/i18n';
|
|
5
|
+
import { ToolbarButton, ToolbarGroup } from '@wordpress/components';
|
|
6
|
+
import { useReducer } from '@wordpress/element';
|
|
7
|
+
import { lock } from '@wordpress/icons';
|
|
8
|
+
import { useSelect } from '@wordpress/data';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Internal dependencies
|
|
12
|
+
*/
|
|
13
|
+
import BlockLockModal from './modal';
|
|
14
|
+
import useBlockDisplayInformation from '../use-block-display-information';
|
|
15
|
+
import { store as blockEditorStore } from '../../store';
|
|
16
|
+
|
|
17
|
+
export default function BlockLockToolbar( { clientId } ) {
|
|
18
|
+
const blockInformation = useBlockDisplayInformation( clientId );
|
|
19
|
+
const { canMove, canRemove } = useSelect(
|
|
20
|
+
( select ) => {
|
|
21
|
+
const { canMoveBlock, canRemoveBlock } = select( blockEditorStore );
|
|
22
|
+
|
|
23
|
+
return {
|
|
24
|
+
canMove: canMoveBlock( clientId ),
|
|
25
|
+
canRemove: canRemoveBlock( clientId ),
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
[ clientId ]
|
|
29
|
+
);
|
|
30
|
+
|
|
31
|
+
const [ isModalOpen, toggleModal ] = useReducer(
|
|
32
|
+
( isActive ) => ! isActive,
|
|
33
|
+
false
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
if ( canMove && canRemove ) {
|
|
37
|
+
return null;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<ToolbarGroup className="block-editor-block-lock-toolbar">
|
|
43
|
+
<ToolbarButton
|
|
44
|
+
icon={ lock }
|
|
45
|
+
label={ sprintf(
|
|
46
|
+
/* translators: %s: block name */
|
|
47
|
+
__( 'Unlock %s' ),
|
|
48
|
+
blockInformation.title
|
|
49
|
+
) }
|
|
50
|
+
onClick={ toggleModal }
|
|
51
|
+
/>
|
|
52
|
+
</ToolbarGroup>
|
|
53
|
+
{ isModalOpen && (
|
|
54
|
+
<BlockLockModal clientId={ clientId } onClose={ toggleModal } />
|
|
55
|
+
) }
|
|
56
|
+
</>
|
|
57
|
+
);
|
|
58
|
+
}
|
|
@@ -46,11 +46,26 @@ export function BlockSettingsDropdown( {
|
|
|
46
46
|
const blockClientIds = castArray( clientIds );
|
|
47
47
|
const count = blockClientIds.length;
|
|
48
48
|
const firstBlockClientId = blockClientIds[ 0 ];
|
|
49
|
-
const {
|
|
49
|
+
const {
|
|
50
|
+
onlyBlock,
|
|
51
|
+
previousBlockClientId,
|
|
52
|
+
nextBlockClientId,
|
|
53
|
+
selectedBlockClientIds,
|
|
54
|
+
} = useSelect(
|
|
50
55
|
( select ) => {
|
|
51
|
-
const {
|
|
56
|
+
const {
|
|
57
|
+
getBlockCount,
|
|
58
|
+
getPreviousBlockClientId,
|
|
59
|
+
getNextBlockClientId,
|
|
60
|
+
getSelectedBlockClientIds,
|
|
61
|
+
} = select( blockEditorStore );
|
|
52
62
|
return {
|
|
53
63
|
onlyBlock: 1 === getBlockCount(),
|
|
64
|
+
previousBlockClientId: getPreviousBlockClientId(
|
|
65
|
+
firstBlockClientId
|
|
66
|
+
),
|
|
67
|
+
nextBlockClientId: getNextBlockClientId( firstBlockClientId ),
|
|
68
|
+
selectedBlockClientIds: getSelectedBlockClientIds(),
|
|
54
69
|
};
|
|
55
70
|
},
|
|
56
71
|
[ firstBlockClientId ]
|
|
@@ -72,7 +87,7 @@ export function BlockSettingsDropdown( {
|
|
|
72
87
|
};
|
|
73
88
|
}, [] );
|
|
74
89
|
|
|
75
|
-
const
|
|
90
|
+
const updateSelectionAfterDuplicate = useCallback(
|
|
76
91
|
__experimentalSelectBlock
|
|
77
92
|
? async ( clientIdsPromise ) => {
|
|
78
93
|
const ids = await clientIdsPromise;
|
|
@@ -86,6 +101,33 @@ export function BlockSettingsDropdown( {
|
|
|
86
101
|
|
|
87
102
|
const blockTitle = useBlockDisplayTitle( firstBlockClientId, 25 );
|
|
88
103
|
|
|
104
|
+
const updateSelectionAfterRemove = useCallback(
|
|
105
|
+
__experimentalSelectBlock
|
|
106
|
+
? () => {
|
|
107
|
+
const blockToSelect =
|
|
108
|
+
previousBlockClientId || nextBlockClientId;
|
|
109
|
+
|
|
110
|
+
if (
|
|
111
|
+
blockToSelect &&
|
|
112
|
+
// From the block options dropdown, it's possible to remove a block that is not selected,
|
|
113
|
+
// in this case, it's not necessary to update the selection since the selected block wasn't removed.
|
|
114
|
+
selectedBlockClientIds.includes( firstBlockClientId ) &&
|
|
115
|
+
// Don't update selection when next/prev block also is in the selection ( and gets removed ),
|
|
116
|
+
// In case someone selects all blocks and removes them at once.
|
|
117
|
+
! selectedBlockClientIds.includes( blockToSelect )
|
|
118
|
+
) {
|
|
119
|
+
__experimentalSelectBlock( blockToSelect );
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
: noop,
|
|
123
|
+
[
|
|
124
|
+
__experimentalSelectBlock,
|
|
125
|
+
previousBlockClientId,
|
|
126
|
+
nextBlockClientId,
|
|
127
|
+
selectedBlockClientIds,
|
|
128
|
+
]
|
|
129
|
+
);
|
|
130
|
+
|
|
89
131
|
const label = sprintf(
|
|
90
132
|
/* translators: %s: block name */
|
|
91
133
|
__( 'Remove %s' ),
|
|
@@ -139,7 +181,7 @@ export function BlockSettingsDropdown( {
|
|
|
139
181
|
onClick={ flow(
|
|
140
182
|
onClose,
|
|
141
183
|
onDuplicate,
|
|
142
|
-
|
|
184
|
+
updateSelectionAfterDuplicate
|
|
143
185
|
) }
|
|
144
186
|
shortcut={ shortcuts.duplicate }
|
|
145
187
|
>
|
|
@@ -197,7 +239,7 @@ export function BlockSettingsDropdown( {
|
|
|
197
239
|
onClick={ flow(
|
|
198
240
|
onClose,
|
|
199
241
|
onRemove,
|
|
200
|
-
|
|
242
|
+
updateSelectionAfterRemove
|
|
201
243
|
) }
|
|
202
244
|
shortcut={ shortcuts.remove }
|
|
203
245
|
>
|
|
@@ -20,16 +20,19 @@ import {
|
|
|
20
20
|
useConvertToGroupButtonProps,
|
|
21
21
|
ConvertToGroupButton,
|
|
22
22
|
} from '../convert-to-group-buttons';
|
|
23
|
+
import { BlockLockMenuItem } from '../block-lock';
|
|
23
24
|
import { store as blockEditorStore } from '../../store';
|
|
24
25
|
|
|
25
26
|
const { Fill, Slot } = createSlotFill( 'BlockSettingsMenuControls' );
|
|
26
27
|
|
|
27
28
|
const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
|
|
28
|
-
const { selectedBlocks, selectedClientIds } = useSelect(
|
|
29
|
+
const { selectedBlocks, selectedClientIds, canRemove } = useSelect(
|
|
29
30
|
( select ) => {
|
|
30
|
-
const {
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
const {
|
|
32
|
+
getBlocksByClientId,
|
|
33
|
+
getSelectedBlockClientIds,
|
|
34
|
+
canRemoveBlocks,
|
|
35
|
+
} = select( blockEditorStore );
|
|
33
36
|
const ids =
|
|
34
37
|
clientIds !== null ? clientIds : getSelectedBlockClientIds();
|
|
35
38
|
return {
|
|
@@ -38,30 +41,48 @@ const BlockSettingsMenuControlsSlot = ( { fillProps, clientIds = null } ) => {
|
|
|
38
41
|
( block ) => block.name
|
|
39
42
|
),
|
|
40
43
|
selectedClientIds: ids,
|
|
44
|
+
canRemove: canRemoveBlocks( ids ),
|
|
41
45
|
};
|
|
42
46
|
},
|
|
43
47
|
[ clientIds ]
|
|
44
48
|
);
|
|
45
49
|
|
|
50
|
+
const showLockButton = selectedClientIds.length === 1;
|
|
51
|
+
|
|
46
52
|
// Check if current selection of blocks is Groupable or Ungroupable
|
|
47
53
|
// and pass this props down to ConvertToGroupButton.
|
|
48
54
|
const convertToGroupButtonProps = useConvertToGroupButtonProps();
|
|
49
55
|
const { isGroupable, isUngroupable } = convertToGroupButtonProps;
|
|
50
|
-
const showConvertToGroupButton =
|
|
56
|
+
const showConvertToGroupButton =
|
|
57
|
+
( isGroupable || isUngroupable ) && canRemove;
|
|
58
|
+
|
|
51
59
|
return (
|
|
52
60
|
<Slot fillProps={ { ...fillProps, selectedBlocks, selectedClientIds } }>
|
|
53
61
|
{ ( fills ) => {
|
|
54
|
-
if (
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
62
|
+
if (
|
|
63
|
+
! fills?.length > 0 &&
|
|
64
|
+
! showConvertToGroupButton &&
|
|
65
|
+
! showLockButton
|
|
66
|
+
) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<MenuGroup>
|
|
72
|
+
{ showLockButton && (
|
|
73
|
+
<BlockLockMenuItem
|
|
74
|
+
clientId={ selectedClientIds[ 0 ] }
|
|
75
|
+
/>
|
|
76
|
+
) }
|
|
77
|
+
{ fills }
|
|
78
|
+
{ showConvertToGroupButton && (
|
|
58
79
|
<ConvertToGroupButton
|
|
59
80
|
{ ...convertToGroupButtonProps }
|
|
60
81
|
onClose={ fillProps?.onClose }
|
|
61
82
|
/>
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
83
|
+
) }
|
|
84
|
+
</MenuGroup>
|
|
85
|
+
);
|
|
65
86
|
} }
|
|
66
87
|
</Slot>
|
|
67
88
|
);
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# Block Title
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
The Block Title component renders a block's configured title as a string.
|
|
4
|
+
|
|
5
|
+
It prioritizes contextual titles such as block variation and reusable block labels when returning a value. If none is found, it will return the display title specified in the block's metadata.
|
|
6
|
+
|
|
7
|
+
The component will be empty if a title cannot be determined.
|
|
8
|
+
|
|
4
9
|
|
|
5
10
|
## Usage
|
|
6
11
|
|
|
@@ -26,6 +26,9 @@ jest.mock( '@wordpress/blocks', () => {
|
|
|
26
26
|
case 'name-with-label':
|
|
27
27
|
return { title: 'Block With Label' };
|
|
28
28
|
|
|
29
|
+
case 'name-with-custom-label':
|
|
30
|
+
return { title: 'Block With Custom Label' };
|
|
31
|
+
|
|
29
32
|
case 'name-with-long-label':
|
|
30
33
|
return { title: 'Block With Long Label' };
|
|
31
34
|
}
|
|
@@ -38,6 +41,9 @@ jest.mock( '@wordpress/blocks', () => {
|
|
|
38
41
|
case 'Block With Long Label':
|
|
39
42
|
return 'This is a longer label than typical for blocks to have.';
|
|
40
43
|
|
|
44
|
+
case 'Block With Custom Label':
|
|
45
|
+
return 'A Custom Label like a Block Variation Label';
|
|
46
|
+
|
|
41
47
|
default:
|
|
42
48
|
return title;
|
|
43
49
|
}
|
|
@@ -61,7 +67,7 @@ jest.mock( '@wordpress/data/src/components/use-select', () => {
|
|
|
61
67
|
} );
|
|
62
68
|
|
|
63
69
|
describe( 'BlockTitle', () => {
|
|
64
|
-
it( 'renders nothing if name is
|
|
70
|
+
it( 'renders nothing if name is falsey', () => {
|
|
65
71
|
useSelect.mockImplementation( () => ( {
|
|
66
72
|
name: null,
|
|
67
73
|
attributes: null,
|
|
@@ -106,6 +112,42 @@ describe( 'BlockTitle', () => {
|
|
|
106
112
|
expect( wrapper.text() ).toBe( 'Test Label' );
|
|
107
113
|
} );
|
|
108
114
|
|
|
115
|
+
it( 'should prioritize reusable block title over title', () => {
|
|
116
|
+
useSelect.mockImplementation( () => ( {
|
|
117
|
+
name: 'name-with-label',
|
|
118
|
+
reusableBlockTitle: 'Reuse me!',
|
|
119
|
+
attributes: null,
|
|
120
|
+
} ) );
|
|
121
|
+
|
|
122
|
+
const wrapper = shallow( <BlockTitle clientId="id-name-with-label" /> );
|
|
123
|
+
|
|
124
|
+
expect( wrapper.text() ).toBe( 'Reuse me!' );
|
|
125
|
+
} );
|
|
126
|
+
|
|
127
|
+
it( 'should prioritize block label over title', () => {
|
|
128
|
+
useSelect.mockImplementation( () => ( {
|
|
129
|
+
name: 'name-with-custom-label',
|
|
130
|
+
attributes: null,
|
|
131
|
+
} ) );
|
|
132
|
+
|
|
133
|
+
const wrapper = shallow( <BlockTitle clientId="id-name-with-label" /> );
|
|
134
|
+
|
|
135
|
+
expect( wrapper.text() ).toBe(
|
|
136
|
+
'A Custom Label like a Block Variation Label'
|
|
137
|
+
);
|
|
138
|
+
} );
|
|
139
|
+
|
|
140
|
+
it( 'should default to block information title if no reusable title or block name is available', () => {
|
|
141
|
+
useSelect.mockImplementation( () => ( {
|
|
142
|
+
name: 'some-rando-name',
|
|
143
|
+
attributes: null,
|
|
144
|
+
} ) );
|
|
145
|
+
|
|
146
|
+
const wrapper = shallow( <BlockTitle clientId="id-name-with-label" /> );
|
|
147
|
+
|
|
148
|
+
expect( wrapper.text() ).toBe( 'Block With Label' );
|
|
149
|
+
} );
|
|
150
|
+
|
|
109
151
|
it( 'truncates the label with custom truncate length', () => {
|
|
110
152
|
useSelect.mockImplementation( () => ( {
|
|
111
153
|
name: 'name-with-long-label',
|
|
@@ -70,14 +70,17 @@ export default function useBlockDisplayTitle( clientId, maximumLength ) {
|
|
|
70
70
|
const blockLabel = blockType
|
|
71
71
|
? getBlockLabel( blockType, attributes )
|
|
72
72
|
: null;
|
|
73
|
+
|
|
73
74
|
const label = reusableBlockTitle || blockLabel;
|
|
74
75
|
// Label will fallback to the title if no label is defined for the current
|
|
75
|
-
// label context. If the label is defined we prioritize it over
|
|
76
|
+
// label context. If the label is defined we prioritize it over a
|
|
76
77
|
// possible block variation title match.
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
78
|
+
const blockTitle =
|
|
79
|
+
label && label !== blockType.title ? label : blockInformation.title;
|
|
80
|
+
|
|
81
|
+
if ( maximumLength && maximumLength > 0 ) {
|
|
82
|
+
return truncate( blockTitle, { length: maximumLength } );
|
|
81
83
|
}
|
|
82
|
-
|
|
84
|
+
|
|
85
|
+
return blockTitle;
|
|
83
86
|
}
|
|
@@ -20,6 +20,7 @@ import BlockParentSelector from '../block-parent-selector';
|
|
|
20
20
|
import BlockSwitcher from '../block-switcher';
|
|
21
21
|
import BlockControls from '../block-controls';
|
|
22
22
|
import BlockSettingsMenu from '../block-settings-menu';
|
|
23
|
+
import { BlockLockToolbar } from '../block-lock';
|
|
23
24
|
import { useShowMoversGestures } from './utils';
|
|
24
25
|
import { store as blockEditorStore } from '../../store';
|
|
25
26
|
|
|
@@ -114,6 +115,11 @@ export default function BlockToolbar( { hideDragHandle } ) {
|
|
|
114
115
|
{ ( shouldShowVisualToolbar || isMultiToolbar ) && (
|
|
115
116
|
<ToolbarGroup className="block-editor-block-toolbar__block-controls">
|
|
116
117
|
<BlockSwitcher clientIds={ blockClientIds } />
|
|
118
|
+
{ ! isMultiToolbar && (
|
|
119
|
+
<BlockLockToolbar
|
|
120
|
+
clientId={ blockClientIds[ 0 ] }
|
|
121
|
+
/>
|
|
122
|
+
) }
|
|
117
123
|
<BlockMover
|
|
118
124
|
clientIds={ blockClientIds }
|
|
119
125
|
hideDragHandle={ hideDragHandle || hasReducedUI }
|
|
@@ -307,3 +307,32 @@
|
|
|
307
307
|
.is-dragging-components-draggable .components-tooltip {
|
|
308
308
|
display: none;
|
|
309
309
|
}
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
// Size multiple sequential buttons to be optically balanced.
|
|
313
|
+
// Icons are 36px, as set by a 24px icon and 12px padding.
|
|
314
|
+
.block-editor-block-toolbar > .components-toolbar > .block-editor-block-toolbar__slot, // When a plugin adds to a slot, the segment has a `components-toolbar` class.
|
|
315
|
+
.block-editor-block-toolbar > .components-toolbar-group > .block-editor-block-toolbar__slot, // When no plugin adds to slots, the segment has a `components-toolbar-group` class.
|
|
316
|
+
.block-editor-block-toolbar > .block-editor-block-toolbar__slot > .components-toolbar, // The nesting order is sometimes reversed.
|
|
317
|
+
.block-editor-block-toolbar > .block-editor-block-toolbar__slot > .components-dropdown, // Targets unique markup for the "Replace" button.
|
|
318
|
+
.block-editor-block-toolbar .block-editor-block-toolbar__slot .components-toolbar-group { // Inline formatting tools use this class.
|
|
319
|
+
padding-left: $grid-unit-15 * 0.5; // 6px.
|
|
320
|
+
padding-right: $grid-unit-15 * 0.5;
|
|
321
|
+
|
|
322
|
+
> .components-button,
|
|
323
|
+
> div > .components-button,
|
|
324
|
+
> .components-dropdown .components-button {
|
|
325
|
+
min-width: $block-toolbar-height - $grid-unit-15;
|
|
326
|
+
padding-left: $grid-unit-15 * 0.5; // 6px.
|
|
327
|
+
padding-right: $grid-unit-15 * 0.5;
|
|
328
|
+
|
|
329
|
+
svg {
|
|
330
|
+
min-width: $button-size-small; // This is the optimal icon size, and we size the whole button after this.
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
&::before {
|
|
334
|
+
left: 2px;
|
|
335
|
+
right: 2px;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
@@ -150,6 +150,10 @@ describe( 'hasMixedValues', () => {
|
|
|
150
150
|
expect( hasMixedValues( '2px' ) ).toBe( false );
|
|
151
151
|
} );
|
|
152
152
|
|
|
153
|
+
it( 'should return false when passed a string value containing a unit with no quantity', () => {
|
|
154
|
+
expect( hasMixedValues( 'em' ) ).toBe( false );
|
|
155
|
+
} );
|
|
156
|
+
|
|
153
157
|
it( 'should return true when passed mixed values', () => {
|
|
154
158
|
const values = {
|
|
155
159
|
bottomLeft: '1em',
|
|
@@ -91,7 +91,8 @@ export function getAllValue( values = {} ) {
|
|
|
91
91
|
*/
|
|
92
92
|
export function hasMixedValues( values = {} ) {
|
|
93
93
|
const allValue = getAllValue( values );
|
|
94
|
-
const isMixed =
|
|
94
|
+
const isMixed =
|
|
95
|
+
typeof values === 'string' ? false : isNaN( parseFloat( allValue ) );
|
|
95
96
|
|
|
96
97
|
return isMixed;
|
|
97
98
|
}
|