@wordpress/block-editor 8.5.2 → 8.5.5
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/build/components/block-content-overlay/index.js +4 -13
- package/build/components/block-content-overlay/index.js.map +1 -1
- package/build/components/block-lock/modal.js +4 -34
- package/build/components/block-lock/modal.js.map +1 -1
- package/build/components/block-lock/toolbar.js +1 -2
- package/build/components/block-lock/toolbar.js.map +1 -1
- package/build/components/block-lock/use-block-lock.js +1 -4
- package/build/components/block-lock/use-block-lock.js.map +1 -1
- package/build/components/inserter/index.js +21 -7
- package/build/components/inserter/index.js.map +1 -1
- package/build/components/inserter/quick-inserter.js +4 -5
- package/build/components/inserter/quick-inserter.js.map +1 -1
- package/build/components/writing-flow/use-click-selection.js +1 -3
- package/build/components/writing-flow/use-click-selection.js.map +1 -1
- package/build/components/writing-flow/use-selection-observer.js +49 -8
- package/build/components/writing-flow/use-selection-observer.js.map +1 -1
- package/build/hooks/duotone.js +66 -16
- package/build/hooks/duotone.js.map +1 -1
- package/build/hooks/index.js +7 -1
- package/build/hooks/index.js.map +1 -1
- package/build/index.js +7 -0
- package/build/index.js.map +1 -1
- package/build/store/selectors.js +0 -24
- package/build/store/selectors.js.map +1 -1
- package/build-module/components/block-content-overlay/index.js +4 -13
- package/build-module/components/block-content-overlay/index.js.map +1 -1
- package/build-module/components/block-lock/modal.js +5 -34
- package/build-module/components/block-lock/modal.js.map +1 -1
- package/build-module/components/block-lock/toolbar.js +1 -2
- package/build-module/components/block-lock/toolbar.js.map +1 -1
- package/build-module/components/block-lock/use-block-lock.js +1 -4
- package/build-module/components/block-lock/use-block-lock.js.map +1 -1
- package/build-module/components/inserter/index.js +21 -7
- package/build-module/components/inserter/index.js.map +1 -1
- package/build-module/components/inserter/quick-inserter.js +4 -5
- package/build-module/components/inserter/quick-inserter.js.map +1 -1
- package/build-module/components/writing-flow/use-click-selection.js +1 -3
- package/build-module/components/writing-flow/use-click-selection.js.map +1 -1
- package/build-module/components/writing-flow/use-selection-observer.js +49 -8
- package/build-module/components/writing-flow/use-selection-observer.js.map +1 -1
- package/build-module/hooks/duotone.js +63 -16
- package/build-module/hooks/duotone.js.map +1 -1
- package/build-module/hooks/index.js +1 -0
- package/build-module/hooks/index.js.map +1 -1
- package/build-module/index.js +1 -1
- package/build-module/index.js.map +1 -1
- package/build-module/store/selectors.js +0 -22
- package/build-module/store/selectors.js.map +1 -1
- package/build-style/style-rtl.css +0 -1
- package/build-style/style.css +0 -1
- package/package.json +6 -6
- package/src/components/block-content-overlay/index.js +2 -19
- package/src/components/block-content-overlay/style.scss +0 -1
- package/src/components/block-lock/modal.js +3 -42
- package/src/components/block-lock/toolbar.js +2 -2
- package/src/components/block-lock/use-block-lock.js +1 -4
- package/src/components/inserter/index.js +20 -0
- package/src/components/inserter/quick-inserter.js +3 -11
- package/src/components/writing-flow/use-click-selection.js +1 -4
- package/src/components/writing-flow/use-selection-observer.js +55 -10
- package/src/hooks/duotone.js +98 -62
- package/src/hooks/index.js +1 -0
- package/src/index.js +1 -0
- package/src/store/selectors.js +0 -20
|
@@ -1018,7 +1018,6 @@
|
|
|
1018
1018
|
border: none;
|
|
1019
1019
|
border-radius: 2px;
|
|
1020
1020
|
z-index: 10;
|
|
1021
|
-
pointer-events: none;
|
|
1022
1021
|
}
|
|
1023
1022
|
.block-editor-block-content-overlay:hover:not(.is-dragging-blocks).overlay-active::before, .block-editor-block-content-overlay.parent-highlighted.overlay-active::before {
|
|
1024
1023
|
background: rgba(var(--wp-admin-theme-color--rgb), 0.1);
|
package/build-style/style.css
CHANGED
|
@@ -1018,7 +1018,6 @@
|
|
|
1018
1018
|
border: none;
|
|
1019
1019
|
border-radius: 2px;
|
|
1020
1020
|
z-index: 10;
|
|
1021
|
-
pointer-events: none;
|
|
1022
1021
|
}
|
|
1023
1022
|
.block-editor-block-content-overlay:hover:not(.is-dragging-blocks).overlay-active::before, .block-editor-block-content-overlay.parent-highlighted.overlay-active::before {
|
|
1024
1023
|
background: rgba(var(--wp-admin-theme-color--rgb), 0.1);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wordpress/block-editor",
|
|
3
|
-
"version": "8.5.
|
|
3
|
+
"version": "8.5.5",
|
|
4
4
|
"description": "Generic block editor.",
|
|
5
5
|
"author": "The WordPress Contributors",
|
|
6
6
|
"license": "GPL-2.0-or-later",
|
|
@@ -36,8 +36,8 @@
|
|
|
36
36
|
"@wordpress/a11y": "^3.6.1",
|
|
37
37
|
"@wordpress/api-fetch": "^6.3.1",
|
|
38
38
|
"@wordpress/blob": "^3.6.1",
|
|
39
|
-
"@wordpress/blocks": "^11.5.
|
|
40
|
-
"@wordpress/components": "^19.8.
|
|
39
|
+
"@wordpress/blocks": "^11.5.3",
|
|
40
|
+
"@wordpress/components": "^19.8.4",
|
|
41
41
|
"@wordpress/compose": "^5.4.1",
|
|
42
42
|
"@wordpress/data": "^6.6.1",
|
|
43
43
|
"@wordpress/date": "^4.6.1",
|
|
@@ -47,12 +47,12 @@
|
|
|
47
47
|
"@wordpress/hooks": "^3.6.1",
|
|
48
48
|
"@wordpress/html-entities": "^3.6.1",
|
|
49
49
|
"@wordpress/i18n": "^4.6.1",
|
|
50
|
-
"@wordpress/icons": "^8.2.
|
|
50
|
+
"@wordpress/icons": "^8.2.2",
|
|
51
51
|
"@wordpress/is-shallow-equal": "^4.6.1",
|
|
52
52
|
"@wordpress/keyboard-shortcuts": "^3.4.1",
|
|
53
53
|
"@wordpress/keycodes": "^3.6.1",
|
|
54
54
|
"@wordpress/notices": "^3.6.1",
|
|
55
|
-
"@wordpress/rich-text": "^5.4.
|
|
55
|
+
"@wordpress/rich-text": "^5.4.2",
|
|
56
56
|
"@wordpress/shortcode": "^3.6.1",
|
|
57
57
|
"@wordpress/style-engine": "^0.5.1",
|
|
58
58
|
"@wordpress/token-list": "^2.6.1",
|
|
@@ -77,5 +77,5 @@
|
|
|
77
77
|
"publishConfig": {
|
|
78
78
|
"access": "public"
|
|
79
79
|
},
|
|
80
|
-
"gitHead": "
|
|
80
|
+
"gitHead": "b97f41a0716be45abd8bf897c7f135b86dc0760c"
|
|
81
81
|
}
|
|
@@ -25,7 +25,6 @@ export default function BlockContentOverlay( {
|
|
|
25
25
|
const [ isHovered, setIsHovered ] = useState( false );
|
|
26
26
|
|
|
27
27
|
const {
|
|
28
|
-
canEdit,
|
|
29
28
|
isParentSelected,
|
|
30
29
|
hasChildSelected,
|
|
31
30
|
isDraggingBlocks,
|
|
@@ -37,10 +36,8 @@ export default function BlockContentOverlay( {
|
|
|
37
36
|
hasSelectedInnerBlock,
|
|
38
37
|
isDraggingBlocks: _isDraggingBlocks,
|
|
39
38
|
isBlockHighlighted,
|
|
40
|
-
canEditBlock,
|
|
41
39
|
} = select( blockEditorStore );
|
|
42
40
|
return {
|
|
43
|
-
canEdit: canEditBlock( clientId ),
|
|
44
41
|
isParentSelected: isBlockSelected( clientId ),
|
|
45
42
|
hasChildSelected: hasSelectedInnerBlock( clientId, true ),
|
|
46
43
|
isDraggingBlocks: _isDraggingBlocks(),
|
|
@@ -62,12 +59,6 @@ export default function BlockContentOverlay( {
|
|
|
62
59
|
);
|
|
63
60
|
|
|
64
61
|
useEffect( () => {
|
|
65
|
-
// The overlay is always active when editing is locked.
|
|
66
|
-
if ( ! canEdit ) {
|
|
67
|
-
setIsOverlayActive( true );
|
|
68
|
-
return;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
62
|
// Reenable when blocks are not in use.
|
|
72
63
|
if ( ! isParentSelected && ! hasChildSelected && ! isOverlayActive ) {
|
|
73
64
|
setIsOverlayActive( true );
|
|
@@ -84,13 +75,7 @@ export default function BlockContentOverlay( {
|
|
|
84
75
|
if ( hasChildSelected && isOverlayActive ) {
|
|
85
76
|
setIsOverlayActive( false );
|
|
86
77
|
}
|
|
87
|
-
}, [
|
|
88
|
-
isParentSelected,
|
|
89
|
-
hasChildSelected,
|
|
90
|
-
isOverlayActive,
|
|
91
|
-
isHovered,
|
|
92
|
-
canEdit,
|
|
93
|
-
] );
|
|
78
|
+
}, [ isParentSelected, hasChildSelected, isOverlayActive, isHovered ] );
|
|
94
79
|
|
|
95
80
|
// Disabled because the overlay div doesn't actually have a role or functionality
|
|
96
81
|
// as far as the a11y is concerned. We're just catching the first click so that
|
|
@@ -103,9 +88,7 @@ export default function BlockContentOverlay( {
|
|
|
103
88
|
onMouseEnter={ () => setIsHovered( true ) }
|
|
104
89
|
onMouseLeave={ () => setIsHovered( false ) }
|
|
105
90
|
onMouseUp={
|
|
106
|
-
isOverlayActive
|
|
107
|
-
? () => setIsOverlayActive( false )
|
|
108
|
-
: undefined
|
|
91
|
+
isOverlayActive ? () => setIsOverlayActive( false ) : undefined
|
|
109
92
|
}
|
|
110
93
|
>
|
|
111
94
|
{ wrapperProps?.children }
|
|
@@ -13,8 +13,7 @@ import {
|
|
|
13
13
|
} from '@wordpress/components';
|
|
14
14
|
import { lock as lockIcon, unlock as unlockIcon } from '@wordpress/icons';
|
|
15
15
|
import { useInstanceId } from '@wordpress/compose';
|
|
16
|
-
import { useDispatch
|
|
17
|
-
import { isReusableBlock, getBlockType } from '@wordpress/blocks';
|
|
16
|
+
import { useDispatch } from '@wordpress/data';
|
|
18
17
|
|
|
19
18
|
/**
|
|
20
19
|
* Internal dependencies
|
|
@@ -25,18 +24,7 @@ import { store as blockEditorStore } from '../../store';
|
|
|
25
24
|
|
|
26
25
|
export default function BlockLockModal( { clientId, onClose } ) {
|
|
27
26
|
const [ lock, setLock ] = useState( { move: false, remove: false } );
|
|
28
|
-
const {
|
|
29
|
-
const { isReusable } = useSelect(
|
|
30
|
-
( select ) => {
|
|
31
|
-
const { getBlockName } = select( blockEditorStore );
|
|
32
|
-
const blockName = getBlockName( clientId );
|
|
33
|
-
|
|
34
|
-
return {
|
|
35
|
-
isReusable: isReusableBlock( getBlockType( blockName ) ),
|
|
36
|
-
};
|
|
37
|
-
},
|
|
38
|
-
[ clientId ]
|
|
39
|
-
);
|
|
27
|
+
const { canMove, canRemove } = useBlockLock( clientId );
|
|
40
28
|
const { updateBlockAttributes } = useDispatch( blockEditorStore );
|
|
41
29
|
const blockInformation = useBlockDisplayInformation( clientId );
|
|
42
30
|
const instanceId = useInstanceId(
|
|
@@ -48,9 +36,8 @@ export default function BlockLockModal( { clientId, onClose } ) {
|
|
|
48
36
|
setLock( {
|
|
49
37
|
move: ! canMove,
|
|
50
38
|
remove: ! canRemove,
|
|
51
|
-
...( isReusable ? { edit: ! canEdit } : {} ),
|
|
52
39
|
} );
|
|
53
|
-
}, [
|
|
40
|
+
}, [ canMove, canRemove ] );
|
|
54
41
|
|
|
55
42
|
const isAllChecked = Object.values( lock ).every( Boolean );
|
|
56
43
|
const isMixed = Object.values( lock ).some( Boolean ) && ! isAllChecked;
|
|
@@ -94,36 +81,10 @@ export default function BlockLockModal( { clientId, onClose } ) {
|
|
|
94
81
|
setLock( {
|
|
95
82
|
move: newValue,
|
|
96
83
|
remove: newValue,
|
|
97
|
-
...( isReusable ? { edit: newValue } : {} ),
|
|
98
84
|
} )
|
|
99
85
|
}
|
|
100
86
|
/>
|
|
101
87
|
<ul className="block-editor-block-lock-modal__checklist">
|
|
102
|
-
{ isReusable && (
|
|
103
|
-
<li className="block-editor-block-lock-modal__checklist-item">
|
|
104
|
-
<CheckboxControl
|
|
105
|
-
label={
|
|
106
|
-
<>
|
|
107
|
-
{ __( 'Restrict editing' ) }
|
|
108
|
-
<Icon
|
|
109
|
-
icon={
|
|
110
|
-
lock.edit
|
|
111
|
-
? lockIcon
|
|
112
|
-
: unlockIcon
|
|
113
|
-
}
|
|
114
|
-
/>
|
|
115
|
-
</>
|
|
116
|
-
}
|
|
117
|
-
checked={ !! lock.edit }
|
|
118
|
-
onChange={ ( edit ) =>
|
|
119
|
-
setLock( ( prevLock ) => ( {
|
|
120
|
-
...prevLock,
|
|
121
|
-
edit,
|
|
122
|
-
} ) )
|
|
123
|
-
}
|
|
124
|
-
/>
|
|
125
|
-
</li>
|
|
126
|
-
) }
|
|
127
88
|
<li className="block-editor-block-lock-modal__checklist-item">
|
|
128
89
|
<CheckboxControl
|
|
129
90
|
label={
|
|
@@ -15,7 +15,7 @@ import useBlockDisplayInformation from '../use-block-display-information';
|
|
|
15
15
|
|
|
16
16
|
export default function BlockLockToolbar( { clientId } ) {
|
|
17
17
|
const blockInformation = useBlockDisplayInformation( clientId );
|
|
18
|
-
const {
|
|
18
|
+
const { canMove, canRemove, canLock } = useBlockLock( clientId );
|
|
19
19
|
|
|
20
20
|
const [ isModalOpen, toggleModal ] = useReducer(
|
|
21
21
|
( isActive ) => ! isActive,
|
|
@@ -26,7 +26,7 @@ export default function BlockLockToolbar( { clientId } ) {
|
|
|
26
26
|
return null;
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
if (
|
|
29
|
+
if ( canMove && canRemove ) {
|
|
30
30
|
return null;
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -19,7 +19,6 @@ export default function useBlockLock( clientId ) {
|
|
|
19
19
|
return useSelect(
|
|
20
20
|
( select ) => {
|
|
21
21
|
const {
|
|
22
|
-
canEditBlock,
|
|
23
22
|
canMoveBlock,
|
|
24
23
|
canRemoveBlock,
|
|
25
24
|
canLockBlockType,
|
|
@@ -28,16 +27,14 @@ export default function useBlockLock( clientId ) {
|
|
|
28
27
|
} = select( blockEditorStore );
|
|
29
28
|
const rootClientId = getBlockRootClientId( clientId );
|
|
30
29
|
|
|
31
|
-
const canEdit = canEditBlock( clientId );
|
|
32
30
|
const canMove = canMoveBlock( clientId, rootClientId );
|
|
33
31
|
const canRemove = canRemoveBlock( clientId, rootClientId );
|
|
34
32
|
|
|
35
33
|
return {
|
|
36
|
-
canEdit,
|
|
37
34
|
canMove,
|
|
38
35
|
canRemove,
|
|
39
36
|
canLock: canLockBlockType( getBlockName( clientId ) ),
|
|
40
|
-
isLocked: !
|
|
37
|
+
isLocked: ! canMove || ! canRemove,
|
|
41
38
|
};
|
|
42
39
|
},
|
|
43
40
|
[ clientId ]
|
|
@@ -30,6 +30,7 @@ const defaultRenderToggle = ( {
|
|
|
30
30
|
blockTitle,
|
|
31
31
|
hasSingleBlockType,
|
|
32
32
|
toggleProps = {},
|
|
33
|
+
prioritizePatterns,
|
|
33
34
|
} ) => {
|
|
34
35
|
let label;
|
|
35
36
|
if ( hasSingleBlockType ) {
|
|
@@ -38,6 +39,8 @@ const defaultRenderToggle = ( {
|
|
|
38
39
|
_x( 'Add %s', 'directly add the only allowed block' ),
|
|
39
40
|
blockTitle
|
|
40
41
|
);
|
|
42
|
+
} else if ( prioritizePatterns ) {
|
|
43
|
+
label = __( 'Add pattern' );
|
|
41
44
|
} else {
|
|
42
45
|
label = _x( 'Add block', 'Generic label for block inserter button' );
|
|
43
46
|
}
|
|
@@ -106,6 +109,7 @@ class Inserter extends Component {
|
|
|
106
109
|
toggleProps,
|
|
107
110
|
hasItems,
|
|
108
111
|
renderToggle = defaultRenderToggle,
|
|
112
|
+
prioritizePatterns,
|
|
109
113
|
} = this.props;
|
|
110
114
|
|
|
111
115
|
return renderToggle( {
|
|
@@ -116,6 +120,7 @@ class Inserter extends Component {
|
|
|
116
120
|
hasSingleBlockType,
|
|
117
121
|
directInsertBlock,
|
|
118
122
|
toggleProps,
|
|
123
|
+
prioritizePatterns,
|
|
119
124
|
} );
|
|
120
125
|
}
|
|
121
126
|
|
|
@@ -138,6 +143,7 @@ class Inserter extends Component {
|
|
|
138
143
|
// This prop is experimental to give some time for the quick inserter to mature
|
|
139
144
|
// Feel free to make them stable after a few releases.
|
|
140
145
|
__experimentalIsQuick: isQuick,
|
|
146
|
+
prioritizePatterns,
|
|
141
147
|
} = this.props;
|
|
142
148
|
|
|
143
149
|
if ( isQuick ) {
|
|
@@ -149,6 +155,7 @@ class Inserter extends Component {
|
|
|
149
155
|
rootClientId={ rootClientId }
|
|
150
156
|
clientId={ clientId }
|
|
151
157
|
isAppender={ isAppender }
|
|
158
|
+
prioritizePatterns={ prioritizePatterns }
|
|
152
159
|
/>
|
|
153
160
|
);
|
|
154
161
|
}
|
|
@@ -206,7 +213,11 @@ export default compose( [
|
|
|
206
213
|
hasInserterItems,
|
|
207
214
|
__experimentalGetAllowedBlocks,
|
|
208
215
|
__experimentalGetDirectInsertBlock,
|
|
216
|
+
getBlockIndex,
|
|
217
|
+
getBlockCount,
|
|
218
|
+
getSettings,
|
|
209
219
|
} = select( blockEditorStore );
|
|
220
|
+
|
|
210
221
|
const { getBlockVariations } = select( blocksStore );
|
|
211
222
|
|
|
212
223
|
rootClientId =
|
|
@@ -218,6 +229,10 @@ export default compose( [
|
|
|
218
229
|
rootClientId
|
|
219
230
|
);
|
|
220
231
|
|
|
232
|
+
const index = getBlockIndex( clientId );
|
|
233
|
+
const blockCount = getBlockCount();
|
|
234
|
+
const settings = getSettings();
|
|
235
|
+
|
|
221
236
|
const hasSingleBlockType =
|
|
222
237
|
size( allowedBlocks ) === 1 &&
|
|
223
238
|
size(
|
|
@@ -236,6 +251,11 @@ export default compose( [
|
|
|
236
251
|
allowedBlockType,
|
|
237
252
|
directInsertBlock,
|
|
238
253
|
rootClientId,
|
|
254
|
+
prioritizePatterns:
|
|
255
|
+
settings.__experimentalPreferPatternsOnRoot &&
|
|
256
|
+
! rootClientId &&
|
|
257
|
+
index > 0 &&
|
|
258
|
+
( index < blockCount || blockCount === 0 ),
|
|
239
259
|
};
|
|
240
260
|
} ),
|
|
241
261
|
withDispatch( ( dispatch, ownProps, { select } ) => {
|
|
@@ -30,6 +30,7 @@ export default function QuickInserter( {
|
|
|
30
30
|
rootClientId,
|
|
31
31
|
clientId,
|
|
32
32
|
isAppender,
|
|
33
|
+
prioritizePatterns,
|
|
33
34
|
} ) {
|
|
34
35
|
const [ filterValue, setFilterValue ] = useState( '' );
|
|
35
36
|
const [ destinationRootClientId, onInsertBlocks ] = useInsertionPoint( {
|
|
@@ -48,11 +49,7 @@ export default function QuickInserter( {
|
|
|
48
49
|
destinationRootClientId
|
|
49
50
|
);
|
|
50
51
|
|
|
51
|
-
const {
|
|
52
|
-
setInserterIsOpened,
|
|
53
|
-
insertionIndex,
|
|
54
|
-
prioritizePatterns,
|
|
55
|
-
} = useSelect(
|
|
52
|
+
const { setInserterIsOpened, insertionIndex } = useSelect(
|
|
56
53
|
( select ) => {
|
|
57
54
|
const { getSettings, getBlockIndex, getBlockCount } = select(
|
|
58
55
|
blockEditorStore
|
|
@@ -63,15 +60,10 @@ export default function QuickInserter( {
|
|
|
63
60
|
|
|
64
61
|
return {
|
|
65
62
|
setInserterIsOpened: settings.__experimentalSetIsInserterOpened,
|
|
66
|
-
prioritizePatterns:
|
|
67
|
-
settings.__experimentalPreferPatternsOnRoot &&
|
|
68
|
-
! rootClientId &&
|
|
69
|
-
index > 0 &&
|
|
70
|
-
( index < blockCount || blockCount === 0 ),
|
|
71
63
|
insertionIndex: index === -1 ? blockCount : index,
|
|
72
64
|
};
|
|
73
65
|
},
|
|
74
|
-
[ clientId
|
|
66
|
+
[ clientId ]
|
|
75
67
|
);
|
|
76
68
|
|
|
77
69
|
const showPatterns =
|
|
@@ -11,10 +11,9 @@ import { store as blockEditorStore } from '../../store';
|
|
|
11
11
|
import { getBlockClientId } from '../../utils/dom';
|
|
12
12
|
|
|
13
13
|
export default function useClickSelection() {
|
|
14
|
-
const {
|
|
14
|
+
const { selectBlock } = useDispatch( blockEditorStore );
|
|
15
15
|
const {
|
|
16
16
|
isSelectionEnabled,
|
|
17
|
-
getBlockParents,
|
|
18
17
|
getBlockSelectionStart,
|
|
19
18
|
hasMultiSelection,
|
|
20
19
|
} = useSelect( blockEditorStore );
|
|
@@ -54,10 +53,8 @@ export default function useClickSelection() {
|
|
|
54
53
|
};
|
|
55
54
|
},
|
|
56
55
|
[
|
|
57
|
-
multiSelect,
|
|
58
56
|
selectBlock,
|
|
59
57
|
isSelectionEnabled,
|
|
60
|
-
getBlockParents,
|
|
61
58
|
getBlockSelectionStart,
|
|
62
59
|
hasMultiSelection,
|
|
63
60
|
]
|
|
@@ -76,36 +76,81 @@ export default function useSelectionObserver() {
|
|
|
76
76
|
const { multiSelect, selectBlock, selectionChange } = useDispatch(
|
|
77
77
|
blockEditorStore
|
|
78
78
|
);
|
|
79
|
-
const { getBlockParents } = useSelect(
|
|
79
|
+
const { getBlockParents, getBlockSelectionStart } = useSelect(
|
|
80
|
+
blockEditorStore
|
|
81
|
+
);
|
|
80
82
|
return useRefEffect(
|
|
81
83
|
( node ) => {
|
|
82
84
|
const { ownerDocument } = node;
|
|
83
85
|
const { defaultView } = ownerDocument;
|
|
84
86
|
|
|
85
|
-
function onSelectionChange() {
|
|
87
|
+
function onSelectionChange( event ) {
|
|
86
88
|
const selection = defaultView.getSelection();
|
|
87
|
-
|
|
88
89
|
// If no selection is found, end multi selection and disable the
|
|
89
90
|
// contentEditable wrapper.
|
|
90
|
-
if ( ! selection.rangeCount
|
|
91
|
+
if ( ! selection.rangeCount ) {
|
|
92
|
+
setContentEditableWrapper( node, false );
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
// If selection is collapsed and we haven't used `shift+click`,
|
|
96
|
+
// end multi selection and disable the contentEditable wrapper.
|
|
97
|
+
// We have to check about `shift+click` case because elements
|
|
98
|
+
// that don't support text selection might be involved, and we might
|
|
99
|
+
// update the clientIds to multi-select blocks.
|
|
100
|
+
// For now we check if the event is a `mouse` event.
|
|
101
|
+
const isClickShift = event.shiftKey && event.type === 'mouseup';
|
|
102
|
+
if ( selection.isCollapsed && ! isClickShift ) {
|
|
91
103
|
setContentEditableWrapper( node, false );
|
|
92
104
|
return;
|
|
93
105
|
}
|
|
94
106
|
|
|
95
|
-
|
|
107
|
+
let startClientId = getBlockClientId(
|
|
96
108
|
extractSelectionStartNode( selection )
|
|
97
109
|
);
|
|
98
|
-
|
|
110
|
+
let endClientId = getBlockClientId(
|
|
99
111
|
extractSelectionEndNode( selection )
|
|
100
112
|
);
|
|
101
|
-
|
|
113
|
+
// If the selection has changed and we had pressed `shift+click`,
|
|
114
|
+
// we need to check if in an element that doesn't support
|
|
115
|
+
// text selection has been clicked.
|
|
116
|
+
if ( isClickShift ) {
|
|
117
|
+
const selectedClientId = getBlockSelectionStart();
|
|
118
|
+
const clickedClientId = getBlockClientId( event.target );
|
|
119
|
+
// `endClientId` is not defined if we end the selection by clicking a non-selectable block.
|
|
120
|
+
// We need to check if there was already a selection with a non-selectable focusNode.
|
|
121
|
+
const focusNodeIsNonSelectable =
|
|
122
|
+
clickedClientId !== endClientId;
|
|
123
|
+
if (
|
|
124
|
+
( startClientId === endClientId &&
|
|
125
|
+
selection.isCollapsed ) ||
|
|
126
|
+
! endClientId ||
|
|
127
|
+
focusNodeIsNonSelectable
|
|
128
|
+
) {
|
|
129
|
+
endClientId = clickedClientId;
|
|
130
|
+
}
|
|
131
|
+
// Handle the case when we have a non-selectable block
|
|
132
|
+
// selected and click another one.
|
|
133
|
+
if ( startClientId !== selectedClientId ) {
|
|
134
|
+
startClientId = selectedClientId;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
// If the selection did not involve a block, return.
|
|
139
|
+
if (
|
|
140
|
+
startClientId === undefined &&
|
|
141
|
+
endClientId === undefined
|
|
142
|
+
) {
|
|
143
|
+
setContentEditableWrapper( node, false );
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
102
146
|
|
|
147
|
+
const isSingularSelection = startClientId === endClientId;
|
|
103
148
|
if ( isSingularSelection ) {
|
|
104
|
-
selectBlock(
|
|
149
|
+
selectBlock( startClientId );
|
|
105
150
|
} else {
|
|
106
151
|
const startPath = [
|
|
107
|
-
...getBlockParents(
|
|
108
|
-
|
|
152
|
+
...getBlockParents( startClientId ),
|
|
153
|
+
startClientId,
|
|
109
154
|
];
|
|
110
155
|
const endPath = [
|
|
111
156
|
...getBlockParents( endClientId ),
|
package/src/hooks/duotone.js
CHANGED
|
@@ -60,82 +60,109 @@ export function getValuesFromColors( colors = [] ) {
|
|
|
60
60
|
*/
|
|
61
61
|
|
|
62
62
|
/**
|
|
63
|
-
*
|
|
63
|
+
* Stylesheet for rendering the duotone filter.
|
|
64
64
|
*
|
|
65
65
|
* @param {Object} props Duotone props.
|
|
66
66
|
* @param {string} props.selector Selector to apply the filter to.
|
|
67
67
|
* @param {string} props.id Unique id for this duotone filter.
|
|
68
|
-
* @param {Values} props.values R, G, B, and A values to filter with.
|
|
69
68
|
*
|
|
70
69
|
* @return {WPElement} Duotone element.
|
|
71
70
|
*/
|
|
72
|
-
function
|
|
73
|
-
const
|
|
71
|
+
function DuotoneStylesheet( { selector, id } ) {
|
|
72
|
+
const css = `
|
|
74
73
|
${ selector } {
|
|
75
74
|
filter: url( #${ id } );
|
|
76
75
|
}
|
|
77
76
|
`;
|
|
77
|
+
return <style>{ css }</style>;
|
|
78
|
+
}
|
|
78
79
|
|
|
80
|
+
/**
|
|
81
|
+
* SVG for rendering the duotone filter.
|
|
82
|
+
*
|
|
83
|
+
* @param {Object} props Duotone props.
|
|
84
|
+
* @param {string} props.id Unique id for this duotone filter.
|
|
85
|
+
* @param {Values} props.values R, G, B, and A values to filter with.
|
|
86
|
+
*
|
|
87
|
+
* @return {WPElement} Duotone element.
|
|
88
|
+
*/
|
|
89
|
+
function DuotoneFilter( { id, values } ) {
|
|
79
90
|
return (
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
>
|
|
95
|
-
<
|
|
96
|
-
<
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
91
|
+
<SVG
|
|
92
|
+
xmlnsXlink="http://www.w3.org/1999/xlink"
|
|
93
|
+
viewBox="0 0 0 0"
|
|
94
|
+
width="0"
|
|
95
|
+
height="0"
|
|
96
|
+
focusable="false"
|
|
97
|
+
role="none"
|
|
98
|
+
style={ {
|
|
99
|
+
visibility: 'hidden',
|
|
100
|
+
position: 'absolute',
|
|
101
|
+
left: '-9999px',
|
|
102
|
+
overflow: 'hidden',
|
|
103
|
+
} }
|
|
104
|
+
>
|
|
105
|
+
<defs>
|
|
106
|
+
<filter id={ id }>
|
|
107
|
+
<feColorMatrix
|
|
108
|
+
// Use sRGB instead of linearRGB so transparency looks correct.
|
|
109
|
+
colorInterpolationFilters="sRGB"
|
|
110
|
+
type="matrix"
|
|
111
|
+
// Use perceptual brightness to convert to grayscale.
|
|
112
|
+
values="
|
|
113
|
+
.299 .587 .114 0 0
|
|
114
|
+
.299 .587 .114 0 0
|
|
115
|
+
.299 .587 .114 0 0
|
|
116
|
+
.299 .587 .114 0 0
|
|
117
|
+
"
|
|
118
|
+
/>
|
|
119
|
+
<feComponentTransfer
|
|
120
|
+
// Use sRGB instead of linearRGB to be consistent with how CSS gradients work.
|
|
121
|
+
colorInterpolationFilters="sRGB"
|
|
122
|
+
>
|
|
123
|
+
<feFuncR
|
|
124
|
+
type="table"
|
|
125
|
+
tableValues={ values.r.join( ' ' ) }
|
|
126
|
+
/>
|
|
127
|
+
<feFuncG
|
|
128
|
+
type="table"
|
|
129
|
+
tableValues={ values.g.join( ' ' ) }
|
|
130
|
+
/>
|
|
131
|
+
<feFuncB
|
|
132
|
+
type="table"
|
|
133
|
+
tableValues={ values.b.join( ' ' ) }
|
|
108
134
|
/>
|
|
109
|
-
<
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
>
|
|
113
|
-
<feFuncR
|
|
114
|
-
type="table"
|
|
115
|
-
tableValues={ values.r.join( ' ' ) }
|
|
116
|
-
/>
|
|
117
|
-
<feFuncG
|
|
118
|
-
type="table"
|
|
119
|
-
tableValues={ values.g.join( ' ' ) }
|
|
120
|
-
/>
|
|
121
|
-
<feFuncB
|
|
122
|
-
type="table"
|
|
123
|
-
tableValues={ values.b.join( ' ' ) }
|
|
124
|
-
/>
|
|
125
|
-
<feFuncA
|
|
126
|
-
type="table"
|
|
127
|
-
tableValues={ values.a.join( ' ' ) }
|
|
128
|
-
/>
|
|
129
|
-
</feComponentTransfer>
|
|
130
|
-
<feComposite
|
|
131
|
-
// Re-mask the image with the original transparency since the feColorMatrix above loses that information.
|
|
132
|
-
in2="SourceGraphic"
|
|
133
|
-
operator="in"
|
|
135
|
+
<feFuncA
|
|
136
|
+
type="table"
|
|
137
|
+
tableValues={ values.a.join( ' ' ) }
|
|
134
138
|
/>
|
|
135
|
-
</
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
+
</feComponentTransfer>
|
|
140
|
+
<feComposite
|
|
141
|
+
// Re-mask the image with the original transparency since the feColorMatrix above loses that information.
|
|
142
|
+
in2="SourceGraphic"
|
|
143
|
+
operator="in"
|
|
144
|
+
/>
|
|
145
|
+
</filter>
|
|
146
|
+
</defs>
|
|
147
|
+
</SVG>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* SVG and stylesheet needed for rendering the duotone filter.
|
|
153
|
+
*
|
|
154
|
+
* @param {Object} props Duotone props.
|
|
155
|
+
* @param {string} props.selector Selector to apply the filter to.
|
|
156
|
+
* @param {string} props.id Unique id for this duotone filter.
|
|
157
|
+
* @param {Values} props.values R, G, B, and A values to filter with.
|
|
158
|
+
*
|
|
159
|
+
* @return {WPElement} Duotone element.
|
|
160
|
+
*/
|
|
161
|
+
function InlineDuotone( { selector, id, values } ) {
|
|
162
|
+
return (
|
|
163
|
+
<>
|
|
164
|
+
<DuotoneFilter id={ id } values={ values } />
|
|
165
|
+
<DuotoneStylesheet id={ id } selector={ selector } />
|
|
139
166
|
</>
|
|
140
167
|
);
|
|
141
168
|
}
|
|
@@ -321,7 +348,7 @@ const withDuotoneStyles = createHigherOrderComponent(
|
|
|
321
348
|
<>
|
|
322
349
|
{ element &&
|
|
323
350
|
createPortal(
|
|
324
|
-
<
|
|
351
|
+
<InlineDuotone
|
|
325
352
|
selector={ selectorsGroup }
|
|
326
353
|
id={ id }
|
|
327
354
|
values={ getValuesFromColors( values ) }
|
|
@@ -335,6 +362,15 @@ const withDuotoneStyles = createHigherOrderComponent(
|
|
|
335
362
|
'withDuotoneStyles'
|
|
336
363
|
);
|
|
337
364
|
|
|
365
|
+
export function PresetDuotoneFilter( { preset } ) {
|
|
366
|
+
return (
|
|
367
|
+
<DuotoneFilter
|
|
368
|
+
id={ `wp-duotone-${ preset.slug }` }
|
|
369
|
+
values={ getValuesFromColors( preset.colors ) }
|
|
370
|
+
/>
|
|
371
|
+
);
|
|
372
|
+
}
|
|
373
|
+
|
|
338
374
|
addFilter(
|
|
339
375
|
'blocks.registerBlockType',
|
|
340
376
|
'core/editor/duotone/add-attributes',
|
package/src/hooks/index.js
CHANGED
|
@@ -19,3 +19,4 @@ export { getBorderClassesAndStyles, useBorderProps } from './use-border-props';
|
|
|
19
19
|
export { getColorClassesAndStyles, useColorProps } from './use-color-props';
|
|
20
20
|
export { getSpacingClassesAndStyles } from './use-spacing-props';
|
|
21
21
|
export { useCachedTruthy } from './use-cached-truthy';
|
|
22
|
+
export { PresetDuotoneFilter } from './duotone';
|