ckeditor5 icon indicating copy to clipboard operation
ckeditor5 copied to clipboard

Declarative nested toolbars

Open oleq opened this issue 3 years ago • 0 comments

📝 Provide a description of the new feature

Let's add a new format of configuration to config.toolbar to make it possible to group toolbar items into drop-downs so that we can squeeze a massive toolbar

into something compact

Screenshot 2022-09-14 at 11 50 41 Screenshot 2022-09-14 at 11 50 46 Screenshot 2022-09-14 at 11 50 51 image

Proposed scope of changes

We're going to need a functionality in the ToolbarView component to allows declarative drop-downs with nested toolbars.

Example toolbar configuration

toolbar: [
	{
		label: 'Import/Export',
		icon: 'importExport',
		items: [
			'exportPdf',
			'exportWord'
		]
	},
	'sourceEditing',
	'|',
	'heading',
	'|',
	'style',
	'|',
	'bold', 'italic', 'link',
	'|',
	{
		label: 'Insert',
		icon: 'plus',
		items: [
			'insertImage', 'ckbox', 'insertTable', 'mediaEmbed', 'htmlEmbed',
			'pageBreak', 'horizontalLine', 'specialCharacters', '|',
			'blockQuote', 'codeBlock'
		]
	},
	
	// ...

Notes:

  • label can be just any string (we could provide translations for several popular ones like we do in the heading feature),
  • icon maps to an object with pre-defined icons (or a SVG string like in ImageStyle feature)
  • items corresponds to the standard items configuration syntax. It support recursive drop-downs with toolbars.

Changes to the source editing feature

To save space, I say we remove the label from the button. Not sure why we decided to have it there in the first place. I suppose we wanted to replicate the look of CKE4.

  • Alternative 1.: Source editing feature could register two components in the factory. One with the label and one without.
  • Alternative 2.: Use advanced toolbar item config (see below) to avoid multiple components in the factory.
image

Changes to the text language feature

To save space, let's remove the label from the button and have a new icon there. This will degrade the UX but OTOH this feature is not very popular.

  • Alternative 1.: Text part language feature could register two components in the factory. One with the label and one without.
  • Alternative 2.: Use advanced toolbar item config (see below) to avoid multiple components in the factory.
image

Other works

  • Let's have a new icon for all export features.
  • Let's have more icons developers could use for their dropdowns. I think they already exist so we only have to move them to ckeditor5-core.

Drawbacks

Drawback: Deep stacking

The drawback of this solution is that in some cases, there's a deep stack of drop-downs/toolbars to reach an option

Screenshot 2022-09-14 at 11 51 18

Drawback: Drop-downs are passive

It could be confusing for some users that these drop-downs (their icons and states) are static:

image

It may look like the icon should change depending on the current selection but it won't. This is just a static icon to give users an idea of what's in there.

Proposal: More config for the dropdown

The syntax I propose is as follows:

{
	label: 'Insert',
	icon: 'plus',
	items: [ ... ]
},

but there could be extra fields like withText so the dropdown' looks

image

instead of

image

Proposal: Advanced atomic toolbar item config

To avoid having multiple components registered by a feature just to have one with a label and the other without it, I think we could have advanced configuration format for toolbar items:

toolbar: [
	// ...
	
	{ name: 'sourceEditing', withText: false, otherOption: ... }
	
	// ...
]

This should be pretty straightforward. When ToolbarView uses component factory to create a component named sourceEditing

https://github.com/ckeditor/ckeditor5/blob/e86c4029b1b4ea184f2451f23b24ce603afead55/packages/ckeditor5-ui/src/toolbar/toolbarview.js#L359-L369

it will then call

const component = factory.create( name );

if ( component instanceof DropdownView ) {
	component.set( component.buttonView, options );
} else if ( component instanceof ButtonView ) {
	component.set( component, options );
}

to set options passed in the config. Since things like withText or tooltip or label are observable properties of ButtonView, this will simply use the public API to customize the component.

Note: It will fail if the component has these properties bound to some external state/model but for many cases this should work.


If you'd like to see this feature implemented, add a 👍 reaction to this post.

oleq avatar Sep 20 '22 08:09 oleq