-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Grid interactivity: Allow blocks to be positioned in manual mode using drag and drop #61025
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 14 commits
539bb86
37ff369
b3e7d95
eb732d1
6b72367
73b821a
9dff09b
eef95b2
ef056c1
ca959da
4ac5e9d
881af91
5f6e8d7
249549b
86f0c1c
fa2b066
28ab6b9
29e97e1
e2b2897
b79494d
81623d5
2b2e16a
9621ddb
2062300
f1141af
3455e3c
51de6e8
f1f82b2
c12b098
c80ce4d
d982fdf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -25,14 +25,22 @@ function BlockMover( { | |
isBlockMoverUpButtonDisabled, | ||
isBlockMoverDownButtonDisabled, | ||
} ) { | ||
const { canMove, rootClientId, isFirst, isLast, orientation } = useSelect( | ||
const { | ||
canMove, | ||
rootClientId, | ||
isFirst, | ||
isLast, | ||
orientation, | ||
isManualGrid, | ||
} = useSelect( | ||
( select ) => { | ||
const { | ||
getBlockIndex, | ||
getBlockListSettings, | ||
canMoveBlocks, | ||
getBlockOrder, | ||
getBlockRootClientId, | ||
getBlockAttributes, | ||
} = select( blockEditorStore ); | ||
const normalizedClientIds = Array.isArray( clientIds ) | ||
? clientIds | ||
|
@@ -44,13 +52,17 @@ function BlockMover( { | |
normalizedClientIds[ normalizedClientIds.length - 1 ] | ||
); | ||
const blockOrder = getBlockOrder( _rootClientId ); | ||
const { layout = {} } = getBlockAttributes( _rootClientId ) ?? {}; | ||
|
||
return { | ||
canMove: canMoveBlocks( clientIds, _rootClientId ), | ||
rootClientId: _rootClientId, | ||
isFirst: firstIndex === 0, | ||
isLast: lastIndex === blockOrder.length - 1, | ||
orientation: getBlockListSettings( _rootClientId )?.orientation, | ||
// TODO: Doesn't feel great to couple BlockMover and grid layouts. | ||
// TODO: Can we use useLayout() instead? | ||
isManualGrid: layout.type === 'grid' && !! layout.columnCount, | ||
|
||
}; | ||
}, | ||
[ clientIds ] | ||
|
@@ -60,8 +72,6 @@ function BlockMover( { | |
return null; | ||
} | ||
|
||
const dragHandleLabel = __( 'Drag' ); | ||
|
||
return ( | ||
<ToolbarGroup | ||
className={ clsx( 'block-editor-block-mover', { | ||
|
@@ -75,7 +85,7 @@ function BlockMover( { | |
icon={ dragHandle } | ||
className="block-editor-block-mover__drag-handle" | ||
aria-hidden="true" | ||
label={ dragHandleLabel } | ||
label={ __( 'Drag' ) } | ||
// Should not be able to tab to drag handle as this | ||
// button can only be used with a pointer device. | ||
tabIndex="-1" | ||
|
@@ -84,26 +94,28 @@ function BlockMover( { | |
) } | ||
</BlockDraggable> | ||
) } | ||
<div className="block-editor-block-mover__move-button-container"> | ||
<ToolbarItem> | ||
{ ( itemProps ) => ( | ||
<BlockMoverUpButton | ||
disabled={ isBlockMoverUpButtonDisabled } | ||
clientIds={ clientIds } | ||
{ ...itemProps } | ||
/> | ||
) } | ||
</ToolbarItem> | ||
<ToolbarItem> | ||
{ ( itemProps ) => ( | ||
<BlockMoverDownButton | ||
disabled={ isBlockMoverDownButtonDisabled } | ||
clientIds={ clientIds } | ||
{ ...itemProps } | ||
/> | ||
) } | ||
</ToolbarItem> | ||
</div> | ||
{ ! isManualGrid && ( | ||
<div className="block-editor-block-mover__move-button-container"> | ||
<ToolbarItem> | ||
{ ( itemProps ) => ( | ||
<BlockMoverUpButton | ||
disabled={ isBlockMoverUpButtonDisabled } | ||
clientIds={ clientIds } | ||
{ ...itemProps } | ||
/> | ||
) } | ||
</ToolbarItem> | ||
<ToolbarItem> | ||
{ ( itemProps ) => ( | ||
<BlockMoverDownButton | ||
disabled={ isBlockMoverDownButtonDisabled } | ||
clientIds={ clientIds } | ||
{ ...itemProps } | ||
/> | ||
) } | ||
</ToolbarItem> | ||
</div> | ||
) } | ||
</ToolbarGroup> | ||
); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -14,6 +14,13 @@ import { | |
} from '@wordpress/components'; | ||
import { __ } from '@wordpress/i18n'; | ||
import { useEffect } from '@wordpress/element'; | ||
import { useSelect, useDispatch } from '@wordpress/data'; | ||
|
||
/** | ||
* Internal dependencies | ||
*/ | ||
import { useGetBlocksBeforeCurrentCell } from '../grid/use-get-blocks-before-current-cell'; | ||
import { store as blockEditorStore } from '../../store'; | ||
|
||
function helpText( selfStretch, parentLayout ) { | ||
const { orientation = 'horizontal' } = parentLayout; | ||
|
@@ -60,9 +67,19 @@ export default function ChildLayoutControl( { | |
type: parentType, | ||
default: { type: defaultParentType = 'default' } = {}, | ||
orientation = 'horizontal', | ||
columnCount, | ||
} = parentLayout ?? {}; | ||
const parentLayoutType = parentType || defaultParentType; | ||
|
||
const gridColumnNumber = parseInt( columnCount, 10 ) || 3; | ||
const rootClientId = useSelect( ( select ) => | ||
select( blockEditorStore ).getBlockRootClientId( panelId ) | ||
); | ||
const { moveBlocksToPosition } = useDispatch( blockEditorStore ); | ||
const getBlocksBeforeCurrentCell = useGetBlocksBeforeCurrentCell( | ||
|
||
rootClientId, | ||
gridColumnNumber, | ||
parentLayoutType === 'grid' | ||
); | ||
const hasFlexValue = () => !! selfStretch; | ||
const flexResetLabel = | ||
orientation === 'horizontal' ? __( 'Width' ) : __( 'Height' ); | ||
|
@@ -196,68 +213,96 @@ export default function ChildLayoutControl( { | |
min={ 1 } | ||
/> | ||
</HStack> | ||
{ window.__experimentalEnableGridInteractivity && ( | ||
// Use Flex with an explicit width on the FlexItem instead of HStack to | ||
// work around an issue in webkit where inputs with a max attribute are | ||
// sized incorrectly. | ||
<Flex | ||
as={ ToolsPanelItem } | ||
hasValue={ hasStartValue } | ||
label={ __( 'Grid placement' ) } | ||
onDeselect={ resetGridStarts } | ||
isShownByDefault={ false } | ||
panelId={ panelId } | ||
> | ||
<FlexItem style={ { width: '50%' } }> | ||
<InputControl | ||
size="__unstable-large" | ||
label={ __( 'Column' ) } | ||
type="number" | ||
onChange={ ( value ) => { | ||
onChange( { | ||
columnStart: value, | ||
rowStart, | ||
columnSpan, | ||
rowSpan, | ||
} ); | ||
} } | ||
value={ columnStart } | ||
min={ 1 } | ||
max={ | ||
parentLayout?.columnCount | ||
? parentLayout.columnCount - | ||
( columnSpan ?? 1 ) + | ||
1 | ||
: undefined | ||
} | ||
/> | ||
</FlexItem> | ||
<FlexItem style={ { width: '50%' } }> | ||
<InputControl | ||
size="__unstable-large" | ||
label={ __( 'Row' ) } | ||
type="number" | ||
onChange={ ( value ) => { | ||
onChange( { | ||
columnStart, | ||
rowStart: value, | ||
columnSpan, | ||
rowSpan, | ||
} ); | ||
} } | ||
value={ rowStart } | ||
min={ 1 } | ||
max={ | ||
parentLayout?.rowCount | ||
? parentLayout.rowCount - | ||
( rowSpan ?? 1 ) + | ||
1 | ||
: undefined | ||
} | ||
/> | ||
</FlexItem> | ||
</Flex> | ||
) } | ||
{ window.__experimentalEnableGridInteractivity && | ||
columnCount && ( | ||
// Use Flex with an explicit width on the FlexItem instead of HStack to | ||
// work around an issue in webkit where inputs with a max attribute are | ||
// sized incorrectly. | ||
<Flex | ||
as={ ToolsPanelItem } | ||
hasValue={ hasStartValue } | ||
label={ __( 'Grid placement' ) } | ||
onDeselect={ resetGridStarts } | ||
isShownByDefault={ false } | ||
panelId={ panelId } | ||
> | ||
<FlexItem style={ { width: '50%' } }> | ||
<InputControl | ||
size="__unstable-large" | ||
label={ __( 'Column' ) } | ||
type="number" | ||
onChange={ ( value ) => { | ||
onChange( { | ||
columnStart: value, | ||
rowStart, | ||
columnSpan, | ||
rowSpan, | ||
} ); | ||
const currentBlockIndex = | ||
( parseInt( rowStart, 10 ) - | ||
1 ) * | ||
gridColumnNumber + | ||
parseInt( value, 10 ) - | ||
1; | ||
moveBlocksToPosition( | ||
[ panelId ], | ||
rootClientId, | ||
rootClientId, | ||
getBlocksBeforeCurrentCell( | ||
currentBlockIndex | ||
) | ||
); | ||
} } | ||
value={ columnStart } | ||
min={ 1 } | ||
max={ | ||
gridColumnNumber | ||
? gridColumnNumber - | ||
( columnSpan ?? 1 ) + | ||
1 | ||
: undefined | ||
} | ||
/> | ||
</FlexItem> | ||
<FlexItem style={ { width: '50%' } }> | ||
<InputControl | ||
size="__unstable-large" | ||
label={ __( 'Row' ) } | ||
type="number" | ||
onChange={ ( value ) => { | ||
onChange( { | ||
columnStart, | ||
rowStart: value, | ||
columnSpan, | ||
rowSpan, | ||
} ); | ||
const currentBlockIndex = | ||
( parseInt( value, 10 ) - 1 ) * | ||
gridColumnNumber + | ||
parseInt( columnStart, 10 ) - | ||
1; | ||
moveBlocksToPosition( | ||
[ panelId ], | ||
rootClientId, | ||
rootClientId, | ||
getBlocksBeforeCurrentCell( | ||
currentBlockIndex | ||
) | ||
); | ||
} } | ||
value={ rowStart } | ||
min={ 1 } | ||
max={ | ||
parentLayout?.rowCount | ||
? parentLayout.rowCount - | ||
( rowSpan ?? 1 ) + | ||
1 | ||
: undefined | ||
} | ||
/> | ||
</FlexItem> | ||
</Flex> | ||
) } | ||
</> | ||
) } | ||
</> | ||
|
Uh oh!
There was an error while loading. Please reload this page.