Skip to content

Instantly share code, notes, and snippets.

@ptesei
Created October 27, 2024 06:59
Show Gist options
  • Select an option

  • Save ptesei/3d5706e9799083362fa724418df8c914 to your computer and use it in GitHub Desktop.

Select an option

Save ptesei/3d5706e9799083362fa724418df8c914 to your computer and use it in GitHub Desktop.
WordPress Gutenberg extend Rich Text Toolbar Button example with popover
//example with popover
import { RichTextToolbarButton } from '@wordpress/block-editor';
import { useSelect } from '@wordpress/data';
import { registerFormatType, applyFormat, removeFormat, useAnchor } from '@wordpress/rich-text';
import {registerBlockVariation} from '@wordpress/blocks';
import { listItem } from '@wordpress/icons';
import {
TextControl,
SelectControl,
Button,
Popover,
__experimentalHStack as HStack,
__experimentalVStack as VStack,
} from '@wordpress/components';
import { useState } from '@wordpress/element';
const { __ } = wp.i18n;
const name = 'mosne/button-icon-inline';
const title = __( 'Inline icon' );
const ButtonIconsEdit = ( { isActive, onChange, contentRef, value } ) => {
const selectedBlock = useSelect( ( select ) => {
return select( 'core/block-editor' ).getSelectedBlock();
}, [] );
// allow only in button blocks
if ( selectedBlock && selectedBlock.name !== 'core/button' ) {
return null;
}
const [ isPopoverVisible, setIsPopoverVisible ] = useState( false );
const togglePopover = () => {
setIsPopoverVisible( ( state ) => ! state );
};
return (
<>
<RichTextToolbarButton
icon={ listItem }
title={ title}
onClick={ () => {
if ( isActive ) {
onChange( removeFormat( value, name ) );
} else {
togglePopover();
}
} }
isActive={ isActive }
role="menuitemcheckbox"
/>
{ isPopoverVisible && (
<InlineIconUI
value={ value }
onChange={ onChange }
onClose={ togglePopover }
contentRef={ contentRef }
/>
) }
</>
);
};
function InlineIconUI( { value, contentRef, onChange, onClose } ) {
const popoverAnchor = useAnchor( {
editableContentElement: contentRef.current,
settings: listItem,
} );
const [ lang, setLang ] = useState( '' );
const [ dir, setDir ] = useState( 'ltr' );
return (
<Popover
className="block-editor-format-toolbar__language-popover"
anchor={ popoverAnchor }
onClose={ onClose }
>
<VStack
as="form"
spacing={ 4 }
className="block-editor-format-toolbar__language-container-content"
onSubmit={ ( event ) => {
event.preventDefault();
onChange(
applyFormat( value, {
type: name,
attributes: {
lang,
dir,
},
} )
);
onClose();
} }
>
<TextControl
__next40pxDefaultSize
__nextHasNoMarginBottom
label={ title }
value={ lang }
onChange={ ( val ) => setLang( val ) }
help={ __(
'A valid language attribute, like "en" or "fr".'
) }
/>
<SelectControl
__next40pxDefaultSize
__nextHasNoMarginBottom
label={ __( 'Text direction' ) }
value={ dir }
options={ [
{
label: __( 'Left to right' ),
value: 'ltr',
},
{
label: __( 'Right to left' ),
value: 'rtl',
},
] }
onChange={ ( val ) => setDir( val ) }
/>
<HStack alignment="right">
<Button
__next40pxDefaultSize
variant="primary"
type="submit"
text={ __( 'Apply' ) }
/>
</HStack>
</VStack>
</Popover>
);
};
registerFormatType( name, {
title: title,
name: name,
tagName: 'span',
className: 'wp-block-button__icon',
ariaHidden: true,
edit: ButtonIconsEdit,
} );
registerBlockVariation('core/button', {
name: 'button-icon-right',
title: 'Icon right',
attributes: {
text: 'Button <span class="wp-block-button__icon" aria-hidde="true">+</span>',
url: '',
},
});
registerBlockVariation('core/button', {
name: 'button-icon-left',
title: 'Icon left',
attributes: {
text: '<span class="wp-block-button__icon" aria-hidde="true">+</span> Button',
url: '',
},
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment