diff --git a/packages/rich-text/src/component/index.js b/packages/rich-text/src/component/index.js index cb62992fa669a1..df4d3f129e9006 100644 --- a/packages/rich-text/src/component/index.js +++ b/packages/rich-text/src/component/index.js @@ -18,6 +18,7 @@ import { useSelectObject } from './use-select-object'; import { useIndentListItemOnSpace } from './use-indent-list-item-on-space'; import { useInputAndSelection } from './use-input-and-selection'; import { useDelete } from './use-delete'; +import { useSpace } from './use-space'; export function useRichText( { value = '', @@ -198,6 +199,7 @@ export function useRichText( { isSelected, onSelectionChange, } ), + useSpace(), useRefEffect( () => { applyFromProps(); didMount.current = true; diff --git a/packages/rich-text/src/component/use-space.js b/packages/rich-text/src/component/use-space.js new file mode 100644 index 00000000000000..5a64f08549a8c2 --- /dev/null +++ b/packages/rich-text/src/component/use-space.js @@ -0,0 +1,40 @@ +/** + * WordPress dependencies + */ +import { useRefEffect } from '@wordpress/compose'; +import { SPACE } from '@wordpress/keycodes'; + +/** + * For some elements like BUTTON and SUMMARY, the space key doesn't insert a + * space character in some browsers even though the element is editable. We have + * to manually insert a space and prevent default behaviour. + * + * DO NOT limit this behaviour to specific tag names! It would mean that this + * behaviour is not widely tested. If there's ever any problems, we should find + * a different solution entirely or remove it entirely. + */ +export function useSpace() { + return useRefEffect( ( element ) => { + function onKeyDown( event ) { + // Don't insert a space if default behaviour is prevented. + if ( event.defaultPrevented ) { + return; + } + + const { keyCode, altKey, metaKey, ctrlKey } = event; + + // Only consider the space key without modifiers pressed. + if ( keyCode !== SPACE || altKey || metaKey || ctrlKey ) { + return; + } + + event.target.ownerDocument.execCommand( 'insertText', false, ' ' ); + event.preventDefault(); + } + + element.addEventListener( 'keydown', onKeyDown ); + return () => { + element.removeEventListener( 'keydown', onKeyDown ); + }; + }, [] ); +}