Skip to content
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

Block Editor: Add new TextAlignmentControl component #60841

Merged
merged 27 commits into from
Apr 26, 2024
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
7b3fd79
Block Editor: Add new `TextAlignControl` component
t-hamano Apr 18, 2024
6c69ce8
Rename `TextAlignControl` to `TextAlignmentControl`
t-hamano Apr 19, 2024
b1dfa99
Replate `align` with `alignment`
t-hamano Apr 19, 2024
5f671ce
Use components to reduce CSS writing
t-hamano Apr 19, 2024
d09a8f8
Merge branch 'trunk' into block-editor/add-text-align-control
t-hamano Apr 20, 2024
cc79460
Refactor using new SegmentedTextControl component
t-hamano Apr 20, 2024
503a20f
Merge branch 'trunk' into block-editor/add-text-align-control
t-hamano Apr 22, 2024
036522b
Make a component private
t-hamano Apr 22, 2024
a050659
SegmentedTextControl: Update JSDoc parameters
t-hamano Apr 22, 2024
7439461
TextAlignmentControl: Update JSDoc parameter
t-hamano Apr 22, 2024
08fca2a
TextAlignmentControl: Cache valid controls filtering
t-hamano Apr 22, 2024
9f12b6a
WritingModeControl: fix control property
t-hamano Apr 22, 2024
cc75116
TextAlignmentControl: Allow `justify` as an allowed value
t-hamano Apr 22, 2024
cfae31a
TextAlignmentControl: Update docs
t-hamano Apr 22, 2024
b672c97
SegmentedTextControl: Update description
t-hamano Apr 23, 2024
0ce16c2
TextAlignmentControl: Update readme
t-hamano Apr 23, 2024
e0acab7
TextAlignmentControl: Fix JSDoc
t-hamano Apr 23, 2024
a533921
TextAlignmentControl: Update readme
t-hamano Apr 23, 2024
62d4003
TextAlignmentControl: Update readme
t-hamano Apr 23, 2024
2288b72
SegmentedTextControl: Update JSDoc
t-hamano Apr 23, 2024
fcb384d
TextAlignmentcontrol: remove unecessary `unlock()`
t-hamano Apr 23, 2024
e038087
TextAlignmentControl: Remove unnecessary styles
t-hamano Apr 23, 2024
12f4fc7
Restor default component classname
t-hamano Apr 23, 2024
00f4ef8
Rename `control(s)` to `option(s)`
t-hamano Apr 26, 2024
6b5442c
TextAlignmentControl: Remove README
t-hamano Apr 26, 2024
8e5cd0f
TextAlignmentControl: Fix control name
t-hamano Apr 26, 2024
e0ab442
Merge branch 'trunk' into block-editor/add-text-align-control
t-hamano Apr 26, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
/**
* External dependencies
*/
import classnames from 'classnames';

/**
* WordPress dependencies
*/
import { BaseControl, Button } from '@wordpress/components';

/**
* @typedef {Object} Control
aaronrobertshaw marked this conversation as resolved.
Show resolved Hide resolved
* @property {string} label The label of the control.
* @property {string} value The value of the control.
* @property {string} icon The icon of the control.
t-hamano marked this conversation as resolved.
Show resolved Hide resolved
*/

/**
* Control to facilitate segmented text selections.
t-hamano marked this conversation as resolved.
Show resolved Hide resolved
*
* @param {Object} props Component props.
* @param {string} props.label A label for the control.
* @param {string} props.value Currently selected value.
* @param {Function} props.onChange Callback to handle onChange.
* @param {Control[]} props.controls Array of controls to display.
* @param {string} props.className Additional class name to apply.
*
* @return {Element} Element to render.
*/
export default function SegmentedTextControl( {
label,
value,
controls,
t-hamano marked this conversation as resolved.
Show resolved Hide resolved
onChange,
className,
} ) {
return (
<fieldset
aaronrobertshaw marked this conversation as resolved.
Show resolved Hide resolved
className={ classnames(
'block-editor-segmented-text-control',
className
) }
>
<BaseControl.VisualLabel as="legend">
{ label }
</BaseControl.VisualLabel>
<div className="block-editor-segmented-text-control__buttons">
{ controls.map( ( control ) => {
return (
<Button
size="compact"
key={ control.value }
icon={ control.icon }
label={ control.label }
isPressed={ control.value === value }
onClick={ () => onChange( control.value ) }
/>
);
} ) }
</div>
</fieldset>
);
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# TextAlignmentControl

The `TextAlignmentControl` component is responsible for rendering a control element that allows users to select and apply text align options to blocks or elements in the Gutenberg editor. It provides an intuitive interface for changing the text alignment by applying different alignments such as `left`, `center`, `right`.
t-hamano marked this conversation as resolved.
Show resolved Hide resolved

## Development guidelines

### Usage

Renders the Text Align Component with `left`, `center`, `right` options.
t-hamano marked this conversation as resolved.
Show resolved Hide resolved

```jsx
import { TextAlignmentControl } from '@wordpress/block-editor';

const MyTextAlignmentControlComponent = () => (
<TextAlignmentControl
value={ textTransform }
onChange={ ( value ) => {
setAttributes( { textTransform: value } );
} }
/>
);
```

### Props

The component accepts the following props.

#### value

The current value of the Text Alignment setting. Available options are `left|center|right|justify`.

- Type: `String`
- Required: No
t-hamano marked this conversation as resolved.
Show resolved Hide resolved

#### controls

An array of strings for what controls to show, by default it shows all. Available options are `left|center|right|justify`.

- Type: `Array`
- Required: No

#### onChange

Callback when the `value` changes.

- Type: `Function`
- Required: Yes

#### className

A string of classes to be added to the control component.

- Type: `String`
- Required: No
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/**
* 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_CONTROLS = [
{
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_CONTROLS = [ '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.controls Array of text align controls to display.
t-hamano marked this conversation as resolved.
Show resolved Hide resolved
*
* @return {Element} Text alignment control.
*/
export default function TextAlignmentControl( {
className,
value,
onChange,
controls = DEFAULT_CONTROLS,
} ) {
const validControls = useMemo(
() =>
TEXT_ALIGNMENT_CONTROLS.filter( ( control ) =>
controls.includes( control.value )
),
[ controls ]
);

if ( ! validControls.length ) {
return null;
}

return (
<SegmentedTextControl
label={ __( 'Text alignment' ) }
controls={ validControls }
className={ className }
value={ value }
onChange={ ( newValue ) => {
onChange( newValue === value ? undefined : newValue );
} }
/>
);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* WordPress dependencies
*/
import { useState } from '@wordpress/element';
import { privateApis as blockEditorPrivateApis } from '@wordpress/block-editor';

/**
* Internal dependencies
*/
import { unlock } from '../../../lock-unlock';

const { TextAlignmentControl } = unlock( blockEditorPrivateApis );
aaronrobertshaw marked this conversation as resolved.
Show resolved Hide resolved

export default {
title: 'BlockEditor/TextAlignmentControl',
component: TextAlignmentControl,
argTypes: {
onChange: { action: 'onChange' },
className: { control: 'text' },
controls: {
t-hamano marked this conversation as resolved.
Show resolved Hide resolved
control: 'check',
options: [ 'left', 'center', 'right', 'justify' ],
},
value: { control: { type: null } },
},
};

const Template = ( { onChange, ...args } ) => {
const [ value, setValue ] = useState();
return (
<TextAlignmentControl
{ ...args }
onChange={ ( ...changeArgs ) => {
onChange( ...changeArgs );
setValue( ...changeArgs );
} }
value={ value }
/>
);
};

export const Default = Template.bind( {} );
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.block-editor-text-alignment-control {
border: 0;
margin: 0;
padding: 0;
}
aaronrobertshaw marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,28 +1,27 @@
/**
* External dependencies
*/
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,
},
Expand All @@ -31,10 +30,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.
*/
Expand All @@ -44,34 +43,14 @@ export default function TextDecorationControl( {
className,
} ) {
return (
<fieldset
className={ classnames(
'block-editor-text-decoration-control',
className
) }
>
<BaseControl.VisualLabel as="legend">
{ __( 'Decoration' ) }
</BaseControl.VisualLabel>
<div className="block-editor-text-decoration-control__buttons">
{ TEXT_DECORATIONS.map( ( textDecoration ) => {
return (
<Button
key={ textDecoration.value }
icon={ textDecoration.icon }
label={ textDecoration.name }
isPressed={ textDecoration.value === value }
onClick={ () => {
onChange(
textDecoration.value === value
? undefined
: textDecoration.value
);
} }
/>
);
} ) }
</div>
</fieldset>
<SegmentedTextControl
label={ __( 'Decoration' ) }
controls={ TEXT_DECORATIONS }
className={ className }
value={ value }
aaronrobertshaw marked this conversation as resolved.
Show resolved Hide resolved
onChange={ ( newValue ) => {
onChange( newValue === value ? undefined : newValue );
} }
/>
);
}

This file was deleted.

Loading
Loading