diff --git a/packages/block-editor/CHANGELOG.md b/packages/block-editor/CHANGELOG.md
index 360ceef02c5754..5ba19b090d9258 100644
--- a/packages/block-editor/CHANGELOG.md
+++ b/packages/block-editor/CHANGELOG.md
@@ -6,6 +6,10 @@
- `LineHeightControl`: Remove deprecated `__nextHasNoMarginBottom` prop and promote to default behavior ([#64281](https://github.com/WordPress/gutenberg/pull/64281)).
+### Enhancements
+
+- `FontFamilyControl`: Add `__nextHasNoMarginBottom` prop for opting into the new margin-free styles ([#64280](https://github.com/WordPress/gutenberg/pull/64280)).
+
## 13.4.0 (2024-07-24)
## 13.3.0 (2024-07-10)
diff --git a/packages/block-editor/src/components/font-family/README.md b/packages/block-editor/src/components/font-family/README.md
index 5300873ab83459..6b37459fd127e7 100644
--- a/packages/block-editor/src/components/font-family/README.md
+++ b/packages/block-editor/src/components/font-family/README.md
@@ -24,6 +24,7 @@ const MyFontFamilyControl = () => {
onChange={ ( newFontFamily ) => {
setFontFamily( newFontFamily );
} }
+ __nextHasNoMarginBottom
/>
);
};
@@ -69,3 +70,10 @@ The current font family value.
- Default: ''
The rest of the props are passed down to the underlying `` instance.
+
+#### `__nextHasNoMarginBottom`
+
+- **Type:** `boolean`
+- **Default:** `false`
+
+Start opting into the new margin-free styles that will become the default in a future version.
diff --git a/packages/block-editor/src/components/font-family/index.js b/packages/block-editor/src/components/font-family/index.js
index 4a40a880e537cb..90a0412463b3ef 100644
--- a/packages/block-editor/src/components/font-family/index.js
+++ b/packages/block-editor/src/components/font-family/index.js
@@ -2,6 +2,7 @@
* WordPress dependencies
*/
import { SelectControl } from '@wordpress/components';
+import deprecated from '@wordpress/deprecated';
import { __ } from '@wordpress/i18n';
/**
@@ -10,6 +11,8 @@ import { __ } from '@wordpress/i18n';
import { useSettings } from '../use-settings';
export default function FontFamilyControl( {
+ /** Start opting into the new margin-free styles that will become the default in a future version. */
+ __nextHasNoMarginBottom = false,
value = '',
onChange,
fontFamilies,
@@ -33,8 +36,21 @@ export default function FontFamilyControl( {
};
} ),
];
+
+ if ( ! __nextHasNoMarginBottom ) {
+ deprecated(
+ 'Bottom margin styles for wp.blockEditor.FontFamilyControl',
+ {
+ since: '6.7',
+ version: '7.0',
+ hint: 'Set the `__nextHasNoMarginBottom` prop to true to start opting into the new styles, which will become the default in a future version',
+ }
+ );
+ }
+
return (
+ );
+ },
+ args: {
+ fontFamilies: [
+ {
+ fontFace: [
+ {
+ fontFamily: 'Inter',
+ fontStretch: 'normal',
+ fontStyle: 'normal',
+ fontWeight: '200 900',
+ src: [
+ 'file:./assets/fonts/inter/Inter-VariableFont_slnt,wght.ttf',
+ ],
+ },
+ ],
+ fontFamily: '"Inter", sans-serif',
+ name: 'Inter',
+ slug: 'inter',
+ },
+ {
+ fontFamily:
+ '-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Oxygen-Sans,Ubuntu,Cantarell,"Helvetica Neue",sans-serif',
+ name: 'System Font',
+ slug: 'system-font',
+ },
+ ],
+ __nextHasNoMarginBottom: true,
+ },
+};
diff --git a/packages/block-editor/src/components/grid/use-grid-layout-sync.js b/packages/block-editor/src/components/grid/use-grid-layout-sync.js
index 2cc17eed6b33bf..3e31530d4e526f 100644
--- a/packages/block-editor/src/components/grid/use-grid-layout-sync.js
+++ b/packages/block-editor/src/components/grid/use-grid-layout-sync.js
@@ -10,6 +10,7 @@ import { usePrevious } from '@wordpress/compose';
*/
import { store as blockEditorStore } from '../../store';
import { GridRect } from './utils';
+import { setImmutably } from '../../utils/object';
export function useGridLayoutSync( { clientId: gridClientId } ) {
const { gridLayout, blockOrder, selectedBlockLayout } = useSelect(
@@ -26,7 +27,8 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
[ gridClientId ]
);
- const { getBlockAttributes } = useSelect( blockEditorStore );
+ const { getBlockAttributes, getBlockRootClientId } =
+ useSelect( blockEditorStore );
const { updateBlockAttributes, __unstableMarkNextChangeAsNotPersistent } =
useDispatch( blockEditorStore );
@@ -40,6 +42,7 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
const previousIsManualPlacement = usePrevious(
gridLayout.isManualPlacement
);
+ const previousBlockOrder = usePrevious( blockOrder );
useEffect( () => {
const updates = {};
@@ -123,6 +126,46 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
},
};
}
+
+ // Unset grid layout attributes for blocks removed from the grid.
+ for ( const clientId of previousBlockOrder ?? [] ) {
+ if ( ! blockOrder.includes( clientId ) ) {
+ const rootClientId = getBlockRootClientId( clientId );
+
+ // Block was removed from the editor, so nothing to do.
+ if ( rootClientId === null ) {
+ continue;
+ }
+
+ // Check if the block is being moved to another grid.
+ // If so, do nothing and let the new grid parent handle
+ // the attributes.
+ const rootAttributes = getBlockAttributes( rootClientId );
+ if ( rootAttributes?.layout?.type === 'grid' ) {
+ continue;
+ }
+
+ const attributes = getBlockAttributes( clientId );
+ const {
+ columnStart,
+ rowStart,
+ columnSpan,
+ rowSpan,
+ ...layout
+ } = attributes.style?.layout ?? {};
+
+ if ( columnStart || rowStart || columnSpan || rowSpan ) {
+ const hasEmptyLayoutAttribute =
+ Object.keys( layout ).length === 0;
+
+ updates[ clientId ] = setImmutably(
+ attributes,
+ [ 'style', 'layout' ],
+ hasEmptyLayoutAttribute ? undefined : layout
+ );
+ }
+ }
+ }
} else {
// Remove all of the columnStart and rowStart values
// when switching from manual to auto mode,
@@ -133,12 +176,14 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
attributes.style?.layout ?? {};
// Only update attributes if columnStart or rowStart are set.
if ( columnStart || rowStart ) {
- updates[ clientId ] = {
- style: {
- ...attributes.style,
- layout,
- },
- };
+ const hasEmptyLayoutAttribute =
+ Object.keys( layout ).length === 0;
+
+ updates[ clientId ] = setImmutably(
+ attributes,
+ [ 'style', 'layout' ],
+ hasEmptyLayoutAttribute ? undefined : layout
+ );
}
}
}
@@ -166,12 +211,14 @@ export function useGridLayoutSync( { clientId: gridClientId } ) {
// Actual deps to sync:
gridClientId,
gridLayout,
+ previousBlockOrder,
blockOrder,
previouslySelectedBlockRect,
previousIsManualPlacement,
// These won't change, but the linter thinks they might:
__unstableMarkNextChangeAsNotPersistent,
getBlockAttributes,
+ getBlockRootClientId,
updateBlockAttributes,
] );
}
diff --git a/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js b/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js
index 6605d2de502fe8..4faf05ba254089 100644
--- a/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js
+++ b/packages/block-editor/src/components/spacing-sizes-control/input-controls/spacing-input-control.js
@@ -9,7 +9,7 @@ import {
__experimentalUnitControl as UnitControl,
__experimentalUseCustomUnits as useCustomUnits,
__experimentalParseQuantityAndUnitFromRawValue as parseQuantityAndUnitFromRawValue,
- privateApis as componentsPrivateApis,
+ CustomSelectControl,
} from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useState, useMemo } from '@wordpress/element';
@@ -31,11 +31,6 @@ import {
getPresetValueFromCustomValue,
isValueSpacingPreset,
} from '../utils';
-import { unlock } from '../../../lock-unlock';
-
-const { CustomSelectControlV2Legacy: CustomSelectControl } = unlock(
- componentsPrivateApis
-);
const CUSTOM_VALUE_SETTINGS = {
px: { max: 300, steps: 1 },
diff --git a/packages/block-editor/src/components/use-block-drop-zone/index.js b/packages/block-editor/src/components/use-block-drop-zone/index.js
index 857a132f1f9fa4..415ed5070d28da 100644
--- a/packages/block-editor/src/components/use-block-drop-zone/index.js
+++ b/packages/block-editor/src/components/use-block-drop-zone/index.js
@@ -301,8 +301,10 @@ export default function useBlockDropZone( {
operation: 'insert',
} );
- const { getBlockType } = useSelect( blocksStore );
+ const { getBlockType, getBlockVariations, getGroupingBlockName } =
+ useSelect( blocksStore );
const {
+ canInsertBlockType,
getBlockListSettings,
getBlocks,
getBlockIndex,
@@ -310,6 +312,7 @@ export default function useBlockDropZone( {
getBlockNamesByClientId,
getAllowedBlocks,
isDragging,
+ isGroupable,
} = unlock( useSelect( blockEditorStore ) );
const {
showInsertionPoint,
@@ -385,21 +388,66 @@ export default function useBlockDropZone( {
};
} );
+ const dropTargetPosition = getDropTargetPosition(
+ blocksData,
+ { x: event.clientX, y: event.clientY },
+ getBlockListSettings( targetRootClientId )?.orientation,
+ {
+ dropZoneElement,
+ parentBlockClientId,
+ parentBlockOrientation: parentBlockClientId
+ ? getBlockListSettings( parentBlockClientId )
+ ?.orientation
+ : undefined,
+ rootBlockIndex: getBlockIndex( targetRootClientId ),
+ }
+ );
+
const [ targetIndex, operation, nearestSide ] =
- getDropTargetPosition(
- blocksData,
- { x: event.clientX, y: event.clientY },
- getBlockListSettings( targetRootClientId )?.orientation,
- {
- dropZoneElement,
- parentBlockClientId,
- parentBlockOrientation: parentBlockClientId
- ? getBlockListSettings( parentBlockClientId )
- ?.orientation
- : undefined,
- rootBlockIndex: getBlockIndex( targetRootClientId ),
- }
+ dropTargetPosition;
+
+ if ( operation === 'group' ) {
+ const targetBlock = blocks[ targetIndex ];
+ const areAllImages = [
+ targetBlock.name,
+ ...draggedBlockNames,
+ ].every( ( name ) => name === 'core/image' );
+ const canInsertGalleryBlock = canInsertBlockType(
+ 'core/gallery',
+ targetRootClientId
);
+ const areGroupableBlocks = isGroupable( [
+ targetBlock.clientId,
+ getDraggedBlockClientIds(),
+ ] );
+ const groupBlockVariations = getBlockVariations(
+ getGroupingBlockName(),
+ 'block'
+ );
+ const canInsertRow =
+ groupBlockVariations &&
+ groupBlockVariations.find(
+ ( { name } ) => name === 'group-row'
+ );
+
+ // If the dragged blocks and the target block are all images,
+ // check if it is creatable either a Row variation or a Gallery block.
+ if (
+ areAllImages &&
+ ! canInsertGalleryBlock &&
+ ( ! areGroupableBlocks || ! canInsertRow )
+ ) {
+ return;
+ }
+ // If the dragged blocks and the target block are not all images,
+ // check if it is creatable a Row variation.
+ if (
+ ! areAllImages &&
+ ( ! areGroupableBlocks || ! canInsertRow )
+ ) {
+ return;
+ }
+ }
registry.batch( () => {
setDropTarget( {
@@ -436,6 +484,10 @@ export default function useBlockDropZone( {
showInsertionPoint,
isDragging,
startDragging,
+ canInsertBlockType,
+ getBlockVariations,
+ getGroupingBlockName,
+ isGroupable,
]
),
200
diff --git a/packages/block-editor/src/components/use-on-block-drop/index.js b/packages/block-editor/src/components/use-on-block-drop/index.js
index 420cd398edfa39..75b9a44e166f5c 100644
--- a/packages/block-editor/src/components/use-on-block-drop/index.js
+++ b/packages/block-editor/src/components/use-on-block-drop/index.js
@@ -232,7 +232,6 @@ export default function useOnBlockDrop(
getBlocksByClientId,
getSettings,
getBlock,
- isGroupable,
} = useSelect( blockEditorStore );
const { getGroupingBlockName } = useSelect( blocksStore );
const {
@@ -255,17 +254,11 @@ export default function useOnBlockDrop(
if ( ! Array.isArray( blocks ) ) {
blocks = [ blocks ];
}
-
const clientIds = getBlockOrder( targetRootClientId );
const clientId = clientIds[ targetBlockIndex ];
- const blocksClientIds = blocks.map( ( block ) => block.clientId );
- const areGroupableBlocks = isGroupable( [
- ...blocksClientIds,
- clientId,
- ] );
if ( operation === 'replace' ) {
replaceBlocks( clientId, blocks, undefined, initialPosition );
- } else if ( operation === 'group' && areGroupableBlocks ) {
+ } else if ( operation === 'group' ) {
const targetBlock = getBlock( clientId );
if ( nearestSide === 'left' ) {
blocks.push( targetBlock );
@@ -325,7 +318,6 @@ export default function useOnBlockDrop(
getBlockOrder,
targetRootClientId,
targetBlockIndex,
- isGroupable,
operation,
replaceBlocks,
getBlock,
diff --git a/packages/block-library/CHANGELOG.md b/packages/block-library/CHANGELOG.md
index 226183e04396ef..652c89fd3540e2 100644
--- a/packages/block-library/CHANGELOG.md
+++ b/packages/block-library/CHANGELOG.md
@@ -2,6 +2,10 @@
## Unreleased
+### New Feature
+
+- Query Loop Block: Moves per page, offset, and pages controls into Inspector Controls. ([#58207](https://github.com/WordPress/gutenberg/pull/58207))
+
## 9.4.0 (2024-07-24)
## 9.3.0 (2024-07-10)
diff --git a/packages/block-library/src/navigation/edit/index.js b/packages/block-library/src/navigation/edit/index.js
index 5477dc1aeebf3a..829c6395e047ef 100644
--- a/packages/block-library/src/navigation/edit/index.js
+++ b/packages/block-library/src/navigation/edit/index.js
@@ -721,7 +721,7 @@ function Navigation( {
);
const accessibleDescriptionId = `${ clientId }-desc`;
-
+ const isHiddenByDefault = 'always' === overlayMenu;
const isManageMenusButtonDisabled =
! hasManagePermissions || ! hasResolvedNavigationMenus;
@@ -760,7 +760,7 @@ function Navigation( {
hasIcon={ hasIcon }
icon={ icon }
isResponsive={ isResponsive }
- isHiddenByDefault={ 'always' === overlayMenu }
+ isHiddenByDefault={ isHiddenByDefault }
overlayBackgroundColor={ overlayBackgroundColor }
overlayTextColor={ overlayTextColor }
>
@@ -899,13 +899,13 @@ function Navigation( {
: undefined
}
>
- { isLoading && (
+ { isLoading && ! isHiddenByDefault && (
) }
- { ! isLoading && (
+ { ( ! isLoading || isHiddenByDefault ) && (
<>
{ !! postType && (
@@ -253,6 +269,47 @@ export default function QueryInspectorControls( props ) {
/>
) }
+ { ! inherit && showDisplayPanel && (
+ {
+ setQuery( {
+ offset: 0,
+ pages: 0,
+ } );
+ } }
+ dropdownMenuProps={ dropdownMenuProps }
+ >
+ perPage > 0 }
+ >
+
+
+ offset > 0 }
+ onDeselect={ () => setQuery( { offset: 0 } ) }
+ >
+
+
+ pages > 0 }
+ onDeselect={ () => setQuery( { pages: 0 } ) }
+ >
+
+
+
+ ) }
{ ! inherit && showFiltersPanel && (
{
+ return (
+ {
+ if (
+ isNaN( newOffset ) ||
+ newOffset < MIN_OFFSET ||
+ newOffset > MAX_OFFSET
+ ) {
+ return;
+ }
+ onChange( { offset: newOffset } );
+ } }
+ />
+ );
+};
+
+export default OffsetControl;
diff --git a/packages/block-library/src/query/edit/inspector-controls/order-control.js b/packages/block-library/src/query/edit/inspector-controls/order-control.js
index 2f6fa0e589d473..d50d3349bcbafd 100644
--- a/packages/block-library/src/query/edit/inspector-controls/order-control.js
+++ b/packages/block-library/src/query/edit/inspector-controls/order-control.js
@@ -27,7 +27,6 @@ const orderOptions = [
function OrderControl( { order, orderBy, onChange } ) {
return (
{
+ return (
+ {
+ if ( isNaN( newPages ) || newPages < 0 ) {
+ return;
+ }
+ onChange( { pages: newPages } );
+ } }
+ help={ __(
+ 'Limit the pages you want to show, even if the query has more results. To show all pages use 0 (zero).'
+ ) }
+ />
+ );
+};
+
+export default PagesControl;
diff --git a/packages/block-library/src/query/edit/inspector-controls/per-page-control.js b/packages/block-library/src/query/edit/inspector-controls/per-page-control.js
new file mode 100644
index 00000000000000..3e0dfbf50b70bd
--- /dev/null
+++ b/packages/block-library/src/query/edit/inspector-controls/per-page-control.js
@@ -0,0 +1,33 @@
+/**
+ * WordPress dependencies
+ */
+import { RangeControl } from '@wordpress/components';
+import { __ } from '@wordpress/i18n';
+
+const MIN_POSTS_PER_PAGE = 1;
+const MAX_POSTS_PER_PAGE = 100;
+
+const PerPageControl = ( { perPage, offset = 0, onChange } ) => {
+ return (
+ {
+ if (
+ isNaN( newPerPage ) ||
+ newPerPage < MIN_POSTS_PER_PAGE ||
+ newPerPage > MAX_POSTS_PER_PAGE
+ ) {
+ return;
+ }
+ onChange( { perPage: newPerPage, offset } );
+ } }
+ value={ parseInt( perPage, 10 ) }
+ />
+ );
+};
+
+export default PerPageControl;
diff --git a/packages/block-library/src/query/edit/query-toolbar.js b/packages/block-library/src/query/edit/query-toolbar.js
index ff670d7c001a6b..cc2d62a54d529f 100644
--- a/packages/block-library/src/query/edit/query-toolbar.js
+++ b/packages/block-library/src/query/edit/query-toolbar.js
@@ -1,14 +1,8 @@
/**
* WordPress dependencies
*/
-import {
- ToolbarGroup,
- Dropdown,
- ToolbarButton,
- __experimentalNumberControl as NumberControl,
-} from '@wordpress/components';
+import { ToolbarGroup, ToolbarButton } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
-import { settings } from '@wordpress/icons';
/**
* Internal dependencies
@@ -16,8 +10,6 @@ import { settings } from '@wordpress/icons';
import { usePatterns } from '../utils';
export default function QueryToolbar( {
- attributes: { query },
- setQuery,
openPatternSelectionModal,
name,
clientId,
@@ -26,87 +18,6 @@ export default function QueryToolbar( {
return (
<>
- { ! query.inherit && (
-
- (
-
- ) }
- renderContent={ () => (
- <>
- {
- if (
- isNaN( value ) ||
- value < 1 ||
- value > 100
- ) {
- return;
- }
- setQuery( {
- perPage: value,
- } );
- } }
- step="1"
- value={ query.perPage }
- isDragEnabled={ false }
- />
- {
- if (
- isNaN( value ) ||
- value < 0 ||
- value > 100
- ) {
- return;
- }
- setQuery( { offset: value } );
- } }
- step="1"
- value={ query.offset }
- isDragEnabled={ false }
- />
- {
- if ( isNaN( value ) || value < 0 ) {
- return;
- }
- setQuery( { pages: value } );
- } }
- step="1"
- value={ query.pages }
- isDragEnabled={ false }
- help={ __(
- 'Limit the pages you want to show, even if the query has more results. To show all pages use 0 (zero).'
- ) }
- />
- >
- ) }
- />
-
- ) }
{ hasPatterns && (
diff --git a/packages/block-library/src/site-logo/edit.js b/packages/block-library/src/site-logo/edit.js
index ac74ac2aeb6eb4..b7e47ec542d1e9 100644
--- a/packages/block-library/src/site-logo/edit.js
+++ b/packages/block-library/src/site-logo/edit.js
@@ -687,7 +687,7 @@ export default function LogoEdit( {
variant="primary"
label={ __( 'Choose logo' ) }
showTooltip
- tooltipPosition="bottom center"
+ tooltipPosition="middle right"
onClick={ () => {
open();
} }
diff --git a/packages/components/CHANGELOG.md b/packages/components/CHANGELOG.md
index 570b7ac308c5fe..a71b5a0ddef35f 100644
--- a/packages/components/CHANGELOG.md
+++ b/packages/components/CHANGELOG.md
@@ -6,6 +6,7 @@
- `ColorPalette`: Remove extra bottom margin when `CircularOptionPicker` is unneeded ([#63961](https://github.com/WordPress/gutenberg/pull/63961)).
- `CustomSelectControl`: Restore `describedBy` functionality ([#63957](https://github.com/WordPress/gutenberg/pull/63957)).
+- `Button`: Improve the aria-disabled focus style ([#62480](https://github.com/WordPress/gutenberg/pull/62480)).
- `Modal`: Fix the dismissal logic for React development mode ([#64132](https://github.com/WordPress/gutenberg/pull/64132)).
### Enhancements
diff --git a/packages/components/src/button/style.scss b/packages/components/src/button/style.scss
index 3541699a08eefd..fcbd363e17c7dd 100644
--- a/packages/components/src/button/style.scss
+++ b/packages/components/src/button/style.scss
@@ -30,16 +30,10 @@
}
&[aria-expanded="true"],
- &:hover {
+ &:hover:not(:disabled, [aria-disabled="true"]) {
color: $components-color-accent;
}
- // Unset some hovers, instead of adding :not specificity.
- &:disabled:hover,
- &[aria-disabled="true"]:hover {
- color: initial;
- }
-
// Focus.
// See https://github.com/WordPress/gutenberg/issues/13267 for more context on these selectors.
&:focus:not(:disabled) {
@@ -87,7 +81,6 @@
color: rgba($white, 0.4);
background: $components-color-accent;
border-color: $components-color-accent;
- opacity: 1;
outline: none;
&:focus:enabled {
@@ -132,7 +125,6 @@
color: $gray-600;
background: transparent;
transform: none;
- opacity: 1;
}
}
@@ -206,17 +198,22 @@
&:not(.is-primary):not(.is-secondary):not(.is-tertiary):not(.is-link) {
color: $alert-red;
- &:hover:not(:disabled) {
+ &:hover:not(:disabled, [aria-disabled="true"]) {
color: darken($alert-red, 20%);
}
- &:focus:not(:disabled) {
+ &:focus {
box-shadow: 0 0 0 var(--wp-admin-border-width-focus) $alert-red;
}
- &:active:not(:disabled) {
+ &:active:not(:disabled, [aria-disabled="true"]) {
background: $gray-400;
}
+
+ &:disabled,
+ &[aria-disabled="true"] {
+ color: $gray-600;
+ }
}
}
@@ -244,6 +241,11 @@
&:focus {
border-radius: $radius-block-ui;
}
+
+ &:disabled,
+ &[aria-disabled="true"] {
+ color: $gray-600;
+ }
}
&:not(:disabled, [aria-disabled="true"]):active {
@@ -253,7 +255,7 @@
&:disabled,
&[aria-disabled="true"] {
cursor: default;
- opacity: 0.3;
+ color: $gray-600;
}
&.is-busy,
@@ -266,7 +268,6 @@
@media (prefers-reduced-motion: reduce) {
animation-duration: 0s;
}
- opacity: 1;
background-size: 100px 100%;
/* stylelint-disable -- Disable reason: This function call looks nicer when each argument is on its own line. */
background-image: linear-gradient(
@@ -332,8 +333,23 @@
// Toggled style.
&.is-pressed {
- color: $components-color-foreground-inverted;
- background: $components-color-foreground;
+ &,
+ &:hover {
+ color: $components-color-foreground-inverted;
+ &:not(:disabled, [aria-disabled="true"]) {
+ background: $components-color-foreground;
+ }
+ }
+
+ &:disabled,
+ &[aria-disabled="true"] {
+ color: $gray-600;
+
+ &:not(.is-primary):not(.is-secondary):not(.is-tertiary) {
+ color: $components-color-foreground-inverted;
+ background: $gray-600;
+ }
+ }
&:focus:not(:disabled) {
box-shadow: inset 0 0 0 1px $components-color-background, 0 0 0 var(--wp-admin-border-width-focus) $components-color-accent;
@@ -341,11 +357,6 @@
// Windows High Contrast mode will show this outline, but not the box-shadow.
outline: 2px solid transparent;
}
-
- &:hover:not(:disabled) {
- color: $components-color-foreground-inverted;
- background: $components-color-foreground;
- }
}
svg {
diff --git a/packages/e2e-tests/plugins/observe-typing.php b/packages/e2e-tests/plugins/observe-typing.php
new file mode 100644
index 00000000000000..a9152bc79684c5
--- /dev/null
+++ b/packages/e2e-tests/plugins/observe-typing.php
@@ -0,0 +1,28 @@
+
+ el(
+ ToolbarButton,
+ {
+ onClick: onToggle,
+ },
+ 'Open Dropdown'
+ ),
+ renderContent: () =>
+ el( TextControl, {
+ label: 'Dropdown field',
+ value,
+ onChange: setValue,
+ __next40pxDefaultSize: true,
+ } ),
+ } )
+ ),
+ el( 'p', {}, 'Hello Editor!' )
+ );
+ },
+ save: () => null,
+ } );
+} )();
diff --git a/packages/editor/src/dataviews/actions/permanently-delete-post.tsx b/packages/editor/src/dataviews/actions/permanently-delete-post.tsx
index 42efb8a32850f3..2124fdc0ffa4ce 100644
--- a/packages/editor/src/dataviews/actions/permanently-delete-post.tsx
+++ b/packages/editor/src/dataviews/actions/permanently-delete-post.tsx
@@ -48,7 +48,7 @@ const permanentlyDeletePost: Action< PostWithPermissions > = {
getItemTitle( posts[ 0 ] )
);
} else {
- successMessage = __( 'The posts were permanently deleted.' );
+ successMessage = __( 'The items were permanently deleted.' );
}
createSuccessNotice( successMessage, {
type: 'snackbar',
@@ -67,7 +67,7 @@ const permanentlyDeletePost: Action< PostWithPermissions > = {
errorMessage = typedError.reason.message;
} else {
errorMessage = __(
- 'An error occurred while permanently deleting the post.'
+ 'An error occurred while permanently deleting the item.'
);
}
// If we were trying to permanently delete multiple posts
@@ -86,13 +86,13 @@ const permanentlyDeletePost: Action< PostWithPermissions > = {
}
if ( errorMessages.size === 0 ) {
errorMessage = __(
- 'An error occurred while permanently deleting the posts.'
+ 'An error occurred while permanently deleting the items.'
);
} else if ( errorMessages.size === 1 ) {
errorMessage = sprintf(
/* translators: %s: an error message */
__(
- 'An error occurred while permanently deleting the posts: %s'
+ 'An error occurred while permanently deleting the items: %s'
),
[ ...errorMessages ][ 0 ]
);
@@ -100,7 +100,7 @@ const permanentlyDeletePost: Action< PostWithPermissions > = {
errorMessage = sprintf(
/* translators: %s: a list of comma separated error messages */
__(
- 'Some errors occurred while permanently deleting the posts: %s'
+ 'Some errors occurred while permanently deleting the items: %s'
),
[ ...errorMessages ].join( ',' )
);
diff --git a/packages/editor/src/dataviews/actions/trash-post.tsx b/packages/editor/src/dataviews/actions/trash-post.tsx
index a8e42c510a6cd0..537a0ebd79a8ac 100644
--- a/packages/editor/src/dataviews/actions/trash-post.tsx
+++ b/packages/editor/src/dataviews/actions/trash-post.tsx
@@ -23,7 +23,7 @@ import type { CoreDataError, PostWithPermissions } from '../types';
const trashPost: Action< PostWithPermissions > = {
id: 'move-to-trash',
- label: __( 'Move to Trash' ),
+ label: __( 'Move to trash' ),
isPrimary: true,
icon: trash,
isEligible( item ) {
@@ -51,15 +51,15 @@ const trashPost: Action< PostWithPermissions > = {
? sprintf(
// translators: %s: The item's title.
__(
- 'Are you sure you want to move to trash "%s"?'
+ 'Are you sure you want to move "%s" to the trash?'
),
getItemTitle( items[ 0 ] )
)
: sprintf(
// translators: %d: The number of items (2 or more).
_n(
- 'Are you sure you want to move to trash %d item?',
- 'Are you sure you want to move to trash %d items?',
+ 'Are you sure you want to move %d item to the trash ?',
+ 'Are you sure you want to move %d items to the trash ?',
items.length
),
items.length
@@ -99,15 +99,15 @@ const trashPost: Action< PostWithPermissions > = {
if ( promiseResult.length === 1 ) {
successMessage = sprintf(
/* translators: The item's title. */
- __( '"%s" moved to trash.' ),
+ __( '"%s" moved to the trash.' ),
getItemTitle( items[ 0 ] )
);
} else {
successMessage = sprintf(
/* translators: The number of items. */
_n(
- '%s item moved to trash.',
- '%s items moved to trash.',
+ '%s item moved to the trash.',
+ '%s items moved to the trash.',
items.length
),
items.length
@@ -130,7 +130,7 @@ const trashPost: Action< PostWithPermissions > = {
typedError.reason.message;
} else {
errorMessage = __(
- 'An error occurred while moving to trash the item.'
+ 'An error occurred while moving the item to the trash.'
);
}
// If we were trying to delete multiple items.
@@ -151,13 +151,13 @@ const trashPost: Action< PostWithPermissions > = {
}
if ( errorMessages.size === 0 ) {
errorMessage = __(
- 'An error occurred while moving to trash the items.'
+ 'An error occurred while moving the items to the trash.'
);
} else if ( errorMessages.size === 1 ) {
errorMessage = sprintf(
/* translators: %s: an error message */
__(
- 'An error occurred while moving to trash the item: %s'
+ 'An error occurred while moving the item to the trash: %s'
),
[ ...errorMessages ][ 0 ]
);
@@ -165,7 +165,7 @@ const trashPost: Action< PostWithPermissions > = {
errorMessage = sprintf(
/* translators: %s: a list of comma separated error messages */
__(
- 'Some errors occurred while moving to trash the items: %s'
+ 'Some errors occurred while moving the items to the trash: %s'
),
[ ...errorMessages ].join( ',' )
);
diff --git a/packages/editor/src/store/private-actions.js b/packages/editor/src/store/private-actions.js
index c5fe1c260071a6..0996d6eb8b9d32 100644
--- a/packages/editor/src/store/private-actions.js
+++ b/packages/editor/src/store/private-actions.js
@@ -393,10 +393,14 @@ export const removeTemplates =
if ( items.length === 1 ) {
// Depending on how the entity was retrieved its title might be
// an object or simple string.
- const title =
- typeof items[ 0 ].title === 'string'
- ? items[ 0 ].title
- : items[ 0 ].title?.rendered;
+ let title;
+ if ( typeof items[ 0 ].title === 'string' ) {
+ title = items[ 0 ].title;
+ } else if ( typeof items[ 0 ].title?.rendered === 'string' ) {
+ title = items[ 0 ].title?.rendered;
+ } else if ( typeof items[ 0 ].title?.raw === 'string' ) {
+ title = items[ 0 ].title?.raw;
+ }
successMessage = isResetting
? sprintf(
/* translators: The template/part's name. */
diff --git a/test/e2e/specs/editor/various/change-detection.spec.js b/test/e2e/specs/editor/various/change-detection.spec.js
index 4ac262f4c1348d..30b2287a8d9439 100644
--- a/test/e2e/specs/editor/various/change-detection.spec.js
+++ b/test/e2e/specs/editor/various/change-detection.spec.js
@@ -416,7 +416,7 @@ test.describe( 'Change detection', () => {
.click();
await page
.getByRole( 'menu' )
- .getByRole( 'menuitem', { name: 'Move to Trash' } )
+ .getByRole( 'menuitem', { name: 'Move to trash' } )
.click();
await page
.getByRole( 'dialog' )
diff --git a/test/e2e/specs/editor/various/is-typing.spec.js b/test/e2e/specs/editor/various/is-typing.spec.js
index 10ac90d1084127..da4492a89bef34 100644
--- a/test/e2e/specs/editor/various/is-typing.spec.js
+++ b/test/e2e/specs/editor/various/is-typing.spec.js
@@ -4,10 +4,18 @@
const { test, expect } = require( '@wordpress/e2e-test-utils-playwright' );
test.describe( 'isTyping', () => {
+ test.beforeAll( async ( { requestUtils } ) => {
+ await requestUtils.activatePlugin( 'gutenberg-test-observe-typing' );
+ } );
+
test.beforeEach( async ( { admin } ) => {
await admin.createNewPost();
} );
+ test.afterAll( async ( { requestUtils } ) => {
+ await requestUtils.deactivatePlugin( 'gutenberg-test-observe-typing' );
+ } );
+
test( 'should hide the toolbar when typing', async ( { editor, page } ) => {
// Enter to reach paragraph block.
await page.keyboard.press( 'Enter' );
@@ -42,33 +50,23 @@ test.describe( 'isTyping', () => {
page,
} ) => {
// Add a block with a dropdown in the toolbar that contains an input.
- await editor.insertBlock( { name: 'core/query' } );
-
- await editor.canvas
- .getByRole( 'document', { name: 'Block: Query Loop' } )
- .getByRole( 'button', { name: 'Start blank' } )
- .click();
-
- await editor.canvas
- .getByRole( 'button', { name: 'Title & Date' } )
- .click();
-
- await editor.openDocumentSettingsSidebar();
- await page.getByLabel( 'Custom' ).click();
+ await editor.insertBlock( { name: 'e2e-tests/observe-typing' } );
// Moving the mouse shows the toolbar.
await editor.showBlockToolbar();
// Open the dropdown.
- const displaySettings = page.getByRole( 'button', {
- name: 'Display settings',
+ await page
+ .getByRole( 'button', {
+ name: 'Open Dropdown',
+ } )
+ .click();
+
+ const textControl = page.getByRole( 'textbox', {
+ name: 'Dropdown field',
} );
- await displaySettings.click();
- const itemsPerPageInput = page.getByLabel( 'Items per Page' );
- // Make sure we're where we think we are
- await expect( itemsPerPageInput ).toBeFocused();
// Type inside the dropdown's input
- await page.keyboard.type( '00' );
+ await textControl.pressSequentially( 'Hello' );
// The input should still be visible.
- await expect( itemsPerPageInput ).toBeVisible();
+ await expect( textControl ).toBeVisible();
} );
} );