diff --git a/packages/block-editor/src/components/segmented-text-control/index.js b/packages/block-editor/src/components/segmented-text-control/index.js
new file mode 100644
index 00000000000000..a6117bcc22151a
--- /dev/null
+++ b/packages/block-editor/src/components/segmented-text-control/index.js
@@ -0,0 +1,63 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { BaseControl, Button } from '@wordpress/components';
+
+/**
+ * @typedef {Object} Option
+ * @property {string} label The label of the option.
+ * @property {string} value The value of the option.
+ * @property {string} icon The icon of the option.
+ */
+
+/**
+ * Control to facilitate selecting a text style from a set of options.
+ *
+ * @param {Object} props Component props.
+ * @param {string} props.label A label for the option.
+ * @param {string} props.value Currently selected value.
+ * @param {Function} props.onChange Callback to handle onChange.
+ * @param {Option[]} props.options Array of options to display.
+ * @param {string} props.className Additional class name to apply.
+ *
+ * @return {Element} Element to render.
+ */
+export default function SegmentedTextControl( {
+ label,
+ value,
+ options,
+ onChange,
+ className,
+} ) {
+ return (
+
+ );
+}
diff --git a/packages/block-editor/src/components/writing-mode-control/style.scss b/packages/block-editor/src/components/segmented-text-control/style.scss
similarity index 58%
rename from packages/block-editor/src/components/writing-mode-control/style.scss
rename to packages/block-editor/src/components/segmented-text-control/style.scss
index 4b865dc0282c08..7a4a3bbea7cb33 100644
--- a/packages/block-editor/src/components/writing-mode-control/style.scss
+++ b/packages/block-editor/src/components/segmented-text-control/style.scss
@@ -1,18 +1,15 @@
-.block-editor-writing-mode-control {
+.block-editor-segmented-text-control {
border: 0;
margin: 0;
padding: 0;
- .block-editor-writing-mode-control__buttons {
+ .block-editor-segmented-text-control__buttons {
// 4px of padding makes the row 40px high, same as an input.
padding: $grid-unit-05 0;
display: flex;
}
.components-button.has-icon {
- height: $grid-unit-40;
margin-right: $grid-unit-05;
- min-width: $grid-unit-40;
- padding: 0;
}
}
diff --git a/packages/block-editor/src/components/text-alignment-control/index.js b/packages/block-editor/src/components/text-alignment-control/index.js
new file mode 100644
index 00000000000000..a8e9ee22df7fd6
--- /dev/null
+++ b/packages/block-editor/src/components/text-alignment-control/index.js
@@ -0,0 +1,91 @@
+/**
+ * External dependencies
+ */
+import classnames from 'classnames';
+
+/**
+ * WordPress dependencies
+ */
+import { __ } from '@wordpress/i18n';
+import {
+ alignLeft,
+ alignCenter,
+ alignRight,
+ alignJustify,
+} from '@wordpress/icons';
+import { useMemo } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import SegmentedTextControl from '../segmented-text-control';
+
+const TEXT_ALIGNMENT_OPTIONS = [
+ {
+ label: __( 'Align text left' ),
+ value: 'left',
+ icon: alignLeft,
+ },
+ {
+ label: __( 'Align text center' ),
+ value: 'center',
+ icon: alignCenter,
+ },
+ {
+ label: __( 'Align text right' ),
+ value: 'right',
+ icon: alignRight,
+ },
+ {
+ label: __( 'Justify text' ),
+ value: 'justify',
+ icon: alignJustify,
+ },
+];
+
+const DEFAULT_OPTIONS = [ 'left', 'center', 'right' ];
+
+/**
+ * Control to facilitate text alignment selections.
+ *
+ * @param {Object} props Component props.
+ * @param {string} props.className Class name to add to the control.
+ * @param {string} props.value Currently selected text alignment.
+ * @param {Function} props.onChange Handles change in text alignment selection.
+ * @param {string[]} props.options Array of text alignment options to display.
+ *
+ * @return {Element} Text alignment control.
+ */
+export default function TextAlignmentControl( {
+ className,
+ value,
+ onChange,
+ options = DEFAULT_OPTIONS,
+} ) {
+ const validOptions = useMemo(
+ () =>
+ TEXT_ALIGNMENT_OPTIONS.filter( ( option ) =>
+ options.includes( option.value )
+ ),
+ [ options ]
+ );
+
+ if ( ! validOptions.length ) {
+ return null;
+ }
+
+ return (
+ {
+ onChange( newValue === value ? undefined : newValue );
+ } }
+ />
+ );
+}
diff --git a/packages/block-editor/src/components/text-alignment-control/stories/index.story.js b/packages/block-editor/src/components/text-alignment-control/stories/index.story.js
new file mode 100644
index 00000000000000..b2c171497acb0a
--- /dev/null
+++ b/packages/block-editor/src/components/text-alignment-control/stories/index.story.js
@@ -0,0 +1,39 @@
+/**
+ * WordPress dependencies
+ */
+import { useState } from '@wordpress/element';
+
+/**
+ * Internal dependencies
+ */
+import TextAlignmentControl from '../';
+
+export default {
+ title: 'BlockEditor/TextAlignmentControl',
+ component: TextAlignmentControl,
+ argTypes: {
+ onChange: { action: 'onChange' },
+ className: { control: 'text' },
+ options: {
+ control: 'check',
+ options: [ 'left', 'center', 'right', 'justify' ],
+ },
+ value: { control: { type: null } },
+ },
+};
+
+const Template = ( { onChange, ...args } ) => {
+ const [ value, setValue ] = useState();
+ return (
+ {
+ onChange( ...changeArgs );
+ setValue( ...changeArgs );
+ } }
+ value={ value }
+ />
+ );
+};
+
+export const Default = Template.bind( {} );
diff --git a/packages/block-editor/src/components/text-decoration-control/index.js b/packages/block-editor/src/components/text-decoration-control/index.js
index 973fb71a7448f1..6a2085e980bd4e 100644
--- a/packages/block-editor/src/components/text-decoration-control/index.js
+++ b/packages/block-editor/src/components/text-decoration-control/index.js
@@ -6,23 +6,27 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { BaseControl, Button } from '@wordpress/components';
import { reset, formatStrikethrough, formatUnderline } from '@wordpress/icons';
import { __ } from '@wordpress/i18n';
+/**
+ * Internal dependencies
+ */
+import SegmentedTextControl from '../segmented-text-control';
+
const TEXT_DECORATIONS = [
{
- name: __( 'None' ),
+ label: __( 'None' ),
value: 'none',
icon: reset,
},
{
- name: __( 'Underline' ),
+ label: __( 'Underline' ),
value: 'underline',
icon: formatUnderline,
},
{
- name: __( 'Strikethrough' ),
+ label: __( 'Strikethrough' ),
value: 'line-through',
icon: formatStrikethrough,
},
@@ -31,10 +35,10 @@ const TEXT_DECORATIONS = [
/**
* Control to facilitate text decoration selections.
*
- * @param {Object} props Component props.
- * @param {string} props.value Currently selected text decoration.
- * @param {Function} props.onChange Handles change in text decoration selection.
- * @param {string} [props.className] Additional class name to apply.
+ * @param {Object} props Component props.
+ * @param {string} props.value Currently selected text decoration.
+ * @param {Function} props.onChange Handles change in text decoration selection.
+ * @param {string} props.className Additional class name to apply.
*
* @return {Element} Text decoration control.
*/
@@ -44,34 +48,17 @@ export default function TextDecorationControl( {
className,
} ) {
return (
-
+ value={ value }
+ onChange={ ( newValue ) => {
+ onChange( newValue === value ? undefined : newValue );
+ } }
+ />
);
}
diff --git a/packages/block-editor/src/components/text-decoration-control/style.scss b/packages/block-editor/src/components/text-decoration-control/style.scss
deleted file mode 100644
index 689707a66b7ca9..00000000000000
--- a/packages/block-editor/src/components/text-decoration-control/style.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-.block-editor-text-decoration-control {
- border: 0;
- margin: 0;
- padding: 0;
-
- .block-editor-text-decoration-control__buttons {
- // 4px of padding makes the row 40px high, same as an input.
- padding: $grid-unit-05 0;
- display: flex;
- }
-
- .components-button.has-icon {
- height: $grid-unit-40;
- margin-right: $grid-unit-05;
- min-width: $grid-unit-40;
- padding: 0;
- }
-}
diff --git a/packages/block-editor/src/components/text-transform-control/index.js b/packages/block-editor/src/components/text-transform-control/index.js
index c5d0ce37e9acd1..8fd1fb9cfdf51b 100644
--- a/packages/block-editor/src/components/text-transform-control/index.js
+++ b/packages/block-editor/src/components/text-transform-control/index.js
@@ -6,7 +6,6 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { BaseControl, Button } from '@wordpress/components';
import { __ } from '@wordpress/i18n';
import {
reset,
@@ -15,24 +14,29 @@ import {
formatUppercase,
} from '@wordpress/icons';
+/**
+ * Internal dependencies
+ */
+import SegmentedTextControl from '../segmented-text-control';
+
const TEXT_TRANSFORMS = [
{
- name: __( 'None' ),
+ label: __( 'None' ),
value: 'none',
icon: reset,
},
{
- name: __( 'Uppercase' ),
+ label: __( 'Uppercase' ),
value: 'uppercase',
icon: formatUppercase,
},
{
- name: __( 'Lowercase' ),
+ label: __( 'Lowercase' ),
value: 'lowercase',
icon: formatLowercase,
},
{
- name: __( 'Capitalize' ),
+ label: __( 'Capitalize' ),
value: 'capitalize',
icon: formatCapitalize,
},
@@ -50,34 +54,17 @@ const TEXT_TRANSFORMS = [
*/
export default function TextTransformControl( { className, value, onChange } ) {
return (
-
+ value={ value }
+ onChange={ ( newValue ) => {
+ onChange( newValue === value ? undefined : newValue );
+ } }
+ />
);
}
diff --git a/packages/block-editor/src/components/text-transform-control/style.scss b/packages/block-editor/src/components/text-transform-control/style.scss
deleted file mode 100644
index 0e097405e332b7..00000000000000
--- a/packages/block-editor/src/components/text-transform-control/style.scss
+++ /dev/null
@@ -1,18 +0,0 @@
-.block-editor-text-transform-control {
- border: 0;
- margin: 0;
- padding: 0;
-
- .block-editor-text-transform-control__buttons {
- // 4px of padding makes the row 40px high, same as an input.
- padding: $grid-unit-05 0;
- display: flex;
- }
-
- .components-button.has-icon {
- height: $grid-unit-40;
- margin-right: $grid-unit-05;
- min-width: $grid-unit-40;
- padding: 0;
- }
-}
diff --git a/packages/block-editor/src/components/writing-mode-control/index.js b/packages/block-editor/src/components/writing-mode-control/index.js
index 2adf8be14ad395..420c3d75ba31ae 100644
--- a/packages/block-editor/src/components/writing-mode-control/index.js
+++ b/packages/block-editor/src/components/writing-mode-control/index.js
@@ -6,18 +6,22 @@ import classnames from 'classnames';
/**
* WordPress dependencies
*/
-import { BaseControl, Button } from '@wordpress/components';
import { __, isRTL } from '@wordpress/i18n';
import { textHorizontal, textVertical } from '@wordpress/icons';
+/**
+ * Internal dependencies
+ */
+import SegmentedTextControl from '../segmented-text-control';
+
const WRITING_MODES = [
{
- name: __( 'Horizontal' ),
+ label: __( 'Horizontal' ),
value: 'horizontal-tb',
icon: textHorizontal,
},
{
- name: __( 'Vertical' ),
+ label: __( 'Vertical' ),
value: isRTL() ? 'vertical-lr' : 'vertical-rl',
icon: textVertical,
},
@@ -35,34 +39,17 @@ const WRITING_MODES = [
*/
export default function WritingModeControl( { className, value, onChange } ) {
return (
-
+ value={ value }
+ onChange={ ( newValue ) => {
+ onChange( newValue === value ? undefined : newValue );
+ } }
+ />
);
}
diff --git a/packages/block-editor/src/private-apis.js b/packages/block-editor/src/private-apis.js
index e81a5eed39d5bc..f10fcc4df2c726 100644
--- a/packages/block-editor/src/private-apis.js
+++ b/packages/block-editor/src/private-apis.js
@@ -23,6 +23,7 @@ import { BlockRemovalWarningModal } from './components/block-removal-warning-mod
import { useLayoutClasses, useLayoutStyles } from './hooks';
import DimensionsTool from './components/dimensions-tool';
import ResolutionTool from './components/resolution-tool';
+import TextAlignmentControl from './components/text-alignment-control';
import {
default as ReusableBlocksRenameHint,
useReusableBlocksRenameHint,
@@ -66,6 +67,7 @@ lock( privateApis, {
useLayoutStyles,
DimensionsTool,
ResolutionTool,
+ TextAlignmentControl,
ReusableBlocksRenameHint,
useReusableBlocksRenameHint,
usesContextKey,
diff --git a/packages/block-editor/src/style.scss b/packages/block-editor/src/style.scss
index 535d1005d274de..5080aa05718bb3 100644
--- a/packages/block-editor/src/style.scss
+++ b/packages/block-editor/src/style.scss
@@ -41,9 +41,8 @@
@import "./components/multi-selection-inspector/style.scss";
@import "./components/responsive-block-control/style.scss";
@import "./components/rich-text/style.scss";
+@import "./components/segmented-text-control/style.scss";
@import "./components/skip-to-selected-block/style.scss";
-@import "./components/text-decoration-control/style.scss";
-@import "./components/text-transform-control/style.scss";
@import "./components/tool-selector/style.scss";
@import "./components/url-input/style.scss";
@import "./components/url-popover/style.scss";