From f6ca65d8bdfb63cff9d786c1440535b306d629cf Mon Sep 17 00:00:00 2001
From: Andrew Serong <14988353+andrewserong@users.noreply.github.com>
Date: Thu, 1 Dec 2022 17:13:37 +1100
Subject: [PATCH] Try a CustomSelectControl for the position input
---
packages/block-editor/src/hooks/position.js | 143 +++++++++++++-----
packages/block-editor/src/hooks/position.scss | 18 +++
packages/block-editor/src/style.scss | 1 +
3 files changed, 121 insertions(+), 41 deletions(-)
create mode 100644 packages/block-editor/src/hooks/position.scss
diff --git a/packages/block-editor/src/hooks/position.js b/packages/block-editor/src/hooks/position.js
index 6e8e7bb12abf02..c4d6eb65f2f629 100644
--- a/packages/block-editor/src/hooks/position.js
+++ b/packages/block-editor/src/hooks/position.js
@@ -6,14 +6,16 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { __ } from '@wordpress/i18n';
+import { __, sprintf } from '@wordpress/i18n';
import { getBlockSupport, hasBlockSupport } from '@wordpress/blocks';
-import {
- __experimentalToggleGroupControl as ToggleGroupControl,
- __experimentalToggleGroupControlOption as ToggleGroupControlOption,
-} from '@wordpress/components';
+import { BaseControl, CustomSelectControl } from '@wordpress/components';
import { createHigherOrderComponent, useInstanceId } from '@wordpress/compose';
-import { useContext, createPortal, Platform } from '@wordpress/element';
+import {
+ useContext,
+ useMemo,
+ createPortal,
+ Platform,
+} from '@wordpress/element';
import { addFilter } from '@wordpress/hooks';
/**
@@ -26,20 +28,36 @@ import { cleanEmptyObject } from './utils';
const POSITION_SUPPORT_KEY = 'position';
-const POSITION_OPTIONS = [
- {
- key: 'default',
- label: __( 'Default' ),
- value: '',
- name: __( 'Default' ),
- },
- {
- key: 'sticky',
- label: __( 'Sticky' ),
- value: 'sticky',
- name: __( 'Sticky' ),
- },
-];
+const OPTION_CLASSNAME =
+ 'block-editor-hooks__position-selection__select-control__option';
+
+const DEFAULT_OPTION = {
+ key: 'static',
+ value: '',
+ name: __( 'Static' ),
+ className: OPTION_CLASSNAME,
+ __experimentalHint: __( 'The default position' ),
+};
+
+const STICKY_OPTION = {
+ key: 'sticky',
+ value: 'sticky',
+ name: __( 'Sticky' ),
+ className: OPTION_CLASSNAME,
+ __experimentalHint: __(
+ 'The block will scroll with the document but stick instead of exiting the viewport'
+ ),
+};
+
+const FIXED_OPTION = {
+ key: 'fixed',
+ value: 'fixed',
+ name: __( 'Fixed' ),
+ className: OPTION_CLASSNAME,
+ __experimentalHint: __(
+ 'The block will not move when the page is scrolled'
+ ),
+};
const POSITION_SIDES = [ 'top', 'right', 'bottom', 'left' ];
const VALID_POSITION_TYPES = [ 'sticky', 'fixed' ];
@@ -79,6 +97,30 @@ export function getPositionCSS( { selector, style } ) {
return output;
}
+/**
+ * Determines if there is sticky position support.
+ *
+ * @param {string|Object} blockType Block name or Block Type object.
+ *
+ * @return {boolean} Whether there is support.
+ */
+export function hasStickyPositionSupport( blockType ) {
+ const support = getBlockSupport( blockType, POSITION_SUPPORT_KEY );
+ return !! ( true === support || support?.sticky );
+}
+
+/**
+ * Determines if there is fixed position support.
+ *
+ * @param {string|Object} blockType Block name or Block Type object.
+ *
+ * @return {boolean} Whether there is support.
+ */
+export function hasFixedPositionSupport( blockType ) {
+ const support = getBlockSupport( blockType, POSITION_SUPPORT_KEY );
+ return !! ( true === support || support?.fixed );
+}
+
/**
* Determines if there is position support.
*
@@ -152,9 +194,24 @@ export function useIsPositionDisabled( { name: blockName } = {} ) {
export function PositionEdit( props ) {
const {
attributes: { style = {} },
+ name: blockName,
setAttributes,
} = props;
+ const allowFixed = hasFixedPositionSupport( blockName );
+ const allowSticky = hasStickyPositionSupport( blockName );
+
+ const options = useMemo( () => {
+ const availableOptions = [ DEFAULT_OPTION ];
+ if ( allowSticky ) {
+ availableOptions.push( STICKY_OPTION );
+ }
+ if ( allowFixed ) {
+ availableOptions.push( FIXED_OPTION );
+ }
+ return availableOptions;
+ }, [ allowFixed, allowSticky ] );
+
if ( useIsPositionDisabled( props ) ) {
return null;
}
@@ -182,30 +239,34 @@ export function PositionEdit( props ) {
} );
};
+ const value = style?.position?.type;
+ const selectedOption = value
+ ? options.find( ( option ) => option.value === value )
+ : DEFAULT_OPTION;
+
return Platform.select( {
web: (
<>
- {
- onChangeType( newValue );
- } }
- isBlock
- >
- { POSITION_OPTIONS.map( ( option ) => (
-
- ) ) }
-
+
+ {
+ onChangeType( selectedItem.value );
+ } }
+ size={ '__unstable-large' }
+ />
+
>
),
native: null,
diff --git a/packages/block-editor/src/hooks/position.scss b/packages/block-editor/src/hooks/position.scss
new file mode 100644
index 00000000000000..b3bd6b1b9ef041
--- /dev/null
+++ b/packages/block-editor/src/hooks/position.scss
@@ -0,0 +1,18 @@
+.block-editor-hooks__position-selection__select-control {
+ .components-custom-select-control__hint {
+ display: none;
+ }
+}
+
+.block-editor-hooks__position-selection__select-control__option {
+ &.has-hint {
+ grid-template-columns: auto 30px;
+ line-height: $default-line-height;
+ margin-bottom: 0;
+ }
+
+ .components-custom-select-control__item-hint {
+ grid-row: 2;
+ text-align: left;
+ }
+}
diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss
index 8237e715e2cc30..8554a5bece5cb5 100644
--- a/packages/block-editor/src/style.scss
+++ b/packages/block-editor/src/style.scss
@@ -49,6 +49,7 @@
@import "./hooks/layout.scss";
@import "./hooks/border.scss";
@import "./hooks/dimensions.scss";
+@import "./hooks/position.scss";
@import "./hooks/typography.scss";
@import "./hooks/color.scss";
@import "./hooks/padding.scss";