@wordpress/block-editor 13.1.0 → 13.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -17
- package/README.md +1 -1
- package/build/components/block-lock/modal.js +67 -67
- package/build/components/block-lock/modal.js.map +1 -1
- package/build/components/block-mover/index.js +12 -6
- package/build/components/block-mover/index.js.map +1 -1
- package/build/components/block-toolbar/shuffle.js +3 -1
- package/build/components/block-toolbar/shuffle.js.map +1 -1
- package/build/components/child-layout-control/index.js +185 -127
- package/build/components/child-layout-control/index.js.map +1 -1
- package/build/components/global-styles/use-global-styles-output.js +4 -3
- package/build/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build/components/grid/grid-item-movers.js +97 -0
- package/build/components/grid/grid-item-movers.js.map +1 -0
- package/build/components/{grid-visualizer → grid}/grid-item-resizer.js +18 -56
- package/build/components/grid/grid-item-resizer.js.map +1 -0
- package/build/components/grid/grid-visualizer.js +225 -0
- package/build/components/grid/grid-visualizer.js.map +1 -0
- package/build/components/{grid-visualizer → grid}/index.js +14 -0
- package/build/components/grid/index.js.map +1 -0
- package/build/components/grid/use-get-number-of-blocks-before-cell.js +40 -0
- package/build/components/grid/use-get-number-of-blocks-before-cell.js.map +1 -0
- package/build/components/grid/use-grid-layout-sync.js +162 -0
- package/build/components/grid/use-grid-layout-sync.js.map +1 -0
- package/build/components/grid/utils.js +145 -0
- package/build/components/grid/utils.js.map +1 -0
- package/build/components/image-editor/aspect-ratio-dropdown.js +0 -1
- package/build/components/image-editor/aspect-ratio-dropdown.js.map +1 -1
- package/build/components/inner-blocks/index.js +1 -1
- package/build/components/inner-blocks/index.js.map +1 -1
- package/build/components/rich-text/event-listeners/input-rules.js +1 -0
- package/build/components/rich-text/event-listeners/input-rules.js.map +1 -1
- package/build/components/rich-text/index.native.js +10 -4
- package/build/components/rich-text/index.native.js.map +1 -1
- package/build/components/rich-text/native/index.native.js +14 -0
- package/build/components/rich-text/native/index.native.js.map +1 -1
- package/build/hooks/block-style-variation.js +26 -7
- package/build/hooks/block-style-variation.js.map +1 -1
- package/build/hooks/layout-child.js +29 -21
- package/build/hooks/layout-child.js.map +1 -1
- package/build/hooks/utils.js +3 -2
- package/build/hooks/utils.js.map +1 -1
- package/build/layouts/grid.js +24 -47
- package/build/layouts/grid.js.map +1 -1
- package/build/lock-unlock.js +1 -1
- package/build/lock-unlock.js.map +1 -1
- package/build/store/actions.js +17 -1
- package/build/store/actions.js.map +1 -1
- package/build-module/components/block-lock/modal.js +67 -67
- package/build-module/components/block-lock/modal.js.map +1 -1
- package/build-module/components/block-mover/index.js +12 -6
- package/build-module/components/block-mover/index.js.map +1 -1
- package/build-module/components/block-toolbar/shuffle.js +3 -1
- package/build-module/components/block-toolbar/shuffle.js.map +1 -1
- package/build-module/components/child-layout-control/index.js +185 -127
- package/build-module/components/child-layout-control/index.js.map +1 -1
- package/build-module/components/global-styles/use-global-styles-output.js +4 -3
- package/build-module/components/global-styles/use-global-styles-output.js.map +1 -1
- package/build-module/components/grid/grid-item-movers.js +90 -0
- package/build-module/components/grid/grid-item-movers.js.map +1 -0
- package/build-module/components/{grid-visualizer → grid}/grid-item-resizer.js +13 -51
- package/build-module/components/grid/grid-item-resizer.js.map +1 -0
- package/build-module/components/grid/grid-visualizer.js +217 -0
- package/build-module/components/grid/grid-visualizer.js.map +1 -0
- package/build-module/components/grid/index.js +5 -0
- package/build-module/components/grid/index.js.map +1 -0
- package/build-module/components/grid/use-get-number-of-blocks-before-cell.js +33 -0
- package/build-module/components/grid/use-get-number-of-blocks-before-cell.js.map +1 -0
- package/build-module/components/grid/use-grid-layout-sync.js +155 -0
- package/build-module/components/grid/use-grid-layout-sync.js.map +1 -0
- package/build-module/components/grid/utils.js +131 -0
- package/build-module/components/grid/utils.js.map +1 -0
- package/build-module/components/image-editor/aspect-ratio-dropdown.js +0 -1
- package/build-module/components/image-editor/aspect-ratio-dropdown.js.map +1 -1
- package/build-module/components/inner-blocks/index.js +1 -1
- package/build-module/components/inner-blocks/index.js.map +1 -1
- package/build-module/components/rich-text/event-listeners/input-rules.js +1 -1
- package/build-module/components/rich-text/event-listeners/input-rules.js.map +1 -1
- package/build-module/components/rich-text/index.native.js +11 -5
- package/build-module/components/rich-text/index.native.js.map +1 -1
- package/build-module/components/rich-text/native/index.native.js +14 -0
- package/build-module/components/rich-text/native/index.native.js.map +1 -1
- package/build-module/hooks/block-style-variation.js +25 -7
- package/build-module/hooks/block-style-variation.js.map +1 -1
- package/build-module/hooks/layout-child.js +27 -19
- package/build-module/hooks/layout-child.js.map +1 -1
- package/build-module/hooks/utils.js +3 -2
- package/build-module/hooks/utils.js.map +1 -1
- package/build-module/layouts/grid.js +24 -47
- package/build-module/layouts/grid.js.map +1 -1
- package/build-module/lock-unlock.js +1 -1
- package/build-module/lock-unlock.js.map +1 -1
- package/build-module/store/actions.js +17 -1
- package/build-module/store/actions.js.map +1 -1
- package/build-style/style-rtl.css +39 -18
- package/build-style/style.css +39 -18
- package/package.json +31 -31
- package/src/components/block-lock/modal.js +95 -82
- package/src/components/block-lock/style.scss +11 -1
- package/src/components/block-mover/index.js +37 -24
- package/src/components/block-toolbar/shuffle.js +3 -1
- package/src/components/child-layout-control/index.js +224 -159
- package/src/components/global-styles/test/use-global-styles-output.js +38 -3
- package/src/components/global-styles/use-global-styles-output.js +4 -3
- package/src/components/grid/grid-item-movers.js +128 -0
- package/src/components/{grid-visualizer → grid}/grid-item-resizer.js +14 -52
- package/src/components/grid/grid-visualizer.js +267 -0
- package/src/components/grid/index.js +4 -0
- package/src/components/grid/style.scss +63 -0
- package/src/components/grid/use-get-number-of-blocks-before-cell.js +30 -0
- package/src/components/grid/use-grid-layout-sync.js +167 -0
- package/src/components/grid/utils.js +178 -0
- package/src/components/image-editor/aspect-ratio-dropdown.js +0 -1
- package/src/components/inner-blocks/index.js +3 -1
- package/src/components/rich-text/event-listeners/input-rules.js +1 -1
- package/src/components/rich-text/index.native.js +10 -8
- package/src/components/rich-text/native/index.native.js +17 -0
- package/src/hooks/block-style-variation.js +24 -6
- package/src/hooks/layout-child.js +34 -14
- package/src/hooks/utils.js +3 -1
- package/src/layouts/grid.js +54 -62
- package/src/lock-unlock.js +1 -1
- package/src/store/actions.js +21 -1
- package/src/style.scss +1 -1
- package/build/components/grid-visualizer/grid-item-resizer.js.map +0 -1
- package/build/components/grid-visualizer/grid-visualizer.js +0 -92
- package/build/components/grid-visualizer/grid-visualizer.js.map +0 -1
- package/build/components/grid-visualizer/index.js.map +0 -1
- package/build/components/grid-visualizer/utils.js +0 -10
- package/build/components/grid-visualizer/utils.js.map +0 -1
- package/build-module/components/grid-visualizer/grid-item-resizer.js.map +0 -1
- package/build-module/components/grid-visualizer/grid-visualizer.js +0 -84
- package/build-module/components/grid-visualizer/grid-visualizer.js.map +0 -1
- package/build-module/components/grid-visualizer/index.js +0 -3
- package/build-module/components/grid-visualizer/index.js.map +0 -1
- package/build-module/components/grid-visualizer/utils.js +0 -4
- package/build-module/components/grid-visualizer/utils.js.map +0 -1
- package/src/components/grid-visualizer/grid-visualizer.js +0 -101
- package/src/components/grid-visualizer/index.js +0 -2
- package/src/components/grid-visualizer/style.scss +0 -34
- package/src/components/grid-visualizer/utils.js +0 -5
- /package/src/components/font-sizes/{README.MD → README.md} +0 -0
|
@@ -9,11 +9,17 @@ import { useState, useEffect } from '@wordpress/element';
|
|
|
9
9
|
*/
|
|
10
10
|
import { __unstableUseBlockElement as useBlockElement } from '../block-list/use-block-props/use-block-refs';
|
|
11
11
|
import BlockPopoverCover from '../block-popover/cover';
|
|
12
|
-
import { getComputedCSS } from './utils';
|
|
12
|
+
import { getComputedCSS, getGridTracks, getClosestTrack } from './utils';
|
|
13
13
|
|
|
14
|
-
export function GridItemResizer( {
|
|
14
|
+
export function GridItemResizer( {
|
|
15
|
+
clientId,
|
|
16
|
+
bounds,
|
|
17
|
+
onChange,
|
|
18
|
+
parentLayout,
|
|
19
|
+
} ) {
|
|
15
20
|
const blockElement = useBlockElement( clientId );
|
|
16
21
|
const rootBlockElement = blockElement?.parentElement;
|
|
22
|
+
const { columnCount } = parentLayout;
|
|
17
23
|
|
|
18
24
|
if ( ! blockElement || ! rootBlockElement ) {
|
|
19
25
|
return null;
|
|
@@ -26,6 +32,9 @@ export function GridItemResizer( { clientId, bounds, onChange } ) {
|
|
|
26
32
|
blockElement={ blockElement }
|
|
27
33
|
rootBlockElement={ rootBlockElement }
|
|
28
34
|
onChange={ onChange }
|
|
35
|
+
isManualGrid={
|
|
36
|
+
!! columnCount && window.__experimentalEnableGridInteractivity
|
|
37
|
+
}
|
|
29
38
|
/>
|
|
30
39
|
);
|
|
31
40
|
}
|
|
@@ -36,6 +45,7 @@ function GridItemResizerInner( {
|
|
|
36
45
|
blockElement,
|
|
37
46
|
rootBlockElement,
|
|
38
47
|
onChange,
|
|
48
|
+
isManualGrid,
|
|
39
49
|
} ) {
|
|
40
50
|
const [ resizeDirection, setResizeDirection ] = useState( null );
|
|
41
51
|
const [ enableSide, setEnableSide ] = useState( {
|
|
@@ -171,59 +181,11 @@ function GridItemResizerInner( {
|
|
|
171
181
|
onChange( {
|
|
172
182
|
columnSpan: columnEnd - columnStart + 1,
|
|
173
183
|
rowSpan: rowEnd - rowStart + 1,
|
|
184
|
+
columnStart: isManualGrid ? columnStart : undefined,
|
|
185
|
+
rowStart: isManualGrid ? rowStart : undefined,
|
|
174
186
|
} );
|
|
175
187
|
} }
|
|
176
188
|
/>
|
|
177
189
|
</BlockPopoverCover>
|
|
178
190
|
);
|
|
179
191
|
}
|
|
180
|
-
|
|
181
|
-
/**
|
|
182
|
-
* Given a grid-template-columns or grid-template-rows CSS property value, gets the start and end
|
|
183
|
-
* position in pixels of each grid track.
|
|
184
|
-
*
|
|
185
|
-
* https://css-tricks.com/snippets/css/complete-guide-grid/#aa-grid-track
|
|
186
|
-
*
|
|
187
|
-
* @param {string} template The grid-template-columns or grid-template-rows CSS property value.
|
|
188
|
-
* Only supports fixed sizes in pixels.
|
|
189
|
-
* @param {number} gap The gap between grid tracks in pixels.
|
|
190
|
-
*
|
|
191
|
-
* @return {Array<{start: number, end: number}>} An array of objects with the start and end
|
|
192
|
-
* position in pixels of each grid track.
|
|
193
|
-
*/
|
|
194
|
-
function getGridTracks( template, gap ) {
|
|
195
|
-
const tracks = [];
|
|
196
|
-
for ( const size of template.split( ' ' ) ) {
|
|
197
|
-
const previousTrack = tracks[ tracks.length - 1 ];
|
|
198
|
-
const start = previousTrack ? previousTrack.end + gap : 0;
|
|
199
|
-
const end = start + parseFloat( size );
|
|
200
|
-
tracks.push( { start, end } );
|
|
201
|
-
}
|
|
202
|
-
return tracks;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/**
|
|
206
|
-
* Given an array of grid tracks and a position in pixels, gets the index of the closest track to
|
|
207
|
-
* that position.
|
|
208
|
-
*
|
|
209
|
-
* https://css-tricks.com/snippets/css/complete-guide-grid/#aa-grid-track
|
|
210
|
-
*
|
|
211
|
-
* @param {Array<{start: number, end: number}>} tracks An array of objects with the start and end
|
|
212
|
-
* position in pixels of each grid track.
|
|
213
|
-
* @param {number} position The position in pixels.
|
|
214
|
-
* @param {string} edge The edge of the track to compare the
|
|
215
|
-
* position to. Either 'start' or 'end'.
|
|
216
|
-
*
|
|
217
|
-
* @return {number} The index of the closest track to the position. 0-based, unlike CSS grid which
|
|
218
|
-
* is 1-based.
|
|
219
|
-
*/
|
|
220
|
-
function getClosestTrack( tracks, position, edge = 'start' ) {
|
|
221
|
-
return tracks.reduce(
|
|
222
|
-
( closest, track, index ) =>
|
|
223
|
-
Math.abs( track[ edge ] - position ) <
|
|
224
|
-
Math.abs( tracks[ closest ][ edge ] - position )
|
|
225
|
-
? index
|
|
226
|
-
: closest,
|
|
227
|
-
0
|
|
228
|
-
);
|
|
229
|
-
}
|
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* External dependencies
|
|
3
|
+
*/
|
|
4
|
+
import clsx from 'clsx';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* WordPress dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { useState, useEffect, forwardRef } from '@wordpress/element';
|
|
10
|
+
import { useSelect, useDispatch } from '@wordpress/data';
|
|
11
|
+
import { __experimentalUseDropZone as useDropZone } from '@wordpress/compose';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Internal dependencies
|
|
15
|
+
*/
|
|
16
|
+
import { __unstableUseBlockElement as useBlockElement } from '../block-list/use-block-props/use-block-refs';
|
|
17
|
+
import BlockPopoverCover from '../block-popover/cover';
|
|
18
|
+
import { range, GridRect, getGridInfo } from './utils';
|
|
19
|
+
import { store as blockEditorStore } from '../../store';
|
|
20
|
+
import { useGetNumberOfBlocksBeforeCell } from './use-get-number-of-blocks-before-cell';
|
|
21
|
+
|
|
22
|
+
export function GridVisualizer( { clientId, contentRef, parentLayout } ) {
|
|
23
|
+
const isDistractionFree = useSelect(
|
|
24
|
+
( select ) =>
|
|
25
|
+
select( blockEditorStore ).getSettings().isDistractionFree,
|
|
26
|
+
[]
|
|
27
|
+
);
|
|
28
|
+
const gridElement = useBlockElement( clientId );
|
|
29
|
+
|
|
30
|
+
if ( isDistractionFree || ! gridElement ) {
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const isManualGrid =
|
|
35
|
+
parentLayout?.columnCount &&
|
|
36
|
+
window.__experimentalEnableGridInteractivity;
|
|
37
|
+
return (
|
|
38
|
+
<GridVisualizerGrid
|
|
39
|
+
clientId={ clientId }
|
|
40
|
+
gridElement={ gridElement }
|
|
41
|
+
isManualGrid={ isManualGrid }
|
|
42
|
+
ref={ contentRef }
|
|
43
|
+
/>
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
const GridVisualizerGrid = forwardRef(
|
|
48
|
+
( { clientId, gridElement, isManualGrid }, ref ) => {
|
|
49
|
+
const [ gridInfo, setGridInfo ] = useState( () =>
|
|
50
|
+
getGridInfo( gridElement )
|
|
51
|
+
);
|
|
52
|
+
const [ isDroppingAllowed, setIsDroppingAllowed ] = useState( false );
|
|
53
|
+
const [ highlightedRect, setHighlightedRect ] = useState( null );
|
|
54
|
+
|
|
55
|
+
useEffect( () => {
|
|
56
|
+
const observers = [];
|
|
57
|
+
for ( const element of [ gridElement, ...gridElement.children ] ) {
|
|
58
|
+
const observer = new window.ResizeObserver( () => {
|
|
59
|
+
setGridInfo( getGridInfo( gridElement ) );
|
|
60
|
+
} );
|
|
61
|
+
observer.observe( element );
|
|
62
|
+
observers.push( observer );
|
|
63
|
+
}
|
|
64
|
+
return () => {
|
|
65
|
+
for ( const observer of observers ) {
|
|
66
|
+
observer.disconnect();
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
}, [ gridElement ] );
|
|
70
|
+
|
|
71
|
+
useEffect( () => {
|
|
72
|
+
function onGlobalDrag() {
|
|
73
|
+
setIsDroppingAllowed( true );
|
|
74
|
+
}
|
|
75
|
+
function onGlobalDragEnd() {
|
|
76
|
+
setIsDroppingAllowed( false );
|
|
77
|
+
}
|
|
78
|
+
document.addEventListener( 'drag', onGlobalDrag );
|
|
79
|
+
document.addEventListener( 'dragend', onGlobalDragEnd );
|
|
80
|
+
return () => {
|
|
81
|
+
document.removeEventListener( 'drag', onGlobalDrag );
|
|
82
|
+
document.removeEventListener( 'dragend', onGlobalDragEnd );
|
|
83
|
+
};
|
|
84
|
+
}, [] );
|
|
85
|
+
|
|
86
|
+
return (
|
|
87
|
+
<BlockPopoverCover
|
|
88
|
+
className={ clsx( 'block-editor-grid-visualizer', {
|
|
89
|
+
'is-dropping-allowed': isDroppingAllowed,
|
|
90
|
+
} ) }
|
|
91
|
+
clientId={ clientId }
|
|
92
|
+
__unstablePopoverSlot="block-toolbar"
|
|
93
|
+
>
|
|
94
|
+
<div
|
|
95
|
+
ref={ ref }
|
|
96
|
+
className="block-editor-grid-visualizer__grid"
|
|
97
|
+
style={ gridInfo.style }
|
|
98
|
+
>
|
|
99
|
+
{ isManualGrid
|
|
100
|
+
? range( 1, gridInfo.numRows ).map( ( row ) =>
|
|
101
|
+
range( 1, gridInfo.numColumns ).map(
|
|
102
|
+
( column ) => (
|
|
103
|
+
<GridVisualizerCell
|
|
104
|
+
key={ `${ row }-${ column }` }
|
|
105
|
+
color={ gridInfo.currentColor }
|
|
106
|
+
>
|
|
107
|
+
<GridVisualizerDropZone
|
|
108
|
+
column={ column }
|
|
109
|
+
row={ row }
|
|
110
|
+
gridClientId={ clientId }
|
|
111
|
+
gridInfo={ gridInfo }
|
|
112
|
+
highlightedRect={
|
|
113
|
+
highlightedRect
|
|
114
|
+
}
|
|
115
|
+
setHighlightedRect={
|
|
116
|
+
setHighlightedRect
|
|
117
|
+
}
|
|
118
|
+
/>
|
|
119
|
+
</GridVisualizerCell>
|
|
120
|
+
)
|
|
121
|
+
)
|
|
122
|
+
)
|
|
123
|
+
: Array.from(
|
|
124
|
+
{ length: gridInfo.numItems },
|
|
125
|
+
( _, i ) => (
|
|
126
|
+
<GridVisualizerCell
|
|
127
|
+
key={ i }
|
|
128
|
+
color={ gridInfo.currentColor }
|
|
129
|
+
/>
|
|
130
|
+
)
|
|
131
|
+
) }
|
|
132
|
+
</div>
|
|
133
|
+
</BlockPopoverCover>
|
|
134
|
+
);
|
|
135
|
+
}
|
|
136
|
+
);
|
|
137
|
+
|
|
138
|
+
function GridVisualizerCell( { color, children } ) {
|
|
139
|
+
return (
|
|
140
|
+
<div
|
|
141
|
+
className="block-editor-grid-visualizer__cell"
|
|
142
|
+
style={ {
|
|
143
|
+
boxShadow: `inset 0 0 0 1px color-mix(in srgb, ${ color } 20%, #0000)`,
|
|
144
|
+
} }
|
|
145
|
+
>
|
|
146
|
+
{ children }
|
|
147
|
+
</div>
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function GridVisualizerDropZone( {
|
|
152
|
+
column,
|
|
153
|
+
row,
|
|
154
|
+
gridClientId,
|
|
155
|
+
gridInfo,
|
|
156
|
+
highlightedRect,
|
|
157
|
+
setHighlightedRect,
|
|
158
|
+
} ) {
|
|
159
|
+
const { getBlockAttributes } = useSelect( blockEditorStore );
|
|
160
|
+
const {
|
|
161
|
+
updateBlockAttributes,
|
|
162
|
+
moveBlocksToPosition,
|
|
163
|
+
__unstableMarkNextChangeAsNotPersistent,
|
|
164
|
+
} = useDispatch( blockEditorStore );
|
|
165
|
+
|
|
166
|
+
const getNumberOfBlocksBeforeCell = useGetNumberOfBlocksBeforeCell(
|
|
167
|
+
gridClientId,
|
|
168
|
+
gridInfo.numColumns
|
|
169
|
+
);
|
|
170
|
+
|
|
171
|
+
const ref = useDropZoneWithValidation( {
|
|
172
|
+
validateDrag( srcClientId ) {
|
|
173
|
+
const attributes = getBlockAttributes( srcClientId );
|
|
174
|
+
const rect = new GridRect( {
|
|
175
|
+
columnStart: column,
|
|
176
|
+
rowStart: row,
|
|
177
|
+
columnSpan: attributes.style?.layout?.columnSpan,
|
|
178
|
+
rowSpan: attributes.style?.layout?.rowSpan,
|
|
179
|
+
} );
|
|
180
|
+
const isInBounds = new GridRect( {
|
|
181
|
+
columnSpan: gridInfo.numColumns,
|
|
182
|
+
rowSpan: gridInfo.numRows,
|
|
183
|
+
} ).containsRect( rect );
|
|
184
|
+
return isInBounds;
|
|
185
|
+
},
|
|
186
|
+
onDragEnter( srcClientId ) {
|
|
187
|
+
const attributes = getBlockAttributes( srcClientId );
|
|
188
|
+
setHighlightedRect(
|
|
189
|
+
new GridRect( {
|
|
190
|
+
columnStart: column,
|
|
191
|
+
rowStart: row,
|
|
192
|
+
columnSpan: attributes.style?.layout?.columnSpan,
|
|
193
|
+
rowSpan: attributes.style?.layout?.rowSpan,
|
|
194
|
+
} )
|
|
195
|
+
);
|
|
196
|
+
},
|
|
197
|
+
onDragLeave() {
|
|
198
|
+
// onDragEnter can be called before onDragLeave if the user moves
|
|
199
|
+
// their mouse quickly, so only clear the highlight if it was set
|
|
200
|
+
// by this cell.
|
|
201
|
+
setHighlightedRect( ( prevHighlightedRect ) =>
|
|
202
|
+
prevHighlightedRect?.columnStart === column &&
|
|
203
|
+
prevHighlightedRect?.rowStart === row
|
|
204
|
+
? null
|
|
205
|
+
: prevHighlightedRect
|
|
206
|
+
);
|
|
207
|
+
},
|
|
208
|
+
onDrop( srcClientId ) {
|
|
209
|
+
setHighlightedRect( null );
|
|
210
|
+
const attributes = getBlockAttributes( srcClientId );
|
|
211
|
+
updateBlockAttributes( srcClientId, {
|
|
212
|
+
style: {
|
|
213
|
+
...attributes.style,
|
|
214
|
+
layout: {
|
|
215
|
+
...attributes.style?.layout,
|
|
216
|
+
columnStart: column,
|
|
217
|
+
rowStart: row,
|
|
218
|
+
},
|
|
219
|
+
},
|
|
220
|
+
} );
|
|
221
|
+
__unstableMarkNextChangeAsNotPersistent();
|
|
222
|
+
moveBlocksToPosition(
|
|
223
|
+
[ srcClientId ],
|
|
224
|
+
gridClientId,
|
|
225
|
+
gridClientId,
|
|
226
|
+
getNumberOfBlocksBeforeCell( column, row )
|
|
227
|
+
);
|
|
228
|
+
},
|
|
229
|
+
} );
|
|
230
|
+
|
|
231
|
+
const isHighlighted = highlightedRect?.contains( column, row ) ?? false;
|
|
232
|
+
|
|
233
|
+
return (
|
|
234
|
+
<div
|
|
235
|
+
ref={ ref }
|
|
236
|
+
className={ clsx( 'block-editor-grid-visualizer__drop-zone', {
|
|
237
|
+
'is-highlighted': isHighlighted,
|
|
238
|
+
} ) }
|
|
239
|
+
/>
|
|
240
|
+
);
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
function useDropZoneWithValidation( {
|
|
244
|
+
validateDrag,
|
|
245
|
+
onDragEnter,
|
|
246
|
+
onDragLeave,
|
|
247
|
+
onDrop,
|
|
248
|
+
} ) {
|
|
249
|
+
const { getDraggedBlockClientIds } = useSelect( blockEditorStore );
|
|
250
|
+
return useDropZone( {
|
|
251
|
+
onDragEnter() {
|
|
252
|
+
const [ srcClientId ] = getDraggedBlockClientIds();
|
|
253
|
+
if ( srcClientId && validateDrag( srcClientId ) ) {
|
|
254
|
+
onDragEnter( srcClientId );
|
|
255
|
+
}
|
|
256
|
+
},
|
|
257
|
+
onDragLeave() {
|
|
258
|
+
onDragLeave();
|
|
259
|
+
},
|
|
260
|
+
onDrop() {
|
|
261
|
+
const [ srcClientId ] = getDraggedBlockClientIds();
|
|
262
|
+
if ( srcClientId && validateDrag( srcClientId ) ) {
|
|
263
|
+
onDrop( srcClientId );
|
|
264
|
+
}
|
|
265
|
+
},
|
|
266
|
+
} );
|
|
267
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
.block-editor-grid-visualizer {
|
|
2
|
+
// Specificity to override the z-index and pointer-events set by .components-popover.
|
|
3
|
+
&.block-editor-grid-visualizer.block-editor-grid-visualizer {
|
|
4
|
+
z-index: z-index(".block-editor-grid-visualizer");
|
|
5
|
+
|
|
6
|
+
.components-popover__content * {
|
|
7
|
+
pointer-events: none;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
&.is-dropping-allowed {
|
|
11
|
+
.block-editor-grid-visualizer__drop-zone {
|
|
12
|
+
pointer-events: all;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
.block-editor-grid-visualizer__grid {
|
|
19
|
+
display: grid;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
.block-editor-grid-visualizer__cell {
|
|
23
|
+
align-items: center;
|
|
24
|
+
display: flex;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.block-editor-grid-visualizer__drop-zone {
|
|
29
|
+
background: rgba($gray-400, 0.1);
|
|
30
|
+
border: $border-width dotted $gray-300;
|
|
31
|
+
width: 100%;
|
|
32
|
+
height: 100%;
|
|
33
|
+
|
|
34
|
+
// Make drop zone 8x8 at minimum so that it's easier to drag into. This will overflow the parent.
|
|
35
|
+
min-width: $grid-unit-10;
|
|
36
|
+
min-height: $grid-unit-10;
|
|
37
|
+
|
|
38
|
+
&.is-highlighted {
|
|
39
|
+
background: var(--wp-admin-theme-color);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
.block-editor-grid-item-resizer {
|
|
44
|
+
// Specificity to override the z-index and pointer-events set by .components-popover.
|
|
45
|
+
&.block-editor-grid-item-resizer.block-editor-grid-item-resizer {
|
|
46
|
+
z-index: z-index(".block-editor-grid-visualizer");
|
|
47
|
+
|
|
48
|
+
.components-popover__content * {
|
|
49
|
+
pointer-events: none;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
.block-editor-grid-item-resizer__box {
|
|
55
|
+
border: $border-width solid var(--wp-admin-theme-color);
|
|
56
|
+
|
|
57
|
+
.components-resizable-box__handle {
|
|
58
|
+
// Specificity to override the pointer-events set by .components-popover.
|
|
59
|
+
&.components-resizable-box__handle.components-resizable-box__handle {
|
|
60
|
+
pointer-events: all;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useSelect } from '@wordpress/data';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Internal dependencies
|
|
8
|
+
*/
|
|
9
|
+
import { store as blockEditorStore } from '../../store';
|
|
10
|
+
|
|
11
|
+
export function useGetNumberOfBlocksBeforeCell( gridClientId, numColumns ) {
|
|
12
|
+
const { getBlockOrder, getBlockAttributes } = useSelect( blockEditorStore );
|
|
13
|
+
|
|
14
|
+
const getNumberOfBlocksBeforeCell = ( column, row ) => {
|
|
15
|
+
const targetIndex = ( row - 1 ) * numColumns + column - 1;
|
|
16
|
+
|
|
17
|
+
let count = 0;
|
|
18
|
+
for ( const clientId of getBlockOrder( gridClientId ) ) {
|
|
19
|
+
const { columnStart, rowStart } =
|
|
20
|
+
getBlockAttributes( clientId ).style?.layout ?? {};
|
|
21
|
+
const cellIndex = ( rowStart - 1 ) * numColumns + columnStart - 1;
|
|
22
|
+
if ( cellIndex < targetIndex ) {
|
|
23
|
+
count++;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return count;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
return getNumberOfBlocksBeforeCell;
|
|
30
|
+
}
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* WordPress dependencies
|
|
3
|
+
*/
|
|
4
|
+
import { useDispatch, useSelect } from '@wordpress/data';
|
|
5
|
+
import { useEffect } from '@wordpress/element';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Internal dependencies
|
|
9
|
+
*/
|
|
10
|
+
import { store as blockEditorStore } from '../../store';
|
|
11
|
+
import { GridRect } from './utils';
|
|
12
|
+
|
|
13
|
+
export function useGridLayoutSync( { clientId: gridClientId } ) {
|
|
14
|
+
const { gridLayout, blockOrder } = useSelect(
|
|
15
|
+
( select ) => {
|
|
16
|
+
const { getBlockAttributes, getBlockOrder } =
|
|
17
|
+
select( blockEditorStore );
|
|
18
|
+
return {
|
|
19
|
+
gridLayout: getBlockAttributes( gridClientId ).layout ?? {},
|
|
20
|
+
blockOrder: getBlockOrder( gridClientId ),
|
|
21
|
+
};
|
|
22
|
+
},
|
|
23
|
+
[ gridClientId ]
|
|
24
|
+
);
|
|
25
|
+
|
|
26
|
+
const { getBlockAttributes } = useSelect( blockEditorStore );
|
|
27
|
+
const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } =
|
|
28
|
+
useDispatch( blockEditorStore );
|
|
29
|
+
|
|
30
|
+
useEffect( () => {
|
|
31
|
+
const updates = {};
|
|
32
|
+
|
|
33
|
+
const { columnCount, rowCount = 2 } = gridLayout;
|
|
34
|
+
const isManualGrid = !! columnCount;
|
|
35
|
+
|
|
36
|
+
if ( isManualGrid ) {
|
|
37
|
+
const rects = [];
|
|
38
|
+
let cellsTaken = 0;
|
|
39
|
+
|
|
40
|
+
// Respect the position of blocks that already have a columnStart and rowStart value.
|
|
41
|
+
for ( const clientId of blockOrder ) {
|
|
42
|
+
const attributes = getBlockAttributes( clientId );
|
|
43
|
+
const {
|
|
44
|
+
columnStart,
|
|
45
|
+
rowStart,
|
|
46
|
+
columnSpan = 1,
|
|
47
|
+
rowSpan = 1,
|
|
48
|
+
} = attributes.style?.layout || {};
|
|
49
|
+
cellsTaken += columnSpan * rowSpan;
|
|
50
|
+
if ( ! columnStart || ! rowStart ) {
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
rects.push(
|
|
54
|
+
new GridRect( {
|
|
55
|
+
columnStart,
|
|
56
|
+
rowStart,
|
|
57
|
+
columnSpan,
|
|
58
|
+
rowSpan,
|
|
59
|
+
} )
|
|
60
|
+
);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// Ensure there's enough rows to fit all blocks.
|
|
64
|
+
const minimumNeededRows = Math.ceil( cellsTaken / columnCount );
|
|
65
|
+
if ( rowCount < minimumNeededRows ) {
|
|
66
|
+
updates[ gridClientId ] = {
|
|
67
|
+
layout: {
|
|
68
|
+
...gridLayout,
|
|
69
|
+
rowCount: minimumNeededRows,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// When in manual mode, ensure that every block has a columnStart and rowStart value.
|
|
75
|
+
for ( const clientId of blockOrder ) {
|
|
76
|
+
const attributes = getBlockAttributes( clientId );
|
|
77
|
+
const { columnStart, rowStart, columnSpan, rowSpan } =
|
|
78
|
+
attributes.style?.layout || {};
|
|
79
|
+
if ( columnStart && rowStart ) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const [ newColumnStart, newRowStart ] = getFirstEmptyCell(
|
|
83
|
+
rects,
|
|
84
|
+
columnCount,
|
|
85
|
+
minimumNeededRows,
|
|
86
|
+
columnSpan,
|
|
87
|
+
rowSpan
|
|
88
|
+
);
|
|
89
|
+
rects.push(
|
|
90
|
+
new GridRect( {
|
|
91
|
+
columnStart: newColumnStart,
|
|
92
|
+
rowStart: newRowStart,
|
|
93
|
+
columnSpan,
|
|
94
|
+
rowSpan,
|
|
95
|
+
} )
|
|
96
|
+
);
|
|
97
|
+
updates[ clientId ] = {
|
|
98
|
+
style: {
|
|
99
|
+
...attributes.style,
|
|
100
|
+
layout: {
|
|
101
|
+
...attributes.style?.layout,
|
|
102
|
+
columnStart: newColumnStart,
|
|
103
|
+
rowStart: newRowStart,
|
|
104
|
+
},
|
|
105
|
+
},
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
} else {
|
|
109
|
+
// When in auto mode, remove all of the columnStart and rowStart values.
|
|
110
|
+
for ( const clientId of blockOrder ) {
|
|
111
|
+
const attributes = getBlockAttributes( clientId );
|
|
112
|
+
const { columnStart, rowStart, ...layout } =
|
|
113
|
+
attributes.style?.layout || {};
|
|
114
|
+
// Only update attributes if columnStart or rowStart are set.
|
|
115
|
+
if ( columnStart || rowStart ) {
|
|
116
|
+
updates[ clientId ] = {
|
|
117
|
+
style: {
|
|
118
|
+
...attributes.style,
|
|
119
|
+
layout,
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if ( Object.keys( updates ).length ) {
|
|
127
|
+
__unstableMarkNextChangeAsNotPersistent();
|
|
128
|
+
updateBlockAttributes(
|
|
129
|
+
Object.keys( updates ),
|
|
130
|
+
updates,
|
|
131
|
+
/* uniqueByBlock: */ true
|
|
132
|
+
);
|
|
133
|
+
}
|
|
134
|
+
}, [
|
|
135
|
+
// Actual deps to sync:
|
|
136
|
+
gridClientId,
|
|
137
|
+
gridLayout,
|
|
138
|
+
blockOrder,
|
|
139
|
+
// Needed for linter:
|
|
140
|
+
__unstableMarkNextChangeAsNotPersistent,
|
|
141
|
+
getBlockAttributes,
|
|
142
|
+
updateBlockAttributes,
|
|
143
|
+
] );
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function getFirstEmptyCell(
|
|
147
|
+
rects,
|
|
148
|
+
columnCount,
|
|
149
|
+
rowCount,
|
|
150
|
+
columnSpan = 1,
|
|
151
|
+
rowSpan = 1
|
|
152
|
+
) {
|
|
153
|
+
for ( let row = 1; row <= rowCount; row++ ) {
|
|
154
|
+
for ( let column = 1; column <= columnCount; column++ ) {
|
|
155
|
+
const rect = new GridRect( {
|
|
156
|
+
columnStart: column,
|
|
157
|
+
rowStart: row,
|
|
158
|
+
columnSpan,
|
|
159
|
+
rowSpan,
|
|
160
|
+
} );
|
|
161
|
+
if ( ! rects.some( ( r ) => r.intersectsRect( rect ) ) ) {
|
|
162
|
+
return [ column, row ];
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return [ 1, 1 ];
|
|
167
|
+
}
|