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

Add setting to display rich text toolbar inline #42399

Merged
merged 5 commits into from
Jul 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
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