diff --git a/packages/components/src/font-size-picker/index.js b/packages/components/src/font-size-picker/index.js
index a52f6ccd841d2..bf3809fbf5a68 100644
--- a/packages/components/src/font-size-picker/index.js
+++ b/packages/components/src/font-size-picker/index.js
@@ -10,19 +10,20 @@ import { __ } from '@wordpress/i18n';
*/
import Button from '../button';
import RangeControl from '../range-control';
-import SelectControl from '../select-control';
+import FontSizePickerSelect from './select';
function getSelectValueFromFontSize( fontSizes, value ) {
if ( value ) {
const fontSizeValue = fontSizes.find( ( font ) => font.size === value );
return fontSizeValue ? fontSizeValue.slug : 'custom';
}
- return 'normal';
+ // We can't be sure what the theme font settings are so let's assume the "normal" size will be second if there are more than 2 sizes, and first if there are 2 or less.
+ return fontSizes.length > 2 ? fontSizes[ 1 ].slug : fontSizes[ 0 ].slug;
}
function getSelectOptions( optionsArray ) {
return [
- ...optionsArray.map( ( option ) => ( { value: option.slug, label: option.name } ) ),
+ ...optionsArray.map( ( option ) => ( { value: option.slug, label: option.name, size: option.size } ) ),
{ value: 'custom', label: __( 'Custom' ) },
];
}
@@ -61,28 +62,28 @@ function FontSizePicker( {
return (
-
+
{ __( 'Font Size' ) }
{ ( fontSizes.length > 0 ) &&
-
}
{ ( ! withSlider && ! disableCustomFontSizes ) &&
+ // eslint-disable-next-line jsx-a11y/label-has-for
+
+ { __( 'Custom' ) }
+
}
{ __( 'Reset' ) }
diff --git a/packages/components/src/font-size-picker/select.js b/packages/components/src/font-size-picker/select.js
new file mode 100644
index 0000000000000..a14ad15b3d371
--- /dev/null
+++ b/packages/components/src/font-size-picker/select.js
@@ -0,0 +1,160 @@
+/**
+ * External dependencies
+ */
+import { map } from 'lodash';
+
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import { withInstanceId } from '@wordpress/compose';
+import { useRef, useCallback, useEffect } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import {
+ Dashicon,
+ BaseControl,
+ Button,
+ NavigableMenu,
+ Dropdown,
+} from '../';
+
+function FontSizePickerSelect( {
+ fontSizes = [],
+ instanceId,
+ onChange,
+ value,
+} ) {
+ const currentFont = fontSizes.find( ( font ) => font.value === value );
+ const currentFontLabel = currentFont ? currentFont.label : '';
+
+ // Work-around to focus active item
+ const popoverRef = useRef( null );
+ const focusActiveItem = useCallback( () => {
+ // Hack work-arounds to control focus timing...
+ window.requestAnimationFrame( () => {
+ const { current } = popoverRef;
+ if ( ! current ) {
+ return;
+ }
+ const node = current.querySelector( '[aria-selected="true"]' );
+ node.blur();
+ window.requestAnimationFrame( () => {
+ if ( node ) {
+ // Hack work-arounds to control focus timing...
+ node.focus();
+ }
+ } );
+ } );
+ }, [] );
+
+ useEffect( () => {
+ focusActiveItem();
+ }, [ focusActiveItem, value ] );
+
+ // Work around to manage + force open state outside of Dropdown
+ const handleOnToggle = ( nextOpen ) => {
+ if ( nextOpen ) {
+ focusActiveItem();
+ }
+ };
+
+ // Work around to prevent scrolling.
+ // Need to adjust navigable-content/container
+ // https://github.com/WordPress/gutenberg/blob/master/packages/components/src/navigable-container/container.js#L89
+ const handleOnKeyDown = ( event ) => {
+ // event.preventDefault();
+ const { key } = event;
+ switch ( key ) {
+ case 'ArrowDown':
+ event.preventDefault();
+ break;
+ case 'ArrowUp':
+ event.preventDefault();
+ break;
+ default:
+ break;
+ }
+ };
+
+ // Improve voiceover consistency compared to native select
+ const ariaHasPopup = 'listbox';
+ const ariaProps = {
+ 'aria-haspopup': ariaHasPopup,
+ };
+
+ const id = `font-size-picker__select-${ instanceId }`;
+
+ return (
+
+ (
+
+ { __( 'Preset Size' ) }
+
+ { currentFontLabel }
+
+
+ ) }
+ renderContent={ () => {
+ return (
+
+
+ { map( fontSizes, ( option ) => {
+ const isSelected = value === option.value;
+ const optionLabel = isSelected ? `${ option.label } (Selected)` : option.label;
+ const itemId = `item-${ option.value }`;
+ const itemRole = 'option';
+ const labelRole = 'presentation';
+
+ return (
+ {
+ onChange( option.value );
+ } }
+ className={ `is-font-${ option.value }` }
+ role={ itemRole }
+ id={ itemId }
+ aria-label={ optionLabel }
+ aria-selected={ isSelected }
+ >
+ { isSelected && }
+
+ { option.label }
+
+
+ );
+ } ) }
+
+
+ );
+ } }
+ />
+
+ );
+}
+
+export default withInstanceId( FontSizePickerSelect );
diff --git a/packages/components/src/font-size-picker/select.scss b/packages/components/src/font-size-picker/select.scss
new file mode 100644
index 0000000000000..f3f57c9e8eeda
--- /dev/null
+++ b/packages/components/src/font-size-picker/select.scss
@@ -0,0 +1,66 @@
+.components-font-size-picker__select {
+ // Need to override a generic rule
+ // that can apply to all controls in the sidebar
+ // Ideally that generic rule shouldn't target
+ // this select in the first place.
+ margin-bottom: 0 !important;
+
+ .components-base-control__field {
+ margin-bottom: 0;
+ }
+}
+
+.components-font-size-picker__select-dropdown {
+ display: inline-block;
+ width: 80px;
+}
+
+.components-font-size-picker__select-dropdown-content button {
+ display: block;
+ width: 100%;
+ text-align: left;
+ position: relative;
+ padding: 10px 5px;
+ line-height: 1;
+}
+
+.components-font-size-picker__select-dropdown-content button:hover {
+ background: #eee !important;
+}
+
+.components-font-size-picker__select-dropdown-content button.highlighted {
+ background: #eee !important;
+}
+
+.components-font-size-picker__select-dropdown-content button svg {
+ position: absolute;
+ left: 5px;
+ top: 50%;
+ transform: translateY(-50%);
+}
+
+.components-font-size-picker__select-dropdown-text-size {
+ margin-left: 30px;
+ display: block;
+}
+
+.components-font-size-picker__select-selector.components-font-size-picker__select-selector {
+ background: #fff;
+ border: 1px solid $dark-gray-200;
+ border-radius: 4px;
+ box-shadow: none;
+ margin-top: $grid-size;
+ padding-left: $grid-size-small;
+ position: relative;
+}
+
+.components-font-size-picker__select-selector::after {
+ content: "▼";
+ position: absolute;
+ right: $grid-size-small;
+}
+
+.components-font-size-picker__select-selector:focus {
+ border: 1px solid $blue-medium-focus !important;
+ outline: none !important;
+}
diff --git a/packages/components/src/font-size-picker/style.scss b/packages/components/src/font-size-picker/style.scss
index 2444087dcf30e..9d1397339fa6f 100644
--- a/packages/components/src/font-size-picker/style.scss
+++ b/packages/components/src/font-size-picker/style.scss
@@ -1,7 +1,9 @@
+@import "./select.scss";
+
.components-font-size-picker__controls {
max-width: $sidebar-width - ( 2 * $panel-padding );
display: flex;
- align-items: center;
+ align-items: flex-end;
margin-bottom: $grid-size * 3;
// Apply the same height as the isSmall Reset button.
@@ -9,6 +11,7 @@
height: 30px;
margin-left: 0;
margin-right: $grid-size;
+ margin-top: $grid-size;
// Show the reset button as disabled until a value is entered.
&[value=""] + .components-button {
@@ -31,6 +34,12 @@
margin-bottom: 0;
}
+.components-range-control__label,
+.components-font-size-picker__select-label {
+ display: flex;
+ flex-direction: column;
+}
+
.components-font-size-picker__custom-input {
.components-range-control__slider + .dashicon {
width: 30px;
diff --git a/packages/components/src/higher-order/with-focus-return/index.js b/packages/components/src/higher-order/with-focus-return/index.js
index 2b504878bdf52..98966c92ff135 100644
--- a/packages/components/src/higher-order/with-focus-return/index.js
+++ b/packages/components/src/higher-order/with-focus-return/index.js
@@ -69,14 +69,9 @@ function withFocusReturn( options ) {
componentWillUnmount() {
const {
activeElementOnMount,
- isFocused,
ownFocusedElements,
} = this;
- if ( ! isFocused ) {
- return;
- }
-
// Defer to the component's own explicit focus return behavior,
// if specified. The function should return `false` to prevent
// the default behavior otherwise occurring here. This allows
diff --git a/packages/e2e-tests/specs/editor-modes.test.js b/packages/e2e-tests/specs/editor-modes.test.js
index 3969ac43f80fc..d6bce7a25dd79 100644
--- a/packages/e2e-tests/specs/editor-modes.test.js
+++ b/packages/e2e-tests/specs/editor-modes.test.js
@@ -78,7 +78,7 @@ describe( 'Editing modes (visual/HTML)', () => {
expect( htmlBlockContent ).toEqual( 'Hello world!
' );
// Change the font size using the sidebar.
- await page.select( '.components-font-size-picker__select .components-select-control__input', 'large' );
+ await page.select( '.components-font-size-picker__select-selector', 'large' );
// Make sure the HTML content updated.
htmlBlockContent = await page.$eval( '.block-editor-block-list__layout .block-editor-block-list__block .block-editor-block-list__block-html-textarea', ( node ) => node.textContent );
diff --git a/packages/e2e-tests/specs/font-size-picker.test.js b/packages/e2e-tests/specs/font-size-picker.test.js
index 362751e8522cc..90ce4fdd95851 100644
--- a/packages/e2e-tests/specs/font-size-picker.test.js
+++ b/packages/e2e-tests/specs/font-size-picker.test.js
@@ -17,7 +17,7 @@ describe( 'Font Size Picker', () => {
// Create a paragraph block with some content.
await clickBlockAppender();
await page.keyboard.type( 'Paragraph to be made "large"' );
- await page.select( '.components-font-size-picker__select .components-select-control__input', 'large' );
+ await page.select( '.components-font-size-picker__select-selector', 'large' );
// Ensure content matches snapshot.
const content = await getEditedPostContent();
@@ -56,7 +56,7 @@ describe( 'Font Size Picker', () => {
await clickBlockAppender();
await page.keyboard.type( 'Paragraph with font size reset using button' );
- await page.select( '.components-font-size-picker__select .components-select-control__input', 'normal' );
+ await page.select( '.components-font-size-picker__select-selector', 'normal' );
const resetButton = ( await page.$x( '//*[contains(concat(" ", @class, " "), " components-font-size-picker__controls ")]//*[text()=\'Reset\']' ) )[ 0 ];
await resetButton.click();
@@ -71,7 +71,7 @@ describe( 'Font Size Picker', () => {
await clickBlockAppender();
await page.keyboard.type( 'Paragraph with font size reset using input field' );
- await page.select( '.components-font-size-picker__select .components-select-control__input', 'large' );
+ await page.select( '.components-font-size-picker__select-selector', 'large' );
// Clear the custom font size input.
await page.click( '.blocks-font-size .components-range-control__number' );