-
Notifications
You must be signed in to change notification settings - Fork 4.7k
Add list view inspector tab for pattern editing #74574
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 all commits
5b79516
02092e8
2097bd8
0389ebe
a74668b
ad4f94d
ea030e6
89554ee
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 |
|---|---|---|
|
|
@@ -36,14 +36,12 @@ function StyleInspectorSlots( { | |
| blockName, | ||
| showAdvancedControls = true, | ||
| showPositionControls = true, | ||
| showListControls = false, | ||
| showBindingsControls = true, | ||
| } ) { | ||
| const borderPanelLabel = useBorderPanelLabel( { blockName } ); | ||
| return ( | ||
| <> | ||
| <InspectorControls.Slot /> | ||
| { showListControls && <InspectorControls.Slot group="list" /> } | ||
| <InspectorControls.Slot | ||
| group="color" | ||
| label={ __( 'Color' ) } | ||
|
|
@@ -377,11 +375,9 @@ const BlockInspectorSingleBlock = ( { | |
| ) } | ||
| <ContentTab contentClientIds={ contentClientIds } /> | ||
| <InspectorControls.Slot group="content" /> | ||
| <InspectorControls.Slot group="list" /> | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may have been for convenience, not sure, but the List tab was previously rendered as part of I've moved it out of that component to here, which feels like the right move to me. |
||
| { ! isSectionBlock && ( | ||
| <StyleInspectorSlots | ||
| blockName={ blockName } | ||
| showListControls | ||
| /> | ||
| <StyleInspectorSlots blockName={ blockName } /> | ||
| ) } | ||
| { isSectionBlock && | ||
| isBlockSynced && | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -195,6 +195,7 @@ function BlockListBlock( { | |
| isParentSelected, | ||
| order, | ||
| mayDisplayControls, | ||
| mayDisplayPatternEditingControls, | ||
| blockEditingMode, | ||
| } = useSelect( | ||
| ( select ) => { | ||
|
|
@@ -263,6 +264,7 @@ function BlockListBlock( { | |
| getMultiSelectedBlockClientIds().every( | ||
| ( id ) => getBlockName( id ) === name | ||
| ) ), | ||
| mayDisplayPatternEditingControls: false, // Section/pattern editing not yet supported on native | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Claude did this, I don't know if it's the right move 🤷
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are these native files still in development? The last mobile-specific edit to this file was mid-2024.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think native has had any content-only/pattern editing changes thus far? Might be wrong.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think so, so I can probably remove the changes. Last I remember the native code doesn't even compile, the CI tests are skipped. |
||
| blockEditingMode: getBlockEditingMode( clientId ), | ||
| }; | ||
| }, | ||
|
|
@@ -403,6 +405,9 @@ function BlockListBlock( { | |
| } | ||
| wrapperProps={ wrapperProps } | ||
| mayDisplayControls={ mayDisplayControls } | ||
| mayDisplayPatternEditingControls={ | ||
| mayDisplayPatternEditingControls | ||
| } | ||
| blockEditingMode={ blockEditingMode } | ||
| /> | ||
| <View onLayout={ onLayout } /> | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -84,26 +84,29 @@ export default function useInspectorControlsTabs( | |
| ...( hasListFills && hasStyleFills > 1 ? advancedFills : [] ), | ||
| ]; | ||
|
|
||
| // When the block fields experiment is active, only rely on `hasContentFills` | ||
| // to determine whether the content tab to be shown. The tab purely uses slot | ||
| // fills in this situation. | ||
| const shouldShowBlockFields = | ||
| window?.__experimentalContentOnlyInspectorFields; | ||
| const hasContentTab = | ||
| hasContentFills || | ||
| !! ( contentClientIds && contentClientIds.length > 0 ); | ||
| ( ! shouldShowBlockFields && contentClientIds?.length ); | ||
|
|
||
| const hasListTab = hasListFills && ! isSectionBlock; | ||
| if ( hasContentTab ) { | ||
| tabs.push( TAB_CONTENT ); | ||
| } | ||
|
|
||
| // Add the tabs in the order that they will default to if available. | ||
| // List View > Content > Settings > Styles. | ||
| if ( hasListTab ) { | ||
| if ( hasListFills ) { | ||
| tabs.push( TAB_LIST_VIEW ); | ||
| } | ||
|
|
||
| if ( hasContentTab ) { | ||
| tabs.push( TAB_CONTENT ); | ||
| } | ||
|
|
||
|
Comment on lines
+96
to
-102
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Reorders the tabs so the List Tab is after the Content tab, like the designs show. |
||
| if ( | ||
| ( settingsFills.length || | ||
| // Advanded fills who up in settings tab if available or they blend into the default tab, if there's only one tab. | ||
| ( advancedFills.length && ( hasContentTab || hasListTab ) ) ) && | ||
| ( advancedFills.length && ( hasContentTab || hasListFills ) ) ) && | ||
| ! isSectionBlock | ||
| ) { | ||
| tabs.push( TAB_SETTINGS ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,15 +15,15 @@ import { useEffect, useContext } from '@wordpress/element'; | |
| import { | ||
| useBlockEditContext, | ||
| mayDisplayControlsKey, | ||
| mayDisplayPatternEditingControlsKey, | ||
| } from '../block-edit/context'; | ||
| import groups from './groups'; | ||
|
|
||
| export function PrivateInspectorControlsFill( { | ||
| export default function InspectorControlsFill( { | ||
| children, | ||
| group = 'default', | ||
| __experimentalGroup, | ||
| resetAllFilter, | ||
| forceDisplayControls, | ||
| } ) { | ||
| if ( __experimentalGroup ) { | ||
| deprecated( | ||
|
|
@@ -43,7 +43,14 @@ export function PrivateInspectorControlsFill( { | |
| warning( `Unknown InspectorControls group "${ group }" provided.` ); | ||
| return null; | ||
| } | ||
| if ( ! forceDisplayControls && ! context[ mayDisplayControlsKey ] ) { | ||
| const shouldDisplayForPatternEditing = | ||
| context[ mayDisplayPatternEditingControlsKey ] && | ||
| ( group === 'list' || group === 'content' ); | ||
|
Comment on lines
+46
to
+48
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Declares exactly which InspectorControls groups support pattern editing, otherwise the Settings tab shows in patterns as well. |
||
|
|
||
| if ( | ||
| ! context[ mayDisplayControlsKey ] && | ||
| ! shouldDisplayForPatternEditing | ||
| ) { | ||
| return null; | ||
| } | ||
|
|
||
|
|
@@ -64,23 +71,6 @@ export function PrivateInspectorControlsFill( { | |
| ); | ||
| } | ||
|
|
||
| export default function InspectorControlsFill( { | ||
| children, | ||
| group = 'default', | ||
| __experimentalGroup, | ||
| resetAllFilter, | ||
| } ) { | ||
| return ( | ||
| <PrivateInspectorControlsFill | ||
| group={ group } | ||
| __experimentalGroup={ __experimentalGroup } | ||
| resetAllFilter={ resetAllFilter } | ||
| > | ||
| { children } | ||
| </PrivateInspectorControlsFill> | ||
| ); | ||
| } | ||
|
|
||
| function RegisterResetAll( { resetAllFilter, children } ) { | ||
| const { registerResetAllFilter, deregisterResetAllFilter } = | ||
| useContext( ToolsPanelContext ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,28 +1,31 @@ | ||
| /** | ||
| * WordPress dependencies | ||
| */ | ||
| import { addFilter } from '@wordpress/hooks'; | ||
| import { privateApis as blocksPrivateApis } from '@wordpress/blocks'; | ||
| import { | ||
| privateApis as blocksPrivateApis, | ||
| getBlockType, | ||
| } from '@wordpress/blocks'; | ||
| import { | ||
| __experimentalHStack as HStack, | ||
| __experimentalTruncate as Truncate, | ||
| } from '@wordpress/components'; | ||
| import { createHigherOrderComponent } from '@wordpress/compose'; | ||
| import { useSelect } from '@wordpress/data'; | ||
| import { DataForm } from '@wordpress/dataviews'; | ||
| import { useContext, useState, useMemo } from '@wordpress/element'; | ||
| import { __ } from '@wordpress/i18n'; | ||
|
|
||
| /** | ||
| * Internal dependencies | ||
| */ | ||
| import { store as blockEditorStore } from '../../store'; | ||
| import { unlock } from '../../lock-unlock'; | ||
| import BlockIcon from '../../components/block-icon'; | ||
| import useBlockDisplayTitle from '../../components/block-title/use-block-display-title'; | ||
| import useBlockDisplayInformation from '../../components/use-block-display-information'; | ||
| const { fieldsKey, formKey } = unlock( blocksPrivateApis ); | ||
| import FieldsDropdownMenu from './fields-dropdown-menu'; | ||
| import { PrivateBlockContext } from '../../components/block-list/private-block-context'; | ||
| import { PrivateInspectorControlsFill } from '../../components/inspector-controls/fill'; | ||
| import InspectorControls from '../../components/inspector-controls/fill'; | ||
|
|
||
| // controls | ||
| import RichText from './rich-text'; | ||
|
|
@@ -49,7 +52,6 @@ function createConfiguredControl( ControlComponent, config = {} ) { | |
| * @param {Object} props | ||
| * @param {string} props.clientId The clientId of the block. | ||
| * @param {Object} props.blockType The blockType definition. | ||
| * @param {Object} props.attributes The block's attribute values. | ||
| * @param {Function} props.setAttributes Action to set the block's attributes. | ||
| * @param {boolean} props.isCollapsed Whether the DataForm is rendered as 'collapsed' with only the first field | ||
| * displayed by default. When collapsed a dropdown is displayed to allow | ||
|
|
@@ -59,7 +61,6 @@ function createConfiguredControl( ControlComponent, config = {} ) { | |
| function BlockFields( { | ||
| clientId, | ||
| blockType, | ||
| attributes, | ||
| setAttributes, | ||
| isCollapsed = false, | ||
| } ) { | ||
|
|
@@ -71,6 +72,11 @@ function BlockFields( { | |
|
|
||
| const blockTypeFields = blockType?.[ fieldsKey ]; | ||
|
|
||
| const attributes = useSelect( | ||
| ( select ) => select( blockEditorStore ).getBlockAttributes( clientId ), | ||
| [ clientId ] | ||
| ); | ||
|
Comment on lines
+75
to
+78
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| const computedForm = useMemo( () => { | ||
| if ( ! isCollapsed ) { | ||
| return blockType?.[ formKey ]; | ||
|
|
@@ -187,56 +193,34 @@ function BlockFields( { | |
| ); | ||
| } | ||
|
|
||
| const withBlockFields = createHigherOrderComponent( | ||
| ( BlockEdit ) => ( props ) => { | ||
| const { | ||
| blockType, | ||
| isSelectionWithinCurrentSection, | ||
| isSectionBlock, | ||
| blockEditingMode, | ||
| isSelected, | ||
| } = useContext( PrivateBlockContext ); | ||
|
|
||
| const shouldShowBlockFields = | ||
| window?.__experimentalContentOnlyInspectorFields; | ||
| const blockTypeFields = blockType?.[ fieldsKey ]; | ||
|
|
||
| if ( ! shouldShowBlockFields || ! blockTypeFields?.length ) { | ||
| return <BlockEdit key="edit" { ...props } />; | ||
| } | ||
| function hasBlockFieldsSupport( blockName ) { | ||
| return !! ( | ||
| window?.__experimentalContentOnlyInspectorFields && | ||
| getBlockType( blockName )?.[ fieldsKey ] | ||
| ); | ||
| } | ||
|
|
||
| return ( | ||
| <> | ||
| <BlockEdit key="edit" { ...props } /> | ||
| { | ||
| // Display the controls of all inner blocks for section/pattern editing. | ||
| isSelectionWithinCurrentSection && | ||
| ( isSectionBlock || | ||
| blockEditingMode === 'contentOnly' ) && ( | ||
| <PrivateInspectorControlsFill | ||
| group="content" | ||
| forceDisplayControls | ||
| > | ||
| <BlockFields | ||
| { ...props } | ||
| blockType={ blockType } | ||
| isCollapsed | ||
| /> | ||
| </PrivateInspectorControlsFill> | ||
| ) | ||
| } | ||
| { ! isSelectionWithinCurrentSection && isSelected && ( | ||
| <PrivateInspectorControlsFill group="content"> | ||
| <BlockFields { ...props } blockType={ blockType } /> | ||
| </PrivateInspectorControlsFill> | ||
| ) } | ||
| </> | ||
| ); | ||
| } | ||
| ); | ||
| export function BlockFieldsPanel( props ) { | ||
| const { blockType, isSelectionWithinCurrentSection } = | ||
| useContext( PrivateBlockContext ); | ||
|
|
||
| addFilter( | ||
| 'editor.BlockEdit', | ||
| 'core/content-only-controls/block-fields', | ||
| withBlockFields | ||
| ); | ||
| return ( | ||
| <InspectorControls group="content"> | ||
| <BlockFields | ||
| { ...props } | ||
| blockType={ blockType } | ||
| isCollapsed={ isSelectionWithinCurrentSection } | ||
| /> | ||
| </InspectorControls> | ||
| ); | ||
| } | ||
|
Comment on lines
+207
to
+216
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is quite a lot simpler now, we generally render the same thing regardless of whether in a pattern or not, the only difference is |
||
|
|
||
| /** | ||
| * Export block support definition. | ||
| */ | ||
| export default { | ||
| edit: BlockFieldsPanel, | ||
| hasSupport: hasBlockFieldsSupport, | ||
| attributeKeys: [], | ||
| supportsPatternEditing: true, | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| }; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm almost certainly missing context here 😅 but my reading of #73845 points to all attribute types (so presumably all the inspector tabs they live in) being displayed in regular (or "design") editing mode? If that's the goal, maybe we don't need this check?
If it does turn out to be needed though, considering that contentOnly mode (not sure if we're still calling it that?) could in future be extended to other places than patterns, it might be good to use a less specific name for this Symbol such as
mayDisplayContentEditingControlsKey.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I'm not sure. Showing Settings for patterns would be a lot. It'd include all of those Advanced panels.
If you're right then there's a chance it can be simplified.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My read was all tabs would be available when not in contentOnly; that would just mean we would always show content/list view. I don't think the settings should be visible in contentOnly.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, they are visible when not in contentOnly.
Example for the List Block:
Kapture.2026-01-14.at.12.59.53.mp4