Skip to content

Commit

Permalink
Merge pull request #16034 from ckeditor/ck/app-menu-bar-font
Browse files Browse the repository at this point in the history
Internal (font): Added menu bar integration for font family, size, color, and background color. Related to #15894.
  • Loading branch information
oleq authored Mar 20, 2024
2 parents 7c95902 + 7c92f23 commit b40fe19
Show file tree
Hide file tree
Showing 9 changed files with 187 additions and 21 deletions.
7 changes: 1 addition & 6 deletions packages/ckeditor5-code-block/src/codeblockui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -108,13 +108,8 @@ export default class CodeBlockUI extends Plugin {
const listItemView = new MenuBarMenuListItemView( locale, menuView );
const buttonView = new MenuBarMenuListItemButtonView( locale );

buttonView.extendTemplate( {
attributes: {
'aria-checked': buttonView.bindTemplate.to( 'isOn' )
}
} );

buttonView.bind( ...Object.keys( definition.model ) as Array<keyof MenuBarMenuListItemButtonView> ).to( definition.model );
buttonView.bind( 'ariaChecked' ).to( buttonView, 'isOn' );
buttonView.delegate( 'execute' ).to( menuView );

buttonView.on( 'execute', () => {
Expand Down
53 changes: 49 additions & 4 deletions packages/ckeditor5-font/src/fontfamily/fontfamilyui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,16 @@

import { Plugin } from 'ckeditor5/src/core.js';
import { Collection } from 'ckeditor5/src/utils.js';
import { ViewModel, createDropdown, addListToDropdown, type ListDropdownItemDefinition } from 'ckeditor5/src/ui.js';
import {
ViewModel,
createDropdown,
addListToDropdown,
MenuBarMenuView,
MenuBarMenuListView,
MenuBarMenuListItemView,
MenuBarMenuListItemButtonView,
type ListDropdownButtonDefinition
} from 'ckeditor5/src/ui.js';

import { normalizeOptions } from './utils.js';
import { FONT_FAMILY } from '../utils.js';
Expand Down Expand Up @@ -41,12 +50,13 @@ export default class FontFamilyUI extends Plugin {

const command: FontFamilyCommand = editor.commands.get( FONT_FAMILY )!;
const accessibleLabel = t( 'Font Family' );
const listOptions = _prepareListOptions( options, command );

// Register UI component.
editor.ui.componentFactory.add( FONT_FAMILY, locale => {
const dropdownView = createDropdown( locale );

addListToDropdown( dropdownView, () => _prepareListOptions( options, command ), {
addListToDropdown( dropdownView, listOptions, {
role: 'menu',
ariaLabel: accessibleLabel
} );
Expand All @@ -73,6 +83,41 @@ export default class FontFamilyUI extends Plugin {

return dropdownView;
} );

editor.ui.componentFactory.add( `menuBar:${ FONT_FAMILY }`, locale => {
const menuView = new MenuBarMenuView( locale );

menuView.buttonView.set( {
label: accessibleLabel,
icon: fontFamilyIcon
} );

const listView = new MenuBarMenuListView( locale );

for ( const definition of listOptions ) {
const listItemView = new MenuBarMenuListItemView( locale, menuView );
const buttonView = new MenuBarMenuListItemButtonView( locale );

buttonView.bind( ...Object.keys( definition.model ) as Array<keyof MenuBarMenuListItemButtonView> ).to( definition.model );
buttonView.bind( 'ariaChecked' ).to( buttonView, 'isOn' );
buttonView.delegate( 'execute' ).to( menuView );

buttonView.on( 'execute', () => {
editor.execute( ( definition.model as any ).commandName, {
value: ( definition.model as any ).commandParam
} );

editor.editing.view.focus();
} );

listItemView.children.add( buttonView );
listView.items.add( listItemView );
}

menuView.panelView.children.add( listView );

return menuView;
} );
}

/**
Expand Down Expand Up @@ -103,8 +148,8 @@ export default class FontFamilyUI extends Plugin {
/**
* Prepares FontFamily dropdown items.
*/
function _prepareListOptions( options: Array<FontFamilyOption>, command: FontFamilyCommand ): Collection<ListDropdownItemDefinition> {
const itemDefinitions = new Collection<ListDropdownItemDefinition>();
function _prepareListOptions( options: Array<FontFamilyOption>, command: FontFamilyCommand ): Collection<ListDropdownButtonDefinition> {
const itemDefinitions = new Collection<ListDropdownButtonDefinition>();

// Create dropdown items.
for ( const option of options ) {
Expand Down
49 changes: 45 additions & 4 deletions packages/ckeditor5-font/src/fontsize/fontsizeui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,11 @@ import {
ViewModel,
createDropdown,
addListToDropdown,
type ListDropdownItemDefinition
type ListDropdownButtonDefinition,
MenuBarMenuView,
MenuBarMenuListView,
MenuBarMenuListItemView,
MenuBarMenuListItemButtonView
} from 'ckeditor5/src/ui.js';
import { Collection } from 'ckeditor5/src/utils.js';

Expand Down Expand Up @@ -48,11 +52,13 @@ export default class FontSizeUI extends Plugin {
const command: FontSizeCommand = editor.commands.get( FONT_SIZE )!;
const accessibleLabel = t( 'Font Size' );

const listOptions = _prepareListOptions( options, command );

// Register UI component.
editor.ui.componentFactory.add( FONT_SIZE, locale => {
const dropdownView = createDropdown( locale );

addListToDropdown( dropdownView, () => _prepareListOptions( options, command ), {
addListToDropdown( dropdownView, listOptions, {
role: 'menu',
ariaLabel: accessibleLabel
} );
Expand Down Expand Up @@ -82,6 +88,41 @@ export default class FontSizeUI extends Plugin {

return dropdownView;
} );

editor.ui.componentFactory.add( `menuBar:${ FONT_SIZE }`, locale => {
const menuView = new MenuBarMenuView( locale );

menuView.buttonView.set( {
label: accessibleLabel,
icon: fontSizeIcon
} );

const listView = new MenuBarMenuListView( locale );

for ( const definition of listOptions ) {
const listItemView = new MenuBarMenuListItemView( locale, menuView );
const buttonView = new MenuBarMenuListItemButtonView( locale );

buttonView.bind( ...Object.keys( definition.model ) as Array<keyof MenuBarMenuListItemButtonView> ).to( definition.model );
buttonView.bind( 'ariaChecked' ).to( buttonView, 'isOn' );
buttonView.delegate( 'execute' ).to( menuView );

buttonView.on( 'execute', () => {
editor.execute( ( definition.model as any ).commandName, {
value: ( definition.model as any ).commandParam
} );

editor.editing.view.focus();
} );

listItemView.children.add( buttonView );
listView.items.add( listItemView );
}

menuView.panelView.children.add( listView );

return menuView;
} );
}

/**
Expand Down Expand Up @@ -122,8 +163,8 @@ export default class FontSizeUI extends Plugin {
/**
* Prepares FontSize dropdown items.
*/
function _prepareListOptions( options: Array<FontSizeOption>, command: FontSizeCommand ): Collection<ListDropdownItemDefinition> {
const itemDefinitions = new Collection<ListDropdownItemDefinition>();
function _prepareListOptions( options: Array<FontSizeOption>, command: FontSizeCommand ): Collection<ListDropdownButtonDefinition> {
const itemDefinitions = new Collection<ListDropdownButtonDefinition>();

for ( const option of options ) {
const def = {
Expand Down
68 changes: 67 additions & 1 deletion packages/ckeditor5-font/src/ui/colorui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@ import {
focusChildOnDropdownOpen,
type ColorSelectorExecuteEvent,
type ColorSelectorColorPickerCancelEvent,
type ColorSelectorColorPickerShowEvent
type ColorSelectorColorPickerShowEvent,
MenuBarMenuView,
ColorSelectorView
} from 'ckeditor5/src/ui.js';

import {
Expand Down Expand Up @@ -208,5 +210,69 @@ export default class ColorUI extends Plugin {

return dropdownView;
} );

// Register menu bar button..
editor.ui.componentFactory.add( `menuBar:${ this.componentName }`, locale => {
const menuView = new MenuBarMenuView( locale );

menuView.buttonView.set( {
label: this.dropdownLabel,
icon: this.icon
} );

menuView.bind( 'isEnabled' ).to( command );

// Font color sub-menu rendering is deferred once it gets open to improve performance (#6192).
let contentRendered = false;

const colorSelectorView = new ColorSelectorView( locale, {
colors: localizedColors.map( option => ( {
label: option.label,
color: option.model,
options: {
hasBorder: option.hasBorder
}
} ) ),
columns: this.columns,
removeButtonLabel: t( 'Remove color' ),
colorPickerLabel: t( 'Color picker' ),
documentColorsLabel: documentColorsCount !== 0 ? t( 'Document colors' ) : '',
documentColorsCount: documentColorsCount === undefined ? this.columns : documentColorsCount,
colorPickerViewConfig: false
} );

colorSelectorView.bind( 'selectedColor' ).to( command, 'value' );

colorSelectorView.delegate( 'execute' ).to( menuView );
colorSelectorView.on<ColorSelectorExecuteEvent>( 'execute', ( evt, data ) => {
editor.execute( this.commandName, {
value: data.value,
batch: this._undoStepBatch
} );

editor.editing.view.focus();
} );

menuView.on( 'change:isOpen', ( evt, name, isVisible ) => {
if ( !contentRendered ) {
contentRendered = true;

colorSelectorView!.appendUI();
}

if ( isVisible ) {
if ( documentColorsCount !== 0 ) {
colorSelectorView!.updateDocumentColors( editor.model, this.componentName );
}

colorSelectorView!.updateSelectedColors();
colorSelectorView!.showColorGridsFragment();
}
} );

menuView.panelView.children.add( colorSelectorView );

return menuView;
} );
}
}
1 change: 1 addition & 0 deletions packages/ckeditor5-heading/src/headingui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@ export default class HeadingUI extends Plugin {
class: option.class
} );

buttonView.bind( 'ariaChecked' ).to( buttonView, 'isOn' );
buttonView.delegate( 'execute' ).to( menuView );

buttonView.on<ButtonExecuteEvent>( 'execute', () => {
Expand Down
7 changes: 7 additions & 0 deletions packages/ckeditor5-ui/src/button/button.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,13 @@ export default interface Button {
*/
class: string | undefined;

/**
* (Optional) The ARIA property reflected by the `aria-checked` DOM attribute used by assistive technologies.
*
* @observable
*/
ariaChecked?: boolean | undefined;

/**
* (Optional) The ARIA property reflected by the `aria-label` DOM attribute used by assistive technologies.
*
Expand Down
6 changes: 6 additions & 0 deletions packages/ckeditor5-ui/src/button/buttonview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,11 @@ export default class ButtonView extends View<HTMLButtonElement> implements Butto
*/
declare public role: string | undefined;

/**
* @inheritDoc
*/
declare public ariaChecked: boolean | undefined;

/**
* @inheritDoc
*/
Expand Down Expand Up @@ -246,6 +251,7 @@ export default class ButtonView extends View<HTMLButtonElement> implements Butto
role: bind.to( 'role' ),
type: bind.to( 'type', value => value ? value : 'button' ),
tabindex: bind.to( 'tabindex' ),
'aria-checked': bind.to( 'ariaChecked' ),
'aria-label': bind.to( 'ariaLabel' ),
'aria-labelledby': bind.to( 'ariaLabelledBy' ),
'aria-disabled': bind.if( 'isEnabled', true, value => !value ),
Expand Down
6 changes: 1 addition & 5 deletions packages/ckeditor5-ui/src/dropdown/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -560,11 +560,7 @@ function bindViewCollectionItemsToDefinitions(

if ( def.type === 'button' ) {
buttonView = new ButtonView( locale );
buttonView.extendTemplate( {
attributes: {
'aria-checked': buttonView.bindTemplate.to( 'isOn' )
}
} );
buttonView.bind( 'ariaChecked' ).to( buttonView, 'isOn' );
} else {
buttonView = new SwitchButtonView( locale );
}
Expand Down
11 changes: 10 additions & 1 deletion packages/ckeditor5-ui/src/menubar/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,9 @@ export const DefaultMenuBarItems: DeepReadonly<MenuBarConfigObject[ 'items' ]> =
{
groupId: 'heading',
items: [
'menuBar:heading'
'menuBar:heading',
'menuBar:fontSize',
'menuBar:fontFamily'
]
},
{
Expand All @@ -531,6 +533,13 @@ export const DefaultMenuBarItems: DeepReadonly<MenuBarConfigObject[ 'items' ]> =
'menuBar:outdent'
]
},
{
groupId: 'fontColor',
items: [
'menuBar:fontColor',
'menuBar:fontBackgroundColor'
]
},
{
groupId: 'removeFormat',
items: [
Expand Down

0 comments on commit b40fe19

Please sign in to comment.