Skip to content

Commit

Permalink
Add setting to display rich text toolbar inline (#42399)
Browse files Browse the repository at this point in the history
  • Loading branch information
ellatrix authored Jul 14, 2022
1 parent d48b6bb commit 7ea4f74
Show file tree
Hide file tree
Showing 7 changed files with 99 additions and 28 deletions.
31 changes: 17 additions & 14 deletions packages/block-editor/src/components/observe-typing/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -115,16 +115,21 @@ export function useMouseMoveTypingReset() {
* field, presses ESC or TAB, or moves the mouse in the document.
*/
export function useTypingObserver() {
const isTyping = useSelect( ( select ) =>
select( blockEditorStore ).isTyping()
);
const { isTyping, hasInlineToolbar } = useSelect( ( select ) => {
const { isTyping: _isTyping, getSettings } = select( blockEditorStore );
return {
isTyping: _isTyping(),
hasInlineToolbar: getSettings().hasInlineToolbar,
};
}, [] );
const { startTyping, stopTyping } = useDispatch( blockEditorStore );

const ref1 = useMouseMoveTypingReset();
const ref2 = useRefEffect(
( node ) => {
const { ownerDocument } = node;
const { defaultView } = ownerDocument;
const selection = defaultView.getSelection();

// Listeners to stop typing should only be added when typing.
// Listeners to start typing should only be added when not typing.
Expand Down Expand Up @@ -170,22 +175,20 @@ export function useTypingObserver() {
* uncollapsed (shift) selection.
*/
function stopTypingOnSelectionUncollapse() {
const selection = defaultView.getSelection();
const isCollapsed =
selection.rangeCount > 0 &&
selection.getRangeAt( 0 ).collapsed;

if ( ! isCollapsed ) {
if ( ! selection.isCollapsed ) {
stopTyping();
}
}

node.addEventListener( 'focus', stopTypingOnNonTextField );
node.addEventListener( 'keydown', stopTypingOnEscapeKey );
ownerDocument.addEventListener(
'selectionchange',
stopTypingOnSelectionUncollapse
);

if ( ! hasInlineToolbar ) {
ownerDocument.addEventListener(
'selectionchange',
stopTypingOnSelectionUncollapse
);
}

return () => {
defaultView.clearTimeout( timerId );
Expand Down Expand Up @@ -242,7 +245,7 @@ export function useTypingObserver() {
node.removeEventListener( 'keydown', startTypingInTextField );
};
},
[ isTyping, startTyping, stopTyping ]
[ isTyping, hasInlineToolbar, startTyping, stopTyping ]
);

return useMergeRefs( [ ref1, ref2 ] );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,32 +2,81 @@
* WordPress dependencies
*/
import { Popover, ToolbarGroup } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import {
isCollapsed,
getActiveFormats,
useAnchorRef,
store as richTextStore,
} from '@wordpress/rich-text';

/**
* Internal dependencies
*/
import BlockControls from '../block-controls';
import FormatToolbar from './format-toolbar';
import { store as blockEditorStore } from '../../store';

function InlineSelectionToolbar( { value, anchorRef, activeFormats } ) {
const lastFormat = activeFormats[ activeFormats.length - 1 ];
const lastFormatType = lastFormat?.type;
const settings = useSelect(
( select ) => select( richTextStore ).getFormatType( lastFormatType ),
[ lastFormatType ]
);
const selectionRef = useAnchorRef( {
ref: anchorRef,
value,
settings,
} );

return <InlineToolbar anchorRef={ selectionRef } />;
}

function InlineToolbar( { anchorRef } ) {
return (
<Popover
position="top center"
focusOnMount={ false }
anchorRef={ anchorRef }
className="block-editor-rich-text__inline-format-toolbar"
__unstableSlotName="block-toolbar"
>
<div className="block-editor-rich-text__inline-format-toolbar-group">
<ToolbarGroup>
<FormatToolbar />
</ToolbarGroup>
</div>
</Popover>
);
}

const FormatToolbarContainer = ( { inline, anchorRef, value } ) => {
const hasInlineToolbar = useSelect(
( select ) => select( blockEditorStore ).getSettings().hasInlineToolbar,
[]
);

const FormatToolbarContainer = ( { inline, anchorRef } ) => {
if ( inline ) {
// Render in popover.
return <InlineToolbar anchorRef={ anchorRef } />;
}

if ( hasInlineToolbar ) {
const activeFormats = getActiveFormats( value );

if ( isCollapsed( value ) && ! activeFormats.length ) {
return null;
}

return (
<Popover
position="top center"
focusOnMount={ false }
<InlineSelectionToolbar
anchorRef={ anchorRef }
className="block-editor-rich-text__inline-format-toolbar"
__unstableSlotName="block-toolbar"
>
<div className="block-editor-rich-text__inline-format-toolbar-group">
<ToolbarGroup>
<FormatToolbar />
</ToolbarGroup>
</div>
</Popover>
value={ value }
activeFormats={ activeFormats }
/>
);
}

// Render regular toolbar.
return (
<BlockControls group="inline">
Expand Down
1 change: 1 addition & 0 deletions packages/block-editor/src/components/rich-text/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -344,6 +344,7 @@ function RichTextWrapper(
<FormatToolbarContainer
inline={ inlineToolbar }
anchorRef={ anchorRef }
value={ value }
/>
) }
<TagName
Expand Down
3 changes: 3 additions & 0 deletions packages/edit-post/src/editor.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ function Editor( {
hasFixedToolbar,
focusMode,
hasReducedUI,
hasInlineToolbar,
hasThemeStyles,
post,
preferredStyleVariations,
Expand Down Expand Up @@ -84,6 +85,7 @@ function Editor( {
__experimentalGetPreviewDeviceType() !== 'Desktop',
focusMode: isFeatureActive( 'focusMode' ),
hasReducedUI: isFeatureActive( 'reducedUI' ),
hasInlineToolbar: isFeatureActive( 'inlineToolbar' ),
hasThemeStyles: isFeatureActive( 'themeStyles' ),
preferredStyleVariations: select( preferencesStore ).get(
'core/edit-post',
Expand Down Expand Up @@ -116,6 +118,7 @@ function Editor( {
hasFixedToolbar,
focusMode,
hasReducedUI,
hasInlineToolbar,

// This is marked as experimental to give time for the quick inserter to mature.
__experimentalSetIsInserterOpened: setIsInserterOpened,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ function useBlockEditorSettings( settings, hasTemplate ) {
'generateAnchors',
'hasFixedToolbar',
'hasReducedUI',
'hasInlineToolbar',
'imageDefaultSize',
'imageDimensions',
'imageEditing',
Expand Down
13 changes: 13 additions & 0 deletions packages/rich-text/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,19 @@ _Returns_

- `RichTextFormat|undefined`: Active format object of the specified type, or undefined.

### getActiveFormats

Gets the all format objects at the start of the selection.

_Parameters_

- _value_ `RichTextValue`: Value to inspect.
- _EMPTY_ACTIVE_FORMATS_ `Array`: Array to return if there are no active formats.

_Returns_

- `RichTextFormatList`: Active format objects.

### getActiveObject

Gets the active object, if there is any.
Expand Down
1 change: 1 addition & 0 deletions packages/rich-text/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export { applyFormat } from './apply-format';
export { concat } from './concat';
export { create } from './create';
export { getActiveFormat } from './get-active-format';
export { getActiveFormats } from './get-active-formats';
export { getActiveObject } from './get-active-object';
export { getTextContent } from './get-text-content';
export { isListRootSelected as __unstableIsListRootSelected } from './is-list-root-selected';
Expand Down

0 comments on commit 7ea4f74

Please sign in to comment.